今天来看一下终端节点是如何加入网络,以及建立绑定操作并发送数据了。首先我们选择工作空间为SimpleSensorEB,好,我们先按一下S2键,因为在SAPI_Init中,我们利用RegisterForKeys( sapi_TaskID);注册了键盘消息,因此我们看一下在sapi如何对按键消息进行响应的。在UINT16 SAPI_ProcessEvent( bytetask_id, UINT16 events )中找到:
case KEY_CHANGE:
#if ( SAPI_CB_FUNC )
zb_HandleKeys( ((keyChange_t *)pMsg)->state,((keyChange_t *)pMsg)->keys );
#endif
break;
好,接下来我们进入到zb_HandleKeys函数中看看源代码:
void zb_HandleKeys( uint8 shift, uint8 keys )
{
uint8 startOptions;
uint8 logicalType;
// Shift is used to make each button/switchdual 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 )
{
if ( myAppState == APP_INIT )
{
// In the init state, keys are used to indicate the logicalmode.
// The Sensor device is always an end-device
logicalType = ZG_DEVICETYPE_ENDDEVICE;
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),&logicalType);
// Do more configuration if necessary and then restart device withauto-start bit set
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),&startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),&startOptions );
zb_SystemReset();
}
}
if ( keys& HAL_KEY_SW_2 )//成立
{
if ( myAppState == APP_INIT )//成立
{
logicalType = ZG_DEVICETYPE_ENDDEVICE;//修改本地设备类型为终端设备
zb_WriteConfiguration(ZCD_NV_LOGICAL_TYPE, sizeof(uint8),&logicalType);//将设备类型写入到flash中
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),&startOptions );
startOptions = ZCD_STARTOPT_AUTO_START;//修改启动选项
zb_WriteConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),&startOptions );//将启动选项写入到flash中
zb_SystemReset();//系统重启
}
}
}
好,系统重启后,程序从头开始执行,在进行SAPI_Init函数的最后时,出现 osal_set_event(task_id,ZB_ENTRY_EVENT);因此,进入到进入事件处理函数当中。我们在SAPI_ProcessEvent函数里找到如下代码:
if ( events & ZB_ENTRY_EVENT )
{
uint8startOptions;
#if ( SAPI_CB_FUNC )
zb_HandleOsalEvent( ZB_ENTRY_EVENT );
#endif
// LEDoff cancels HOLD_AUTO_START blink set in the stack
HalLedSet(HAL_LED_4, HAL_LED_MODE_OFF);//首先关闭LED_4。
zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8),&startOptions );//从flash中读出启动选项
if (startOptions & ZCD_STARTOPT_AUTO_START)//条件成立
{
zb_StartRequest();//执行启动请求函数。
}
else
{
// blink leds and wait for external input to config andrestart
HalLedBlink(HAL_LED_2, 0, 50, 500);
}
return(events ^ ZB_ENTRY_EVENT );
}
继续到启动请求函数中去看一下源代码:
void zb_StartRequest()
{
uint8 logicalType;
zb_ReadConfiguration( ZCD_NV_LOGICAL_TYPE,sizeof(uint8), &logicalType );
//以下代码主要是确认设备类型是否正确,可以判断if中的条件为0,执行else中的语句
if ((logicalType >ZG_DEVICETYPE_ENDDEVICE) ||
#if !ZG_BUILD_ENDDEVICE_TYPE //Only RTR or Coord possible.
(logicalType ==ZG_DEVICETYPE_ENDDEVICE) ||
#endif
#if!ZG_BUILD_RTR_TYPE // Only End Device possible.
(logicalType ==ZG_DEVICETYPE_ROUTER) ||
(logicalType ==ZG_DEVICETYPE_COORDINATOR) ||
#elifZG_BUILD_RTRONLY_TYPE // Only RTR possible.
(logicalType ==ZG_DEVICETYPE_COORDINATOR) ||
#elif !ZG_BUILD_JOINING_TYPE //Only Coord possible.
(logicalType ==ZG_DEVICETYPE_ROUTER) ||
#endif
(0))
{
logicalType= ZB_INVALID_PARAMETER;
SAPI_SendCback(SAPICB_START_CNF, logicalType, 0);
}
else
{
logicalType= ZB_SUCCESS;//设置本地设备类型为ZB_SUCCESS
ZDOInitDevice(zgStartDelay);//执行ZDO初始化设备函数。
}
return;
}
下面我们接着去初始化设备函数当中看一下源代码,可以找到:
uint8 ZDOInitDevice( uint16 startDelay )
{
uint8 networkStateNV =ZDO_INITDEV_NEW_NETWORK_STATE; //设置网络状态为初始化新的网络
uint16 extendedDelay = 0;
if ( devState == DEV_HOLD )
{
//Initialize the RAM items table, in case an NV item has beenupdated.
zgInitItems(FALSE ); //初始化RAM item列表
}
ZDConfig_InitDescriptors();
//devtag.071807.todo - fix this temporarysolution
_NIB.CapabilityInfo =ZDO_Config_Node_Descriptor.CapabilityFlags;
devState =DEV_INIT; //Remove the Hold state
// Initialize leave control logic
ZDApp_LeaveCtrlInit(); //离开控制初始化
// Check leave control reset settings
ZDApp_LeaveCtrlStartup(&devState, &startDelay);//离开控制的一些设置
// Leave may make the hold state comeback
if ( devState == DEV_HOLD )
{
// Set theNV startup option to force a "new" join.
zgWriteStartupOptions( ZG_STARTUP_SET,ZCD_STARTOPT_DEFAULT_NETWORK_STATE );
// Notifythe applications
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
return (ZDO_INITDEV_LEAVE_NOT_STARTED); // Don't join - (onetime).
}
#if defined ( NV_RESTORE )//编译不通过,并不是上电保留数据 模式
// Get Keypad directly to see if a reset nv isneeded.
// Hold down the SW_BYPASS_NV key (defined inOnBoard.h)
// while booting to skip past NV Restore.
if ( HalKeyRead() == SW_BYPASS_NV )
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
else
{
// Determineif NV should be restored
networkStateNV = ZDApp_ReadNetworkRestoreState();
}
if ( networkStateNV ==ZDO_INITDEV_RESTORED_NETWORK_STATE )
{
networkStateNV = ZDApp_RestoreNetworkState();
}
else
{
// Wipe outthe network state in NV
NLME_InitNV();
NLME_SetDefaultNV();
}
#endif
if ( networkStateNV ==ZDO_INITDEV_NEW_NETWORK_STATE )//成立
{
ZDAppDetermineDeviceType();
// Onlydelay if joining network - not restoring network state
extendedDelay = (uint16)((NWK_START_DELAY + startDelay)
+ (osal_rand() &EXTENDED_JOINING_RANDOM_MASK));
}
// Initialize the security for type ofdevice
ZDApp_SecInit( networkStateNV); //初始化安全属性
// Trigger the network start
ZDApp_NetworkInit( extendedDelay);//开启网络初始化函数
// set broadcast address mask to supportbroadcast filtering
NLME_SetBroadcastFilter(ZDO_Config_Node_Descriptor.CapabilityFlags );
return ( networkStateNV );
}
好,我们进入到网络初始化函数当中,看看终端节点如何进行网络初始化,在此之前我们看过的函数与协调器执行的函数没有什么区别,在这以后区别开始出现了。
void ZDApp_NetworkInit( uint16 delay )
{
if ( delay )
{
// Waitawhile before starting the device
osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );
}
else
{
osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );//设置了一个网络初始化事件,在ZDO层的任务处理函数中处理。
}
}
找到 UINT16 ZDApp_event_loop( uint8 task_id, UINT16events )中的:
if ( events & ZDO_NETWORK_INIT )
{
devState =DEV_INIT;//改变设备状态为初始化状态。
ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType,devStartMode,
DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER);//开启设备函数,参数分别为设备类型,启动模式,信标帧,超帧.第一个参数是在初始化设备时调用初始化节点描述符函数里赋值的。
return(events ^ ZDO_NETWORK_INIT);
}
进入到启动设备函数中,看看源代码:
void ZDO_StartDevice( byte logicalType, devStartModes_tstartMode, byte beaconOrder, byte superframeOrder )
{
ZStatus_t ret;
#if defined ( ZIGBEE_FREQ_AGILITY )
static uint8 discRetries = 0;
#endif
#if defined ( ZIGBEE_COMMISSIONING )
static uint8 scanCnt = 0;
#endif
ret = ZUnsupportedMode;
if ( ZG_BUILD_COORDINATOR_TYPE&& logicalType ==NODETYPE_COORDINATOR )//条件不通过,不是协调器
{
if (startMode == MODE_HARD )
{
devState = DEV_COORD_STARTING;
ret = NLME_NetworkFormationRequest( zgConfigPANID,zgApsUseExtendedPANID, zgDefaultChannelList,
zgDefaultStartingScanDuration, beaconOrder,
superframeOrder, false );
}
else if (startMode == MODE_RESUME )
{
// Just start the coordinator
devState = DEV_COORD_STARTING;
ret = NLME_StartRouterRequest( beaconOrder, beaconOrder, false);
}
else
{
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
#endif
}
}
if ( ZG_BUILD_JOINING_TYPE&& (logicalType == NODETYPE_ROUTER|| logicalType == NODETYPE_DEVICE) )//条件通过
{
if ((startMode == MODE_JOIN) || (startMode == MODE_REJOIN))//条件通过
{
devState = DEV_NWK_DISC; //将设备状态修改为网络发现状态
#if defined( MANAGED_SCAN )
ZDOManagedScan_Next();
ret = NLME_NetworkDiscoveryRequest( managedScanChannelMask,BEACON_ORDER_15_MSEC );
#else
ret = NLME_NetworkDiscoveryRequest( zgDefaultChannelList,zgDefaultStartingScanDuration);//向网络层发送网络发现请求,交由网络层处理。怎么处理代码看不到。
#if defined( ZIGBEE_FREQ_AGILITY )
if ( !( ZDO_Config_Node_Descriptor.CapabilityFlags& CAPINFO_RCVR_ON_IDLE )&&
( ret == ZSuccess ) && (++discRetries == 4 ) )
{
// For devices with RxOnWhenIdle equals to FALSE, any networkchannel
// change will not be recieved. On these devices or routers thathave
// lost the network, an active scan shall be conducted on theDefault
// Channel list using the extended PANID to find the network. Ifthe
// extended PANID isn't found using the Default Channel list, anscan
// should be completed using all channels.
zgDefaultChannelList = MAX_CHANNELS_24GHZ;
}
#endif //ZIGBEE_FREQ_AGILITY
#if defined( ZIGBEE_COMMISSIONING )
if (startMode == MODE_REJOIN &&scanCnt++ >= 5 )
{
// When ApsUseExtendedPanID is commissioned to a non zero valuevia
// application specific means, the device shall conduct an activescan
// on the Default Channel list and join the PAN with the same
// ExtendedPanID. If the PAN is not found, an scan should becompleted
// on all channels.
// When devices rejoin the network and the PAN is not foundfrom
zgDefaultChannelList = MAX_CHANNELS_24GHZ;
}
#endif //ZIGBEE_COMMISSIONING
#endif
}
else if (startMode == MODE_RESUME )
{
if ( logicalType == NODETYPE_ROUTER )
{
ZMacScanCnf_t scanCnf;
devState = DEV_NWK_ORPHAN;
scanCnf.hdr.Status = ZSUCCESS;
scanCnf.ScanType = ZMAC_ORPHAN_SCAN;
scanCnf.UnscannedChannels = 0;
scanCnf.ResultListSize = 0;
nwk_ScanJoiningOrphan(&scanCnf);
ret = ZSuccess;
}
else
{
devState = DEV_NWK_ORPHAN;
ret = NLME_OrphanJoinRequest( zgDefaultChannelList,
zgDefaultStartingScanDuration );
}
}
else
{
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "StartDevice ERR", "MODE unknown" );
#endif
}
}
if ( ret != ZSuccess )
osal_start_timerEx(ZDAppTaskID, ZDO_NETWORK_INIT, NWK_RETRY_DELAY);
}