文档介绍:关于 Zigbee 协议的 C 语言实现一、协议:Zigbee 联盟规范了协议,具体的协议编程语言表述则由 IC厂商指定,如德州仪器 2430 与CC2530 的Z-Stack 意法半导体 ST等公司也有自己的 Zigbee 协议的实现方式二、开源:虽然宣称的 Zigbee 是开源的,但是跟底层硬件(如CC2530 的寄存器具体配置)密切相关部分:MAC 层与 NWK 层 TI并未开源,而是以 lib (库)配合相应的头文件(用户接口)实现,lib 库的位置在:ZStack -CC2530 - -\Projects\zstack\Libraries 下所以更上的 AF(应用程序框架), ZCL ,ZDO 等层只要包含 lib 对应的头文件,即可调用库里的 API 函数三、Z-Stack :Z-Stack 几乎都是 C语言写的,即便是平时经常用 C写过单片机程序的,读Z-Stack 代码是还是有点困难的,原因如下 1、用了大量的宏定义。程序中把用到的常量统统用宏定义表示,这样程序维护起来很方便 2、用到大量的结构体 struct 与枚举 emun 比如简单的类型定义 int ,char ,unsigned char 等,只能表示简单的数据结构,复杂的数据结构用 struct 定义。如描述 EndPoint 的数据结构 endPointDesc_t 定义如下: 此数据结构中又包含一层数据结构:SimpleDescriptionFormat_t 最后在编写应用程序时,只要用像 int num; 一样定义一个变量就可以描述很复杂的数据了枚举:enum 协议里的状态值基本上都是 enum 定义的值,如在 SampleApp 中的 devStates_t SampleApp_NwkState; 函数的状态返回值一般是用 uint8 (unsigned char )类型定义的,但是这样不够直观,不能通过名称表达返回的状态属于谁所以经过层层的 typedef 定义得到 afStatus_t 退去一层 typedef typedef ZStatus_t afStatus_t; 再退去一层 typedef typedef Status_t ZStatus_t; 最后得到的 uint8 typedef uint8 Status_t; 到这一层定义我们就熟悉的 typedef unsigned char uint8; unsigned char 则是 C语言中的基本数据类型 3、随处可见的指针、引用(以下例子在上图的 AF_DataRequest() 函数的参数中抽取) 协议里的指针有如下几种 最简单的指针类型 uint8 *buf 即一维数组 结构体指针 afAddrType_t *dstAddr 函数指针 2 tasksArr[] 其实是函数指针类型定义的函数指针数据,说得有点绕,看下图 pTaskEventHandlerFn 是可以定义形如下面语句的指针数据类型即可以定义像这样的函数:unsigned short Function (参数 1,参数 2) 其中 unsigned short 是返回值这样就可以用 pTaskEventHandlerFn 定义函数变量了 pTaskEventHandlerFn taskArr[], 由于 taskArr 是数组类型,所以只要给 taskArr 指定不同的索引值就可以调用不同的函数 OSAL 层的任务切换就是通过此方法协议里的引用引用是函数参数传递的一种变种,因为函数要求参数传递要一一对应,如上参数 afAddrType_t *dstAddr 的,所以当调用 AF_DataRequest() 函数时,必须传递一个 afAddrType_t 类型的指针变量但是,请看, 文件中并不是结构体指针,而是普通的结构体变量,所以在AF_DataRequest() 函数调用时要使用引用,此时函数获得的仍然是此变量的地址, 而不是变量的值四、 OSAL Z-Stack 中引入了操作系统层 OSAL ,这样大大提高编程的灵活性,并且提高了 CPU 的运行效率但是此 OS不是真正意义上的 OS,因为他是通过在 OS的一个主循环不停的调用 task 任务函数来实现任务调度的,并未实现真正的上下文切换 Z-Stack 的难度之一是 OSAL 层的编程,还有 task 、events 、msg 的理解,还有任务切换的方法具体分析请看 Sheet2 表五、最后是对协议本身的理解对TI提供的文档阅读几遍是必要的,即使不能完全理解,但是多读几遍会有一个整体的理解,这样在 code 中遇到的陌生词汇 ZDO 、ZCL ,AF等就不会陌生这样再去翻阅具体的 ZDO 等部