引用请注明出处!联系邮箱是
本例程讲解,基于TI CC2530-2.5.1a中的HomeAutomation文件夹中的SampleLight和SampleSwitch例子来讲解。
由于使用了ZCL标准簇库和HA profile,在数据传输处理上,相对比较复杂,只要耐心的去看,多和别人沟通交流,搞懂流程是迟早的事。
1. 功能介绍
双方板子上电后,在Switch的板子上,按下SW_2,会向SampleLight板子发送绑定请求,SampleLight的板子接收此请求后,建立绑定关系。之后,Switch的板子上面,按下SW_1,会向SampleLight的板子发送切换灯状态的命令,SampleLight收到此命令后,进行相关的操作。
samplesw 规定了三个按键:
SW_1:向灯泡发起开关的命令
SW_2:初始化终端设备绑定请求(开关只有输出命令)
SW_4:初始化匹配描述请求(我给出输入配置,周围哪个设备可以接收此输入配置)
samplelight 定义了一个按键的:
SW_2:初始化终端设备绑定请求
2. ZCL详细初始化
需要使用ZCL层,必须先把应用程序的简单描述符注册到HA profile里面去,zclHA_Init初始化里面,比较重要的一句话是
基于ZCL的应用程序,注册端点信息时,需要将自己接受任务的ID赋予为ZCL_TaskID,这意味着,发向应用程序的消息,会首先被ZCL层接收并且处理,ZCL层处理不了的数据,会转发到应用层来处理。
注册ZCL通用簇库的回调函数列表,通用簇库已经定义好了不同命令处理程序的框架表,我们需要实现什么功能,就填充对于的回调函数处理。
注册应用程序属性列表,表明此端点绑定的相关属性信息,一个簇,可以有多个属性,每个属性有属性ID,数据类型,权限,数据组成。对命令(簇)的操作,实际上是对之前已经和簇建立关系的属性值的操作,簇属性由ZCL_samplelight_data.c来定义。
下图是ZCL簇命令和对于的回调函数列表
1. 标准簇ID(ZCL_CLUSTER_ID_GEN_BASIC)下面,可以有硬件版本的属性、ZCL版本属性、制造商名称属性等。
当收到ZCL_CLUSTER_ID_GEN_BASIC命令时,会调用zclSampleLight_BasicResetCB来响应,其他的类似。
2. 认证簇(ZCL_CLUSTER_ID_GEN_IDENTIFY)下面,可以有认证时间的属性。
当接收到认证簇下面的Identify command命令时,通过zclSampleLight_IdentifyCB来响应
当接收到认证簇下面的Identify Query Response命令,通过zclSampleLight_IdentifyQueryRspCB来响应。
当接收到On/Off簇下面的On/Off/Toggle命令时,通过zclSampleLight_OnOffCB来响应。
上面是对ZCL层大致处理流程的接收,接下来,是对ZCL如何处理这些流程,进行详细的分析。
1. 首先是ZCL的初始化,它的初始时是在应用程序初始化之前进行的,主要进行插件和属性列表的初始化。
2. 在应用程序的初始化中,有如下调用
初始化时,zcl_RegisteredMsgTaskID为0xFF,所以,这条函数执行后,zcl_RegisteredMsgTaskID会为应用程序的TaskID。
在ZCL的事件处理循环中,有如下语句:
在ZCL的事件轮训处理中,当端点接收到发向ZCL或者应用程序的消息时,会触发SYS_EVENT_MSG消息,在消息列表中取出zcl_TaskID的消息,如果是数据,则由 zclProcessMessageMSG 来处理,如果是其他类型的数据,则向应用程序(zclSampleLight_TaskID)发送SYS_EVENT_MSG事件,并且携带msgPtr消息信息。
下面来,分析ZCL的具体事件处理函数 zclProcessMessageMSG。
从函数的说明上来说,此函数处理所有到来的数据消息,基于消息中的簇ID来分发消息,执行对于的消息回调函数,下面来看看,具体是怎么个流程。
先把收到的信息进行简单的解析,然后,根据端点号找到对应的端点描述符(epDesc),
然后根据端点号和簇ID,找到对应的发送选项值。
再然后,根据簇ID到合适的处理插件(plugin),具体函数为zclFindPlugin。每一种处理插件,都只针对一定范围内的簇ID起作用,以下是插件的数据结构:
在不同的插件,通过不同的簇ID范围来区分,针对一个特定的簇ID,获取对于的回调函数来处理。问题来了,插件的初始化在ZCL_init中是为空的呀?那具体填充簇ID和对于处理函数的操作在哪里呢?跟着这个问题,继续往下找。
在这里:
看到没有,对于每一个插件的注册,都需要起始簇ID,结束簇ID,他们规定了插件的使用范围,后面一个参数,就是不同簇对于的回调函数列表了,插件与插件之间,通过链表相连。插件的初始化是在
插件的回调函数统一由zclGeneral_HdlIncoming来处理,这个函数,对收到的命令,进行一些基本的过滤
上述函数的下半部分:
根据传入进来的回调函数数组指针,赋值为全局ZCL通用回调指针。
在zclGeneral_HdlInSpecificCommands中,在根据收到信息的端点,在找到对应的回调函数
根据端点找对于的回调函数,是在zclGenCBs链表中去找,具体函数为zclGeneral_FindCallbacks。问题又来了,zclGenCBs由是在哪里初始化的呢?上文已经提及到了。这里就不再提及的。
后面的处理流程,就比较好理解了,根据簇ID,来调用不同的处理函数,由于是统一的回调处理,不同的处理函数的调用格式是完全一样的,在这里,就以开关灯来说明。
pInMsg为接收到的数据,pCBs为指定端点对于的回调函数列表。
处理函数,首先判断接收到的数据方向和命令ID的有效范围,如果通过的话,则调用对于的处理函数来处理。从这里面可以看出,不同命令ID和处理函数之间,是人为的指定对应关系。上述的调用,就会跳到:
zclSampleLight_OnOffCB
上述,从开关的发送命令
zclGeneral_SendOnOff_CmdToggle( SAMPLESW_ENDPOINT, &zclSampleSw_DstAddr, false, 0 );
到灯光这边的接收处理,zclSampleLight_OnOffCB
基本上流程,大体上分析清楚了,其他的命令和响应,只需要遵旨一定的操作,就可以完成。
2014-06-16 浩天之家 完成