最新消息: USBMI致力于为网友们分享Windows、安卓、IOS等主流手机系统相关的资讯以及评测、同时提供相关教程、应用、软件下载等服务。

ZStackOSAL中文说明

IT圈 admin 86浏览 0评论

2024年10月13日发(作者:雷嘉运)

1.概述

OSAL (Operating System Abstraction Layer),

翻译为“操作系统抽象层”。

在基于

ZigBee

协议的应用开发中,应用程序框架中包含了最多

240

个应用

程序对象。如果我们把一个应用程序对象看做为一个任务的话,那么应用程序框 架将包含

一个支持多任务的资源分配机制。于是

它正是

Z-Stack

为了实现这样一个机制而存在的。

OSAL

就是以实现多任务为核心的系统资源管理机制。 所以

OSAL

与标准的 操作系统

OSAL

便有了存在的必要性,

还是有很大的区别的。简单而言,

OSAL

实现了类似操作系统的某些功 能,但并不能称之为

真正意义上的操作系统。

2. OSAL 的 API 接口

函数名称

void osal_ nv_in it()

ui nt8 osal

ni t_system()

void osal_mem

n it()

void osalTimerl nit()

void osall nitTasks()

void osal_start_system()

void osal_ru n_system()

void osalTimeUpdate()

void Hal_ProcessPoll()

功能描述

初始化

FLASH

存储器

初始化操作系统

初始化内存分配系统

初始化定时器

初始化系统任务

进入操作系统

运行操作系统

操作系统时间更新

硬件层检查

2.1

消息管理功能

(1)

uint8 * osal_msg_allocate( uint16 len )

:申请一个指定长度的消息缓存区, 该函数调用

void *osal_mem_alloc( uint16 size )

函数实现,从堆中申请存储空间。

(2)

uint8 osal_msg_deallocate( uint8 *msg_ptr )

:接收到消息的任务处理完成 后释放消

息的缓存空间。

(3)

uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr )

发送消息至

U

指定

任务,将消息放入队列,并把任务的相应事件标志置位。

(4)

uint8 *osal_msg_receive( uint8 task_id

):接收发送到某个消息的任务,在 任务处理

完消息后,必修释放消息的存储空间。该函数查找消息队列,如果消息 队列中有多个发送给

该任务的消息,保持事件标志位。

(5)

osal_eve nt_hdr_t *osal_msg_fi nd(ui nt8 task_id, uint8 eve nt)

寻找发送给具 有某

个事件的任务的消息。

2.2

任务同步功能

(1)

uint8 osal_set_event(uint8 task_id, uint16 event_flag )

:设置某个任务的某 个事件

标志。

event_flag

16

位,只有一个系统事件

SYS_EVENT_MSG

,其余 的事件都是用户定

义的事件。

2.3

时间管理功能

时间管理的

API

既可以被

Z-stack

协议栈中的任务使用,也可以被应用级任 务使用。粒

度为

1ms

(

1

)

uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value)

:为某

个任务设置一个定时器,

taskID

为任务

ID

event_id

为用户 指定的事件标志位,

timeout_value

为超时时间,以

ms

为单位。

(

2

)

uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint16

timeout_value )

:设置定时器,与上一个函数不同的是该函数设置的定时器超时 后被重新装载。

(

3

)

uint8 osal_stop_timerEx( uint8 task_id, uint16 event_id )

:停止一个已经开 始的定时

器。

(

4

)

uint32 osal_GetSystemClock( void

):获取系统时间,返回值以

ms

为单位。

2.4

中断管理功能

(1)

uint8 osal_int_enable( uint8 interrupt_id )

:使能某个中断

(2)

uint8 osal_int_disable( uint8 interrupt_id )

:禁止某个中断

2.5

任务管理功能

const pTaskEve ntHa ndler Fn tasksArr[]=

{

macEve ntLoop,

n wk_eve nt_loop,

Hal_ProcessEve nt,

MT_ProcessEve nt,

APS_eve nt_loop,

APSF_ProcessEve nt,

ZDApp_eve nt_loop,

ZDNwkMgr_eve nt_loop,

Gen ericApp_ProcessEve nt

};

const uint8 tasksC nt = sizeof( tasksArr ) / sizeof( tasksArr[0]);

数组

tasksArr

定义了各个任务的事件回调函数,如果有用户自己定义的任 务,必须将

其事件回调函数加入到该数组中。

void osalI nitTasks( void )

uint8 taskID = 0;

tasksEve nts = (ui nt16 *)osal_mem_alloc( sizeof( ui nt16 ) * tasksC nt);

份配内存

osal_memset( tasksEve nts, 0, (sizeof( ui nt16 ) * tasksC nt));

清零

macTaskI nit( tasklD++ );

n wk_i nit( taskID++ );

Hal_l nit( taskID++ );

MT_Task In it( taskID++ );

APS

nit( taskID++ );

APSF_I nit( taskID++ );

ZDApp

nit( taskID++ );

ZDNwkMgr

nit( taskID++ );

Ge nericApp

nit( taskID );

}

以上函数在

osal_init_system()

函数中被调用。

2.6

电源管理功能

(1)

void osal_pwrmgr_init( void )

:初始化电源管理模块的变量,被

osal

ni t_system()

调用。

(2)

void osal_pwrmgr_powerconserve( void )

:使系统进入节电模式,已经在 系统的主

循环中被调用,不能调用。

(3)

void osal_pwrmgr_device( uint8 pwrmgr_device )

:全局设备电源的开关。

(4)

uint8 osal_pwrmgr_task_state(uint8 task_id, uint8 state )

:控制任务节电状 ^态。

2.7

非易失性存储器管理功能

非易失性存储器的操作很耗时,并且将暂时关闭中断,因此最好在收发器关 闭的时候

调用这些函数。不要频繁的写

NV mem

,因为这非常耗时耗电。

(1)

uint8 osal_nv_item

nit( uint16 id, uint16 len, void *buf )

:初始化一个

NV item

(2)

uint8 osal_nv_read( uint16 id, uint16 offset, uint16 len, void *buf )

:读取

NV

(3)

uint8 osal_nv_write( uint16 id, uint16 offset, uint16 len, void *buf )

:写入

NV

(4)

osal_offsetof(type, member)

计算一个结构体中某个成员的偏移。

2.8

内存管理功能

(1)

void *osal_ mem_alloc( uint16 size)

:在堆上分配指定大小的缓冲区。

(2)

void osal mem_free( void *ptr)

:释放使用

osal_mem_alloc(

分配的缓冲区。

以上两个函数要成对使用,防止产生内存泄露。

3. Zigbee协议栈 OSAL 分析

3.1 OSAL

运行机理

OSAL

是事件驱动的操作系统

(Event-driven OS)

,负责调度各个任务的运 行,如果有事

件发生了,则会调用相应的事件处理函数进行处理。

ZigBee

协议栈的实时性要求并不高,因此在设计任务调度程序时,

OSAL

只采用了轮询任务调度队列的方法来进行任务调度管理。

那么,事件和任务的事件处理函数是如何联系起来的昵?

ZigBee

中采用的

方法是:建立一个事件表,保存各个任务的对应的事件,建立另一个函数表,保 存各个任务

事件处理函数的地址,然后将这两张表建立某种对应关系,当某一事 件发生时则查找函数表

找到对应的事件处理函数即可。

ZigBee

协议栈中,有三个变量至关重要。

(

1

)

tasksCnt---

该变量保存了任务的总个数。

(2

)

tasksEvents---

这是一个指针,指向了事件表的首地址。这个数组中的

某个元素不为

0

,即代表此任务有事件需要相应,事件类型取决于这个元素的值

(3)

tasksArr----

这是一个数组,该数组的每一项都是一

个函数指针,指向 了事件处理函数。该数组的声明为:

con st pTaskEve ntHa ndlerFn

tasksArr[

。其中

pTaskEventHandlerFn

的定义为:

typedef unsigned short (*pTaskEventHandlerFn) (un sig

ned char task_id, un sig ned short eve nt

。)这是定义了一个函数指针。因此,

tasksArr

组的每一项都是一个函数指针,指向了事件处理函数。

总结一下

OSAL

的工作原理:通过

tasksEvents

指针访问事件表的每一项, 如果有事件

发生,则查找函数表找到相应事件处理函数进行处理, 处理完后,继

续访问事件表,查看是否有事件发生,无限循环。通常用关中断的方式保护共享 资源。

从这种意义上说,

OSAL

是一种基于事件驱动的轮询式操作系统。事件驱 动是指发生

事件后采取相应的事件处理方法,轮询指的是不断地查看是否有事件 发生。

不过接下来就有了更加深入的问题了,事件是如何被捕获的?直观一些来说 就是,

tasksEvents

这个数组里的元素是什么时候被设定为非零数,来表示有

事件需要处理的?

OSAL

的死循环中,各个事件只是在某些特定的情况下发生,所以这里 就引入了心

跳的概念,也就是

OS

的时钟节奏。在

Zstack OSAL

中这个节奏定义 为

1ms,

8 bits

HW_TIMER4

来控制。每当

1ms

心跳来临时,

Timer4

的中断标 志置位,这样在

OSAL

的死

循环中检测到这个标志置位后,就通过

osalTimerUpdate

()函数去轮询

Timer

事件链表,没

有检测到这个标志位则继续 死循环。其中,

Timer

事件链表通常在各任务事件的初始化时建

立。

Timer

事件链表是下面这样一个结构,

next

指向下一个

Timer

事件,

timeout

值表明本

Timer

事件还需要

timeout

个心跳才需要被处理,因为此处心跳是

1ms

, 所以也就是说还需

timeout

ms

才处理。所谓的处理也就是检测

timeout

是否 小于

1ms,

如果小于

1ms,

通过

osal_set_event(

)将

tasksEvents

相应位置置为

event_flag

。如果大于

1ms,

说明该

Timer

事件还不到处理的时候,则

Timeout = Timeout-1,

然后继续耐心等待下一次心跳。

Timer

件链表结构体定义如下:

typedef struct

{

void *n ext;

UINT16 timeout;

UINT16 eve nt_flag;

byte task_id;

} osalTimerRec_t;

3.2 OSAL

消息队列

事件是驱动任务去执行某些操作的条件,当系统中产生了一个事件,

OSAL

将这个事件传递给相应的任务后,任务才能执行一个相应的操作(调用事件处理 函数去处理)。

通常某些事件发生时,又伴随着一些附加信息的产生,例如:从 天线接收数据后,会产生

AF_INCOMING_MSG_CMD

事件,但是任务的事件处 理函数在处理这个事件的时候,还需

要得到所收到的数据。因此,这就需要将事 件和数据封装成一个消息,将消息发送到消息队

列,然后在事件处理函数中就可 以使用

osal_msg_receive

从消息队列中得到该消息。如下

代码可以从消息队列 中得到一个消息:

MSGpkt = (afIncomingMSGPacket_t *)osal_msg

_receive (Gen ericApp_TasklD)

OSAL

维护了一个消息队列,每一个消息都会被放到这个消息队列中去, 当 任务接收

到事件后,可以从消息队列中获取属于自己的消息, 然后调用消息处理 函数进行相应的处

理即可。 通常在不同任务间通讯时使用消息机制。

3.4 OSAL

添加任务

tasksArr[]

数组里存放了所有任务的事件处理函数的地址;

OSAL

的任务初始化函数,所有任务的初始化工作都在这里面完成,

osallnitTasks

并且自动给

每个任务分配一个

ID

。因此,要添加新任务,只需要编写两个函数:新任务的 初始化函数

和新任务的事件处理函数。

将新任务的初始化函数添加在

osall ni tTasks

函数的最后,如下代码所示

const

pTaskEventHandlerFn tasksArr[]=(

macEventLoopj

nwk_event_loop,

Hal_ProeessEventj

#if definedf )

sEvent

t

Nendi f

APS_event 1oop,

#if defined ( NTATION )

APSF_ProcessEventj

#endlf

ZDApp_EVETlt_l 口叩」

«if defined ( ZIGBEE_FREQ_AGTLITY ) || defined ( ZIGBEE_PANID_CONFLICT )

ZDNwkffigr-event-loop,

tfendi f

^enericApp_ProcessEvent

};

将事件处理函数的地址加入

tasksArr[]

数组,如下所示。

void osallni tTasks( void j

{

uintS taskID = 0;

tasksEvents = (uint 16 *)osal_mern_al loc ( sizeof ( uint 16 ) * tasksCnt); oEal_meniset ( t asksEvent

s

3

0

(sizeof ( uint 16 ) * t asksCnt));

tnacTasklni t ( taskID++ );

wk_init( taskID++ );

Hal_Init( taskID++ );

#if definedC IT^TASK )

KT_TaskInil( TAskID+1

》;

#endi f

APS Init( taskID++ );

#lf defined ( HTATION )

APSF_Init( taskID++ );

#endif

ZDApp_Ini t( 1askID++ );

#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )

ZDNwkMgr_lnit( tasklD++ );

rtendif

GenericApp^Init( taskID J

需要注意两点:

1

tasksArr[]

数组里各事件处理函数的排列顺序要与

osallnitTasks

函数中 调

用各任务初始化函数的顺序保持一致,只有这样才能够保证每个任务的事件处 理函数能够接

收到正确的任务

ID

(在

osallnitTasks

函数中分配)。

2

) 为了保存

osallnitTasks

函数所分配的任务

ID

,需要给每一个任务定义 一个全局

变量。如在

Coordinator.c

中定义了一个全局变量

GenericApp_TaskID

, 并且在

GenericApp_lnit

函数中进行了赋值。

3.5

原语通信

原语只是一个理论层面上的术语,描述了服务层次的关系,以及两个通信的

N

用户和

它们相连的

N

层(子层)对待协议实体之间的关系。

一个原语的操作往往需要逐层调用下层函数并根据下层返回的结果来进行 进一步的操

作。在这种情况下,一个原主的操作从发起到完成需要很长时间。

此,如果让程序一直等待下层返回的结果再进一步处理,

间处于循环等待之中,无法及时处理其它请求。

因此,与请求、响应原语操作相对应的函数,一旦调用了下层相关函数后, 就立即返

回。下层处理函数在操作结束后,将结果以消息的形式发送到上层并产 生一个系统事件,调

度程序发现这个事件后就会调用相应的事件处理函数对它进 行处理。(调用就返回,而不管

函数有没有处理完成。当函数处理完成后将结果 以消息的形式发送到上层产生一个系统事

件)。

会使微处理器大部分时

2024年10月13日发(作者:雷嘉运)

1.概述

OSAL (Operating System Abstraction Layer),

翻译为“操作系统抽象层”。

在基于

ZigBee

协议的应用开发中,应用程序框架中包含了最多

240

个应用

程序对象。如果我们把一个应用程序对象看做为一个任务的话,那么应用程序框 架将包含

一个支持多任务的资源分配机制。于是

它正是

Z-Stack

为了实现这样一个机制而存在的。

OSAL

就是以实现多任务为核心的系统资源管理机制。 所以

OSAL

与标准的 操作系统

OSAL

便有了存在的必要性,

还是有很大的区别的。简单而言,

OSAL

实现了类似操作系统的某些功 能,但并不能称之为

真正意义上的操作系统。

2. OSAL 的 API 接口

函数名称

void osal_ nv_in it()

ui nt8 osal

ni t_system()

void osal_mem

n it()

void osalTimerl nit()

void osall nitTasks()

void osal_start_system()

void osal_ru n_system()

void osalTimeUpdate()

void Hal_ProcessPoll()

功能描述

初始化

FLASH

存储器

初始化操作系统

初始化内存分配系统

初始化定时器

初始化系统任务

进入操作系统

运行操作系统

操作系统时间更新

硬件层检查

2.1

消息管理功能

(1)

uint8 * osal_msg_allocate( uint16 len )

:申请一个指定长度的消息缓存区, 该函数调用

void *osal_mem_alloc( uint16 size )

函数实现,从堆中申请存储空间。

(2)

uint8 osal_msg_deallocate( uint8 *msg_ptr )

:接收到消息的任务处理完成 后释放消

息的缓存空间。

(3)

uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr )

发送消息至

U

指定

任务,将消息放入队列,并把任务的相应事件标志置位。

(4)

uint8 *osal_msg_receive( uint8 task_id

):接收发送到某个消息的任务,在 任务处理

完消息后,必修释放消息的存储空间。该函数查找消息队列,如果消息 队列中有多个发送给

该任务的消息,保持事件标志位。

(5)

osal_eve nt_hdr_t *osal_msg_fi nd(ui nt8 task_id, uint8 eve nt)

寻找发送给具 有某

个事件的任务的消息。

2.2

任务同步功能

(1)

uint8 osal_set_event(uint8 task_id, uint16 event_flag )

:设置某个任务的某 个事件

标志。

event_flag

16

位,只有一个系统事件

SYS_EVENT_MSG

,其余 的事件都是用户定

义的事件。

2.3

时间管理功能

时间管理的

API

既可以被

Z-stack

协议栈中的任务使用,也可以被应用级任 务使用。粒

度为

1ms

(

1

)

uint8 osal_start_timerEx( uint8 taskID, uint16 event_id, uint16 timeout_value)

:为某

个任务设置一个定时器,

taskID

为任务

ID

event_id

为用户 指定的事件标志位,

timeout_value

为超时时间,以

ms

为单位。

(

2

)

uint8 osal_start_reload_timer( uint8 taskID, uint16 event_id, uint16

timeout_value )

:设置定时器,与上一个函数不同的是该函数设置的定时器超时 后被重新装载。

(

3

)

uint8 osal_stop_timerEx( uint8 task_id, uint16 event_id )

:停止一个已经开 始的定时

器。

(

4

)

uint32 osal_GetSystemClock( void

):获取系统时间,返回值以

ms

为单位。

2.4

中断管理功能

(1)

uint8 osal_int_enable( uint8 interrupt_id )

:使能某个中断

(2)

uint8 osal_int_disable( uint8 interrupt_id )

:禁止某个中断

2.5

任务管理功能

const pTaskEve ntHa ndler Fn tasksArr[]=

{

macEve ntLoop,

n wk_eve nt_loop,

Hal_ProcessEve nt,

MT_ProcessEve nt,

APS_eve nt_loop,

APSF_ProcessEve nt,

ZDApp_eve nt_loop,

ZDNwkMgr_eve nt_loop,

Gen ericApp_ProcessEve nt

};

const uint8 tasksC nt = sizeof( tasksArr ) / sizeof( tasksArr[0]);

数组

tasksArr

定义了各个任务的事件回调函数,如果有用户自己定义的任 务,必须将

其事件回调函数加入到该数组中。

void osalI nitTasks( void )

uint8 taskID = 0;

tasksEve nts = (ui nt16 *)osal_mem_alloc( sizeof( ui nt16 ) * tasksC nt);

份配内存

osal_memset( tasksEve nts, 0, (sizeof( ui nt16 ) * tasksC nt));

清零

macTaskI nit( tasklD++ );

n wk_i nit( taskID++ );

Hal_l nit( taskID++ );

MT_Task In it( taskID++ );

APS

nit( taskID++ );

APSF_I nit( taskID++ );

ZDApp

nit( taskID++ );

ZDNwkMgr

nit( taskID++ );

Ge nericApp

nit( taskID );

}

以上函数在

osal_init_system()

函数中被调用。

2.6

电源管理功能

(1)

void osal_pwrmgr_init( void )

:初始化电源管理模块的变量,被

osal

ni t_system()

调用。

(2)

void osal_pwrmgr_powerconserve( void )

:使系统进入节电模式,已经在 系统的主

循环中被调用,不能调用。

(3)

void osal_pwrmgr_device( uint8 pwrmgr_device )

:全局设备电源的开关。

(4)

uint8 osal_pwrmgr_task_state(uint8 task_id, uint8 state )

:控制任务节电状 ^态。

2.7

非易失性存储器管理功能

非易失性存储器的操作很耗时,并且将暂时关闭中断,因此最好在收发器关 闭的时候

调用这些函数。不要频繁的写

NV mem

,因为这非常耗时耗电。

(1)

uint8 osal_nv_item

nit( uint16 id, uint16 len, void *buf )

:初始化一个

NV item

(2)

uint8 osal_nv_read( uint16 id, uint16 offset, uint16 len, void *buf )

:读取

NV

(3)

uint8 osal_nv_write( uint16 id, uint16 offset, uint16 len, void *buf )

:写入

NV

(4)

osal_offsetof(type, member)

计算一个结构体中某个成员的偏移。

2.8

内存管理功能

(1)

void *osal_ mem_alloc( uint16 size)

:在堆上分配指定大小的缓冲区。

(2)

void osal mem_free( void *ptr)

:释放使用

osal_mem_alloc(

分配的缓冲区。

以上两个函数要成对使用,防止产生内存泄露。

3. Zigbee协议栈 OSAL 分析

3.1 OSAL

运行机理

OSAL

是事件驱动的操作系统

(Event-driven OS)

,负责调度各个任务的运 行,如果有事

件发生了,则会调用相应的事件处理函数进行处理。

ZigBee

协议栈的实时性要求并不高,因此在设计任务调度程序时,

OSAL

只采用了轮询任务调度队列的方法来进行任务调度管理。

那么,事件和任务的事件处理函数是如何联系起来的昵?

ZigBee

中采用的

方法是:建立一个事件表,保存各个任务的对应的事件,建立另一个函数表,保 存各个任务

事件处理函数的地址,然后将这两张表建立某种对应关系,当某一事 件发生时则查找函数表

找到对应的事件处理函数即可。

ZigBee

协议栈中,有三个变量至关重要。

(

1

)

tasksCnt---

该变量保存了任务的总个数。

(2

)

tasksEvents---

这是一个指针,指向了事件表的首地址。这个数组中的

某个元素不为

0

,即代表此任务有事件需要相应,事件类型取决于这个元素的值

(3)

tasksArr----

这是一个数组,该数组的每一项都是一

个函数指针,指向 了事件处理函数。该数组的声明为:

con st pTaskEve ntHa ndlerFn

tasksArr[

。其中

pTaskEventHandlerFn

的定义为:

typedef unsigned short (*pTaskEventHandlerFn) (un sig

ned char task_id, un sig ned short eve nt

。)这是定义了一个函数指针。因此,

tasksArr

组的每一项都是一个函数指针,指向了事件处理函数。

总结一下

OSAL

的工作原理:通过

tasksEvents

指针访问事件表的每一项, 如果有事件

发生,则查找函数表找到相应事件处理函数进行处理, 处理完后,继

续访问事件表,查看是否有事件发生,无限循环。通常用关中断的方式保护共享 资源。

从这种意义上说,

OSAL

是一种基于事件驱动的轮询式操作系统。事件驱 动是指发生

事件后采取相应的事件处理方法,轮询指的是不断地查看是否有事件 发生。

不过接下来就有了更加深入的问题了,事件是如何被捕获的?直观一些来说 就是,

tasksEvents

这个数组里的元素是什么时候被设定为非零数,来表示有

事件需要处理的?

OSAL

的死循环中,各个事件只是在某些特定的情况下发生,所以这里 就引入了心

跳的概念,也就是

OS

的时钟节奏。在

Zstack OSAL

中这个节奏定义 为

1ms,

8 bits

HW_TIMER4

来控制。每当

1ms

心跳来临时,

Timer4

的中断标 志置位,这样在

OSAL

的死

循环中检测到这个标志置位后,就通过

osalTimerUpdate

()函数去轮询

Timer

事件链表,没

有检测到这个标志位则继续 死循环。其中,

Timer

事件链表通常在各任务事件的初始化时建

立。

Timer

事件链表是下面这样一个结构,

next

指向下一个

Timer

事件,

timeout

值表明本

Timer

事件还需要

timeout

个心跳才需要被处理,因为此处心跳是

1ms

, 所以也就是说还需

timeout

ms

才处理。所谓的处理也就是检测

timeout

是否 小于

1ms,

如果小于

1ms,

通过

osal_set_event(

)将

tasksEvents

相应位置置为

event_flag

。如果大于

1ms,

说明该

Timer

事件还不到处理的时候,则

Timeout = Timeout-1,

然后继续耐心等待下一次心跳。

Timer

件链表结构体定义如下:

typedef struct

{

void *n ext;

UINT16 timeout;

UINT16 eve nt_flag;

byte task_id;

} osalTimerRec_t;

3.2 OSAL

消息队列

事件是驱动任务去执行某些操作的条件,当系统中产生了一个事件,

OSAL

将这个事件传递给相应的任务后,任务才能执行一个相应的操作(调用事件处理 函数去处理)。

通常某些事件发生时,又伴随着一些附加信息的产生,例如:从 天线接收数据后,会产生

AF_INCOMING_MSG_CMD

事件,但是任务的事件处 理函数在处理这个事件的时候,还需

要得到所收到的数据。因此,这就需要将事 件和数据封装成一个消息,将消息发送到消息队

列,然后在事件处理函数中就可 以使用

osal_msg_receive

从消息队列中得到该消息。如下

代码可以从消息队列 中得到一个消息:

MSGpkt = (afIncomingMSGPacket_t *)osal_msg

_receive (Gen ericApp_TasklD)

OSAL

维护了一个消息队列,每一个消息都会被放到这个消息队列中去, 当 任务接收

到事件后,可以从消息队列中获取属于自己的消息, 然后调用消息处理 函数进行相应的处

理即可。 通常在不同任务间通讯时使用消息机制。

3.4 OSAL

添加任务

tasksArr[]

数组里存放了所有任务的事件处理函数的地址;

OSAL

的任务初始化函数,所有任务的初始化工作都在这里面完成,

osallnitTasks

并且自动给

每个任务分配一个

ID

。因此,要添加新任务,只需要编写两个函数:新任务的 初始化函数

和新任务的事件处理函数。

将新任务的初始化函数添加在

osall ni tTasks

函数的最后,如下代码所示

const

pTaskEventHandlerFn tasksArr[]=(

macEventLoopj

nwk_event_loop,

Hal_ProeessEventj

#if definedf )

sEvent

t

Nendi f

APS_event 1oop,

#if defined ( NTATION )

APSF_ProcessEventj

#endlf

ZDApp_EVETlt_l 口叩」

«if defined ( ZIGBEE_FREQ_AGTLITY ) || defined ( ZIGBEE_PANID_CONFLICT )

ZDNwkffigr-event-loop,

tfendi f

^enericApp_ProcessEvent

};

将事件处理函数的地址加入

tasksArr[]

数组,如下所示。

void osallni tTasks( void j

{

uintS taskID = 0;

tasksEvents = (uint 16 *)osal_mern_al loc ( sizeof ( uint 16 ) * tasksCnt); oEal_meniset ( t asksEvent

s

3

0

(sizeof ( uint 16 ) * t asksCnt));

tnacTasklni t ( taskID++ );

wk_init( taskID++ );

Hal_Init( taskID++ );

#if definedC IT^TASK )

KT_TaskInil( TAskID+1

》;

#endi f

APS Init( taskID++ );

#lf defined ( HTATION )

APSF_Init( taskID++ );

#endif

ZDApp_Ini t( 1askID++ );

#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )

ZDNwkMgr_lnit( tasklD++ );

rtendif

GenericApp^Init( taskID J

需要注意两点:

1

tasksArr[]

数组里各事件处理函数的排列顺序要与

osallnitTasks

函数中 调

用各任务初始化函数的顺序保持一致,只有这样才能够保证每个任务的事件处 理函数能够接

收到正确的任务

ID

(在

osallnitTasks

函数中分配)。

2

) 为了保存

osallnitTasks

函数所分配的任务

ID

,需要给每一个任务定义 一个全局

变量。如在

Coordinator.c

中定义了一个全局变量

GenericApp_TaskID

, 并且在

GenericApp_lnit

函数中进行了赋值。

3.5

原语通信

原语只是一个理论层面上的术语,描述了服务层次的关系,以及两个通信的

N

用户和

它们相连的

N

层(子层)对待协议实体之间的关系。

一个原语的操作往往需要逐层调用下层函数并根据下层返回的结果来进行 进一步的操

作。在这种情况下,一个原主的操作从发起到完成需要很长时间。

此,如果让程序一直等待下层返回的结果再进一步处理,

间处于循环等待之中,无法及时处理其它请求。

因此,与请求、响应原语操作相对应的函数,一旦调用了下层相关函数后, 就立即返

回。下层处理函数在操作结束后,将结果以消息的形式发送到上层并产 生一个系统事件,调

度程序发现这个事件后就会调用相应的事件处理函数对它进 行处理。(调用就返回,而不管

函数有没有处理完成。当函数处理完成后将结果 以消息的形式发送到上层产生一个系统事

件)。

会使微处理器大部分时

发布评论

评论列表 (0)

  1. 暂无评论