关闭

Z-stack中OSAL任务机制分析

标签: zigebeeZ-stackOSALtasksEventtasksArr
848人阅读 评论(0) 收藏 举报
分类:

  关于Z-STACK的任务处理机制已经有很多前辈写过了一些教程,我这里写一点自己的理解。
  首先认识几个名词:
  协议:标准,约定。
  协议栈:各层协议的总和,也就是实现这些协议的代码。
  Z-STACK:zigbee协议栈的名字。
  OSAL类似于操作系统,是以实现多任务为核心的系统资源管理机制。
  任务:又可称为线程(个人理解,这里说的可能不对),是一个简单的任务执行过程,在任务执行的过程中CPU完全属于该任务。在Z-STACK中,不同的层拥有不同的任务ID,并且这个任务ID的号码与该层任务的执行次序一致。
  Z-STACK中重要的三个变量:
  TasksCnt,TasksEvents,tasksArr[idx];
  TasksCnt:任务的总个数,写死了,不会变化。
  TasksEvents:是个指针,当然同时也是一个数组。其索引idx代表不同的层,由于Z-stack的每一个层都有一个唯一的任务ID,所以idx的值与同层的任务ID值一样。同时,数组的某个元素的值表示了该层有几个事件。下面以应用层为例说明:
  看tasksEvents的定义与动态内存分配:

uint16 *tasksEvents;
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);

  等价为uint16 tasksEvents[TasksCnt],一个数组,数组中的每个元素都是个两字节的数字,共有TasksCnt个元素。
  再看OSAL的任务初始化函数

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++ );
#if defined ( ZIGBEE_FRAGMENTATION )
  APSF_Init( taskID++ );
#endif
  ZDApp_Init( taskID++ );
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
  ZDNwkMgr_Init( taskID++ );
#endif
  GenericApp_Init( taskID );
}

  发现每个层的初始化函数传入的参数taskID都是递增的,这个taskID也就是本层的任务号,同时也是本层tasksEvents[idx]中idx的值。例如GenericApp_Init( taskID ),这个是应用层的初始化(用户自定义的函数,可能名字会不一样),到这里的taskID值为8的话,那么代表用户自定义任务的tasksEvents[idx]中idx的值也是8。
  再看tasksEvents[idx]这个元素的值,代表的是某一层的事件,初始值0x0000,按位展开就是:0000 0000 0000 0000,每一个二进制位都可以用来设置一个事件,例如系统事件宏定义:

#define    SYS_EVENT_MSG               0x8000

  按位展开就是1000 0000 0000 0000,
  假如我们定义一个发送事件为

#define   SERIALAPP_SEND_EVT           0x0001,

  按位展开就是0000 0000 0000 0001,
  那么假如tasksEvents[8]= 0x8001,就代表着同时有SYS_EVENT_MSG和SERIALAPP_SEND_EVT两个事件。
  任务调度中有个死循环,不断检测这个元素的值是否非0,检测到

  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;//有事件发生则跳出循环
    }
  } while (++idx < tasksCnt);

  具体怎么处理每个任务的不同事件,见tasksArr[idx];
tasksArr[idx]的定义:

typedef unsigned short (*pTaskEventHandlerFn)( unsigned char task_id, unsigned short event );

const pTaskEventHandlerFn tasksArr[] = {
  macEventLoop,
  nwk_event_loop,
  Hal_ProcessEvent,
#if defined( MT_TASK )
  MT_ProcessEvent,
#endif
  APS_event_loop,
#if defined ( ZIGBEE_FRAGMENTATION )
  APSF_ProcessEvent,
#endif
  ZDApp_event_loop,
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
  ZDNwkMgr_event_loop,
#endif
  GenericApp_ProcessEvent
};

  可以看出tasksArr[idx]是一个指针(也就是数组),指向一个函数(数组元素是函数),函数的参数就是task_id与events。task_id与本层的任务ID是对应的,当然也对应着tasksEvents[idx]中idx的值,而events正好也对应这元素tasksEvents[idx]的值。如

uint16 GenericApp_ProcessEvent( uint8 task_id, uint16 events )

  这些函数也就是各个层的处理函数。
  再来看一下每个事件具体是怎样处理的:
在处理用户自定义的任务函数——GenericApp_ProcessEvent函数中,有如下语句:
  如果检测到SYS_EVENT_MSG(也就是tasksEvents[8]的二进制位最高位是1)

  if ( events & SYS_EVENT_MSG )
{
    处理语句
}
return (events ^ SYS_EVENT_MSG);

  返回值执行了异或操作,也就是说把SYS_EVENT_MSG占据的这一个二进制位清零了,代表这个事件执行完毕,且不会影响其它位所代表的事件。
例如此时这一层的任务有两个事件SYS_EVENT_MSG与SERIALAPP_SEND_EVT(此事件是自定义的),那么传入的参数events值就是0x8001,执行完return (events ^ SYS_EVENT_MSG)之后值为0x0001,不会影响if ( events & SERIALAPP_SEND_EVT )的判断结果。当然,由于函数已经执行了返回值的操作,无法再执行后边的语句,SERIALAPP_SEND_EVT事件只能等到下一次执行GenericApp_ProcessEvent函数的时候,才有可能处理。
  再来看一下死循环osal_run_system中的任务处理相关语句:

    events = tasksEvents[idx];//提取需要处理的任务事件
    tasksEvents[idx] = 0;  // Clear the Events for this task.

    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events );//通过指针调用处理函数,处理结束事件按位清零
    activeTaskID = TASK_NO_TASK;

    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.

  关注events,先从tasksEvents中提取idx层中的所有事件(可能不是一个),然后作为参数传入(tasksArr[idx])( idx, events )中进行处理,处理函数在处理了一个事件之后会执行一个异或操作,消除已经处理了的一个事件,然后作为tasksArr[idx]的返回值重新赋值给events,再有events传值给tasksEvents[idx],如果这一层的任务中还有别的事件,那么就由主函数的下一次循环来处理。

  顺带提一下,占据二进制位的顺序越靠左,那么这个事件的优先级就越高。tasksEvents[idx]中idx的值越小,那么这一层任务的优先级也就越高。
以上

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:54814次
    • 积分:1017
    • 等级:
    • 排名:千里之外
    • 原创:48篇
    • 转载:1篇
    • 译文:1篇
    • 评论:13条
    文章分类
    最新评论