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

/* 热火实现了卫冕,詹姆斯背负的骂名也渐渐少去,马刺和GDP的失利,让人无限唏嘘,失败者落寞的身影让人感叹岁月的无情,马刺王朝就此解体了吗,看着呆呆满脸和满眼的遗憾,心中竟不能替热火高兴,也许人们总是对“曾经”感到留恋,曾经离冠军只有5.2秒,但从天堂到地狱也只是5.2秒。。。戏剧化的让人以为这是一部电影,一部符合美国人胃口的电影,迫入绝境,然后峰回路转,诸葛波波最后换下呆呆让人觉着这是联盟干爹给热火的机会,但是如果阿伦不能进下那个救命球,那也是徒劳的,所以,我觉着这就是宿命,TIM-D已然证明了自己的老而弥坚,NBA史上最厉害的大前,这是毫无疑问的。我是热蜜,但不黑任何人,不明白为什么有些人会这么黑詹姆斯,就是因为打球比较丑陋?最好笑的是有人因为詹姆斯的天赋而恨他,恨他为什么打球不受伤(这里真要吐槽一下,球员受伤你心里就舒服是吧?),恨他为什么那么暴力,还拿凌晨四点钟的洛杉矶来暗喻着什么。。。真是无语,哪个牛逼的球员不是靠天赋去打球?乔丹不是公认的天赋最好的那个?。。。。。。。。。其实,不管你黑谁,密谁,当我们这代人逐渐退出社会舞台的时候,当人们回顾NBA历史时,邓肯,科比,詹姆斯都将是载入史册的人,恨与不恨,爱或不爱,这就是事实,NBA是个生意更是事实。最后想说一下,AV5频道出了一部小短片,大体意思说的就是“詹姆斯缺少一种超级巨星的气质,关键时刻舍我其谁的王者气质”,的确,关键时刻猩猩是有点不太相信自己,这是他需要加强的地方! forsakening @hdu 2013/6/22 */


还是说说上次自己写的CC1101无线通信协议吧,周一的时候完成了协议的主体部分,周二在LINUX下进行了模拟,大致上是没什么问题了,周三在具体的硬件上进行移植,主要是在CC1101无线模块和51mcu上面进行,这里遇到了不少麻烦,当天晚上留在了实验室搞到了3点,周四早晨8点多又开始搞,终于调通了,貌似时序上面有点不稳定,一直觉得是因为中断的原因,所以在周四晚上的时候又重新基于51mcu制定了一个逻辑性更强一点的方案,并且测试完全没问题,很稳定:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

主节点

主节点:51mcu + cc1101无线模块(当接收到数据的时候便会产生一个下降沿,用于和51mcu相连,产生外部中断)

主节点主要完成的工作:

1)发送CMD_Init命令,获取有多少从节点可以连接至主节点

2)发送CMD_UsrCmd命令,用户命令

这里面有个问题,就是cc1101在发送的时候无法保证其余的模块一定可以接收到这个数据,所以有了所谓“面向连接”一说,我的面向连接指的是:主节点发送一命令后,从节点必须对这个命令进行响应,否则的话主节点就一直发送这条命令,直至发送到最大重发次数为止。这里仿照了TCP协议的实现,用了一个seqno来标记每次发送的序号,只有收到当前seqno的响应,才算是一次正确的“面向”连接发送

还有一个主要修改的地方:主节点在发送命令之后,就开启接收中断,等待从节点发来的响应报文,而在其余时刻主节点的接收中断是处在关闭状态的。这也是51mcu ram较小的一种折中方法,否则进入中断深度过大的话,会产生程序跑飞重新启动mcu的问题。

主节点侧的“面向连接”发送:

/* 面向连接的发送:除非收到ack报文,否则会重复发送 */
unsigned int pcc_server_link_send(PCC_FRAME *frame, unsigned long time_init)
{	
	int resend_cnt = 0;    /* 重发次数 */

	/* STEP 1:切换主节点的状态,改变主节点的全局信息 */
	pcc_server_state_change(frame, SEND_FRAME);
	server_info.pcc_server_conn_address = frame->address.dstaddr;	

	putstring("pcc_server_link_send start......");
	putstring("--------------------------------");

	for (; resend_cnt < RESEND_CNT; resend_cnt++)
	{
		putstring_no_nr("pcc_server_link_send trying time:");
		put_hex(sizeof(resend_cnt), (resend_cnt + 1));
		putstring("......");

		/* 每次发送就增加一次seqno 以保证面向连接 */
		(server_info.pcc_server_seqno)++;
		frame->seqno = server_info.pcc_server_seqno;
		print_pcc_frame_flow(frame);
		
		/* STEP 2:在不超过最大重发次数情况下循环发送 */
		send_pack((unsigned char*)frame, sizeof(PCC_FRAME));

		/* STEP 3:开中断 */
		enable_int();

		/* STEP 4:启动定时器:这里定时器其实是一个软件延时,用于等待接收中断,若接收到响应报文,则跳出定时器,证明此次发送成功 */
		if (0 == linksend_timeout(time_init))
		{
			/* STEP 5:若超时了,则关中断后继续发送,知道超过重发次数 */
			disable_int();
			continue;
		}
		else
		{
			putstring_no_nr("pcc_server_link_send success, and resend_cnt:");
			put_hex(sizeof(resend_cnt), resend_cnt);
			putstring("......");
			return 1;
		}
	}

	/* STEP 6:大于重发次数,关中断并且打印提示信息 */
	if (RESEND_CNT == resend_cnt)
	{
		disable_int();
		putstring("pcc_server_link_send over max resend_cnt......");
		putstring("-----------------------------------------------");
		send_nr();
		return 0;
	}
	
	return 0;
}
/* 返回0代表超时,非0表示未超时 */
unsigned int linksend_timeout(unsigned long time_init)
{	
	unsigned int ret = 0;

	#ifdef DEBUG_51
	putstring("start linksend_timeout......");
	#endif
	
	while(time_init > 0)
	{
		time_init--;	

		/* 若接收到中断则去处理中断 */
		if (Rcv_Status)
		{
			if (pcc_server_handle_interrupt())
			{
				putstring_no_nr("handle_interrupt success, break timeout:");
				put_hex(sizeof(time_init), time_init);
				putstring("......");
				ret = 1;
				break;
			}				
		}
	}

	if (0 == time_init)
	{
		putstring("timeout......");
	}

	return ret;
}
/* 返回0表示非pccframe 或者 是不符合server侧的协议 */
unsigned int pcc_server_handle_interrupt(void)
{
	int ret = 0;
	/* 处理中断的时候要把中断先关掉 */
	disable_int();
	putstring("Start handle_interrupt ......");

	/* 这里进行处理接收到得数据 */
	/**********************************************/
	print_pcc_frame_flow((PCC_FRAME *)&frame_rcv);
	ret = pcc_server_dispatchFrame((unsigned char *)&frame_rcv);
	/**********************************************/

	putstring("End handle...");
	putstring("------------------------");
	send_nr();
	Rcv_Status = 0;

	return ret;
}
void exint1()  interrupt 2
{
	unsigned char len = BUF_LEN;
	
	if(halRfReceivePacket((unsigned char *)&frame_rcv, &len))
	{
		LED = ~LED;
		Rcv_Status = 1;	/* 中断处理不宜过长,只是标识一个标志位 */		
	}
}


从节点

从节点的话,更改后的方案:只用于接收报文,只有在处理中断的过程中,才关闭中断:

void pcc_client_handle_interrupt(void)
{
	/* 处理中断的时候要把中断先关掉,结束处理后再打开 */
	disable_int();
	putstring("Receive buffer...Start handling......");

	/* 这里进行处理接收到得数据 */
	/**********************************************/
	print_pcc_frame_flow((PCC_FRAME *)&frame_rcv);
	pcc_client_dispatchFrame((unsigned char *)&frame_rcv);
	/**********************************************/

	putstring("End handle...");
	putstring("------------------------");
	send_nr();
	Rcv_Status = 0;
	enable_int();	
}
/* 从节点侧的解析报文,从中断中调用 */
void pcc_client_dispatchFrame(unsigned char *rcvbuf)
{
	PCC_FRAME *frame;
	PCC_FRAME_TYPE frame_type;
	SUB_FRAME_TYPE subtype;
	PCC_ADDRESS address;
	SUB_FRAME_TYPE sub_frame_type;
//	PCC_USER_CMD flag_user_cmd;
	
	/* 强制转换为PCC格式 */
	frame = (PCC_FRAME *)rcvbuf;

	#ifdef DEBUG_51
	putstring("Client dispatchFrame......");
	#endif

	/* 验证是否符合PCC */
	if (PCC_PROTOCOL != frame->protocol)
	{
		putstring("client dispatchFrame PCC_PROTOCOL error!");
		return;	
	}
	
	if (Ser2Cli != frame->type)
	{
		putstring("client dispatchFrame Ser2Cli error!");
		return;	
	}
	
	if (((unsigned char)server_addr != frame->address.srcaddr) ||
		((unsigned char)client_addr != frame->address.dstaddr))
	{
		putstring("client dispatchFrame addr error!");
		return;	
	}

	/* 处理到这步应该可以确认是正确的PCC报文,继续处理命令 */
	frame_type = frame->frame_type;
	subtype = frame->subtype;

	switch (frame_type)
	{
		/* 处理CMD命令 */
		case CMD:
		{
			if (CMD_InitLink == subtype.subtype_cmd)
			{
				/* 从节点收到CMD_InitLink后发送ACK_InitLink给主节点 */
				putstring("client process CMD_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);
				frame_send.seqno = frame->seqno;

				send_pack((unsigned char *)&frame_send, sizeof(frame_send));

				return ;
			}
			
			if (CMD_UserCmd == subtype.subtype_cmd)
			{
				/* 从节点收到CMD_UserCmd后发送ACK_UserCmd给主节点,以告知主节点不用继续发送命令字 */	
				putstring("client process CMD_UserCmd......");
				frame_clear(&frame_send);

				address.dstaddr = server_addr;
				address.srcaddr = client_addr;
				sub_frame_type.subtype_ack = ACK_UserCmd;
				/********************************************************/
				/* 这里是对echo函数的真正响应,如读取温度值等 */
				/********************************************************/
				build_frame(&frame_send, Cli2Ser, address, ACK, sub_frame_type, USER_CMD_NULL, "12", 2);
				frame_send.seqno = frame->seqno;
				
				send_pack((unsigned char *)&frame_send, sizeof(frame_send));											
				return ;
			}
		}
		
		/* 目前为止从节点只处理ACK_UserCmd_Ret @2013/6/17 */
		case ACK:
		{
			if (ACK_InitLink == subtype.subtype_ack)
			{
				return;
			}

			
			if(ACK_UserCmd == subtype.subtype_ack)
			{
				return ;
			}
		}
		
		/* 其余情况出错 */
		default:
			return;
	}
}

后记

1)这个简单的主从无线通信协议呢,可以满足选址,以及可靠性的要求,虽然简陋,但五脏俱全。。。

2)通过写这么一个简单的主从协议,发现了自身的很多不足,其实本应该对整体方案有个充分的考虑的情况下再去动手敲代码,无奈对于51mcu已经忘的差不多了,对于中断的处理,时序上的考虑都不够完善,所以在协议自身的设计上一开始就存在缺陷,在code的过程中才慢慢发现,虽然对自身帮助挺大,但这其实非常的浪费时间。。。

3)From 2013/6/17 to 2013/6/20 with FeedBack。。。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值