ZStack-1.4.2-1.1.0版本的协议栈与ZStack-1.4.3-1.2.1版本的协议栈,发生了很大的变化,在添加用户自己的任务的方式,以及启动操作系统的函数void osal_start_system( void )都发生了变化。一开始我看的书《ZigBee2006无线网络与无线定位实践》中的例子中,操作系统添加任务有一个函数,该函数void osalAddTasks(void)具体实现如下:在其中添加了各个层的初始化函数和事件处理函数。包括Z-Stack自己本身的,还有用户自己添加的任务。
void osalAddTasks( void )
{
/* This task must be loaded first because Hal_Init() initializes
many things that other task_init functions may need.
*/
osalTaskAdd( Hal_Init, Hal_ProcessEvent, OSAL_TASK_PRIORITY_LOW );
#if defined( ZMAC_F8W )
osalTaskAdd( macTaskInit, macEventLoop, OSAL_TASK_PRIORITY_HIGH );
#endif
#if defined( MT_TASK )
osalTaskAdd( MT_TaskInit, MT_ProcessEvent, OSAL_TASK_PRIORITY_LOW );
#endif
osalTaskAdd( nwk_init, nwk_event_loop, OSAL_TASK_PRIORITY_MED );
osalTaskAdd( APS_Init, APS_event_loop, OSAL_TASK_PRIORITY_LOW );
osalTaskAdd( ZDApp_Init, ZDApp_event_loop, OSAL_TASK_PRIORITY_LOW );
osalTaskAdd( SampleApp_Init, SampleApp_ProcessEvent, OSAL_TASK_PRIORITY_LOW );
#if defined ( LOCATION_REFNODE )
osalTaskAdd( RefNode_Init, RefNode_ProcessEvent, OSAL_TASK_PRIORITY_LOW );
#endif
#if defined ( LOCATION_BLINDNODE )
osalTaskAdd( BlindNode_Init, BlindNode_ProcessEvent, OSAL_TASK_PRIORITY_LOW );
#endif
#if defined ( LOCATION_DONGLE )
osalTaskAdd( LocDongle_Init, LocDongle_ProcessEvent, OSAL_TASK_PRIORITY_LOW );
#endif
}
void osalTaskAdd( pTaskInitFn pfnInit,
pTaskEventHandlerFn pfnEventProcessor,
byte taskPriority)
{
osalTaskRec_t *newTask;
osalTaskRec_t *srchTask;
osalTaskRec_t **ptr;
newTask = osal_mem_alloc( sizeof( osalTaskRec_t ) );
if ( newTask )
{
// Fill in new task
newTask->pfnInit = pfnInit;
newTask->pfnEventProcessor = pfnEventProcessor;
newTask->taskID = taskIDs++;
newTask->taskPriority = taskPriority;
newTask->events = 0;
newTask->next = (osalTaskRec_t *)NULL;
// 'ptr' is the address of the pointer to the new task when the new task is
// inserted. Initially it is set to address of 'tasksHead' in case the new
// task is higher priority than the existing head or the queue is empty.
ptr = &tasksHead;
srchTask = tasksHead;
while (srchTask) {
if (newTask->taskPriority > srchTask->taskPriority) {
// insert here. New task has a higher priority than the task
// with which is being compared and a lower or equal priority
// to any task that precedes it.
newTask->next = srchTask;
*ptr = newTask;
return;
}
// set 'ptr' to address of the pointer to 'next' in the current
// (soon to be previous) task control block
ptr = &srchTask->next;
srchTask = srchTask->next;
}
// We're at the end of the current queue. New task is not higher
// priority than any other already in the list. Make it the tail.
// (It is also the head if the queue was initially empty.)
*ptr = newTask;
}
return;
}
这个函数中的osalTaskAdd()函数在文件OSAL_Tasks.c文件中定义,而在ZStack-1.4.3-1.2.1版本中,这两个函数应该都放弃不用了,我安装上ZStack-1.4.3-1.2.1版本的协议栈以后发现OSAL_Tasks.c文件中什么内容都没有,没有了osalTaskAdd()函数的具体实现。一开始还以为是安装有问题呢,重新安装了两次还是一样的问题,最后发现这个版本的协议栈已经有了另外一种处理的方式。其中在这个版本的协议中增加了几个比较重要的结构体来代替了原先的函数。其中之一就是:下面这个可以叫作函数指针数组。这个就和原先版本中的函数osalTaskAdd( Hal_Init, Hal_ProcessEvent, OSAL_TASK_PRIORITY_LOW );第2个参数相对应,其中void osalInitTasks( void ),这个函数也和ZStack-1.4.3-1.2.1版本有了不同,这两个函数虽然都是在初始化各个任务,但是在ZStack-1.4.3-1.2.1中初始化任务并且以递增的任务ID号为参数,相当于了不同的优先级。这个函数在前面的文章也有介绍。
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
ZDApp_event_loop,
SampleApp_ProcessEvent
};
还有一个重要的结构uint16 *tasksEvents;,指向分配给任务的内存地址。
那我们就看看在ZStack-1.4.3-1.2.1版本中添加自己的应用任务的流程是怎么样的。其实前面的文章也有进到,这里就当专门一个总结吧!
在ZStack-1.4.3-1.2.1中添加自己的任务,需要两个相关的处理函数,这两个函数的作用和ZStack-1.4.2-1.1.0版本是一样的,都要初始化函数,也都需要自己的事件处理函数。
(1)第一个就是用于初始化的函数,如例子中的SampleApp_Init(),这个函数在
void osalInitTasks( void )函数中调用,目的就是把用户自己的任务中的一些变量,网络的模式,网络EndPoint进行初始化
(2)用于引起该任务状态变化的事件发生后所需要执行的事件处理函数,如SampleApp_ProcessEvent(),这个函数首先在上面提到的数组const pTaskEventHandlerFn tasksArr[ ]中进行绑定,然后在void osal_start_system( void )中查找是否有事件发生,如果有事件发生就跳到绑定的事件处理函数中。这和ZStack-1.4.2-1.1.0版本的处理流程已经发生了变化。
那么添加一个任务就和上面的两个结构体密切相关了。这是我们以Example任务为例,来看一下添加任务的具体的步骤。主要是在osalInitTasks() 和taskArr[]添加相应的项就可以了。
(1) 修改osalInitTasks()
void osalInitTasks( void )
{
uint8 taskID = 0;
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
macTaskInit( taskID++ );
nwk_init( taskID++ );
Hal_Init( taskID++ );
#if defined( MT_TASK )
MT_TaskInit( taskID++ );
#endif
APS_Init( taskID++ );
ZDApp_Init( taskID++ );
Example_Init( taskID );
}
2. 修改taskArr[]数组
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
ZDApp_event_loop,
Example_ProcessEvent
};
这两个结构都在自己建立的OSAL_Example.c文件中。
后面就是根据不同的需要添加Example_Init()和Example_ProcessEvent()的具体的实现了。
其实这两个函数在前面的文章中都有涉及到,也就是SampleApp_Init()和SampleApp_ProcessEvent()函数。
从这里可以看到,其实添加自己的任务还是很简单的,这样的改进也效率也应该更高了。其中最复杂的应该还是后面任务事件的处理,才是完实际的功能。还是要说一点就是tasksArr[]和osalInitTasks()添加的顺序要一致。