Zigbee协议简单学习
不完全记录
本工程以TI公司的CC2530芯片为例,简单记录了ZigBee协议栈下的种种,也是对目前所学课程的二次理解和输出吧。
首先是应用层的App.c文件
cId_t DNUI_SampleApp_ClusterIDS[DNUI_SAMPLEAPP_CLUSTER_NUM] =
{
DNUI_SAMPLEAPP_DATATEST_CLUSTER_ID
};
首先在AF.h文件中定义了一个cID_t即unit16的数据类型,在app.c中一开始定义了一个根据簇的编号来存放簇ID数据的一个数组。
```c
SimpleDescriptionFormat_t DNUI_Sample_SimpleDesc =
{
DNUI_SAMPLEAPP_ENDPOINT,
DNUI_SAMPLEAPP_PROFILE_ID,
DNUI_SAMPLEAPP_DEVICE_ID,
DNUI_SAMPLEAPP_DEVICE_VER,
0,
DNUI_SAMPLEAPP_CLUSTER_NUM,
(cId_t*)DNUI_SampleApp_ClusterIDS,
DNUI_SAMPLEAPP_CLUSTER_NUM,
(cId_t*)DNUI_SampleApp_ClusterIDS
};
本段代码是根据所定义的简单描述符的格式为其中的参数赋值。
其中包括端点号、协议ID、设备ID、设备版本、“0”为一个保留选项、应用层输入簇ID的数目、指向输入簇ID列表的指针以及相应的输出簇的ID的数目、指向输出簇ID列表的指针。
void DNUI_SampleApp_Init( uint8 task_id )
{
//--start--给三个重要的变量赋初值---不需要修改
DNUI_SampleAppTaskID = task_id;
DNUI_SampleApp_NwkState = DEV_INIT;
DNUI_SampleApp_TransID = 0;
//--end--给三个重要的变量赋初值---不需要修改
//--start--构造端点描述符,并注册端点--需要修改
DNUI_SampleApp_epDesc.endPoint = DNUI_SAMPLEAPP_ENDPOINT;
DNUI_SampleApp_epDesc.task_id = &DNUI_SampleAppTaskID;
DNUI_SampleApp_epDesc.latencyReq = noLatencyReqs;
DNUI_SampleApp_epDesc.simpleDesc = (SimpleDescriptionFormat_t*)&DNUI_Sample_SimpleDesc;
afRegister(&DNUI_SampleApp_epDesc);
//--end--构造端点描述符,并注册端点--需要修改
//--start--做应用相关的初始化工作--需要根据应用进行添加
Coor_Addr.addrMode = (afAddrMode_t) Addr16Bit;
Coor_Addr.endPoint = DNUI_SAMPLEAPP_ENDPOINT;
Coor_Addr.addr.shortAddr = 0x0;// 定义协调器的地址
UartInit(NULL);
//--end--做应用相关的初始化工作--需要根据应用进行添加
}
应用层初始化函数,给相关变量赋值并且构造端点描述符。
以下是端点描述符的具体结构:
typedef struct
{
uint8 endPoint;
uint8 *task_id; // Pointer to location of the Application task ID.
SimpleDescriptionFormat_t *simpleDesc;
afNetworkLatencyReq_t latencyReq;
} endPointDesc_t;
成员变量有端点号、指向应用层任务ID的指针、端点描述符的格式在上面已经介绍过,接下来是应用框架层(application frame)的潜藏周期,为枚举类型,可供选择的模式有:没有潜藏周期,信标模式的快慢等。
typedef enum
{
noLatencyReqs,
fastBeacons,
slowBeacons
} afNetworkLatencyReq_t;
枚举类型的afAddrMode_t即地址模式。
typedef enum
{
afAddrNotPresent = AddrNotPresent,
afAddr16Bit = Addr16Bit,
afAddr64Bit = Addr64Bit,
afAddrGroup = AddrGroup,
afAddrBroadcast = AddrBroadcast
} afAddrMode_t;
- 按绑定地址传输
- 按16位短地址传输
- 按64位MAC地址传输
- 组播
- 广播
接下来是地址类型afAddrType_t
typedef struct
{
union
{
uint16 shortAddr;
ZLongAddr_t extAddr;
} addr;
afAddrMode_t addrMode;
uint8 endPoint;
uint16 panId; // used for the INTER_PAN feature
} afAddrType_t;
- 一个联合体存放地址,其中包括16为短地址也叫网络地址,64位长地址即IEEE地址,一般在芯片出厂前就已经定好。
- 刚才的地址模式
- 端点
- 网络标号
接下来就是协议栈中顶顶重要的事件处理函数啦。它有两个重要的参数:任务号和事件类号。函数的主要工作为:
- 根据事件类号event来提取并判断该事件是何种类型。
- 根据任务号得到消息指针MSGpkt
- 再根据MSGpkt结构里的事件号具体处理事件。
首先呢定义了一个收发函数的指针类型,
如下 定义的收发消息的包类型中的具体参数为
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 */
uint8 nwkSeqNum; /* network header frame sequence number */
afMSGCommandFormat_t cmd; /* Application Data */
} afIncomingMSGPacket_t;
应用数据包的格式为·:
- 信息头部
- 组ID,默认为0
- 簇ID
- 源地址
- 目的地址
- 端点号
- 如果是广播为true
- 接收数据帧链路质量
- 接收数据帧的相关系数
- 接收的信号强度
- 不建议使用**
- 时间戳 来自MAC地址的时间
- 网络帧顺序数
- 最后是应用数据
如果获得的事件类型是系统消息事件SYS_EVENT_MSG,
用switch-case语句判断该事件是哪种具体类型。
当是系统收发事件时,如果网络状态是协调器接收数据便调用串口写入函数,如果节点状态是路由器或者是终端则写入相应的操作便可。
A设备用AF_DataRequest函数发出报文消息
B设备收到报文消息将触发AF_INCOMING_MSG_CMD事件
当是网络状态改变事件时,定义一个变量来放入当前网络状态。
typedef enum
{
DEV_HOLD, // Initialized - not started automatically
DEV_INIT, // Initialized - not connected to anything
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;
- 保持状态 即当前没有被授权
- 初始化状态 但没有连接任何设备
- 网络发现状态 发现一个PANID准备加入
- 网络加入状态 已经加入了一个信道
- 重加入状态 即重新加入了一个信道,只限于终端设备
- 设备未授权状态
- 终端状态
- 路由器状态
- 协调器正在组建网络状态
- 协调器状态
- 孤儿(orphan)状态 即节点失去了它的父节点的信息
如果网络状态是终端的话,启动了一个定时器函数。
osal_start_timerEx(task_id,DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT,1000);
1000ms后触发
”DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT“
此事件。
同理,当网络状态是其他两种时做相应的操作。
接着类操作系统回收消息指针所占用的内存,重新判断当前是何种类型的事件。
如果当前事件为用户自定义的事件时,有一个无线收发函数的数据请求参数如下:
afStatus_t AF_DataRequest( afAddrType_t *dstAddr, endPointDesc_t *srcEP,
uint16 cID, uint16 len, uint8 *buf, uint8 *transID,
uint8 options, uint8 radius )
- 目的地址即网络地址+端点号
- 源地址
- 簇ID
- 发送数据的长度
- 存放数据的缓冲区
- 传输有效位的掩码?
- 跳数(传输半径)
该函数实参如下(例)
AF_DataRequest( &Coor_Addr, //
&DNUI_SampleApp_epDesc,
DNUI_SAMPLEAPP_DATATEST_CLUSTER_ID,
11, //Lab6
"I'm a Node!",
&DNUI_SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
当前节点发送11个字节的数据 "I’m a Node!"给协调器。
发送完毕又触发一个定时器函数
osal_start_timerEx( task_id, DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT,1000);
1000ms后再次执行用户自定义事件,在这个函数的不断循环手动调用中就实现了定时器的重载,周期性地执行该事件。
到此为止应用层初始化和事件处理函数就简单地介绍完毕啦。
附事件处理函数的完整代码
uint16 DNUI_SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( task_id );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case AF_INCOMING_MSG_CMD:
if(DNUI_SampleApp_NwkState == DEV_ZB_COORD)
{//--start--协调器接收数据的处理逻辑
HalUARTWrite(0,MSGpkt->cmd.Data,MSGpkt->cmd.DataLength-1);
//--end--协调器接收数据的处理逻辑
}else if(DNUI_SampleApp_NwkState == DEV_END_DEVICE)
{//--start--终端设备接收数据的处理逻辑
//--end--终端设备接收数据的处理逻辑
}else if(DNUI_SampleApp_NwkState == DEV_ROUTER)
{
//--start--路由器接收数据的处理逻辑
//--end--路由器接收数据的处理逻辑
}
break;
case ZDO_STATE_CHANGE:
DNUI_SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
if(DNUI_SampleApp_NwkState == DEV_END_DEVICE)
{ //--start--终端设备接收数据的处理逻辑
osal_start_timerEx(task_id,DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT,1000);
//--end--终端设备接收数据的处理逻辑
} else if(DNUI_SampleApp_NwkState == DEV_ZB_COORD)
{//--start--协调器接收数据的处理逻辑
//--end--协调器接收数据的处理逻辑
}else if(DNUI_SampleApp_NwkState == DEV_ROUTER)
{
//--start--路由器接收数据的处理逻辑
//--end--路由器接收数据的处理逻辑
}
break;
default:
break;
}
osal_msg_deallocate( (uint8 *)MSGpkt );
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( DNUI_SampleAppTaskID);
}
return (events ^ SYS_EVENT_MSG);
}
if ( events & DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT )
{
ret = Temperature_GetVal(buf);
if(ret == TEMPERATURE_GET_OK)
AF_DataRequest( &Coor_Addr, //
&DNUI_SampleApp_epDesc,
DNUI_SAMPLEAPP_DATATEST_CLUSTER_ID,
11, //Lab6
"I'm a Node!",
&DNUI_SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
osal_start_timerEx( task_id, DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT,1000);
return (events ^ DNUI_SAMPLEAPP_ENDDEVICE_PERIODIC_MSG_EVT);
}
上一篇: linux网络协议栈br_handle_frame
下一篇: git的远程仓库版本回退