一种简陋的CC1100/CC1101主从通信协议

/* 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协议,这个协议没仔细看,不过感觉还是有些复杂的,而且资料不是太多,这也是促使自己编写简单协议的原因


  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值