查看: 2425|回复: 2
打印 上一主题 下一主题

zigbee协议与开发-ZStack协议栈结构的初步解析

[复制链接]
跳转到指定楼层
沙发
发表于 2014-7-22 18:18:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 伊海 于 2014-7-24 08:41 编辑

在阅读了Zigbee及IEEE802.15.4协议的理论知识后,接下来看一下TI公司开发的基于Zigbee的协议实现ZStack。

我们仍然从TI提供的温度监测程序开始,首先查看一下,程序的主函数在ZMain.c文件中,从程序的说明看出,是ZStack的startup和shutdown代码.

以下是其中的main()函数,其实英文注释已经很清楚说明每一步,这里翻译一下:

  1. int main( void )
  2. {
  3.   // Turn off interrupts(关中断)
  4.   osal_int_disable( INTS_ALL );
  5.   // Initialization for board related stuff such as LEDs(初始化板上组件,如LED)
  6.   HAL_BOARD_INIT();
  7.   // Make sure supply voltage is high enough to run(电压检查)
  8.   zmain_vdd_check();
  9.   // Initialize board I/O(初始化I/O接口)
  10.   InitBoard( OB_COLD );
  11.   // Initialze HAL drivers(初始化HAL设备,在hal_drivers.c中实现)
  12.   HalDriverInit();
  13.   // Initialize NV System(初始化NV系统,即非易失设备,如Flash)
  14.   osal_nv_init( NULL );
  15.   // Initialize the MAC(初始化MAC)
  16.   ZMacInit();
  17.   // Determine the extended address(确定设备的长地址)
  18.   zmain_ext_addr();
  19.   // Initialize basic NV items(初始化ZStack的全局变量,如果在NV内存中不存在,则写入缺省值)
  20.   zgInit();
  21. #ifndef NONWK
  22.   // Since the AF isn't a task, call it's initialization routine
  23.   afInit();
  24. #endif
  25.   // Initialize the operating system(初始化操作系统)
  26.   osal_init_system();
  27.   // Allow interrupts(开中断)
  28.   osal_int_enable( INTS_ALL );
  29.   // Final board initialization(最后初始化板)
  30.   InitBoard( OB_READY );
  31.   // Display information about this device(显示设备信息,比如CollectorEB板的IEEE地址就是在这个函数里面显示出来的。)
  32.   zmain_dev_info();
  33.   /* Display the device info on the LCD */(显示LCD设备信息)
  34. #ifdef LCD_SUPPORTED
  35.   zmain_lcd_init();
  36. #endif
  37. #ifdef WDT_IN_PM1
  38.   /* If WDT is used, this is a good place to enable it. */(开WatchDog)
  39.   WatchDogEnable( WDTIMX );
  40. #endif
  41.   osal_start_system(); // No Return from here(启动操作系统,实际上进入一个死循环)
  42.   return 0;  // Shouldn't get here.
  43. } // main()
复制代码


说明:以上初始化有的跟硬件相关,有的跟操作系统(以osal开头)相关,最后系统调用osal_start_system进入循环,然后在循环中处理消息,下面是这个函数的主体(见osal.c):

  1. void osal_start_system( void )
  2. {
  3. #if !defined ( ZBIT ) && !defined ( UBIT )
  4.   for(;;)  // Forever Loop (死循环)
  5. #endif
  6.   {
  7.     uint8 idx = 0;
  8.     osalTimeUpdate();  //更新时间
  9.     Hal_ProcessPoll();  // This replaces MT_SerialPoll() and osal_check_timer().(轮询UART和Timer等设备消息)
  10.    
  11.     do {
  12.       if (tasksEvents[idx])  // Task is highest priority that is ready.
  13.       {
  14.         break;
  15.       }
  16.     } while (++idx < tasksCnt);
  17.     if (idx < tasksCnt)
  18.     {
  19.       uint16 events;
  20.       halIntState_t intState;
  21.       HAL_ENTER_CRITICAL_SECTION(intState);   //加锁防上访问事件队列充突
  22.       events = tasksEvents[idx];
  23.       tasksEvents[idx] = 0;  // Clear the Events for this task.
  24.       HAL_EXIT_CRITICAL_SECTION(intState);
  25.       events = (tasksArr[idx])( idx, events );                 //处理当前要处理的事件,并返回事件ID
  26.       HAL_ENTER_CRITICAL_SECTION(intState);
  27.       tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.(更新事件状态)
  28.       HAL_EXIT_CRITICAL_SECTION(intState);
  29.     }
  30. #if defined( POWER_SAVING )
  31.     else  // Complete pass through all task events with no activity?
  32.     {
  33.       osal_pwrmgr_powerconserve();  // Put the processor/system into sleep(没有事件处理,进入休眠状态)
  34.     }
  35. #endif
  36.   }
  37. }
复制代码

需要特别解析的是上面红色标注的行,这个地方看起来象是一个函数指针的形式,查看taskArr定义(见SAPI.c)如下:

  1. #if OSAL_SAPI
  2. // The order in this table must be identical to the task initialization calls below inosalInitTask.
  3. const pTaskEventHandlerFn tasksArr[] = {
  4.   macEventLoop,
  5.   nwk_event_loop,
  6.   Hal_ProcessEvent,
  7. #if defined( MT_TASK )
  8.   MT_ProcessEvent,
  9. #endif
  10.   APS_event_loop,
  11.   ZDApp_event_loop,
  12.   SAPI_ProcessEvent
  13. };
复制代码




回复

使用道具 举报

板凳
 楼主| 发表于 2014-7-22 18:18:41 | 只看该作者
本帖最后由 伊海 于 2014-7-24 08:42 编辑

上面基本上是***EventLoop,可以推测是处理不同层的信息,如mac, NWK, Hal, APS, ZDAPP的事件处理函数。以macEventLoop为例,可以在mac_api.h文件中找到这个函数的定义如下:
  1. extern uint16 macEventLoop(uint8 taskId, uint16 events);
复制代码
但是,没有跟踪到上述函数的实现在哪个文件中。但是对于温度监测应用DEMo来讲,上述的SAPI_ProcessEvent()函数在SAPI.c中实现如下:
  1. UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )
  2. {
  3.   osal_event_hdr_t *pMsg;
  4.   afIncomingMSGPacket_t *pMSGpkt;
  5.   afDataConfirm_t *pDataConfirm;

  6.   if ( events & SYS_EVENT_MSG )          //系统事件消息,只有定义了SAPI_CB_FUNC 的似乎才会被上层应用处理。
  7.   {
  8.     ...
  9. case KEY_CHANGE:
  10. #if ( SAPI_CB_FUNC )
  11.           zb_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys );
  12. #endif
  13.           break;
  14.   ...
  15.   // Return unprocessed events
  16.     return (events ^ SYS_EVENT_MSG);
  17.   }
  18.   if ( events & ZB_ALLOW_BIND_TIMER )   //ZB_ALLOW_BIND_TIMER
  19.   {
  20.     afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
  21.     return (events ^ ZB_ALLOW_BIND_TIMER);
  22.   }
  23.   if ( events & ZB_BIND_TIMER )  //ZB_BIND_TIMER
  24.   {
  25.     // Send bind confirm callback to application
  26.     SAPI_BindConfirm( sapi_bindInProgress, ZB_TIMEOUT );
  27.     sapi_bindInProgress = 0xffff;
  28.     return (events ^ ZB_BIND_TIMER);
  29.   }
  30.   if ( events & ZB_ENTRY_EVENT )   //ZB_ENTRY_EVENT
  31.   {
  32.     uint8 startOptions;
  33.     // Give indication to application of device startup
  34. #if ( SAPI_CB_FUNC )
  35.     zb_HandleOsalEvent( ZB_ENTRY_EVENT );
  36. #endif
  37.     // LED off cancels HOLD_AUTO_START blink set in the stack
  38.     HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);
  39.     zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
  40.     if ( startOptions & ZCD_STARTOPT_AUTO_START )
  41.     {
  42.       zb_StartRequest();
  43.     }
  44.     else
  45.     {
  46.       // blink leds and wait for external input to config and restart
  47.       HalLedBlink(HAL_LED_2, 0, 50, 500);
  48.     }
  49.     return (events ^ ZB_ENTRY_EVENT );
  50.   }
  51.   // This must be the last event to be processed
  52.   if ( events & ( ZB_USER_EVENTS ) )
  53.   {
  54.     // User events are passed to the application
  55. #if ( SAPI_CB_FUNC )
  56.     zb_HandleOsalEvent( events );
  57. #endif
  58.     // Do not return here, return 0 later
  59.   }
  60.   // Discard unknown events
  61.   return 0;
  62. }
复制代码
上述代码中,只有黑色标注的才被上传到应用层APL进行处理,而这些代码正好是用户需要实现的,分别在DemoSensor.c和DemoCollector.c中实现。以路由器的代码为例,显示如下,其作用主要是对按键进行处理:
  1. void zb_HandleKeys( uint8 shift, uint8 keys )
  2. {
  3.   static uint8 allowBind=FALSE;
  4.   static uint8 allowJoin=TRUE;
  5.   uint8 logicalType;
  6.   
  7.   
  8.   // Shift is used to make each button/switch dual purpose.
  9.   if ( shift )
  10.   {
  11.     if ( keys & HAL_KEY_SW_1 )
  12.     {
  13.     }
  14.     if ( keys & HAL_KEY_SW_2 )
  15.     {
  16.     }
  17.     if ( keys & HAL_KEY_SW_3 )
  18.     {
  19.     }
  20.     if ( keys & HAL_KEY_SW_4 )
  21.     {
  22.     }
  23.   }
  24.   else
  25.   {
  26.     if ( keys & HAL_KEY_SW_1 )     //Joystick Up key (Set as cordinator,设置为协调器)
  27.     {
  28.       if ( appState == APP_INIT  )
  29.       {
  30.         // Key 1 starts device as a coordinator
  31.         logicalType = ZG_DEVICETYPE_COORDINATOR;
  32.         zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
  33.                
  34.         // Reset the device with new configuration
  35.         zb_SystemReset();
  36.       }
  37.     }
  38.     if ( keys & HAL_KEY_SW_2 )    //Joystick Right key (Allow bind,允许绑定,一个网络中只有一个节点,即协调器有此设置。)
  39.     {
  40.       allowBind ^= 1;
  41.       if (allowBind)
  42.       {
  43.         // Turn ON Allow Bind mode infinitly
  44.         zb_AllowBind( 0xFF );
  45.         HalLedSet( HAL_LED_2, HAL_LED_MODE_ON );
  46.         //This node is the gateway node
  47.         isGateWay = TRUE;
  48.         
  49.         // Update the display
  50.         #if defined ( LCD_SUPPORTED )
  51.         HalLcdWriteString( "Gateway Mode", HAL_LCD_LINE_2 );
  52.         #endif
  53.       }
  54.       else
  55.       {
  56.         // Turn OFF Allow Bind mode infinitly
  57.         zb_AllowBind( 0x00 );
  58.         HalLedSet( HAL_LED_2, HAL_LED_MODE_OFF );
  59.         isGateWay = FALSE;
  60.         
  61.         // Update the display
  62.         #if defined ( LCD_SUPPORTED )
  63.         HalLcdWriteString( "Collector", HAL_LCD_LINE_2 );
  64.         #endif
  65.       }
  66.     }
  67.     if ( keys & HAL_KEY_SW_3 )    //Joystick down key(路由器有效,用于定时向协调器报告事件,以生成拓扑图)
  68.     {
  69.       // Start reporting
  70.       osal_set_event( sapi_TaskID, MY_REPORT_EVT );
  71.     }
  72.     if ( keys & HAL_KEY_SW_4 )      //Joystick Left key(用于禁止/允许节点加入,此功能用于协调器设置禁止或允许节点加入,但是不知为何无效!!?)
  73.     {
  74.       // Key 4 is used to control which routers
  75.       // that can accept join requests
  76.       allowJoin ^= 1;
  77.       if(allowJoin)
  78.       {
  79.         NLME_PermitJoiningRequest(0xFF);
  80.       }
  81.       else {
  82.         NLME_PermitJoiningRequest(0);
  83.       }
  84.     }
  85.   }
  86. }
复制代码
对应的另一个处理函数如下:
  1. void zb_HandleOsalEvent( uint16 event )
  2. {
  3.   uint8 logicalType;
  4.   
  5.   if(event & SYS_EVENT_MSG)  //系统消息,多数在底层已经处理,因此此处为空。
  6.   {
  7.    
  8.   }
  9.   
  10.   if( event & ZB_ENTRY_EVENT )          //系统启动事件,需要做一些设置。
  11.   {  
  12.     // Initialise UART
  13.     initUart(uartRxCB);
  14.    
  15.     // blind LED 1 to indicate starting/joining a network
  16.     HalLedBlink ( HAL_LED_1, 0, 50, 500 );
  17.     HalLedSet( HAL_LED_2, HAL_LED_MODE_OFF );
  18.    
  19.     // Read logical device type from NV
  20.     zb_ReadConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
  21.    
  22.     // Start the device
  23.     zb_StartRequest();
  24.   }
  25.   
  26.   if ( event & MY_START_EVT )
  27.   {
  28.     zb_StartRequest();
  29.   }
  30.   
  31.   if ( event & MY_REPORT_EVT )
  32.   {
  33.     if (isGateWay)
  34.     {
  35.       osal_start_timerEx( sapi_TaskID, MY_REPORT_EVT, myReportPeriod );
  36.     }
  37.     else if (appState == APP_BINDED)
  38.     {
  39.       sendDummyReport();
  40.       osal_start_timerEx( sapi_TaskID, MY_REPORT_EVT, myReportPeriod );
  41.     }
  42.   }
  43.   if ( event & MY_FIND_COLLECTOR_EVT )
  44.   {
  45.     // Find and bind to a gateway device (if this node is not gateway)
  46.     if (!isGateWay)
  47.     {
  48.       zb_BindDevice( TRUE, DUMMY_REPORT_CMD_ID, (uint8 *)NULL );
  49.     }
  50.   }
  51.   
  52. }
复制代码

回复 支持 反对

使用道具 举报

地板
发表于 2014-8-5 12:44:51 | 只看该作者
这是一个完整的协议栈吗
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入中科因仑

本版积分规则

快速回复 返回顶部 返回列表