/* 热火实现了卫冕,詹姆斯背负的骂名也渐渐少去,马刺和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。。。