|
Z-STACK 2006协议栈硬件驱动的精简
By kennan
(2010.11)
TI的zigbee协议栈Z-Stack因为考虑他公司自己软件维护以及多种类型处理器的兼容性问题,协议栈中关于硬件驱动部分写的非常晦涩难懂,很多新手往往在这些一层一层的#define中被转的晕头转向,还有的人手里的板子没有按钮,简单到只有1~2个led 灯和射频部分,针对TI公司 BB,DB,EB板的那些例子程序都无法在没有按键的板子上直接运行演示(TI的很多例子用joystick按钮来演示的,这个很多板子没有或者不兼容TI)。一直想对现有的协议栈硬件驱动部分进行一下精简,剥掉原有驱动对硬件寄存器的包装,让新手更容易在已有单片机基础上来理解和修改应用范例,尽快在手头的板子上运行例程,同时本人有机会自己练练手。
我手里有两块2430的板子,当时花了N多大洋买的,后悔啊。板子上只有射频基本电路,串口,以及接在P0_0和P0_1端口上的两个LED。再无别的按钮啊(对,还有一个复位按钮 ),液晶啊,摇杆啊,反正是统统地没有,相当地裸。本文档修改的目的是用最直接的方式来控制这两个LED端口和串口。其余关于多于的led,按钮之类的统统删除,搞就搞一个最简单的 。
修改以2006版本的1.4.3-1.2.1中的GenericApp为原始例程,以DB板为原型,精简硬件接口驱动部分程序,并将App任务精简到一个协调器建立网络之后定时向网络广播发送数据,其余节点(不管是router还是end device)则只是等待有广播数据接收,然后经串口送PC显示。(修改和读码我还是推荐配合使用source insight,否则。。。。 。)
一 GenericApp.c文件的解释和处理
首先处理GenericApp.c文件。这个文件是实现无线数据收发的实现所在,包括初始化端点描述符、简单描述符、cluster列表这些,也包括应用层面的一些消息处理内容。我们现在要做的是把所有关于key和LED的东西统统干掉,只保留coordinator的定时发送数据和router或end device的接收消息并串口输出数据功能,这样这个例程就不需要key来控制了。
开工吧。
对于coordinator,注释掉以下三个函数声明
//void GenericApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg );
//void GenericApp_HandleKeys( byte shift, byte keys );
//void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
只留下
void GenericApp_SendTheMessage( void );因为我们只要求coordinato发送数据就可以了。调用这个函数就OK了。
Init函数中的 RegisterForKeys( GenericApp_TaskID );也注释掉,我们没有键盘哦。
以下两个register函数注释掉
ZDO_RegisterForZDOMsg( GenericApp_TaskID, End_Device_Bind_rsp );
ZDO_RegisterForZDOMsg( GenericApp_TaskID, Match_Desc_rsp );
这两个是ZDO方面的消息返回到应用层面处理的一个请求注册,注册后就可以把底层的数据活动情况通过消息的方式发到应用层,我们不打算处理绑定问题和匹配问题,最后完成的目标就是广播发送,所以不需要这两个。
在GenericApp_ProcessEvent函数的系统消息“if ( events & SYS_EVENT_MSG )“处理循环中,我们只保留
case ZDO_STATE_CHANGE:
GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if ( (GenericApp_NwkState == DEV_ZB_COORD)
|| (GenericApp_NwkState == DEV_ROUTER)
|| (GenericApp_NwkState == DEV_END_DEVICE) )
{
// Start sending "the" message in a regular interval.
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_SEND_MSG_EVT,
GENERICAPP_SEND_MSG_TIMEOUT );
}
break;
这一部分,因为我打算让这个coodinator建立网络后就定时广播数据,所以当ZDO_STATE_CHANGE发生后,启动定时器,在定时器的消息处理函数中发送消息。这段程序原意是不管是COORD,DEV_ROUTER还是END_DEVCIE,建立起网络后(或加入网络后)都启动定时器,这和我们的初衷不一样,我们只要求COORD有这个功能,所以把if里面只保留GenericApp_NwkState == DEV_ZB_COORD判断条件,其余两个||的条件删除。
接下来:
if ( events & GENERICAPP_SEND_MSG_EVT )
{
// Send "the" message
GenericApp_SendTheMessage();
// Setup to send message again
osal_start_timerEx( GenericApp_TaskID,
GENERICAPP_SEND_MSG_EVT,
GENERICAPP_SEND_MSG_TIMEOUT );
// return unprocessed events
return (events ^ GENERICAPP_SEND_MSG_EVT);
}
这段程序保留,目的是得到定时消息后通过无线把信息发送出去,然后重新启动定时器,这样COORD就能一直按照定时间隔发数据出去啦,网络中其余节点的工作就是不停地收到广播信息,然后用串口传到PC呗。
文件中剩下后面的函数只保留:
void GenericApp_SendTheMessage( void )
{
char theMessageData[] = "Hello World";
if ( AF_DataRequest( &GenericApp_DstAddr, &GenericApp_epDesc,
GENERICAPP_CLUSTERID,
(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&GenericApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
{
// Successfully requested to be sent.
}
else
{
// Error occurred in request to send.
}
}
这个是发数据的具体实现函数。其余的注释掉,这样coord的主程序就定型了,里面没有LED,也没有key,如果想加进去LED作指示,等我们处理好LED之后再回到这里在想要的地方加进去就是了。
到这里,coordinator的app主程序就算改好了,router和end device的修改方式类似,不过网络状态变化消息放在哪里就好,什么也不用干。但是要保留
void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pckt );
去掉:void GenericApp_SendTheMessage( void );具体程序见附件源代码。
至此,我们这个例子就不需要key和LED了,uart还没有修改,接下来进行下面的工作。
|
|