Z-Stack协议栈接收数据过程探究

TI公司推出的Z-Stack协议栈是ZigBee协议的一种具体实现。

2018-12-27 Ø


在协调器这一端接收到来自终端的数据如何解析处理,并把净荷数据通过串口发送到PC机,在这里对整个程序流程进行一下分析。
首先,通信节点接收到数据包后会触发进入事件处理函数GenericApp_ProcessEvent();
第二步,进入数据事件处理函数之后,定义一个afIncomingMSGPacket_t结构体类型的指针变量MSGpkt用来指向消息队列中的数据包;afIncomingMSGPacket_t *MSGpkt;

  • 第三步,通过*osal_msg_receive(GenericApp_TaskID)函数来从消息队列中读取该数据;其中GenericApp_TaskID为任务优先级ID全局变量,在执行任务初始化函数GenericApp_Init()时将会被赋值!MSGpkt=(afIncomingMSGPacket_t)*osal_msg_receive(GenericApp_TaskID);
  • 第四步,通过if语句判断事件是否属于强制事件SYS_EVENT_MSG,是的则执行下面的语句。
  • 第五步,通过读取事件的头来判断事件的类型;
    afIncomingMSGPacket_t 有到来的报文包结构体类型
    在AF.h文件中的定义如下,它用来接收AF_DataRequest函数发来的数据以及各种其他类型的数据
    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 endpointis 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 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;
    1、 afIncomingMSGPacket_t结构体类型中的成员变量hdr是一个osal_event_hdr_t结构体类型的变量, osal_event_hdr_t事件头结构体类型在OSAL.h中定义如下:
    typedef struct
    { uint8 event; //通过这个变量可以获取事件类型
    uint8 status; //表示设备的状态,比如说是路由器还是终端节点
    } osal_event_hdr_t;
    1)因此,可以通过switch(MSGpkt->hdr.event)语句来判断事件的类型;强制事件SYS_EVENT_MSG的类型主要有:
    AF_DATA_CONFIRM_CMD
    AF_INCOMING_MSG_CMD 接收到新的无线数据包
    KEY_CHANGE 有按键按下的指示
    ZDO_STATE_CHANGE 网络状态发生改变
    ZDO_CB_MSG 指示每一个注册的ZDO响应消息
    在ZComDef.h文件中定义了ZigBee协议栈中每个消息对应事件的ID。
    #define AF_DATA_CONFIRM_CMD 0xFD // Data confirmation
    #define AF_INCOMING_MSG_CMD 0x1A // Incoming MSG type message
    2)设备状态status是一个枚举型的数据类型;其定义如下:
    typedef enum
    {DEV_HOLD, // Initialized - not started automatically
    DEV_INIT, // 初始化,没有连接到任何设备
    DEV_NWK_DISC, // Discovering PAN’s to join
    DEV_NWK_JOINING, // Joining a PAN
    DEV_NWK_REJOIN, // ReJoining a PAN, only for end devices
    DEV_END_DEVICE_UNAUTH, //Joined but not yet authenticated by trust center DEV_END_DEVICE, // Started as device after authentication
    DEV_ROUTER, // Device joined, authenticated and is a router
    DEV_COORD_STARTING, // Started as Zigbee Coordinator
    DEV_ZB_COORD, // Started as Zigbee Coordinator
    DEV_NWK_ORPHAN // Device has lost information about its parent…} devStates_t;
    2、afAddrType_t地址类型结构体类型在AF.h文件中的定义如下
    typedef struct
    {
    union { uint16 shortAddr;
    ZLongAddr_t extAddr;
    } addr;
    afAddrMode_t addrMode;
    uint8 endPoint;
    uint16 panId; // used for the INTER_PAN feature
    } afAddrType_t;

第六步,如果读取出来的事件的类型是AF_INCOMING_MSG_CMD,则调用接收数据处理函数;
case AF_INCOMING_MSG_CMD:
GenericApp_MessageMSGCB( MSGpkt );
break;
接收数据处理函数原型如下:
void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pkt)
{ unsigned char buffer[10];
switch ( pkt->clusterId ) //通过读取数据包的簇ID的值来判断这个数据包的类型究竟想完成什么任务
{
case GENERICAPP_CLUSTERID: // Put your code here to process the incoming data osal_memcpy(buffer,pkt->cmd.Data,10);
HalUARTWrite(0,buffer,10);
break;
}
}
函数中通过读取数据包的簇ID的值来判断这个数据包的类型究竟想完成什么任务,而一个节点发过来的数据包的簇ID的类型数量取决于发送节点简单描述符中所定义的输出簇ID的个数以及输出簇ID的列表;
例如发送节点的简单描述符定义如下,描述的是协调器节点
const SimpleDescriptionFormat_t GenericApp_SimpleDesc =
{ GENERICAPP_ENDPOINT, // GENERICAPP_PROFID, 智能家居的Profile ID是0x0104
GENERICAPP_DEVICEID, // uint16 AppDeviceId[2];
GENERICAPP_DEVICE_VERSION, // int AppDevVer:4;
GENERICAPP_FLAGS, //
GENERICAPP_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)GenericApp_ClusterList, //byte *pAppInClusterList;
0, //
(cId_t *)NULL //
};
而简单描述符结构体类型的定义如下
typedef struct{ int Endpoint; // 端口号
uint16 AppProfId[2]; // 应用规范ID
uint16 AppDeviceId[2]; // 应用设备ID
int AppDevVer:4; // 应用设备版本号
int AppFlags:4; // 保留
byte AppNumInClusters; // 输入簇ID的个数
byte *pAppInClusterList; // 输入簇ID的列表
byte AppNumInClusters; // 输出簇ID的个数
byte *pAppInClusterList; // 输出簇ID的列表
}SimpleDescriptionFormat_t;
输出簇ID的列表的定义如下
const cId_t GenericApp_ClusterList[GENERICAPP_MAX_CLUSTERS] =
{ GENERICAPP_CLUSTERID};
也就是说输出簇ID的个数只有一个,就是GENERICAPP_CLUSTERID,某一个簇ID可以理解成用来控制某一个应用领域下的一个特定对象,例如这个簇ID是用来控制灯光的开关的。当我们需要控制该应用领域的其他特定对象,比如需要传送采集的温度,此时我们需要另外设定一个簇ID.这样输出簇ID就要加一个,输出簇ID列表数组中就会多出一个簇ID。
在本例中簇ID为GENERICAPP_CLUSTERID意味着把接收到的数据通过串口传向PC机,因此先通过函数osal_memcpy( void *dst, const void GENERIC *src, unsigned int len )把数据包中携带的src所指向的数据拷贝到dst所指向的数组中afMSGCommandFormat_t结构体类型定义如下:
typedef struct{ uint8 TransSeqNumber; //存储的是发送端的发送序列号
uint16 DataLength; // 存储的是发送数据的长度信息
uint8 *Data; //存储的是接收到的数据缓冲区的指针
} afMSGCommandFormat_t;
所以,接收到的报文数据就封装在这个报文命令格式结构体中,pkt->cmd.Data,指的就是接收到的净荷数据的指针,然后,通过函数uint16 HalUARTWrite(uint8 port,uint8 *buf,uint16 length); 把接收到的数据通过CC2530的串口0发送给了PC机。HalUARTWrite(0,buffer,10);//通过串口0将buffer所指向的数组中的10个字节发出
第七步,当把收到数据包事件处理完了,就可以释放消息指针所占用的内存,便于让消息指针指向下一个消息。释放消息指针所占用的内存函数如下 osal_msg_deallocate( (uint8 *)MSGpkt );
第八步,将指针指向下一个已接收到的放在缓冲区的待处理的事件,返回while( MSGpkt )重新处理事件,直到缓冲区没有等待处理事件为止。MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(GenericApp_TaskID);

第九步,将已经处理过的事件消除掉后作为返回值返回,采用异或的运算逻辑,没有处理的事件将不会受影响。return(events ^ SYS_EVENT_MSG); Ø
完整程序如下:

uint16 GenericApp_ProcessEvent( uint8 task_id, uint16 events )  
 1{  afIncomingMSGPacket_t *MSGpkt;  
         if ( events & SYS_EVENT_MSG ) 
          2{    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( GenericApp_TaskID );    
          while( MSGpkt )//需要将消息队列中所有的事件处理完毕才跳出这个循环    
              3{      switch ( MSGpkt->hdr.event )      
                   4{   case AF_INCOMING_MSG_CMD:         
                        GenericApp_MessageMSGCB( MSGpkt );        
                         break;      
                       default:        break;      
                    }4      // 以上把收到数据包事件处理完了,释放消息指针所占用的内存                       
                      osal_msg_deallocate( (uint8 *)MSGpkt );     
                      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(GenericApp_TaskID);    
              }3    return(events ^ SYS_EVENT_MSG);// return unprocessed events 
        }2  return 0;
    }1 
               
    static void GenericApp_MessageMSGCB(afIncomingMSGPacket_t *pkt )
    {  
    unsigned char buffer[10];  switch ( pkt->clusterId ) 
     {   
         case GENERICAPP_CLUSTERID:    
         osal_memcpy(buffer,pkt->cmd.Data,10);// 将收到的数据拷贝到缓冲区buffer中         
         HalUARTWrite(0,buffer,10);  
         break; 
      }
    }  
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值