一个端点对应一个任务,每一个任务都有唯一的任务号及任务处理函数,ZDO_RegisterForZDOMsg( )在相应的任务中注册事件,并且每一个事件只能被成功注册一次,每一个任务也只能注册一次事件, 因为:
ZStatus_t ZDO_RegisterForZDOMsg( uint8 taskID, uint16 clusterID ) {
ZDO_MsgCB_t *pList; ZDO_MsgCB_t *pLast; ZDO_MsgCB_t *pNew;
// Look for duplicate
pList = pLast = zdoMsgCBs;//zdoMsgCBs此指针变量始终指向注册事件链表的头 while ( pList ) {
if ( pList->taskID == taskID && pList->clusterID == clusterID )
return ( ZSuccess );//若之这个任务已注册了事件(本事件或其他事件),那 pLast = pList; //么此次注册将不会把注册信息加入链表,就相当于没有注册 pList = (ZDO_MsgCB_t *)pList->next; }
// Add to the list若没有被注册过(之前链表里没有),则将其添加到链表的末尾(注册) pNew = (ZDO_MsgCB_t *)osal_mem_alloc( sizeof ( ZDO_MsgCB_t ) ); if ( pNew ) {
pNew->taskID = taskID;
pNew->clusterID = clusterID; pNew->next = NULL; if ( zdoMsgCBs ) {
pLast->next = pNew; } else
zdoMsgCBs = pNew; return ( ZSuccess ); } else
return ( ZMemError ); }
/***********************************************************
遗留问题:链表中的事件,在何时何地,什么情况下被销毁呢?
************************************************************/
接着说,那么注册了以后它有什么用?怎么用呢?
先看Z-Stack API中对此函数的解释:
Call this function request an OTA message. A copy of the message will be send to a task in an OSAL message .The task recevice the OTA message can either prase the message themselves or call a ZDO prase function to prase the message. Only response messages have a ZDO prase function.
After registering for a message ,and the message(OTA) is receviced,the message is send to the application/task as a ZDO_CB_MSG(OSAL Msg).
大意:
调用这个函数用来请求一个无线消息,这个消息的备份将被作为一个系统消息
送给一个任务。这个任务接收到这个消息后,它将自己解析这个消息,或者调用一个ZDO解析函数来解析这个消息。仅仅响应(rsp)消息才有解析函数。
/******************************************************* Only response messages have a ZDO prase function.
仅仅响应(rsp)消息才有解析函数,现在对这句话不是很理解
我想可以这样理解:对于req消息,目标节点在收到req消息后,Z-stack会自动处理(代码协议栈已经实现),Z-stack实现了大多数响应req消息的函数,然后返回给源节点一个rsp 对于rsp消息来说,源节点在收到rsp消息后并不会自动处理,因为Z-stack没有实现rsp消息的代码,可是为什么Z-stack没有实现rsp消息的代码呢?因为对于rsp消息的处理,不同的用户会有不同的想法,所以Z-stack就没有实现,其实它也不能实现
********************************************************/
在一个消息注册后,并且接收到这个消息后,这个消息将被作为一个系统消息 ZDO_CB_MSG发送给注册了这个消息的应用或任务
/************************************************************/
其实,这个函数是用来注册一些事件的,比如说IEEE_addr_rsp、NWK_addr_rsp、End_Device_Bind_req、Bind_req等,这些事件都是需要与远处的节点通信的事件,也就是说,处理这些事件时,是需要无线发送数据包的。那么注册的实质是什么呢?注册的实质就是,将注册事件信息以ZDO_MsgCB_t的形式加入链表之中,其中zdoMsgCBs保留链表的头指针。
对于发生这些事件的参与者,大体上可分为两种: 1.发送数据方 2.接收数据方
这些事件的注册是在数据的接收方,可是为什么是在数据的接收方呢?
那就要看这 “注册” 的作用何在。上面说到注册的实质(就是注册是怎么用程序实现的),现在我们来说说注册的意义(也就是注册的作用或者说注册怎么来用,用来做什么)。
在说注册的意义之前,我们先来说说这无线数据包的发送与接收,
发送无线数据:
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t
*srcEP,uint16 cID, uint16 len, uint8 *buf, uint8 *transID,uint8 options, uint8 radius )
此函数是Z-Stack中用来发送无线数据包的
此函数属于上层,执行此函数后无线数据包将被发往下层,直到物理层,物理层将数据包以无线电波的形式发送出去
无线数据的接收:
当有无线数据包到来时,节点的最下层,也就是物理层将接收这个无线数据包,然后层层上传,直到应用层(数据包已经在到达应用层之前被解析完成,至于是那一层,或者是哪几层,怎样解析的数据包这就不是我们要关心的了), 数据被解析出来后被存储在一个结构体中: typedef struct {
osal_event_hdr_t hdr; /* OSAL Message header */
uint16 groupId; /* Message's group ID - 0 if not set */ uint16 clusterId; /* Message's cluster ID */
afAddrType_t srcAddr; /* Source Address, if endpoint is
STUBAPS_INTER_PAN_EP,it's an InterPAN message */ uint16 macDestAddr; /* MAC header destination short address */ uint8 endPoint; /* destination endpoint */
uint8 wasBroadcast; /* TRUE if network destination was a broadcast address */ uint8 LinkQuality; /* The link quality of the received data frame */
uint8 correlation; /* The raw correlation value of the received data frame */ int8 rssi; /* The received RF power in units dBm */ uint8 SecurityUse; /* deprecated */
uint32 timestamp; /* receipt timestamp from MAC */ afMSGCommandFormat_t cmd; /* Application Data */ } afIncomingMSGPacket_t;
现在数据解析出来了,看看这些信息是要告诉我们什么呢?又要我们做什么呢?
不应该说要我们做什么,而应该说要操作系统做什么。要想让操作系统做事,就要依法设置事件。
其实数据在由下层往上层传输的时候,就已经设置了系统事AF_INCOMING_MSG_CMD,事件的任务号是由数据包里的目标端点号决定的。
但是由ZDO_RegisterForZDOMsg( )注册的事件,在进入系统事AF_INCOMING_MSG_CMD后,会被ZDO_SendMsgCBs( )函数 “劫下”,并发送系统消息ZDO_CB_MSG,这些事件将在这里得到真正的处理
这样OSAL就触发系统事件ZDO_CB_MSG,在这个事件的处理函数中,我们可以依据这个解析出来的数据包,做我们想做的事

