在ZStack-1.4.3-1.2.1中添加自己的任务,需要两个相关的处理函数,这两个函数的作用和ZStack-1.4.2-1.1.0版本是一样的,都要初始化函数,也都需要自己的事件处理函数。
***************************************添加任务*************************************************************************
(1)第一个就是用于初始化的函数,如例子中的XXXX_Init(),这个函数在
void osalInitTasks( void )
函数中调用,目的就是把用户自己的任务中的一些变量
特别是把任务ID传递给当前任务
,网络的模式,网络
EndPoint
进行初始化.
void XXXXXX_Int( uint8 taskId )
{
OSALTaskId = taskId;
。。。。。。。。。。。
}
(2)登记初始化函数并分配对应的事件ID
修改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++ );
xxxx_Init( taskID );
}
(3) 编写用于引起该任务状态变化的事件发生后所需要执行的事件处理函数,如xxxx_ProcessEvent(),这个函数首先在数组const pTaskEventHandlerFn tasksArr[ ]中进行绑定,然后在void osal_start_system( void )中查找是否有事件发生,如果有事件发生就跳到绑定事件处理函数xxxx_ProcessEvent()中。
xxxx_ProcessEvent()
{
有如下代码
if( events & TEST_TIMER_EVT ) //测试定时器功能
{
//
.................. //要根据不同的事件分类调用相应的处理函数 这就是事件响应函数
}
}
(4)修改taskArr[]数组
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK )
MT_ProcessEvent,
#endif
APS_event_loop,
ZDApp_event_loop,
xxxxxx_ProcessEvent
};
***************************************添加事件*************************************************************************
(5)定义事件,就是自己在此任务中可能有不同情况,就是不同事件了。
eg:
#define MSG_SD_AND_RV 0x0001 //测试信息发送与接收 事件一
#define TEST_EVENT_EVT 0x0001 //测试事件触发与停止 事件二
(7)触发事件
就是说在程序的某个地方应该有类似如下的语句开启一个事件
osal_set_event( OSALTaskId, TEST_EVENT_EVT );//触发一个事件
(8)事件响应 就是执行如下中的代码
xxxx_ProcessEvent()
{
有如下代码
if( events & TEST_TIMER_EVT ) //测试定时器功能
{
//
.................. //要根据不同的事件分类调用相应的处理函数 这就是事件响应函数
}
}
***********************************************如何添加超时定时事件**********************************************
(1)编写开启超时定时器函数
osal_start_timerEx( OSALTaskId, TEST_TIMER_EVT, 3000 );//开启一个超时事件
(2)制定超时定时器的响应功能函数
if( events & TEST_TIMER_EVT ) //测试定时器功能
{
HalLcdPutString16_8(0, 0, " Test Timer ", 12, 1);
debug_str( "respond TEST_TIMER_EVT event!\r\n");
osal_start_timerEx( OSALTaskId, TEST_TIMER_EVT, 3000 );//重新开启一个超时事件
return events ^ TEST_TIMER_EVT;
}
(3)停止一个超时定时器
osal_stOP_timerEx(.....)
***********************************************如何编写 OS信息发送功能
***********************************************
(1)信息单元分配与发送功能
z 调用 osal_msg_allocate 分配一个指定大小的内存块
z 往内存块中存放事件值与指针
z 调用 osal_msg_send 向指定的任务发送信息
ptr = ( MSGS * )osal_msg_allocate( sizeof( MSGS ) );//分配一个内存块
if( ptr != NULL )
{
msgCt ++;
ptr->events = MSG_SD_AND_RV;
ptr->msg = &msgCt;
osal_msg_send( OSALTaskId, (void *)ptr );
}
(2)
接收一个 OS 信息并处理
当一个任务收到 OS 信息后会产生一次 SYS_EVENT_MSG 事件用户可以通过调用 osal_msg_receive 接收指定任务 id 的信息
if ( events & SYS_EVENT_MSG )
{
ptr = ( MSGS *)osal_msg_receive( OSALTaskId );
while( ptr )
{
switch( ptr->events )
{
case MSG_SD_AND_RV:
val = *ptr->msg;
bPtr[9] = val/100 + '0';
temp = val%100;
bPtr[10] = temp/10 + '0';
bPtr[11] = temp%10 + '0';
HalLcdPutString16_8(0, 0, bPtr, 12, 1);
//显示记数
break;
}
osal_msg_deallocate( (uint8 *)ptr ); //册除已经使用并分配的缓存区
ptr = ( MSGS *)osal_msg_receive( OSALTaskId ); //一次性收完所有需要接收的数据,也可以不一次接受
}
return (events ^ SYS_EVENT_MSG);//清除当前事件位
}
1.用户自己设计的任务代码在Zstack中的调用过程
(1).main() 执行(在ZMain.c中)
main() ---> osal_init_system()
(2). osal_init_system()调用osalInitTasks(), (在OSAL.c中)
osal_init_system() ---> osalInitTasks()
(3). osalInitTasks()调用SampleApp_Init() , (在OSAL_SampleApp.c中)
osalInitTasks() ---> SampleApp_Init()
在osalInitTasks()中实现了多个任务初始化的设置,其中macTaskInit( taskID++ )到ZDApp_Init( taskID++ )的几行代码表示对于几个系统运行初始化任务的调用,而用户自己实现的SampleApp_Init()在最后,这里taskID随着任务的增加也随之递增.所以用户自己实现的任务的初始化操作应该在osalInitTasks()中增加.
void osalInitTasks( void )
{
uint8 taskID = 0;
//这里很重要, 调用osal_mem_alloc()为当前OSAL中的各任务分配存储空间(实际上是一个任//务数组),并用tasksEvents指向该任务数组(任务队列).
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt)); //将taskSEvents所指向的空间清零
macTaskInit( taskID++ );
nwk_init( taskID++ );
Hal_Init( taskID++ );
#if defined( MT_TASK )
MT_TaskInit( taskID++ );
#endif
APS_Init( taskID++ );
ZDApp_Init( taskID++ );
SampleApp_Init( taskID ); //用户自己需要添加的任务
}
2.任务处理调用的重要数据结构
这里要解释一下,在Zstack里,对于同一个任务可能有多种事件发生,那么需要执行不同的事件处理,为了方便,对于每个任务的事件处理函数都统一在一个事件处理函数中实现,然后根据任务的ID号(task_id)和该任务的具体事件(events)调用某个任务的事件处理函数,进入了该任务的事件处理函数之后,再根据events再来判别是该任务的哪一种事件发生,进而执行相应的事件处理.pTaskEventHandlerFn 是一个指向函数(事件处理函数)的指针,这里实现的每一个数组元素各对应于一个任务的事件处理函数,比如SampleApp_ProcessEvent对于用户自行实现的事件处理函数uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events ),所以这里如果我们实现了一个任务,还需要把实现的该任务的事件处理函数在这里添加.
const pTaskEventHandlerFn tasksArr[] = {
macEventLoop,
nwk_event_loop,
Hal_ProcessEvent,
#if defined( MT_TASK ) //一个MT任务命令
MT_ProcessEvent,
#endif
APS_event_loop,
ZDApp_event_loop,
SampleApp_ProcessEvent
};
注意, tasksEvents和tasksArr[]里的顺序是一一对应的, tasksArr[]中的第i个事件处理函数对应于tasksEvents中的第i个任务的事件.
//计算出任务的数量
const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
uint16 *tasksEvents;
3. 对于不同事件发生后的任务处理函数的调用
osal_start_system() 很重要,决定了当某个任务的事件发生后调用对应的事件处理函数
void osal_start_system(void)
{
#if !defined ( ZBIT )
for(;;) // Forever Loop
#endif
{
uint8 idx = 0;
Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer().
//这里是轮训任务队列,并检查是否有某个任务的事件发生
do {
if (tasksEvents[idx]) // Task is highest priority that is ready.
{
break;
}
} while (++idx < tasksCnt);
if (idx < tasksCnt)
{
uint16 events;
halIntState_t intState;
HAL_ENTER_CRITICAL_SECTION(intState);
events = tasksEvents[idx]; //处理该idx的任务事件, 是第idx个任务的事件发生了
tasksEvents[idx] = 0; // Clear the Events for this task.
HAL_EXIT_CRITICAL_SECTION(intState);
//对应调用第idx个任务的事件处理函数,用events说明是什么事件
events = (tasksArr[idx])( idx, events );