7.1 概述
传感器类的终端设备可以使用属性上报API把数据上报到协调器中,例如温湿度传感器把采集到温湿度数据上报、人体红外传感器检测到有人时上报这个信息等。
本节课将以实验的方式讲解基于ZCL的属性上报技术,主要的实验设备包括一个协调器设备和一个终端(或路由器)设备,实验内容是:
- 终端设备定期地上报数据给协调器。
- 协调器接收到数据并显示到屏幕上。
7.2 终端设备开发
终端设备开发内容主要有以下这几部分:
#ifdef ZDO_COORDINATOR
#else
/*
* 此处省略了部分代码
*/
#define SAMPLEAPP_REPORT_EVT 0x0040
#define SAMPLEAPP_REPORT_PERIOD 3000
#endif
在zcl_samplesw.c文件中的应用层初始化函数zclSample_Init中添加启动属性上报事件代码:
osal_start_timerEx(zclSampleSw_TaskID,
SAMPLEAPP_REPORT_EVT,//事件
SAMPLEAPP_REPORT_PERIOD);//延迟处理事件的时间长度
定义事件处理函数
定义事件后,需要添加事件处理函数。打开zcl_samplesw.c文件找到事件处理函数zclSampleSw_event_loop,添加如下代码:
#ifdef ZDO_COORDINATOR
#else
/*
* 此处省略了部分代码
*/
if ( events & SAMPLEAPP_REPORT_EVT )
{
zclSampleSw_ReportTest();//属性上报事件的处理函数
//启动下一个属性上报事件
osal_start_timerEx(zclSampleSw_TaskID,
SAMPLEAPP_REPORT_EVT,
SAMPLEAPP_REPORT_PERIOD);
return ( events ^ SAMPLEAPP_REPORT_EVT );
}
#endif
属性上报API 简介
只需调用属性上报API即可完成属性上报功能。在zcl.c文件中,可以找到属性上报API,代码如下:
/*
* 上报一个或多个属性值
*/
extern ZStatus_t zcl_SendReportCmd(
uint8 srcEP, //源端点号
afAddrType_t *dstAddr, //目标设备地址信息
uint16 realClusterID, //属性所属Cluster ID
zclReportCmd_t *reportCmd,//描述待上报的属性值
uint8 direction, //通信方向
uint8 disableDefaultRsp, //是否关闭默认响应(目标设备的响应)
uint8 seqNum); //数据包标号,由开发者自定义
属性上报处理函数
学习完API后,即可编写属性上报事件处理函数zclSampleSw_ReportTest,其代码定义如下:
/*
* 数据上报事件的处理函数,用于上报数据
*/
static void zclSampleSw_ReportTest(void)
{
static uint8 seqNum = 0;
zclReportCmd_t *reportCmd;
//目标设备的地址信息
afAddrType_t destAddr;
destAddr.addrMode = afAddr16Bit;
destAddr.endPoint = SAMPLESW_ENDPOINT;
destAddr.addr.shortAddr = 0x0000;//0x0000表示协调器的网络地址
reportCmd = (zclReportCmd_t *)osal_mem_alloc(sizeof(zclReportCmd_t)+sizeof(zclReport_t));//申请内存空间
if(reportCmd == NULL)//判断内存空间是否申请成功
return;
reportCmd->attrList[0].attrData = (uint8 *)osal_mem_alloc(sizeof(uint8));//申请内存空间
if(reportCmd->attrList[0].attrData == NULL)//判断内存空间是否申请成功
return;
reportCmd->numAttr = 1;//属性数量为1
reportCmd->attrList[0].attrID = ATTRID_ON_OFF_SWITCH_TYPE;//属性ID
reportCmd->attrList[0].dataType = ZCL_DATATYPE_ENUM8;//数据类型
*((uint8 *)(reportCmd->attrList[0].attrData)) = seqNum;//属性值
//上报数据
zcl_SendReportCmd(SAMPLESW_ENDPOINT,//源端点号
&destAddr,//地址信息
ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG,//Cluster ID
reportCmd,
ZCL_FRAME_CLIENT_SERVER_DIR,//通信方向为从客户端到服务端
TRUE,//关闭默认响应(目标设备的响应)
seqNum++ );//数据包标号,每上报一次数据seqNum的值就会增加1
HalLcdWriteStringValue("Report: ", (seqNum-1), 10, 4);//显示
// 释放内存空间!
osal_mem_free(reportCmd->attrList[0].attrData);
osal_mem_free(reportCmd);
}
启用对应的宏定义
最后,还需要开启一个宏定义ZCL_REPORTING_DEVICE,如下图所示。
7.3 协调器设备开发
协调器设备开发内容主要有一下这几部分:
- 接收和处理属性数据。
- 启用对应的宏定义。
接收和处理属性数据
与读写命令类似,协调器在接收到上报信息后,就会发生系统事件ZCL_INCOMING_MSG。打开在zcl_samplesw.c文件中的zdSampleSw_event_loop函数,可以找到ZCL_INCOMING_MSG的事件处理函数zclSamplesw_ProcessIncomingMsg,其中的部分代码如下:
1.static void zclSampleSw_ProcessIncomingMsg( zclIncomingMsg_t *pInMsg )
2.{
3. switch ( pInMsg->zclHdr.commandID )
4. {
5. ...... // 不展开
6.
7.#ifdef ZCL_REPORT
8. ...... // 不展开
9. case ZCL_CMD_REPORT://属性上报
10. zclSampleSw_ProcessInReportCmd( pInMsg ); //属性上报处理函数
11. break;
12.#endif
13. ...... // 不展开
14. }
15. if ( pInMsg->attrCmd )
16. osal_mem_free( pInMsg->attrCmd );
17.}
其中的属性上报处理函数zclSampleSw_ProcessInReportCmd,由笔者自定义,代码如下:
#ifdef ZCL_REPORT
static uint8 zclSampleSw_ProcessInReportCmd( zclIncomingMsg_t *pInMsg )
{
zclReportCmd_t *reportCmd;
uint8 i;
reportCmd = (zclReportCmd_t *)pInMsg->attrCmd;
for ( i = 0; i < reportCmd->numAttr; i++ )//reportCmd->numAttr为属性数量
{
if( pInMsg- >clusterId == ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG//Cluster ID
&& reportCmd->attrList[i].attrID == ATTRID_ON_OFF_SWITCH_TYPE)//属性ID
{
int8 attrDat = *(reportCmd->attrList[i].attrData);//读取属性值
HalLcdWriteStringValue("Rx Value:", attrDat, 10, 4);//显示属性值
}
}
return ( TRUE );
}
#endif // ZCL_REPORT
启用对应的宏定义
最后,需要开启两个宏:ZCL_REPORT_DESTINATION_DEVICE 和 ZCL_REPORT,如下图所示。
7.4 仿真调试
- 分别编译协调器和终端(路由器)工程,然后分别下载到两个开发板中。
- 终端(路由器)设备加入到ZigBee网络中后,可以看到协调器屏幕显示如下提示信息。