概述
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;
}
}
最后
以上就是纯真镜子为你收集整理的Z-Stack协议栈接收数据过程探究的全部内容,希望文章能够帮你解决Z-Stack协议栈接收数据过程探究所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复