zigbee任务的处理流程

来源:互联网 发布:5vb阻燃级别 编辑:程序博客网 时间:2024/04/28 10:46

1、  添加任务

在协议栈中的OSAL.c文件中,byte osal_init_system( void )函数的功能是初始化OS、添加任务到OS任务表中。在这个函数中通过调用osalAddTasks()函数来定制项目所需要应用的任务,该函数属于应用层和OS之间的接口函数,一般项目的建立需要根据系统的需要自己编写改函数,并将函数放到应用层。osalAddTasks()函数是通过osalTaskAdd()函数完成任务添加。

       值得注意的是在一个空的协议栈里osalAddTasks()只是在OSAL_Custom.h中申明,并未写出具体操作,需要我们在自己在接口处编写,osalTaskAdd()函数也是自己加进去的

osalTaskAdd()已经不支持,现在用下面的方法添加任务

在协议栈ZStack-CC2430-1.4.3中是这样添加任务的:

1)任务初始化函数的添加

main ()

--->byte osal_init_system( void ) 【OSAL.c】

--->osalInitTasks()【OSAL_SampleApp.c】 //初始化系统任务

---> void SampleApp_Init( uint8 task_id )【SampleApp.c】//应用初始化

2)任务处理函数的流程

首先在任务函数列表中添加处理函数

const pTaskEventHandlerFn tasksArr[] = {

  macEventLoop,

  nwk_event_loop,

  Hal_ProcessEvent,

#if defined( MT_TASK )

  MT_ProcessEvent,

#endif

  APS_event_loop,

  ZDApp_event_loop,

  SampleApp_ProcessEvent

};

该列表中处理函数的出现的顺序需要和osalInitTasks()函数中初始化的顺序一致

oid 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++ );

SampleApp_Init( taskID ); //注意顺序要和pTaskEventHandlerFn中处理函数一致

}

 

 

 

2、  任务初始化--- void SampleApp_Init( uint8 task_id )【SampleApp.c】

命名规则:应用名_init()

       初始化内容:

              初始化Application Objects对应的变量

              相应Application Objects的实例化—afRegister()

              注册应用OSAL或HAL系统服务—RegisterForKeys()

     /*********************************************************************

 * @fn      SampleApp_Init

 *

 * @brief   Initialization function for the Generic App Task.

 *          This is called during initialization and should contain

 *          any application specific initialization (ie. hardware

 *          initialization/setup, table initialization, power up

 *          notificaiton ... ).

 *

 * @param   task_id - the ID assigned by OSAL.  This ID should be

 *                    used to send messages and set timers.

 *

 * @return  none

 */

void SampleApp_Init( uint8 task_id )

{

  SampleApp_TaskID = task_id;

  SampleApp_NwkState = DEV_INIT;

  SampleApp_TransID = 0;

 

  // Device hardware initialization can be added here or in main() (Zmain.c).

  // If the hardware is application specific - add it here.

  // If the hardware is other parts of the device add it in main().

  

 #if defined ( SOFT_START )

  // The "Demo" target is setup to have SOFT_START and HOLD_AUTO_START

  // SOFT_START is a compile option that allows the device to start

  //  as a coordinator if one isn't found.

  // We are looking at a jumper (defined in SampleAppHw.c) to be jumpered

  // together - if they are - we will start up a coordinator. Otherwise,

  // the device will start as a router.

  if ( readCoordinatorJumper() )

    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;

  else

    zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;

#endif // SOFT_START

  

#if defined ( HOLD_AUTO_START )

  // HOLD_AUTO_START is a compile option that will surpress ZDApp

  //  from starting the device and wait for the application to

  //  start the device.

  ZDOInitDevice(0);

#endif

  

  // Setup for the periodic message's destination address

  // Broadcast to everyone

  SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;

  SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;

  SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;

 

  // Setup for the flash command's destination address - Group 1

  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;

  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;

  SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;

 

  // Fill out the endpoint description.

  SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;

  SampleApp_epDesc.task_id = &SampleApp_TaskID;

  SampleApp_epDesc.simpleDesc

            = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;

  SampleApp_epDesc.latencyReq = noLatencyReqs;

 

  // Register the endpoint description with the AF

  afRegister( &SampleApp_epDesc );

 

  // Register for all key events - This app will handle all key events

  RegisterForKeys( SampleApp_TaskID );  //注册按键事件后,按键回调函数将会把OSAl系统事件KEY_CHANGE发送到注册的SampleApp_TaskID

 

  // By default, all devices start out in Group 1  

  SampleApp_Group.ID = 0x0001;

  osal_memcpy( SampleApp_Group.name, "Group 1", 7  );

  aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );

 

#if defined ( LCD_SUPPORTED )

  HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );

#endif

}

3、  任务处理---uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )【SampleApp.c】

1)当SampleApp_TaskID对应的OSAL事件发生时,在OSAL的主循环函数会调用该处理函数;

2)SYS_EVENT_MSG是全局系统消息,该消息包含以下消息:

--AF_DATA_CONFIRM_CMD

--AF_INCOMING_MSG_CMD

--KEY_CHANGE

--ZDO_STATE_CHANGE

3)如果一个OSAL任务已经注册为按键按下通知,则任何的按键事件将会以KEY_CHANGE系统事件消息的形式接收。有两种可能的程序流程会使一个任务接收到此KEY_CHANGE

   物理层按键的程序流程如下:

   --HAL检测按键状态(通过H/W中断或H/W循环检测);

   --HAL OSAL任务检测到一个按键状态变化,并调用OSAL按键变化回调函数;

   --OSAL按键变化回调函数发送OSAL系统事件消息KEY_CHANGE到通过RegisterForKeys()注册的TaskID

4)TransID  其作用是识别消息,可为每个不同的Endpoint或每个clusterID对应的事件设置一TransID以对其进行区别。

 

/*********************************************************************

 * @fn      SampleApp_ProcessEvent

 *

 * @brief   Generic Application Task event processor.  This function

 *          is called to process all events for the task.  Events

 *          include timers, messages and any other user defined events.

 *

 * @param   task_id  - The OSAL assigned task ID.

 * @param   events - events to process.  This is a bit map and can

 *                   contain more than one event.

 *

 * @return  none

 */

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )

{

  afIncomingMSGPacket_t *MSGpkt;

 

  if ( events & SYS_EVENT_MSG )

  {

    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );  //从OS的消息队列中接收一个消息

    while ( MSGpkt )

    {

      switch ( MSGpkt->hdr.event )

      {

        // Received when a key is pressed

        case KEY_CHANGE:

          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys ); //按键处理函数

          break;

 

        // Received when a messages is received (OTA) for this endpoint

        case AF_INCOMING_MSG_CMD:

          SampleApp_MessageMSGCB( MSGpkt );  //对于接收消息的节点,将执行此函数

          break;

zigbee任务的处理流程(二)

  // Release the memory

      osal_msg_deallocate( (uint8 *)MSGpkt );

 

      // Next - if one is available

      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );  //继续取消息队列中的消息

    }

 

    // return unprocessed events

    return (events ^ SYS_EVENT_MSG);

  }

 

  // Send a message out - This event is generated by a timer

  //  (setup in SampleApp_Init()).

  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )

  {

    // Send the periodic message

    SampleApp_SendPeriodicMessage();

 

    // Setup to send message again in normal period (+ a little jitter)

    osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,

        (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );

 

    // return unprocessed events

    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);

  }

 

  // Discard unknown events

  return 0;

}

5)在该实例程序中,按键处理程序SampleApp_HandleKeys对按键进行处理:

       (1)按键1—向group1的设备发送闪烁消息SampleApp_SendFlashMessage()

       该函数中的SampleApp_Flash_DstAddr为发送的目的地址,该参数在SampleApp_Init()中初始化为组1:

// Setup for the flash command's destination address - Group 1

  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;

  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;

  SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;

 所以设备在初始化时初始化为组1,组初始化方法为:

       aps_Group_t SampleApp_Group;

       ….

       SampleApp_Group.ID = 0x0001;

       Osal_memcpy(SampleApp_Group.name,”Group 1”,7);

       aps_AddGroup(SAMPLEAPP_ENDPOINT,&SampleApp_Group);

      

       aps_Group_t结构体为:

       typedef struct

       {

              Uint16 ID;

              Uint8 name[APS_GROUP_NAME_LEN];

}aps_Group_t;

       按键1的处理函数为:

void SampleApp_SendFlashMessage( uint16 flashTime )

{

  uint8 buffer[3];

  buffer[0] = (uint8)(SampleAppFlashCounter++);  //发送闪烁消息的次数

  buffer[1] = LO_UINT16( flashTime );  //闪烁频率的计数

  buffer[2] = HI_UINT16( flashTime );

  

  if ( AF_DataRequest( &SampleApp_Flash_DstAddr,   //目的的组地址,group1

&SampleApp_epDesc,  //源EndPoint description

                       SAMPLEAPP_FLASH_CLUSTERID, //cluster ID

                       3, //要发送数据的长度

                       buffer, //发送数据的指针

                       &SampleApp_TransID, //事物需要指针,若果消息缓存发送,这个函数将会增加此数

                       AF_DISCV_ROUTE, //发送选项

                       AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )

  {

  }

  else

  {

    // Error occurred in request to send.

  }

}

       注:AF_DataRequest生命如下

afStatus_t AF_DataRequest( afAddrType_t *dstAddr,

endPointDesc_t *srcEP,

                           uint16 cID,

uint16 len,

uint8 *buf,

uint8 *transID,

                            uint8 options,

uint8 radius )

该函数中参数option为以下值:

       AF_ACK_REQUEST 0x10---请求,应用层调用,要求APS应答,这是应用层的应答,只在直接发送(单播)时使用

       AF_DISCV_ROUNTE 0x20 ---路由发现,总是包含此项

       AF_SKIP_RONTING 0x80---使设备跳过路由而直接发送消息,终点设备将不向其父亲发送消息

       (2)按键2—按一次会使设备脱离组1,再按一次会使设备加入组1

             aps_Group_t *grp;

    grp = aps_FindGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );

    if ( grp )

    {

      // Remove from the group

      aps_RemoveGroup( SAMPLEAPP_ENDPOINT, SAMPLEAPP_FLASH_GROUP );

    }

    else

    {

      // Add to the flash group

      aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );

}

                        i.              接收到的消息处理

若收到AF_INCOMING_MSG_CMD,则调用函数SampleApp_MessageMSGCB()【SampleApp.c】对消息进行处理。

                      ii.              osal_start_timerEx( )

为指定的task启动定时器,当定时器到时后,指定的event位将会置位

byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16

timeout_value);

        taskID—定时器到时时获取event的task ID,即event通知给task ID

        event_id ---用户定义的event bit,当定时器到时后,会向task id通知event

        timeout_value---时间(微秒)

 

0 0