ZigBee 3.0通信实验
1.设备初始化 sampleswitch工程代码,在zcl_samplesw.c文件中的应用层初始化函数zclSampleSW_Init()的末尾,添加一些代码(协调器的通信模式)
2.协调器角色初始化
协调器角色下,调用bdb_StartCommissioning()创建一个ZigBee网络,然后调用NLME_PermitJoiningRequest(255)允许其他设备加入到这个网络中。接着调用osal_start_timerEx()产生了一个广播事件和组播事件。事件和对应是事件周期定义在zcl_samplesw.h文件中。
3.终端(路由器角色)初始化
在终端(路由器)首先调用bdb_StartCommissioning()加入ZigBee网络,然后创建一个组,创建组的代码有:// Add groupaps_Group_t group={.ID=GROUP_ID,.name="",};
GROUP_ID的定义同样在zcl_samplesw.c文件中
// GroupId#define GROUP_ID21
接着调用aps_AddGroup()加入到这个组中,代码如下:
aps_AddGroup(SAMPLESW_ENDPOINT,//端点号&group);//待加入的组
最后,调用osal_start_timerEx()启动一个点对点通信事件,这个事件和事件周期的定义在zcl_samplesw.h文件中,代码如下:
// P2P #define SAMPLEAPP_P2P_EVT0x0100#define SAMPLEAPP_P2P_PERIOD3000
4.协调器的事件处理
应用层初始化函数zclSampleSw_Init()中,协调器角色设备产生了一个广播事件,SAMPLEAPP_BROADCASR_EVT和一个组播事件SAMPLEAPP_GROUPCAST_EVT,因此需要编写对应的事件处理代码。
在zcl_samplesw.c文件中的应用层事件处理函数zclSampleSw_event_loop()添加对应的时间处理代码。
5.终端(路由器)的事件处理
应用层初始化函数zclSampleSw_Init(),终端(路由器)设备产生了一个点对点通信时间,因此需要编写对应的事件处理代码。
在zcl_samplesw.c文件中的应用层事件处理函数zclSampleSw_event_loop()添加对应的时间处理代码。
在点对点通信事件处理中,首先调用了zclSampleSw_AF_Broadcast()发送一个点对点信息。其中的网络地址0x0000是协调器的网络地址。跟广播和组播事件处理类似,在发送数据之后,调用osal_start_timerEx()重新产生一个点对点通信事件。
6.接受和处理数据
以上是如何发送数据?(没看懂),下面是如何接受数据。在ZigBee组网成功后,接受到数据会产生一个系统事件AF_INCOMING_MSG_CMD表示现在接收到数据了。
打开zcl_samplesw.c文件,可以找到一个应用层事件处理函数zclSampleSw_event_loop()。
系统事件处理代码中已经包含了对系统事件AF_INCOMING_MSG_CMD的识别了,开发者只需要在接收到这个事件后进行相应的处理就可以了。
定义一个数据处理函数zclSampleSw_AF_RxProc()来处理接收到的数据。
省略...
代码中用到了之前定义的3个Cluster ID,它们可以用来标识利用不同的通信方式发送过来的数据包,含义如下:
CLUSTER_P2P:在P2P通信方式时发送
CLUSTER_BROADCAST:在广播通信方式时发送
CLUSTER_GROUPCAST:在组播方式时发送
5.1应用层对ZCL API的调用
应用层调用 ZCL API 的基本模式。
1.zcl_samplesw.c文件中的应用层初始化函数zclSampleSw_Init,有这四个类型的代码。
zclGeneral_RegisterCmdCallbacks()
注册一个命令执行回调(Call Back)。这个回调中包含一个命令处理函数列表。当设备接收到命令时,就在这个列表中找打到对应的命令处理函数,处理该命令。
zclSampleSw_ResetAttributesToDefaultValues()
把一些属性设置为默认值。
zcl_registerAttrList()
为设备注册一个属性列表。前面章节已讲过,函数参数zclSampleSw_Attrs是一个属性列表,可在zcl_samplesw_data.c文件找到其定义。
zcl_registerForMsg()
告诉设备需要接收未处理的Foundation(基础)命令或者响应消息。调用该函数后,在接收到例如读命令、写命令或上报命令等基础命令时,就会发生系统事件ZCL_INCOMING_MSG,开发者在该事件处理函数中做相关处理即可。
2.zclSampleSw_CmdCallbacks()
(1)可在zcl_samplesw.c文件中找到命令执行回调的定义
(2)zclSampleSw_CmdCallbacks是一个命令处理函数列表(数组),其中的每个元素均表示某个特定命令的处理函数。可以通过注释或者查看该函数列表的类型定义可以查看每个元素代表的是哪个命令的处理函数。如果元素值为NULL,表示该命令无处理函数,即不处理该命令。如果需要on/off Cluster的命令,那么在其对应的元素位置设置处理处理函数即可。
3.ZCL_INCOMING_MSG()
1)在AF通信章节中,当设备接收到AF层的数据时就会产生系统事件AF_INCOMING_MSG_CMD,开发者只需在对应的事件处理函数中做相应处理即可。ZCL_INCOMING_MSG的意义与之类似,如果发生系统事件ZCL_INCOMING_MSG就表示有基础命令或消息需要处理。
(2)打开zcl_samplesw.c文件中的zdSampleSw_event_loop()函数,可以找到ZCL_INCOMING_MSG的事件处理函数zclSamplesw_ProcessIncomingMsg():
(3)zclSampleSw_ProcessIncomingMsg()函数的定义代码大致就是根据不同的commandID做相应的处理。
(4)需要注意的是,使用ZCL的基础命令前,需要开启相应的宏的,例如使用“读”命令需要开启ZCL_READ 。其开启方式与HAL宏的开启方式是相同的
5.2 ZCL 开关命令收发 API
发送命令API
前文提及到的On/Off命令是一个Cluster限定命令,在On/Off Cluster中。On/Off Cluster中还包含其他的命令,例如Toggle(反转状态)。可以调用专门的API来使用命令。打开Profile文件夹,可以找到zcl_general.h文件
在zcl_general.h文件中可以找如下3个API:on .off .toggle
这3个API分别实现了发送关闭、打开和反转状态命令。它们均是使用#define来定义,并且最终是调用zcl_SendCommand函数来发送命令的。zcl_SendCommand函数的定义如下:
extern ZStatus_tzcl_SendCommand(uint8 srcEP,//源端点,发送者的端点号afAddrType_t*dstAddr,//目标设备地址uint16 clusterID,uint8 cmd,//Cluster ID和命令uint8 specific,//是否为属性关联命令uint8 direction,//通信方向uint8 disableDefaultRsp,//是否关闭默认响应(目标设备的响应)uint16 manuCode,//manu codeuint8 seqNum,//数据包标识号,由开发者自定义uint16 cmdFormatLen,//命令格式长度uint8*cmdFormat//命令格式);
以zclGeneral_SendOnOff_CmdOff为例子展开简介一下其对zcl_SendCommand的调用,代码如下:
zcl_SendCommand((a),(b),ZCL_CLUSTER_ID_GEN_ON_OFF,//Cluster IDCOMMAND_OFF,//待发送命令为关闭命令TRUE,//TRUE表示属性关联命令ZCL_FRAME_CLIENT_SERVER_DIR,//表示通信方向为从Client到Server(c),0,//manu code为0(d),0,//命令格式长度为0NULL)//命令格式为空
开发者调用基于zcl_SendCommand封装出来的各种命令发送API即可,例如上述的3个命令发送API。
接收On/Off命令的方法比较简单,只需要在ZCL命令处理函数列表zclSampleSw_CmdCallbacks的对应位置添加命令处理函数即可实现命令的接收和处理了
5.3 ZCL 开关命令收发实验
使用ZCL通信API发送On/Off命令,实验设备包含一个网关(协调器)和一个智能插座(终端或路由器), 内容:当智能插座加入到网络后,网关自动定期地向这个智能插座发送On和Off指令来控制智能插座的开关。
1.智能插座开发:
在zcl_samplesw.c文件中,应用初始化函数zdSampleSw_Init。这里定义协调器/终端,进行网络组建和发送通知信息。
#else与#endif中的代码是当设备处于终端(或路由器)角色时执行,其中的bdb_StartCommissioning函数是用于组建网络的的
zclSampleSw_DeviceAnnce函数是由开发人员自定义的,用于向整个网络广播一个数据包,该数据包中包含本设备的地址。当协调器收到这个数据包时,就知道这个设备的地址信息了。其定义代码如下:
static voidzclSampleSw_DeviceAnnce(void){ZDP_DeviceAnnce(NLME_GetShortAddr(),//获取本设备的网络地址(短地址)NLME_GetExtAddr(),//获取本设备的物理地址(通常就是MAC地址)ZDO_Config_Node_Descriptor.CapabilityFlags,//暂不展开简介,可忽略0//暂不展开讲解,可忽略);}
这个函数调用了 ZDP_DeviceAnnce函数,是一个协议栈的API。(可以套用上述代码实现向网络中广播本设备的地址信息。)
2.处理指令
在处理On/Off命令前,需要现在ZCL命令回调函数列表中注册一个回调函数,即在zcl_samplesw.c文件中添加zclSampleSw_OnOffCB函数。
3.网关开发:
它的任务:1接收并处理智能插座广播的地址信息;2启动一个周期性事件来周期地向智能插座发送On/Off指令
接收地址信息:
当协调器收到由智能插座广播的地址消息时,会产生系统事件ZDO_CB_MSG,可以在应用层事件处理函数中处理事件。
事件处理函数zclSampleSw_ProcessZDOMgs的代码定义在该代码下。(处理函数接收地址信息和消息信息,并在屏幕上显示,并周期的产生SAMPLEAPP_ONOFF_TEST_EVT事件,即发送On/off指令)
处理SAMPLEAPP_ONOFF_TEST_EVT事件
在zcl_samplesw.c文件中找到zclSampelSw_eventloop函数,添加事件处理代码,如下图所示
发送On/Off指令
就是一步步拆解呗,大的函数就是框架,里面用了很多定义的函数,函数又用函数来解释。直到完全做完每一步,每一个信息都有源头有流向。
最后仿真调试
7.2终端设备开发
终端设备开发内容主要有以下这几部分:
定义和启动属性上报事件。
定义事件处理函数,进行属性上报。
启用对应的宏定义。
1定义和启动属性上报事件
在zcl_samplesw.h文件中添加事件定义和事件发生时间定义
在zcl_samplesw.c文件中的应用层初始化函数zclSample_Init中添加启动属性上报事件代码:
2定义事件处理函数,打开zcl_samplesw.c文件找到事件处理函数zclSampleSw_event_loop
3属性上报API 简介
只需调用属性上报API即可完成属性上报功能。在zcl.c文件中,可以找到属性上报API
4属性上报处理函数
学习完API后,即可编写属性上报事件处理函数zclSampleSw_ReportTest,代码
5启用对应的宏定义
开启一个宏定义ZCL_REPORTING_DEVI
7.3协调器设备开发
它的任务:接收和处理属性数据,启用对应的宏定义。
1.接收和处理属性数据
读写命令类似,协调器在接收到上报信息后,就会发生系统事件ZCL_INCOMING_MSG。打开在zcl_samplesw.c文件中的zdSampleSw_event_loop函数,可以找到ZCL_INCOMING_MSG的事件处理函数zclSamplesw_ProcessIncomingMsg,其中的部分代码
其中的属性上报处理函数zclSampleSw_ProcessInReportCmd,由笔者自定义,代码如下:
启用对应的宏定义
要开启两个宏:ZCL_REPORT_DESTINATION_DEVICE 和 ZCL_REPORT,
iptions--c++--proprecess--defined symbols