/* forsakening @hdu 2013/6/18 */
/* 版权所有~~^ _ ^ */
---------------------------------------------------------------------------------------------------------------------------
花了有15个小时完成的,还不够完善,写的很慢而且不够完善,逻辑性不够强,就当练手吧,握手,linux下的signal的应用
验证完全可用,将下述文件拷贝成独立文件即可,或者至
http://download.csdn.net/detail/forsakening/5604931 下载~
菜鸟一个,只是自己的一个学习记录~若能有幸帮到别人,荣幸之至~^ _ ^
---------------------------------------------------------------------------------------------------------------------------
介绍:
1. 首先说一下需求:CC1101无线模块(51MCU的spi方式驱动),区分主从节点,主节点发送数据与命令,从节点接收与响应,主节点可以和特定的从节点通信,面向连接通信(带握手)
2. 解决思路:实现一简单的私有主从通信协议
3. 协议简介:private_cc1101(private_cc, pcc姑且这么叫吧~~)
a)协议帧(由于CC1101的发送缓冲有64字节,所以定义PCC帧长度为64字节,固定)
* PRIVATE_CC FRAME:
* ---------------------------------------------------------------------------------------------
* PROTOCOL | TYPE | ADDRESS | FRAME_TYPE | SUB_FRAME_TYPE | PAYLOAD
* ----------|---------|-----------|--------------|------------------|----------------------
* PROTOCOL | Ser2Cli | SrcAddr | CMD | E_CMD | USER_CMD | Real_Value
* | Cli2Ser | DstAddr | ACK | E_ACK | |
* -----------------------------------------------------------------------------------------
各字段含义:
PROTOCOL:协议名称,用于区分不同协议,定义为0XCC1101
TYPE:类型,是server to client类型还是client to server类型,代码中用枚举实现
ADDRESS:地址,分为源地址和目的地址
FRAME_TYPE:分为CMD和ACK两种类型,CMD为命令,ACK为对应的响应类型
SUB_FRAME_TYPE:具体区分CMD和ACK
PAYLOAD:负载,分为USER_CMD和Real_Value字段
b)操作规程:
b.1)主节点发送CMD_InitLink命令,以通知所有从节点建立和主节点的链接,主要用于初始化,这里的链接都是面向连接方式,带有简单握手;
从节点在收到CMD_InitLink后,需要发送ACK_InitLink命令以通知主节点本身已收到命令,主节点无需重复发送
若从节点不返回ACK_InitLink,主节点重复发送CMD_InitLink命令,当超过一定次数,返回失败,超时
b.2)主节点发送CMD_UserCmd命令,发送给对应的从节点命令
从节点收到CMD_UserCmd后立即返回ACK_UserCmd命令,以通知主节点本身已收到命令,主节点无需重复发送该命令(因为从节点对命令进行响应需要时间,所以此次返回只是告知主节点已经收到该命令,具体的real_value由从节点主动发送)
从节点处理完成数据后,发送给主节点ACK_UserCmd_Ret命令,这个才是真正主节点需要的数据
主节点收到ACK_UserCmd_Ret命令后,也返回给从ACK_UserCmd_Ret命令,以通知从节点本身已收到命令,从节点无需重复发送
协议CODE:
实现及模拟在linux系统下:
[root@zx signal]# uname -a
Linux zx 2.6.27.5-117.fc10.i686 #1 SMP Tue Nov 18 12:19:59 EST 2008 i686 i686 i386 GNU/Linux
包括以下文件:
协议本身:pcc_client.c pcc_server.c server pcc_common.c private_cc.h
linux下测试:test_client.c test_server.c
makefile文件:Makefile
协议:
private_cc.h
/* forsakening @hdu 2013/6/17 */
/*
* PRIVATE_CC FRAME:
* ---------------------------------------------------------------------------------------------
* PROTOCOL | TYPE | ADDRESS | FRAME_TYPE | SUB_FRAME_TYPE | PAYLOAD
* ----------|---------|-----------|--------------|------------------|----------------------
* PROTOCOL | Ser2Cli | SrcAddr | CMD | E_CMD | USER_CMD | Real_Value
* | Cli2Ser | DstAddr | ACK | E_ACK | |
* -----------------------------------------------------------------------------------------
*/
/************************************************************************************/
/* PROTOCOL 协议号 */
#define PCC_PROTOCOL 0xCC1101
typedef unsigned int PROTOCOL;
/* TYPE */
typedef enum eType
{
Ser2Cli = 0,
Cli2Ser,
}PCC_TYPE;
/* ADDRESS: 1字节,0表示主节点,1-254表示从节点,255表示广播地址 */
typedef struct stPCC_ADDRESS
{
unsigned char srcaddr;
unsigned char dstaddr;
}PCC_ADDRESS;
/* FRAME_TYPE 是CMD类型的帧还是ACK类型的帧 */
typedef enum eFRAME_TYPE
{
CMD = 0,
ACK,
}PCC_FRAME_TYPE;
/* SUB_FRAME_TYPE 具体的命令字 */
typedef enum eSUB_FRAME_TYPE_CMD
{
CMD_InitLink = 0, /* 用于主节点初始化link */
CMD_UserCmd, /* 用户命令 */
}PCC_SUB_FRAME_TYPE_CMD;
/*
* ACK_UserCmd代表响应用户命令本身,因为处理用户数据本身需要一定的时间?
* 为了不与timeout冲突,采取这种方法:当发送用户命令的时候,接收端响应一个ACK_UserCmd,通知发送端不要重复发送这条命令,
* 接收端发送ACK_UserCmd后,真正的处理用户命令,处理完成后发送ACK_UserCmd_Ret命令以告知发送端真实的处理数据
*/
typedef enum eSUB_FRAME_TYPE_ACK
{
ACK_InitLink = 0,
ACK_UserCmd,
ACK_UserCmd_Ret,
}PCC_SUB_FRAME_TYPE_ACK;
typedef union tagSUB_FRAME_TYPE
{
PCC_SUB_FRAME_TYPE_CMD subtype_cmd;
PCC_SUB_FRAME_TYPE_ACK subtype_ack;
}SUB_FRAME_TYPE;
/* PAYLOAD用户数据负载 */
#define MAX_REAL_PAYLOAD_SIZE 42
//typedef unsigned char PAYLOAD[MAX_PAYLOAD_SIZE];
/* 用户命令 */
typedef enum tagUSER_CMD
{
USER_CMD_NULL = 0,
USER_CMD_ECHO,
USER_CMD_RESET,
}PCC_USER_CMD;
typedef struct tagPCC_PAYLOAD
{
PCC_USER_CMD user_cmd;
unsigned char real_payload[MAX_REAL_PAYLOAD_SIZE];
}PCC_PAYLOAD;
/* sizeof(PCC_FRAME) = 64 */
#ifdef LINUX_DEBUG
#pragma pack(1)
#endif
typedef struct tag_PCC_FRAME
{
PROTOCOL protocol; /* 4字节 */
PCC_TYPE type; /* 4字节 */
PCC_ADDRESS address; /* 2字节 */
PCC_FRAME_TYPE frame_type; /* 4字节 */
SUB_FRAME_TYPE subtype; /* 4字节 */
PCC_PAYLOAD payload; /* 46字节 */
}PCC_FRAME;
#ifdef LINUX_DEBUG
#pragma pack()
#endif
/***************************************************/
/* 变量声明 */
/***************************************************/
#ifndef LINUX_DEBUG
#define NULL (void *)0
#endif
#define RESEND_CNT 3 /* 重发次数 */
/***************************************************/
/* 公用函数声明 */
/***************************************************/
/* 构建PCC的一帧 */
void build_frame(PCC_FRAME *frame, PCC_TYPE type, PCC_ADDRESS address, PCC_FRAME_TYPE frame_type,
SUB_FRAME_TYPE sub_frame_type, PCC_USER_CMD user_cmd, unsigned char *ucUserData, unsigned int len);
/* pcc帧清0 */
void frame_clear(PCC_FRAME *frame);
/* 解析报文 */
void dispatchFrame(unsigned char *rcvbuf);
/* 启动定时器 */
void timeout_start(void);
/* 处理定时器 */
void handle_timeout(void);
/* 加解码帧 */
void encode(unsigned char*);
void decode(unsigned char*);
/* 面向连接的发送:除非收到ack报文,否则会重复发送 */
void link_send(PCC_FRAME *frame);
/* 面向连接的发送成功 提示消息 */
void link_send_success(void);
void link_send_failed(void);
/* 发送PCC的一帧 */
void send_frame(PCC_FRAME *frame);
void receive_frame(unsigned char *rcvbuf, int fd);
/* 主节点端建立link */
void server_init_link(void);
/* 简单延时 */
void pcc_simple_delay(void);
/* client根据标志位处理usercmd */
void client_handle_user_cmd(void);
#ifdef LINUX_DEBUG
void print_pcc_frame(PCC_FRAME *frame);
void test_user_cmd_echo(void);
#endif
pcc_common.c(主从公用文件)
#include "private_cc.h"
#ifdef LINUX_DEBUG
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
extern int send_fd;
const char server_send_buffer_name[] = "server_send_buffer";
#endif
/* 桩函数 */
void send(unsigned char* sendbuf, int len) { return; }
void receive(unsigned char* rcvbuf, int len) { return; }
void decode(unsigned char* rcvbuf) { return; }
/* 内存拷贝函数 */
void simple_memcpy(unsigned char *dst, unsigned char *src, int len)
{
int i = 0;
while(i < len)
{
dst[i] = src[i];
i++;
}
return ;
}
/* pcc帧清0 */
void frame_clear(PCC_FRAME *frame)
{
unsigned char *tmp = (unsigned char *)frame;
unsigned char size = sizeof(PCC_FRAME);
int i = 0;
for(; i < size; i++)
tmp[i++] = 0;
return;
}
/* 构建PCC的一帧 */
void build_frame(PCC_FRAME *frame, PCC_TYPE type, PCC_ADDRESS address, PCC_FRAME_TYPE frame_type,
SUB_FRAME_TYPE sub_frame_type, PCC_USER_CMD user_cmd, unsigned char *ucUserData, unsigned int len)
{
frame->protocol = PCC_PROTOCOL;
frame->type = type;
frame->address.srcaddr = address.srcaddr;
frame->address.dstaddr = address.dstaddr;
frame->frame_type = frame_type;
frame->subtype = sub_frame_type;
frame->payload.user_cmd = user_cmd;
simple_memcpy((unsigned char*)&(frame->payload.real_payload), ucUserData, len);
#ifdef LINUX_DEBUG
printf("--------\nFuntion build_frame:\n--------\n");
print_pcc_frame(frame);
#endif
return;
}
#ifdef LINUX_DEBUG
void print_pcc_frame(PCC_FRAME *frame)
{
#if 0
printf("PROTOCOL:%4x ", frame->protocol);
//printf("TYPE:%s\n", (frame->type) ? "Cli2Ser" : "Ser2Cli");
printf("TYPE:%4d ", frame->type);
printf("SRCADDR:%4d ", (unsigned int)(frame->address.srcaddr));
printf("DSTADDR:%4d ", (unsigned int)(frame->address.dstaddr));
printf("FRAME_TYPE:%4d \n--------\n", frame->frame_type);
#endif
printf("%8s ", "PROTOCOL:");
printf("%8s ", "TYPE:");
printf("%8s ", "SRCADDR:");
printf("%8s ", "DSTADDR:");
printf("%8s ", "FRAME_TYPE:");
printf("%8s ", "SUB_FRAME_TYPE:");
printf(" %8s\n-------------------------------------------------------------------------------------\n", "PAY_LOAD");
printf("%8X ", frame->protocol);
printf("%8d ", frame->type);
printf("%8d ", (unsigned int)(frame->address.srcaddr));
printf("%8d ", (unsigned int)(frame->address.dstaddr));
printf("%8d ", frame->frame_type);
printf("%8d ", (frame->frame_type) ? (frame->subtype.subtype_ack) : (frame->subtype.subtype_cmd));
printf(" %s%d | ", "USER_CMD:", frame->payload.user_cmd);
printf("Real_Value:%s\n", (unsigned char*)&(frame->payload.real_payload));
}
#endif
/* 发送PCC的一帧 */
void send_frame(PCC_FRAME *frame)
{
int len = sizeof(PCC_FRAME);
#ifdef LINUX_DEBUG
int n;
n = write(send_fd, (unsigned char*)frame, len);
printf("--------\nFunction send_frame:\n--------\n");
print_pcc_frame(frame);
#else
send((unsigned char*)frame, len);
#endif
return;
}
/* 简单延时 */
void pcc_simple_delay(void)
{
int i = 20000000;
for (; i > 0; i--)
{
}
if (0 == i)
return;
}
/*
* 接收报文处理函数:
* 响应中断后,从buffer里面读取接收到得数据,然后进行数据包的处理
* 解析是否符合PCC协议,符合则处理,不符合则丢弃
*/
void receive_frame(unsigned char *rcvbuf, int fd)
{
int len = sizeof(PCC_FRAME);
#ifdef LINUX_DEBUG
int n;
n = read(fd, (unsigned char*)rcvbuf, len);
printf("--------\nFunction receive_frame:\n--------\n");
print_pcc_frame((PCC_FRAME *)rcvbuf);
/* 获取之后需要将server_buffer清空,相当于关中断 */
#ifdef LINUX_DEBUG_SERVER
printf("server clear server_rcv_buffer!\n");
system("> server_rcv_buffer");
#endif
#ifdef LINUX_DEBUG_CLIENT
printf("client clear %s...\n", server_send_buffer_name);
system("> server_send_buffer");
#endif
#else
receive(rcvbuf, len);
#endif
dispatchFrame(rcvbuf);
}
/* 启动定时器 */
unsigned int timeout_para;
unsigned int timeout_flag;
void timeout_start(void)
{
timeout_para = 20000000;
timeout_flag = 1;
while(timeout_para > 0)
{
timeout_para--;
}
return;
}
/* 处理定时器 */
void handle_timeout(void)
{
timeout_flag = 0;
return;
}
/* 面向连接的发送:除非收到ack报文,否则会重复发送 */
void link_send(PCC_FRAME *frame)
{
#ifdef LINUX_DEBUG
printf("--------\nFunction link_send:\n");
#endif
int resend_cnt = 0;
for(; resend_cnt < RESEND_CNT; resend_cnt++)
{
send_frame(frame);
/* 启动定时器 */
timeout_start();
/* 未超时则break */
if (0 == timeout_flag)
{
/* 若面向连接的发送成功,显示打印,或者LED亮灯 */
link_send_success();
break;
}
}
if (RESEND_CNT == resend_cnt)
{
/* 若重发次数超过最大次数,则说明失败,显示打印,或者LED亮灯 */
/* ... */
#ifdef LINUX_DEBUG
printf("Over the max resend cnt!\n");
#endif
}
return;
}
void link_send_success(void)
{
/* 打印或者LED亮灯...以提示发送成功 */
#ifdef LINUX_DEBUG
printf("link_send_success!\n");
#endif
return;
}
void link_send_failed(void)
{
/* 打印或者LED亮灯...以提示发送失败 */
#ifdef LINUX_DEBUG
printf("link_send_failed!\n");
#endif
return;
}
pcc_server.c(主节点文件)
/* server节点处理文件,也即主节点的处理 */
#ifdef LINUX_DEBUG_SERVER
#ifdef LINUX_DEBUG
#include <stdio.h>
#endif
#include "private_cc.h"
#define client_number 3
#define server_addr (unsigned char)0
unsigned char client_addr[client_number] = {1, 2, 3};
/* 发送的帧,定义为全局变量,初始化为0 */
static PCC_FRAME frame_send;
/* 主节点端建立link */
void server_init_link(void)
{
int i = 0 ;
PCC_ADDRESS address;
address.srcaddr = server_addr;
SUB_FRAME_TYPE sub_frame_type;
sub_frame_type.subtype_cmd = CMD_InitLink;
for (; i < client_number; i++)
{
frame_clear(&frame_send);
address.dstaddr = client_addr[i];
/* 建立CMD_INIT报文 */
build_frame(&frame_send, Ser2Cli, address, CMD, sub_frame_type, USER_CMD_NULL, NULL, 0);
/* 面向连接的发送 */
link_send(&frame_send);
}
}
/* 主节点侧的解析报文 */
void dispatchFrame(unsigned char *rcvbuf)
{
#ifdef LINUX_DEBUG
printf("server dispatchFrame!\n--------\n");
#endif
decode(rcvbuf);
/* 强制转换为PCC格式 */
PCC_FRAME *frame = (PCC_FRAME *)rcvbuf;
/* 接收数据的处理 */
if (PCC_PROTOCOL != frame->protocol)
{
#ifdef LINUX_DEBUG
printf("server dispatchFrame PCC_PROTOCOL error!\n--------\n");
#endif
return;
}
if (Cli2Ser != frame->type)
{
#ifdef LINUX_DEBUG
printf("server dispatchFrame Cli2Ser error!\n--------\n");
#endif
return;
}
if (server_addr != frame->address.dstaddr)
{
#ifdef LINUX_DEBUG
printf("server dispatchFrame server_addr error!\n--------\n");
#endif
return;
}
/* 处理到这步应该可以确认是正确的PCC报文 */
PCC_FRAME_TYPE frame_type = frame->frame_type;
SUB_FRAME_TYPE subtype = frame->subtype;
switch (frame_type)
{
/* 处理CMD命令 */
case CMD:
{
/* 目前为止主节点不会处理CMD命令,只处理ACK命令 @2013/6/17 */
if (CMD_InitLink == subtype.subtype_cmd)
{
return ;
}
if (CMD_UserCmd == subtype.subtype_cmd)
{
return ;
}
}
/* 处理ACK命令 */
case ACK:
{
/* 接收到从节点返回的ack */
if (ACK_InitLink == subtype.subtype_ack)
{
/* 接收到ack则处理定时器:此时说明从节点确实受到主节点发送的cmd_init命令 */
printf("server ACK_InitLink OK!\n");
handle_timeout();
return ;
}
if(ACK_UserCmd == subtype.subtype_ack)
{
/* 接收到ack则处理定时器:此时说明从节点确实受到主节点发送的USERCMD命令 */
printf("server ACK_UserCmd OK!\n");
handle_timeout();
return ;
}
if (ACK_UserCmd_Ret == subtype.subtype_ack)
{
/* 接收到从节点发来的真实处理数据后,立马返回一个ACK_UserCmd_Ret,通知从节点不再继续发送 */
frame->address.dstaddr = frame->address.srcaddr;
frame->address.srcaddr = server_addr;
frame->type = Ser2Cli;
send_frame(frame);
return ;
}
}
/* 其余情况出错 */
default:
return;
}
return ;
}
#ifdef LINUX_DEBUG
void test_user_cmd_echo(void)
{
printf("--------\nStart Test USER_CMD_ECHO:--------\n");
/* 建立USER_CMD_ECHO报文 */
PCC_ADDRESS address;
address.dstaddr = 3;
address.srcaddr = server_addr;
SUB_FRAME_TYPE sub_frame_type;
sub_frame_type.subtype_cmd = CMD_UserCmd;
frame_clear(&frame_send);
build_frame(&frame_send, Ser2Cli, address, CMD, sub_frame_type, USER_CMD_ECHO, NULL, 0);
send_frame(&frame_send);
printf("--------\nEnd Test USER_CMD_ECHO:--------\n");
}
#endif
#endif
pcc_client.c(从节点文件)
/* file pcc_client.c forsakening @hdu 2013/6/17 */
#ifdef LINUX_DEBUG_CLIENT
#ifdef LINUX_DEBUG
#include <stdio.h>
extern int send_fd;
#endif
#include "private_cc.h"
/* 不同的从节点这里需要修改 */
#define server_addr (unsigned char)0
//#define client_addr (unsigned char)1
unsigned char client_addr;
static PCC_FRAME frame_send;
PCC_USER_CMD flag_user_cmd;
/* 从节点侧的解析报文,从中断中调用 */
void dispatchFrame(unsigned char *rcvbuf)
{
#ifdef LINUX_DEBUG
printf("client dispatchFrame!\n--------\n");
#endif
/* 解码整个报文 */
decode(rcvbuf);
/* 强制转换为PCC格式 */
PCC_FRAME *frame = (PCC_FRAME *)rcvbuf;
/* 验证是否符合PCC */
if (PCC_PROTOCOL != frame->protocol)
{
#ifdef LINUX_DEBUG
printf("client dispatchFrame PCC_PROTOCOL error!\n--------\n");
#endif
return;
}
if (Ser2Cli != frame->type)
{
#ifdef LINUX_DEBUG
printf("client dispatchFrame Ser2Cli error!\n--------\n");
#endif
return;
}
if (((unsigned char)server_addr != frame->address.srcaddr) ||
((unsigned char)client_addr != frame->address.dstaddr))
{
#ifdef LINUX_DEBUG
printf("client dispatchFrame addr error!\n--------\n");
#endif
return;
}
/* 处理到这步应该可以确认是正确的PCC报文,继续处理命令 */
PCC_FRAME_TYPE frame_type = frame->frame_type;
SUB_FRAME_TYPE subtype = frame->subtype;
PCC_ADDRESS address;
SUB_FRAME_TYPE sub_frame_type;
switch (frame_type)
{
/* 处理CMD命令 */
case CMD:
{
if (CMD_InitLink == subtype.subtype_cmd)
{
/* 从节点收到CMD_InitLink后发送ACK_InitLink给主节点 */
frame_clear(&frame_send);
address.dstaddr = server_addr;
address.srcaddr = client_addr;
sub_frame_type.subtype_ack = ACK_InitLink;
build_frame(&frame_send, Cli2Ser, address, ACK, sub_frame_type, USER_CMD_NULL, NULL, 0);
#ifdef LINUX_DEBUG
printf("client send frame:\n--------\n");
#endif
send_frame(&frame_send);
return ;
}
if (CMD_UserCmd == subtype.subtype_cmd)
{
/* 从节点收到CMD_UserCmd后发送ACK_UserCmd给主节点,以告知主节点不用继续发送命令字 */
#ifdef LINUX_DEBUG
printf("client receive CMD_UserCmd, now send ack...\n");
#endif
frame_clear(&frame_send);
address.dstaddr = server_addr;
address.srcaddr = client_addr;
sub_frame_type.subtype_ack = ACK_UserCmd;
build_frame(&frame_send, Cli2Ser, address, ACK, sub_frame_type, USER_CMD_NULL, "Client_Ack_CMD_UserCmd", 40);
send_frame(&frame_send);
PCC_USER_CMD user_cmd = frame->payload.user_cmd;
/* 置处理标志位 */
switch(user_cmd)
{
case USER_CMD_ECHO:
flag_user_cmd = USER_CMD_ECHO;
break;
case USER_CMD_RESET:
flag_user_cmd = USER_CMD_RESET;
break;
default:
flag_user_cmd = USER_CMD_NULL;
break;
}
return ;
}
}
/* 目前为止从节点只处理ACK_UserCmd_Ret @2013/6/17 */
case ACK:
{
if (ACK_InitLink == subtype.subtype_ack)
{
return;
}
if(ACK_UserCmd == subtype.subtype_ack)
{
return ;
}
if (ACK_UserCmd_Ret == subtype.subtype_ack)
{
#ifdef LINUX_DEBUG
printf("server ack ACK_UserCmd_Ret!\n");
#endif
handle_timeout();
return ;
}
}
/* 其余情况出错 */
default:
return;
}
}
static void client_handler_user_cmd_echo(void)
{
PCC_ADDRESS address;
address.dstaddr = server_addr;
address.srcaddr = client_addr;
SUB_FRAME_TYPE sub_frame_type;
sub_frame_type.subtype_ack = ACK_UserCmd_Ret;
frame_clear(&frame_send);
build_frame(&frame_send, Cli2Ser, address, ACK, sub_frame_type, USER_CMD_ECHO, "This is from client", 20);
/* 发送用户数据用link_send */
pcc_simple_delay();
link_send(&frame_send);
}
static void client_handler_user_cmd_reset(void)
{
#if 0
PCC_ADDRESS address;
address.dstaddr = server_addr;
address.srcaddr = client_addr;
SUB_FRAME_TYPE sub_frame_type;
sub_frame_type.subtype_ack = ACK_UserCmd_Ret;
frame_clear(&frame_send);
build_frame(&frame_send, Cli2Ser, address, ACK, sub_frame_type, USER_CMD_ECHO, "this is from client", 20);
/* 由于之前已经建立link 所以应该不会出错,发送后主节点应该可以确定收到,不再继续发送命令字 */
link_send(&frame_send);
#endif
}
/* client根据标志位处理usercmd */
void client_handle_user_cmd(void)
{
if ( USER_CMD_NULL != flag_user_cmd )
{
#ifdef LINUX_DEBUG
printf("start int client_handle_user_cmd and flag_user_cmd is :%d\n", flag_user_cmd);
#endif
switch (flag_user_cmd)
{
case USER_CMD_ECHO:
/* 处理USER_CMD_ECHO */
#ifdef LINUX_DEBUG
printf("client_handle_user_cmd: USER_CMD_ECHO\n");
#endif
client_handler_user_cmd_echo();
break;
case USER_CMD_RESET:
/* 处理USER_CMD_RESET */
client_handler_user_cmd_reset();
break;
default:
break;
}
}
flag_user_cmd = USER_CMD_NULL;
}
#endif
linux测试文件:
test_server.c
/* file test_server.c forsakening @hdu 2013/6/17 */
#include "private_cc.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
static PCC_FRAME frame_rcv;
int rcv_fd;
int send_fd;
/* 用于监视server_buffer是否有数据,有数据则向父进程发送signal */
void server_child(void)
{
int ppid = getppid();
printf("father id is: %d\n", ppid);
int n, fd;
if((fd = open("server_rcv_buffer",O_RDONLY | O_CREAT)) < 0)
{
fprintf(stderr,"child: fail to open %s : %s.\n","server_buffer",strerror(errno));
return ;
}
char buf[sizeof(PCC_FRAME)];
while (1)
{
n = read(fd,buf,sizeof(PCC_FRAME));
if (0 < n)
{
kill(ppid, SIGUSR2);
}
}
}
/* 模拟CC芯片的中断处理程序 */
void father_signal_process(int signum)
{
if(signum == SIGUSR2)
{
printf("Receive signal SIGUSR2 & start into interrupt:\n--------\n");
frame_clear(&frame_rcv);
receive_frame((unsigned char *)&frame_rcv, rcv_fd);
}
}
void server_father(void)
{
if((rcv_fd = open("server_rcv_buffer",O_RDONLY)) < 0)
{
fprintf(stderr,"father: fail to open %s : %s.\n","server_buffer",strerror(errno));
return ;
}
signal(SIGUSR2, father_signal_process);
}
extern const char server_send_buffer_name[];
int main(int argc, char *argv[])
{
int pid;
if((pid = fork()) < 0)
{
perror("Fail to fork");
exit(EXIT_FAILURE);
}
else if(pid == 0)
{
/* 子进程负责实时查询fifo是否有数据 */
server_child();
}
else
{
printf("child id is: %d\n", pid);
if((send_fd = open((const char*)server_send_buffer_name, O_WRONLY | O_CREAT)) < 0)
{
fprintf(stderr,"father: fail to open %s : %s.\n",server_send_buffer_name,strerror(errno));
return 1;
}
server_father();
server_init_link();
/* 测试USER_CMD_ECHO */
test_user_cmd_echo();
while(1);
}
return 0;
}
test_client.c
/* file test_client.c forsakening @hdu 2013/6/17 */
#ifdef LINUX_DEBUG
#include "private_cc.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
extern const char server_send_buffer_name[];
static PCC_FRAME frame_rcv;
int send_fd;
int rcv_fd;
/* 用于监视server_send_buffer是否有数据,有数据则向父进程发送signal */
void client_child(void)
{
int ppid = getppid();
printf("father id is: %d\n", ppid);
int n, fd;
if((fd = open(server_send_buffer_name, O_RDONLY)) < 0)
{
fprintf(stderr,"child: fail to open %s : %s.\n",server_send_buffer_name, strerror(errno));
return ;
}
char buf[sizeof(PCC_FRAME)];
while (1)
{
n = read(fd,buf,sizeof(PCC_FRAME));
if (0 < n)
{
kill(ppid, SIGUSR2);
}
}
}
void client_signal_process(int signum)
{
if(signum == SIGUSR2)
{
printf("Receive signal SIGUSR2 & start into interrupt:\n--------\n");
receive_frame((unsigned char *)&frame_rcv, rcv_fd);
}
}
void client_father(void)
{
if((rcv_fd = open(server_send_buffer_name,O_RDONLY)) < 0)
{
fprintf(stderr,"father: fail to open %s : %s.\n",server_send_buffer_name,strerror(errno));
return ;
}
signal(SIGUSR2, client_signal_process);
}
extern unsigned char client_addr;
extern PCC_USER_CMD flag_user_cmd;
int main(int argc, char *argv[])
{
client_addr = (char)*(argv[1]) - '0';
printf("client_addr is %d\n", (unsigned int)client_addr);
int pid;
if((pid = fork()) < 0)
{
perror("Fail to fork");
exit(EXIT_FAILURE);
}
else if(pid == 0)
{
/* 子进程负责实时查询fifo是否有数据 */
client_child();
}
else
{
printf("child id is: %d\n", pid);
if((send_fd = open("server_rcv_buffer",O_WRONLY | O_CREAT)) < 0)
{
fprintf(stderr,"father: fail to open %s : %s.\n","server_rcv_buffer",strerror(errno));
return 1;
}
client_father();
while(1)
{
client_handle_user_cmd();
}
}
return 0;
}
#endif
Makefile:
all:server client
server:
gcc -Wall pcc_common.c pcc_server.c test_server.c *.h -DLINUX_DEBUG -DLINUX_DEBUG_SERVER -o server
client:
gcc -Wall pcc_common.c pcc_client.c test_client.c *.h -DLINUX_DEBUG -DLINUX_DEBUG_CLIENT -o client
clean:
rm -rf *.o server client
测试:
step1编译:
[root@zx private_cc]# make clean
rm -rf *.o server client
[root@zx private_cc]# make all
gcc -Wall pcc_common.c pcc_server.c test_server.c *.h -DLINUX_DEBUG -DLINUX_DEBUG_SERVER -o server
gcc -Wall pcc_common.c pcc_client.c test_client.c *.h -DLINUX_DEBUG -DLINUX_DEBUG_CLIENT -o client
pcc_client.c: 在函数‘dispatchFrame’中:
pcc_client.c:98: 警告:传递‘build_frame’的参数 7 给指针时,目标与指针符号不一致
pcc_client.c: 在函数‘client_handler_user_cmd_echo’中:
pcc_client.c:160: 警告:传递‘build_frame’的参数 7 给指针时,目标与指针符号不一致
[root@zx private_cc]#
step2:输入以下命令,用于创建server_send_buffer(这个文件用于模拟cc芯片的发送缓存)
[root@zx private_cc]# touch server_send_buffer
[root@zx private_cc]# ls
client pcc_client.c pcc_server.c server server_send_buffer test_client.c
Makefile pcc_common.c private_cc.h server_rcv_buffer si_prj test_server.c
[root@zx private_cc]# > server_send_buffer
[root@zx private_cc]#
step3:在两个终端窗口分别运行./client 3 和 ./server 命令(3代表节点的地址),一定要先执行client
[root@zx private_cc]# ./client 3
client_addr is 3
father id is: 8432
child id is: 8433
step4:执行./server命令后,出现下列信息:
client的窗口:
[root@zx private_cc]# ./client 3
client_addr is 3
father id is: 8448
child id is: 8449
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 1 0 0 USER_CMD:0 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
client dispatchFrame addr error!
--------
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 1 0 0 USER_CMD:0 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
client dispatchFrame addr error!
--------
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 1 0 0 USER_CMD:0 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
client dispatchFrame addr error!
--------
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 2 0 0 USER_CMD:0 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
client dispatchFrame addr error!
--------
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 2 0 0 USER_CMD:0 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
client dispatchFrame addr error!
--------
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 2 0 0 USER_CMD:0 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
client dispatchFrame addr error!
--------
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 0 0 USER_CMD:0 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
--------
Funtion build_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 0 USER_CMD:0 | Real_Value:
client send frame:
--------
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 0 USER_CMD:0 | Real_Value:
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 0 1 USER_CMD:1 | Real_Value:
client clear server_send_buffer...
client dispatchFrame!
--------
client receive CMD_UserCmd, now send ack...
--------
Funtion build_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 1 USER_CMD:0 | Real_Value:Client_Ack_CMD_UserCmd
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 1 USER_CMD:0 | Real_Value:Client_Ack_CMD_UserCmd
start int client_handle_user_cmd and flag_user_cmd is :1
client_handle_user_cmd: USER_CMD_ECHO
--------
Funtion build_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 2 USER_CMD:1 | Real_Value:This is from client
--------
Function link_send:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 2 USER_CMD:1 | Real_Value:This is from client
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 1 2 USER_CMD:1 | Real_Value:This is from client
client clear server_send_buffer...
client dispatchFrame!
--------
server ack ACK_UserCmd_Ret!
link_send_success!
server的窗口:
[root@zx private_cc]# ./server
father id is: 8450
child id is: 8451
--------
Funtion build_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 1 0 0 USER_CMD:0 | Real_Value:
--------
Function link_send:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 1 0 0 USER_CMD:0 | Real_Value:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 1 0 0 USER_CMD:0 | Real_Value:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 1 0 0 USER_CMD:0 | Real_Value:
Over the max resend cnt!
--------
Funtion build_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 2 0 0 USER_CMD:0 | Real_Value:
--------
Function link_send:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 2 0 0 USER_CMD:0 | Real_Value:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 2 0 0 USER_CMD:0 | Real_Value:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 2 0 0 USER_CMD:0 | Real_Value:
Over the max resend cnt!
--------
Funtion build_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 0 0 USER_CMD:0 | Real_Value:
--------
Function link_send:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 0 0 USER_CMD:0 | Real_Value:
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 0 USER_CMD:0 | Real_Value:
server clear server_rcv_buffer!
server dispatchFrame!
--------
server ACK_InitLink OK!
link_send_success!
--------
Start Test USER_CMD_ECHO:--------
--------
Funtion build_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 0 1 USER_CMD:1 | Real_Value:
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 0 1 USER_CMD:1 | Real_Value:
--------
End Test USER_CMD_ECHO:--------
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 1 USER_CMD:0 | Real_Value:Client_Ack_CMD_UserCmd
server clear server_rcv_buffer!
server dispatchFrame!
--------
server ACK_UserCmd OK!
Receive signal SIGUSR2 & start into interrupt:
--------
--------
Function receive_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 1 3 0 1 2 USER_CMD:1 | Real_Value:This is from client
server clear server_rcv_buffer!
server dispatchFrame!
--------
--------
Function send_frame:
--------
PROTOCOL: TYPE: SRCADDR: DSTADDR: FRAME_TYPE: SUB_FRAME_TYPE: PAY_LOAD
-------------------------------------------------------------------------------------
CC1101 0 0 3 1 2 USER_CMD:1 | Real_Value:This is from client
后记:
1.之前一直有个问题:无线通信,若两个数据同时到达接收端的时候该如何处理呢?
其实,这个因为没有底层协议的原因,可以实现一个csma/cd协议来防止这种问题的出现,这个协议在以太网中处于数据链路层协议,在LLC协议之下,除了CSMA/CD外,还有FDMA,TDMA,FHSS等协议,都可以应用在CC1101上面,具体参见CC1110/CC2510无线单片机和无线自组织网络入门与实战/李文仲,段朝玉等编著一书
zigbee通信协议也是有csma/cd协议的~
2. TI公司有个SimpliciTi协议,这个协议没仔细看,不过感觉还是有些复杂的,而且资料不是太多,这也是促使自己编写简单协议的原因