ZigBee 协议栈依据 IEEE 802.15.4 标准和 ZigBee 协议规范。
ZigBee 网络中的各种操作需要 ,利用协议栈各层所提供的原语操作来共同完成。原语操作的实现过程往往需要向下一层发起一 个原语操作并且通过下层返回的操作结果来判断出下一条要执行的原语操作。IEEE 802 .15 .4 标准和 ZigBee 协议规范中定义的各层原语操作多达数十条,原语的操作过程也比较复杂,它 已经不是一个简单的单任务软件。对于这样一个复杂的嵌入式通信软件来说,其实现通常需要 依靠嵌入式操作系统来完成。
挪威半导体公司 Chipcon( 目前已经被TI 公司收购)作为业界领先的 ZigBee 一站式方案供应 商,在推出其 CC2530 开发平台时,也向用户提供了自己的 ZigBee 协议栈软件-Z-Stack 。这是 一款业界领先的商业级协议栈,使用 CC2530 射频芯片,可以使用户很容易的开发出具体的应 用程序来。Z-Stack 使用瑞典公司 IAR 开发的 IAR Embedded Workbench for MCS .51 作为它的 集成开发环境。Chipcon 公司为自己设计的 Z-Stack 协议栈中提供了一个名为操作系统抽象层 OSAL 的协议栈调度程序。对于用户来说,除了能够看到这个调度程序外,其它任何协议栈操 作的具体实现细节都被封装在库代码中。用户在进行具体的应用开发时只能够通过调用API 接 口来进行,而无权知道 Zig,Bee 协议栈实现的具体细节。
1
Z-Stack1.4.3及以后的版本中引入了一个OSAL(Operating System Abstraction Layer 操作系统抽象层),但在我们整个的ZigBee协议栈的结构图中,我并没有能够发现这个层在哪个位置。但是整个的协议栈都要在OS的基础上才能运行。OSAL和我们通常所说的RTOS,pc上的操作系统还是有很大的不同,ZigBee2006中只是利用了操作系统的概念和思想,利用OS把Z-Stack软件组件从特殊的处理过程相分离,并将软件成分保护了起来。它提供了如下的管理功能: ◆任务的注册、初始化、开始 ◆ 任务间的消息交换 ◆任务同步 ◆ 中断处理 ◆时间管理 ◆ 内存分配
OSAL主要是这样一种机制,一种任务分配资源的机制,从而形成了一个简单多任务的操作系统。首先,osal初始化系统,包括软件系统初始化和资源初始化.其中软件系统初始化就是初始化一些变量,比如osal重要的组成部分任务表,任务结构体和序列号.资源初始化主要包括内存,中断,NV等各种设备模块资源.这就和我们嵌入式系统中的RTOS操作系统μC/OS-II有了很大的相似处。μC/OS-II中也是
2
通过建立任务把一个问题进行分解,任务之间可以通过消息队列的方式进行通信。
接着,osal通过osal_add_task添加任务到任务表中,形成一个任务链表.这个任务链表是以任务的优先级先后排序的.优先级高的排在前,低者排于后.
最后,开始运行系统,系统是以一个死循环的形式工作的.在循环体当中不断地检测各个任务,看是否要运行等.这就相当于我们平时用的linux和window等多任务系统,把CPU分成N个时间片(有多少任务就分成多少时间片),只要处理频率高,就相当于多任务同时运行了。下面我们来结合sampleAPP来说明一下OSAL的具体工作情况。
Sample Application是ZStack协议栈提供的一个非常简单的演示实例,实例中的每个设备都可以发送和接收两种信息:周期信息和闪烁信息。
周期信息---------当设备加入该网络后,所有设备每隔 5S(加上一个随机数,毫秒mS为单位)发送一个周期信息,该信息的数据载荷为发送信息的次数。
闪烁信息---------通过按下按键 SW1发送一个控制LED灯闪烁的广播信息,该广播信息只针对组 1 内的所有设备。所有设备初始化都被加入组 1,所以网络一旦建立完成便可执行LED灯闪烁实验。可
3
以通过按下设备的 SW2 退出组 1,如果设备退出组1则不再接收来自组1的消息,其按键SW1发送的消息也不再控制组1LED灯的闪烁。通过再次按下 SW2 便可让设备再次加入到组1,从而又可以接受来自组1的消息,其SW1也可以控制组1内设备的LED灯闪烁了。 当设备接收到闪烁信息会闪烁LED灯,而当接收到周期信息时协议栈没有提供具体的实验现象,留给了用户自行处理,可以根据实际需要自行更改实验代码。
在该工程中使用了两个按键SW1和SW2。即ZStack协议栈中的HAL_KEY_SW_1和HAL_KEY_SW_2。同时工程中也定义了一个事件用来处理周期信息事件,即
SAMPLEAPP_SEND_PERIODIC_MSG_EVT[SampleApp.h]。 二、一般工程说明:
在学习ZStack协议栈的时候我们要把握一个重点就是事件的产生和事件的处理。任务的初始化为事件的产生制造了“温床”,是事件产生的前提,任何工程都需要先初始化。当有事件产生OS就会调用相应的处理函数进行处理。在OS循环那一节我们可以看到在任务初始化的最后一项就是应用层的初始化,而在指向处理函数的指针数组中最后一项是对应的应用层的处理函数。应用层相关事件会由应用层处理函数进行处理。每一层都是相互对应,各司其职。
程序执行流程如下: ZMain.c的main()--->osal.c的
4
osal_init_system()---->OSAL_SampleApp.c的
osalInitTasks()之后分两部分执行-------->首先执行SampleApp.c的
SampleApp_Init(),接着执行osal.c中的事件循环,不停的执行 SampleApp_ProcessEvent(),进行应用层事件检测。 两个关键函数 1.SampleApp_Init 2.SampleApp_ProcessEvent 具体代码如下: SampleApp_init
void SampleApp_Init( uint8 task_id ) {
//osal应用层的任务ID赋值 SampleApp_TaskID = task_id;
//设备状态设定为ZDO层中定义的初始化状态 SampleApp_NwkState = DEV_INIT; //定义消息ID
SampleApp_TransID = 0;
//后面的demo例子中用到这个编译选项
5
#if defined ( SOFT_START )
//如果选择了SOFT编译选项,则作为协调器启动
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
#endif // SOFT_START
//如果定义了HOLD_AUTO_START选项,则调用层的ZDOInitDevice,按照默认顺
//序网络中的第一个设备作为协调器,其他的设备作为子设备 #if defined ( HOLD_AUTO_START )
ZDOInitDevice(0); #endif //定义广播地址 //地址模式
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast; //指定端点号
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT //指定目的网络地址为广播地址
SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;
6
// 设定flash中命令即按键命令要发送的目的地址
SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup; SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;
// 定义本设备用来通信的APS层端点描述符 //端点号
SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; //任务ID
SampleApp_epDesc.task_id = &SampleApp_TaskID; //简单描述符
SampleApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc; //延时策略
SampleApp_epDesc.latencyReq = noLatencyReqs; // 向AF层注册端点描述符 afRegister( &SampleApp_epDesc ); // 向osal层注册按键消息
RegisterForKeys( SampleApp_TaskID );
7
// 设定一个新的组 //组号
SampleApp_Group.ID = 0x0003; //设定组名
osal_memcpy( SampleApp_Group.name, \"Group 3\//把该组添加到网络中
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group ); #if defined ( LCD_SUPPORTED )
//如果选择了LCD_SUPPORTED编译选项,会打印一串字符 Print8(HAL_LCD_LINE_2,20,\"SampleApp\#endif }
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ) {
//定义应用层数据包
afIncomingMSGPacket_t *MSGpkt;
//判断osal层的消息类型 //如果系统消息到来
if ( events & SYS_EVENT_MSG ) {
8
//接收数据包
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); //如果数据包不为空 while ( MSGpkt ) {
//判断消息类型
switch ( MSGpkt->hdr.event ) {
// 如果是按键消息 case KEY_CHANGE: //调用按键处理函数
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state,
((keyChange_t *)MSGpkt)->keys ); break;
// 如果是别的组设备周期发送的消息 case AF_INCOMING_MSG_CMD: //调用对周期消息的处理函数
SampleApp_MessageMSGCB( MSGpkt ); break;
9
// 如果是设备状态变换的命令 case ZDO_STATE_CHANGE: //获取设备状态
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status); //如果是三种状态之一
if ( (SampleApp_NwkState == DEV_ZB_COORD) || (SampleApp_NwkState == DEV_ROUTER)
|| (SampleApp_NwkState == DEV_END_DEVICE) ) {
// 按正常间隔启动一个定时器
osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT ); } else {
//设备不在网络中的不做任何处理
10
// Device is no longer in the network } break; default: break; }
// 释放消息占用的存储区
osal_msg_deallocate( (uint8 *)MSGpkt ); // 判断操作系统层是否有未处理的数据包,继续处理缓冲区中的包
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID ); }
//判断是否有未处理的系统消息,有则接收数据包,放到缓冲区一个个处理
return (events ^ SYS_EVENT_MSG); }
11
// 判断是否有定时消息
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT ) {
// 定时时间到发送一个消息 SampleApp_SendPeriodicMessage(); // 重新启动定时器
osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
// 判断是否有未处理的周期消息,有则继续处理 return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT); }
// 其它事件不予处理,直接返回 return 0; }
总之,OSAL实现了类似操作系统的某些功能,但我认为并不能称之
12
为真正意义上的操作系统。它的复杂性和功能性和通常的操作系统都有所不同。OSAL层是与协议栈的,但是整个协议都要基于OS才能运行。
13
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igat.cn 版权所有 赣ICP备2024042791号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务