06 ZStack的task工作流程分析

本文深入解析ZStack-CC2530的安装与使用,重点介绍了其内部多任务操作系统的工作原理,包括任务调度机制、事件处理流程及任务间的通信方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

安装ZStack-CC2530-2.5.1a.exe

默认安装到”C:\Texas Instruments\ZStack-CC2530-2.5.1a”目录下.
这里写图片描述

Components目录里实现 hal层、stack网络协议栈、mac层的封装, 而且也实现了osal操作系统的功能等. 通常情况下我们就是调用里面实现好的功能函数就可以了.

Documents目录里存放有各个分层的的功能函数的说明文档.

Projects目录存放TI提供的应用案例,我们可以基于这些案例上根据项目需要求进行修改.

Tools目录里存放TI提供的,用于在pc端使用的工具.

/
这里写图片描述
打开此目录下的SampleApp.eww工程.

///
在此位置选择要编译的设备类型, 不管是要作协调器,路由器,终端设备都是共用一个工程源码的。只要选择不同的设备类型,在编译时会自动编译加入相应的设备角色功能.
这里写图片描述

工程里目录说明(摘自开发板文档):
这里写图片描述

ZStack虽然叫zigbee协议栈,但除了网络数据的协议栈外还有一个多任务的操作系统。

协议栈里的操作系统工作原理分析:
里面的操作系统是支持多任务(多进程)同时执行的, 每个任务都是基于事件触发调度的。简单来说, 此系统就是在main函数里用个死循环,循环检查每个任务是否有事件发生, 如有事件发生则调用此任务的事件处理函数。

每个任务都有一个唯一的任务号,根据此任务号可以区别相应的任务。每个任务的事件都由一个uint16类型变量来存放,
每种事件占用一位,相应的位为1即表示有相应的事件发生。而且每个任务都有一个事件处理函数,只要有事件发生了,
系统就会调用任务的事件处理函数来处理已发生的事件. 除此外,每个任务还有一个初始化函数,
用于记录分配的任务号并作任务工作前的初始化工作

在OSAL_SampleApp.c源文件里:

每个任务的事件处理函数地址由全局函数指针数组tasksArr数组来存放。此数组的元素个数即就是系统里的任务个数。
同时此数组里是按任务的任务号从小到大顺序来存放的,即可以tasksArr[任务号]得到相应任务的事件处理函数地址.
//协议栈里的每个分层都由一个任务来实现相应的功能。
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
  SampleApp_ProcessEvent  // SampleApp任务的事件处理函数
};

const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] ); //此全局变量记录任务的个数
uint16 *tasksEvents; //注意全局指针变量tasksEvents其实相当于一个数组(uint16 tasksEvents[tasksCnt]), 每个任务的事件都由一个uint16元素来记录。 即tasksEvents[任务号]可得到相应任务的事件信息.

void osalInitTasks( void ) //系统初始化所有任务的函数,此函数在系统初始化后被调用
{
  uint8 taskID = 0; //用于分配的任务号

  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt); //这里动态分配空间,用于记录每个任务的事件信息.
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt)); //就是先把每个任务的事件信息清零

  //下面是调用每个任务的初始化函数,并传递分配的任务号。注意此顺序需与在tasksArr函数指针数组里的初始化顺序一致.
  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
  SampleApp_Init( taskID ); //调用SampleApp任务的初始化函数
}


//
系统的具体工作流程:

系统最先是从工程的ZMain目录里的ZMain.c的79行的main函数开始执行的.

//这里只关注任务的调度,其它的就不深入了
int main(void)
{
    ...
    osal_init_system();  //系统初始化函数
        ...
        //里面有调用上面的系统任务函数
        osalInitTasks();
            ...
            //再进一步也就会调用各个任务的初始化函数,也包括SampleApp任务的初始化函数
            SampleApp_Init( taskID ); 

    ...
    //main函数最后,就是开始系统工作了
    osal_start_system();    
        //osal_start_system函数里面就是个死循环,循环调用osal_run_system
        osal_run_system(); //此函数就是任务调度的实现
}

void osal_run_system( void )
{
  uint8 idx = 0; //此变量用于记录当前检查的任务的任务号

  osalTimeUpdate();
  Hal_ProcessPoll();

  do {
    if (tasksEvents[idx])  //不要忘了tasksEvents就是一个记录所有任务事件的数组,以任务号为下标.
    {
      break;  //如果tasksEvents[idx]不为零,则表示任务号为idx的任务有事件发生需要处理事件, 结束当前循环.
    }
  } while (++idx < tasksCnt); //tasksCnt为任务的个数

  if (idx < tasksCnt)  // 有事件发生的任务需处理
  {
    uint16 events;
    halIntState_t intState;

    HAL_ENTER_CRITICAL_SECTION(intState); //进入防止并发处理的状态(上锁)
    events = tasksEvents[idx]; //先用events变量记录任务的事件
    tasksEvents[idx] = 0;  // Clear the Events for this task.
    HAL_EXIT_CRITICAL_SECTION(intState); //退出防止并发的状态(解锁)

    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events ); //不要忘了tasksArr是一个全局函数指针变量数组,记录所有任务的事件处理函数的地址. 这里调用有事件发生的任务的事件处理函数,并传递它的任务号及事件信息。最后用events变量存放返回值,返回值为尚未处理的事件信息,如返回0则表示当前已发生事件都已经处理了.

    ...
    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events; //把没有处理的事件信息存放到tasksEvent数组里,下次检查时,将会处理还没有处理的事件.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
    ...
}

总结,每个任务有一个初始化函数及事件处理函数, 而且所有任务的事件都在tasksEvent里存放起来。任务间的通信可以通过改变相应任务的事件信息来实现.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值