中科因仑“3+1”工程特种兵精英论坛
标题: zigbee协议与开发-ZStack协议栈结构的初步解析 [打印本页]
作者: 伊海 时间: 2014-7-22 18:18
标题: zigbee协议与开发-ZStack协议栈结构的初步解析
本帖最后由 伊海 于 2014-7-24 08:41 编辑
在阅读了Zigbee及IEEE802.15.4协议的理论知识后,接下来看一下TI公司开发的基于Zigbee的协议实现ZStack。
我们仍然从TI提供的温度监测程序开始,首先查看一下,程序的主函数在ZMain.c文件中,从程序的说明看出,是ZStack的startup和shutdown代码.
以下是其中的main()函数,其实英文注释已经很清楚说明每一步,这里翻译一下:
- int main( void )
- {
- // Turn off interrupts(关中断)
- osal_int_disable( INTS_ALL );
- // Initialization for board related stuff such as LEDs(初始化板上组件,如LED)
- HAL_BOARD_INIT();
- // Make sure supply voltage is high enough to run(电压检查)
- zmain_vdd_check();
- // Initialize board I/O(初始化I/O接口)
- InitBoard( OB_COLD );
- // Initialze HAL drivers(初始化HAL设备,在hal_drivers.c中实现)
- HalDriverInit();
- // Initialize NV System(初始化NV系统,即非易失设备,如Flash)
- osal_nv_init( NULL );
- // Initialize the MAC(初始化MAC)
- ZMacInit();
- // Determine the extended address(确定设备的长地址)
- zmain_ext_addr();
- // Initialize basic NV items(初始化ZStack的全局变量,如果在NV内存中不存在,则写入缺省值)
- zgInit();
- #ifndef NONWK
- // Since the AF isn't a task, call it's initialization routine
- afInit();
- #endif
- // Initialize the operating system(初始化操作系统)
- osal_init_system();
- // Allow interrupts(开中断)
- osal_int_enable( INTS_ALL );
- // Final board initialization(最后初始化板)
- InitBoard( OB_READY );
- // Display information about this device(显示设备信息,比如CollectorEB板的IEEE地址就是在这个函数里面显示出来的。)
- zmain_dev_info();
- /* Display the device info on the LCD */(显示LCD设备信息)
- #ifdef LCD_SUPPORTED
- zmain_lcd_init();
- #endif
- #ifdef WDT_IN_PM1
- /* If WDT is used, this is a good place to enable it. */(开WatchDog)
- WatchDogEnable( WDTIMX );
- #endif
- osal_start_system(); // No Return from here(启动操作系统,实际上进入一个死循环)
- return 0; // Shouldn't get here.
- } // main()
复制代码
说明:以上初始化有的跟硬件相关,有的跟操作系统(以osal开头)相关,最后系统调用osal_start_system进入循环,然后在循环中处理消息,下面是这个函数的主体(见osal.c):
- void osal_start_system( void )
- {
- #if !defined ( ZBIT ) && !defined ( UBIT )
- for(;;) // Forever Loop (死循环)
- #endif
- {
- uint8 idx = 0;
- osalTimeUpdate(); //更新时间
- Hal_ProcessPoll(); // This replaces MT_SerialPoll() and osal_check_timer().(轮询UART和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];
- tasksEvents[idx] = 0; // Clear the Events for this task.
- HAL_EXIT_CRITICAL_SECTION(intState);
- events = (tasksArr[idx])( idx, events ); //处理当前要处理的事件,并返回事件ID
- HAL_ENTER_CRITICAL_SECTION(intState);
- tasksEvents[idx] |= events; // Add back unprocessed events to the current task.(更新事件状态)
- HAL_EXIT_CRITICAL_SECTION(intState);
- }
- #if defined( POWER_SAVING )
- else // Complete pass through all task events with no activity?
- {
- osal_pwrmgr_powerconserve(); // Put the processor/system into sleep(没有事件处理,进入休眠状态)
- }
- #endif
- }
- }
复制代码需要特别解析的是上面红色标注的行,这个地方看起来象是一个函数指针的形式,查看taskArr定义(见SAPI.c)如下:
- #if OSAL_SAPI
- // The order in this table must be identical to the task initialization calls below inosalInitTask.
- const pTaskEventHandlerFn tasksArr[] = {
- macEventLoop,
- nwk_event_loop,
- Hal_ProcessEvent,
- #if defined( MT_TASK )
- MT_ProcessEvent,
- #endif
- APS_event_loop,
- ZDApp_event_loop,
- SAPI_ProcessEvent
- };
复制代码
作者: 伊海 时间: 2014-7-22 18:18
本帖最后由 伊海 于 2014-7-24 08:42 编辑
上面基本上是***EventLoop,可以推测是处理不同层的信息,如mac, NWK, Hal, APS, ZDAPP的事件处理函数。以macEventLoop为例,可以在mac_api.h文件中找到这个函数的定义如下:
- extern uint16 macEventLoop(uint8 taskId, uint16 events);
复制代码 但是,没有跟踪到上述函数的实现在哪个文件中。但是对于温度监测应用DEMo来讲,上述的SAPI_ProcessEvent()函数在SAPI.c中实现如下:
- UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )
- {
- osal_event_hdr_t *pMsg;
- afIncomingMSGPacket_t *pMSGpkt;
- afDataConfirm_t *pDataConfirm;
- if ( events & SYS_EVENT_MSG ) //系统事件消息,只有定义了SAPI_CB_FUNC 的似乎才会被上层应用处理。
- {
- ...
- case KEY_CHANGE:
- #if ( SAPI_CB_FUNC )
- zb_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys );
- #endif
- break;
- ...
- // Return unprocessed events
- return (events ^ SYS_EVENT_MSG);
- }
- if ( events & ZB_ALLOW_BIND_TIMER ) //ZB_ALLOW_BIND_TIMER
- {
- afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);
- return (events ^ ZB_ALLOW_BIND_TIMER);
- }
- if ( events & ZB_BIND_TIMER ) //ZB_BIND_TIMER
- {
- // Send bind confirm callback to application
- SAPI_BindConfirm( sapi_bindInProgress, ZB_TIMEOUT );
- sapi_bindInProgress = 0xffff;
- return (events ^ ZB_BIND_TIMER);
- }
- if ( events & ZB_ENTRY_EVENT ) //ZB_ENTRY_EVENT
- {
- uint8 startOptions;
- // Give indication to application of device startup
- #if ( SAPI_CB_FUNC )
- zb_HandleOsalEvent( ZB_ENTRY_EVENT );
- #endif
- // LED off cancels HOLD_AUTO_START blink set in the stack
- HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);
- zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );
- if ( startOptions & ZCD_STARTOPT_AUTO_START )
- {
- zb_StartRequest();
- }
- else
- {
- // blink leds and wait for external input to config and restart
- HalLedBlink(HAL_LED_2, 0, 50, 500);
- }
- return (events ^ ZB_ENTRY_EVENT );
- }
- // This must be the last event to be processed
- if ( events & ( ZB_USER_EVENTS ) )
- {
- // User events are passed to the application
- #if ( SAPI_CB_FUNC )
- zb_HandleOsalEvent( events );
- #endif
- // Do not return here, return 0 later
- }
- // Discard unknown events
- return 0;
- }
复制代码 上述代码中,只有黑色标注的才被上传到应用层APL进行处理,而这些代码正好是用户需要实现的,分别在DemoSensor.c和DemoCollector.c中实现。以路由器的代码为例,显示如下,其作用主要是对按键进行处理:
- void zb_HandleKeys( uint8 shift, uint8 keys )
- {
- static uint8 allowBind=FALSE;
- static uint8 allowJoin=TRUE;
- uint8 logicalType;
-
-
- // Shift is used to make each button/switch dual purpose.
- if ( shift )
- {
- if ( keys & HAL_KEY_SW_1 )
- {
- }
- if ( keys & HAL_KEY_SW_2 )
- {
- }
- if ( keys & HAL_KEY_SW_3 )
- {
- }
- if ( keys & HAL_KEY_SW_4 )
- {
- }
- }
- else
- {
- if ( keys & HAL_KEY_SW_1 ) //Joystick Up key (Set as cordinator,设置为协调器)
- {
- if ( appState == APP_INIT )
- {
- // Key 1 starts device as a coordinator
- logicalType = ZG_DEVICETYPE_COORDINATOR;
- zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
-
- // Reset the device with new configuration
- zb_SystemReset();
- }
- }
- if ( keys & HAL_KEY_SW_2 ) //Joystick Right key (Allow bind,允许绑定,一个网络中只有一个节点,即协调器有此设置。)
- {
- allowBind ^= 1;
- if (allowBind)
- {
- // Turn ON Allow Bind mode infinitly
- zb_AllowBind( 0xFF );
- HalLedSet( HAL_LED_2, HAL_LED_MODE_ON );
- //This node is the gateway node
- isGateWay = TRUE;
-
- // Update the display
- #if defined ( LCD_SUPPORTED )
- HalLcdWriteString( "Gateway Mode", HAL_LCD_LINE_2 );
- #endif
- }
- else
- {
- // Turn OFF Allow Bind mode infinitly
- zb_AllowBind( 0x00 );
- HalLedSet( HAL_LED_2, HAL_LED_MODE_OFF );
- isGateWay = FALSE;
-
- // Update the display
- #if defined ( LCD_SUPPORTED )
- HalLcdWriteString( "Collector", HAL_LCD_LINE_2 );
- #endif
- }
- }
- if ( keys & HAL_KEY_SW_3 ) //Joystick down key(路由器有效,用于定时向协调器报告事件,以生成拓扑图)
- {
- // Start reporting
- osal_set_event( sapi_TaskID, MY_REPORT_EVT );
- }
- if ( keys & HAL_KEY_SW_4 ) //Joystick Left key(用于禁止/允许节点加入,此功能用于协调器设置禁止或允许节点加入,但是不知为何无效!!?)
- {
- // Key 4 is used to control which routers
- // that can accept join requests
- allowJoin ^= 1;
- if(allowJoin)
- {
- NLME_PermitJoiningRequest(0xFF);
- }
- else {
- NLME_PermitJoiningRequest(0);
- }
- }
- }
- }
复制代码 对应的另一个处理函数如下:
- void zb_HandleOsalEvent( uint16 event )
- {
- uint8 logicalType;
-
- if(event & SYS_EVENT_MSG) //系统消息,多数在底层已经处理,因此此处为空。
- {
-
- }
-
- if( event & ZB_ENTRY_EVENT ) //系统启动事件,需要做一些设置。
- {
- // Initialise UART
- initUart(uartRxCB);
-
- // blind LED 1 to indicate starting/joining a network
- HalLedBlink ( HAL_LED_1, 0, 50, 500 );
- HalLedSet( HAL_LED_2, HAL_LED_MODE_OFF );
-
- // Read logical device type from NV
- zb_ReadConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8), &logicalType);
-
- // Start the device
- zb_StartRequest();
- }
-
- if ( event & MY_START_EVT )
- {
- zb_StartRequest();
- }
-
- if ( event & MY_REPORT_EVT )
- {
- if (isGateWay)
- {
- osal_start_timerEx( sapi_TaskID, MY_REPORT_EVT, myReportPeriod );
- }
- else if (appState == APP_BINDED)
- {
- sendDummyReport();
- osal_start_timerEx( sapi_TaskID, MY_REPORT_EVT, myReportPeriod );
- }
- }
- if ( event & MY_FIND_COLLECTOR_EVT )
- {
- // Find and bind to a gateway device (if this node is not gateway)
- if (!isGateWay)
- {
- zb_BindDevice( TRUE, DUMMY_REPORT_CMD_ID, (uint8 *)NULL );
- }
- }
-
- }
复制代码
作者: 杨玉玺 时间: 2014-8-5 12:44
这是一个完整的协议栈吗
欢迎光临 中科因仑“3+1”工程特种兵精英论坛 (http://bbs.enlern.com/) |
Powered by Discuz! X3.4 |