/************************************************************************************************** Filename: ZDNwkMgr.c Revised: $Date: 2007-10-17 15:38:45 -0700 (Wed, 17 Oct 2007) $ Revision: $Revision: 15716 $ Description: The ZigBee Network Manager. Copyright 2007 Texas Instruments Incorporated. All rights reserved. IMPORTANT: Your use of this Software is limited to those specific rights granted under the terms of a software license agreement between the user who downloaded the software, his/her employer (which must be your employer) and Texas Instruments Incorporated (the "License"). You may not use this Software unless you agree to abide by the terms of the License. The License limits your use, and you acknowledge, that the Software may not be modified, copied or distributed unless embedded on a Texas Instruments microcontroller or used solely and exclusively in conjunction with a Texas Instruments radio frequency transceiver, which is integrated into your product. Other than for the foregoing purpose, you may not use, reproduce, copy, prepare derivative works of, modify, distribute, perform, display or sell this Software and/or its documentation for any purpose. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. Should you have any questions regarding your right to use this Software, contact Texas Instruments Incorporated at www.TI.com. **************************************************************************************************/ #ifdef __cplusplus extern "C" { #endif /****************************************************************************** * INCLUDES */ #include "ZComdef.h" #include "nwk_util.h" #include "ZDApp.h" #include "ZDObject.h" #include "ZGlobals.h" #include "ZDNwkMgr.h" #if defined( MT_ZDO_FUNC ) #include "MT_ZDO.h" #endif #if defined ( LCD_SUPPORTED ) #include "OnBoard.h" #endif /* HAL */ #include "hal_lcd.h" /****************************************************************************** * CONSTANTS */ #define ONE_MINUTE 60000 // 1(m) * 60(s) * 1000(ms) #if defined ( LCD_SUPPORTED ) const char NwkMgrStr_1[] = "NM-fail not hi"; const char NwkMgrStr_2[] = "NM-curevent ) { case ZDO_CB_MSG: // ZDO sends the message that we registered for ZDNwkMgr_ProcessMsgCBs( (zdoIncomingMsg_t *)msgPtr ); break; case NM_CHANNEL_INTERFERE: // NWK layer sends the message when it detectes Channel Interference ZDNwkMgr_ProcessChannelInterference( (ZDNwkMgr_ChanInterference_t *)msgPtr ); break; case NM_ED_SCAN_CONFIRM: // NWK layer sends the message when it receives an ED scan confirmation ZDNwkMgr_ProcessEDScanConfirm( (ZDNwkMgr_EDScanConfirm_t *)msgPtr ); break; #if defined ( NWK_MANAGER ) case ZDO_NETWORK_REPORT: // NWK layer sends this message when it receives a Network Report message ZDNwkMgr_ProcessNetworkReport( (ZDNwkMgr_NetworkReport_t *)msgPtr ); break; case ZDO_NETWORK_UPDATE: // NKW layer sends this message when it receives a Network Update message ZDNwkMgr_ProcessNetworkUpdate( (ZDNwkMgr_NetworkUpdate_t *)msgPtr ); break; #endif // NWK_MANAGER default: break; } // Release the memory osal_msg_deallocate( (uint8 *)msgPtr ); // Next msgPtr = (osal_event_hdr_t *)osal_msg_receive( ZDNwkMgr_TaskID ); } // Return unprocessed events return (events ^ SYS_EVENT_MSG); } if ( events & ZDNWKMGR_CHANNEL_CHANGE_EVT ) { // Switch channel _NIB.nwkLogicalChannel = ZDNwkMgr_NewChannel; ZMacSetReq( ZMacChannel, &ZDNwkMgr_NewChannel ); // Our Channel has been changed -- notify to save info into NV ZDApp_NwkStateUpdateCB(); // Reset the total transmit count and the transmit failure counters _NIB.nwkTotalTransmissions = 0; nwkTransmissionFailures( TRUE ); return ( events ^ ZDNWKMGR_CHANNEL_CHANGE_EVT ); } if ( events & ZDNWKMGR_UPDATE_NOTIFY_EVT ) { // Update the Update Notify timer if ( ZDNwkMgr_UpdateNotifyTimer > 0 ) { ZDNwkMgr_UpdateNotifyTimer--; osal_start_timerEx( ZDNwkMgr_TaskID, ZDNWKMGR_UPDATE_NOTIFY_EVT, ONE_MINUTE ); } else { ZDNwkMgr_NumUpdateNotifySent = 0; } return ( events ^ ZDNWKMGR_UPDATE_NOTIFY_EVT ); } #if defined ( NWK_MANAGER ) if ( events & ZDNWKMGR_UPDATE_REQUEST_EVT ) { // Update the Update Request timer if ( ZDNwkMgr_UpdateRequestTimer > 0 ) { ZDNwkMgr_UpdateRequestTimer--; osal_start_timerEx( ZDNwkMgr_TaskID, ZDNWKMGR_UPDATE_REQUEST_EVT, ONE_MINUTE ); } return ( events ^ ZDNWKMGR_UPDATE_REQUEST_EVT ); } #endif // NWK_MANAGER if ( events & ZDNWKMGR_SCAN_REQUEST_EVT ) { if ( ZDNwkMgr_MgmtNwkUpdateReq.scanCount > 0 ) { if ( NLME_EDScanRequest( ZDNwkMgr_MgmtNwkUpdateReq.channelMask, ZDNwkMgr_MgmtNwkUpdateReq.scanDuration ) == ZSuccess ) { ZDNwkMgr_MgmtNwkUpdateReq.scanCount--; } } return ( events ^ ZDNWKMGR_SCAN_REQUEST_EVT ); } // Discard or make more handlers return 0; } /********************************************************************* * @fn ZDNwkMgr_ProcessMsgCBs * * @brief Process the incoming messages. * * @param msgPtr - message to process * * @return TRUE if message to be freed. FALSE otherwise. */ static void ZDNwkMgr_ProcessMsgCBs( zdoIncomingMsg_t *inMsg ) { switch ( inMsg->clusterID ) { case Mgmt_NWK_Update_req: ZDNwkMgr_ProcessMgmtNwkUpdateReq( inMsg ); break; #if defined ( NWK_MANAGER ) case Mgmt_NWK_Update_notify: ZDNwkMgr_ProcessMgmtNwkUpdateNotify( inMsg ); break; #endif // NWK_MANAGER case Server_Discovery_rsp: ZDNwkMgr_ProcessServerDiscRsp( inMsg ); break; default: // Unknown message break; } } /********************************************************************* * Frequency Agility Routines */ #if defined ( NWK_MANAGER ) /********************************************************************* * @fn ZDNwkMgr_ProcessMgmtNwkUpdateNotify * * @brief This function processes the incoming Management * Network Update notify. * * @param pUpdateNotify - notify message * * @return TRUE if message to be freed. FALSE otherwise. */ static void ZDNwkMgr_ProcessMgmtNwkUpdateNotify( zdoIncomingMsg_t *inMsg ) { if ( zgNwkMgrMode == ZDNWKMGR_ENABLE ) { ZDO_MgmtNwkUpdateNotify_t *pNotify = ZDO_ParseMgmtNwkUpdateNotify( inMsg ); if ( pNotify ) { ZDNwkMgr_CheckForChannelChange( pNotify ); osal_mem_free( pNotify ); } } } /********************************************************************* * @fn ZDNwkMgr_CheckForChannelChange * * @brief This function processes the incoming Management Network * Update notify and starts an Update Request if a channel * change is needed. * * @param pUpdateNotify - notify message * * @return none */ static void ZDNwkMgr_CheckForChannelChange( ZDO_MgmtNwkUpdateNotify_t *pNotify ) { uint8 i; uint16 failureRate; uint8 lowestEnergyIndex; uint8 lowestEnergyValue = 0xFF; // If any device has more than 50% transmission failures, a channel // change should be considered failureRate = ( pNotify->transmissionFailures * 100 ) / pNotify->totalTransmissions; if ( failureRate < ZDNWKMGR_CC_TX_FAILURE ) { #if defined ( LCD_SUPPORTED ) HalLcdWriteString( (char*)NwkMgrStr_1, HAL_LCD_LINE_1 ); HalLcdWriteStringValueValue( ": ", failureRate, 10, ZDNWKMGR_CC_TX_FAILURE, 10, HAL_LCD_LINE_2 ); #endif return; } // If the current failure rate is higher than the last failure rate, // a channel change should be considered if ( failureRate < ZDNwkMgr_LastChannelFailureRate ) { #if defined ( LCD_SUPPORTED ) HalLcdWriteString( (char*)NwkMgrStr_2, HAL_LCD_LINE_1 ); HalLcdWriteStringValueValue( ": ", failureRate, 10, ZDNwkMgr_LastChannelFailureRate, 10, HAL_LCD_LINE_2 ); #endif return; } // Select a single channel based on the Mgmt_NWK_Update_notify based on // the lowest energy. This is the proposed new channel. for ( i = 0; i < pNotify->listCount; i++ ) { if ( pNotify->energyValues[i] < lowestEnergyValue ) { lowestEnergyIndex = i; lowestEnergyValue = pNotify->energyValues[i]; } } // If this new channel does not have an energy level below an acceptable // threshold, a channel change should not be done. if ( lowestEnergyValue > ZDNWKMGR_ACCEPTABLE_ENERGY_LEVEL ) { #if defined ( LCD_SUPPORTED ) HalLcdWriteString( (char*)NwkMgrStr_3, HAL_LCD_LINE_1 ); HalLcdWriteStringValueValue( ": ", lowestEnergyValue, 10, ZDNWKMGR_ACCEPTABLE_ENERGY_LEVEL, 10, HAL_LCD_LINE_2 ); #endif return; } // Channel change should be done -- find out the new active channel for ( i = 0; i < ED_SCAN_MAXCHANNELS; i++ ) { if ( ( (uint32)1 << i ) & pNotify->scannedChannels ) { if ( lowestEnergyIndex == 0 ) break; lowestEnergyIndex--; } } if ( ( _NIB.nwkLogicalChannel != i ) && ( ZDNwkMgr_UpdateRequestTimer == 0 ) ) { uint32 channelMask; zAddrType_t dstAddr; // The new channel ZDNwkMgr_NewChannel = i; // Prior to changing channels, the network manager should store the // energy scan value as the last energy scan value and the failure // rate from the existing channel as the last failure rate. These // values are useful to allow comparison of the failure rate and energy // level on the previous channel to evaluate if the network is causing // its own interference. ZDNwkMgr_LastChannelEnergy = lowestEnergyValue; ZDNwkMgr_LastChannelFailureRate = failureRate; // The network manager should broadcast a Mgmt_NWK_Update_req notifying // devices of the new channel. The broadcast shall be to all routers // and coordinator. dstAddr.addrMode = AddrBroadcast; dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVRXON; channelMask = (uint32)1 << i; // Increment the nwkUpdateId parameter and set the updateID in the beacon NLME_SetUpdateID(_NIB.nwkUpdateId + 1); ZDP_MgmtNwkUpdateReq( &dstAddr, channelMask, 0xfe, 0, _NIB.nwkUpdateId, 0 ); // The network manager shall set a timer based on the value of // apsChannelTimer upon issue of a Mgmt_NWK_Update_req that changes // channels and shall not issue another such command until this // timer expires. ZDNwkMgr_UpdateRequestTimer = ZDNWKMGR_UPDATE_REQUEST_TIMER; osal_start_timerEx( ZDNwkMgr_TaskID, ZDNWKMGR_UPDATE_REQUEST_EVT, ONE_MINUTE ); // Upon receipt of a Mgmt_NWK_Update_req with a change of channels, // the local network manager shall set a timer equal to the // nwkNetworkBroadcastDeliveryTime and shall switch channels upon // expiration of this timer. NOTE: since we won't recevied our own // broadcasted Update Request, we start the channel change timer here. osal_start_timerEx( ZDNwkMgr_TaskID, ZDNWKMGR_CHANNEL_CHANGE_EVT, ZDNWKMGR_BCAST_DELIVERY_TIME ); } } #endif // NWK_MANAGER /********************************************************************* * @fn ZDNwkMgr_ProcessMgmtNwkUpdateReq * * @brief This function processes the incoming Management * Network Update request and starts the request (if needed). * * @param Request message * * @return none */ static void ZDNwkMgr_ProcessMgmtNwkUpdateReq( zdoIncomingMsg_t *inMsg ) { ZDO_MgmtNwkUpdateReq_t Req; ZDO_ParseMgmtNwkUpdateReq( inMsg, &Req ); if ( Req.scanDuration <= 0x05 ) { // Request is to scan over channelMask. The result will be reported by Confirm if ( ( !inMsg->wasBroadcast ) && ( Req.scanCount > ZDNWKMGR_MIN_SCAN_COUNT ) && ( Req.scanCount <= ZDNWKMGR_MAX_SCAN_COUNT ) ) { if ( NLME_EDScanRequest( Req.channelMask, Req.scanDuration ) == ZSuccess ) { // Save off the information to be used for the notify ZDNwkMgr_MgmtNwkUpdateNotifyTransSeq = inMsg->TransSeq; ZDNwkMgr_MgmtNwkUpdateNotifyAddr.addr.shortAddr = inMsg->srcAddr.addr.shortAddr; Req.scanCount--; // Save off scan info for the subsequent scans ZDNwkMgr_MgmtNwkUpdateReq = Req; } } } else if ( Req.scanDuration == 0xFE ) { // Request is to change Channel. The command provide a new active // channel as a single channel in the channelMask. if ( Req.nwkUpdateId > _NIB.nwkUpdateId ) { uint8 i; // Set update ID in the Beacon NLME_SetUpdateID(Req.nwkUpdateId); // Find out the new active channel for ( i = 0; i < ED_SCAN_MAXCHANNELS; i++ ) { if ( ( (uint32)1 << i ) & Req.channelMask ) { break; } } if ( _NIB.nwkLogicalChannel != i ) { ZDNwkMgr_NewChannel = i; // Upon receipt of a Mgmt_NWK_Update_req with a change of channels, // the local network manager shall set a timer equal to the // nwkNetworkBroadcastDeliveryTime and shall switch channels upon // expiration of this timer. Each node shall also increment the // nwkUpdateId parameter and also reset the total transmit count // and the transmit failure counters. osal_start_timerEx( ZDNwkMgr_TaskID, ZDNWKMGR_CHANNEL_CHANGE_EVT, ZDNWKMGR_BCAST_DELIVERY_TIME ); } } } else if ( Req.scanDuration == 0xFF ) { // Request is to change apsChannelMask and nwkManagerAddr if ( Req.nwkUpdateId > _NIB.nwkUpdateId ) { NLME_SetUpdateID(Req.nwkUpdateId); // Set the updateID in the beacon if ( ( Req.channelMask != 0 ) && ( _NIB.channelList != Req.channelMask ) ) { _NIB.channelList = Req.channelMask; // Our Channel List has been changed -- notify to save info into NV ZDApp_NwkStateUpdateCB(); } ZDNwkMgr_SetNwkManagerAddr( Req.nwkManagerAddr ); } } else // 0x06-0xFD { // Request is invalid if ( !inMsg->wasBroadcast ) { ZDNwkMgr_MgmtNwkUpdateNotifyAddr.addr.shortAddr = inMsg->srcAddr.addr.shortAddr; ZDP_MgmtNwkUpdateNotify( inMsg->TransSeq, &ZDNwkMgr_MgmtNwkUpdateNotifyAddr, ZDP_INVALID_REQTYPE, 0, 0, 0, 0, NULL, AF_TX_OPTIONS_NONE, false ); } } } /********************************************************************* * @fn ZDNwkMgr_ProcessServerDiscRsp * * @brief Process the incoming System Server Discovery Response * * @param pRsp - Structure containing Server Discovery response * * @return none */ void ZDNwkMgr_ProcessServerDiscRsp( zdoIncomingMsg_t *inMsg ) { ZDO_ServerDiscRsp_t Rsp; ZDO_ParseServerDiscRsp( inMsg, &Rsp ); if ( Rsp.status == ZSuccess ) { // Is the Network Manager bit set in the response? if ( Rsp.serverMask & NETWORK_MANAGER ) { // Set the Remote Device's NWK Address as the Network Manager Address ZDNwkMgr_SetNwkManagerAddr( inMsg->srcAddr.addr.shortAddr ); } } } /********************************************************************* * @fn ZDNwkMgr_ProcessChannelInterference * * @brief This function processes the incoming Channel Interference * detection message and sends out a notify (if needed). * * @param pChannelInterference - interference message * * @return none */ static void ZDNwkMgr_ProcessChannelInterference( ZDNwkMgr_ChanInterference_t *pChanInterference ) { // To avoid a device with communication problems from constantly // sending reports to the network manager, the device should not // send a Mgmt_NWK_Update_notify more than 4 times per hour. if ( ZDNwkMgr_NumUpdateNotifySent < 4 ) { // Conduct an energy scan on all channels. if ( NLME_EDScanRequest( MAX_CHANNELS_24GHZ, _NIB.scanDuration ) == ZSuccess ) { // Save the counters for the Update Notify message to be sent ZDNwkMgr_TotalTransmissions = pChanInterference->totalTransmissions; ZDNwkMgr_TxFailures = pChanInterference->txFailures; // Mark scan as channel inetrference check ZDNwkMgr_MgmtNwkUpdateReq.scanCount = 0xFF; } } } /********************************************************************* * @fn ZDNwkMgr_ProcessEDScanConfirm * * @brief This function processes the incoming ED Scan Confirm * message and sends out a notify (if needed). * * @param pEDScanConfirm - SD Scan Confirmation message * * @return none */ static void ZDNwkMgr_ProcessEDScanConfirm( ZDNwkMgr_EDScanConfirm_t *pEDScanConfirm ) { if ( ZDNwkMgr_MgmtNwkUpdateReq.scanCount == 0xFF ) { // Confirm to scan all channels for channel interference check ZDNwkMgr_CheckForChannelInterference( pEDScanConfirm ); ZDNwkMgr_MgmtNwkUpdateReq.scanCount = 0; } else { // Confirm to the requested scan uint16 txFailures = nwkTransmissionFailures( FALSE ); ZDNwkMgr_BuildAndSendUpdateNotify( ZDNwkMgr_MgmtNwkUpdateNotifyTransSeq, &ZDNwkMgr_MgmtNwkUpdateNotifyAddr, _NIB.nwkTotalTransmissions, txFailures, pEDScanConfirm, AF_TX_OPTIONS_NONE ); // More scans needed? if ( ZDNwkMgr_MgmtNwkUpdateReq.scanCount > 0 ) { osal_start_timerEx( ZDNwkMgr_TaskID, ZDNWKMGR_SCAN_REQUEST_EVT, 50 ); } } } /********************************************************************* * @fn ZDNwkMgr_CheckForChannelInterference * * @brief This function processes the incoming ED Scan Confirm * message and sends out an Update Notify (if needed). * * @param pEDScanConfirm - SD Scan Confirmation message * * @return none */ static void ZDNwkMgr_CheckForChannelInterference( ZDNwkMgr_EDScanConfirm_t *pEDScanConfirm ) { uint8 i; uint8 channelEnergy = 0; uint8 energyIncreased = FALSE; // Get the current channel energy if ( ( (uint32)1 << _NIB.nwkLogicalChannel ) & pEDScanConfirm->scannedChannels ) { channelEnergy = pEDScanConfirm->energyDetectList[_NIB.nwkLogicalChannel]; } // If this energy scan does not indicate higher energy on the current // channel then other channels, no action is taken. The device should // continue to operate as normal and the message counters are not reset. for ( i = 0; i < ED_SCAN_MAXCHANNELS; i++ ) { if ( ( ( (uint32)1 << i ) & pEDScanConfirm->scannedChannels ) && ( channelEnergy > pEDScanConfirm->energyDetectList[i] ) ) { energyIncreased = TRUE; break; } } // If the energy scan does indicate increased energy on the channel // in use, a Mgmt_NWK_Update_notify should be sent to the Network // Manager to indicate interference is present. if ( energyIncreased ) { // Send a Management Network Update notify to the Network Manager ZDNwkMgr_MgmtNwkUpdateNotifyAddr.addr.shortAddr = _NIB.nwkManagerAddr; ZDNwkMgr_BuildAndSendUpdateNotify( 0, &ZDNwkMgr_MgmtNwkUpdateNotifyAddr, ZDNwkMgr_TotalTransmissions, ZDNwkMgr_TxFailures, pEDScanConfirm, AF_MSG_ACK_REQUEST ); ZDNwkMgr_WaitingForNotifyConfirm = TRUE; // Confirm will clear the counters if ( ZDNwkMgr_NumUpdateNotifySent == 0 ) { // First notify message sent within this hour. Start the Update Notify timer. ZDNwkMgr_UpdateNotifyTimer = ZDNWKMGR_UPDATE_NOTIFY_TIMER; osal_start_timerEx( ZDNwkMgr_TaskID, ZDNWKMGR_UPDATE_NOTIFY_EVT, ONE_MINUTE ); } ZDNwkMgr_NumUpdateNotifySent++; } #if defined ( LCD_SUPPORTED ) else { HalLcdWriteString( (char*)NwkMgrStr_4, HAL_LCD_LINE_1 ); HalLcdWriteStringValueValue( ": ", _NIB.nwkLogicalChannel, 10, channelEnergy, 10, HAL_LCD_LINE_2 ); } #endif } /********************************************************************* * @fn ZDNwkMgr_BuildAndSendUpdateNotify * * @brief This builds and send a Mgmt_NWK_Update_notify message. This * function sends a unicast message. * * @param TransSeq - transaction sequence number * @param dstAddr - destination address of the message * @param pEDScanConfirm - update notify info * * @return afStatus_t */ static void ZDNwkMgr_BuildAndSendUpdateNotify( uint8 TransSeq, zAddrType_t *dstAddr, uint16 totalTransmissions, uint16 txFailures, ZDNwkMgr_EDScanConfirm_t *pEDScanConfirm, uint8 txOptions ) { uint8 i; uint8 listCount = 0; uint8 *energyValues = NULL; // Count number of energy detects for ( i = 0; i < ED_SCAN_MAXCHANNELS; i++ ) { if ( ( (uint32)1 << i ) & pEDScanConfirm->scannedChannels ) listCount++; } if ( listCount > 0 ) { energyValues = (uint8 *)osal_mem_alloc( listCount ); if ( energyValues ) { uint8 j = 0; for ( i = 0; i < ED_SCAN_MAXCHANNELS; i++ ) { if ( ( (uint32)1 << i ) & pEDScanConfirm->scannedChannels ) energyValues[j++] = pEDScanConfirm->energyDetectList[i]; } } } // Send a Management Network Update notify back ZDP_MgmtNwkUpdateNotify( TransSeq, dstAddr, pEDScanConfirm->status, pEDScanConfirm->scannedChannels, totalTransmissions, txFailures, listCount, energyValues, txOptions, false ); if ( energyValues ) osal_mem_free( energyValues ); } #if defined ( NWK_MANAGER ) /********************************************************************* * @fn NwkMgr_SetNwkManager * * @brief Set the local device as the Network Manager * * @param none * * @return none */ void NwkMgr_SetNwkManager( void ) { if ( zgNwkMgrMode == ZDNWKMGR_ENABLE ) { // We're the Network Manager. Set our address as the Network Manager Address ZDNwkMgr_SetNwkManagerAddr( _NIB.nwkDevAddress ); // Set the Network Manager bit of the Server Mask ZDO_Config_Node_Descriptor.ServerMask |= NETWORK_MANAGER; } } #endif // NWK_MANAGER /********************************************************************* * @fn ZDApp_SetNwkManagerAddr() * * @brief Sets the nwkManagerAddr in NIB. * * @param nwkManagerAddr * * @return none */ void ZDNwkMgr_SetNwkManagerAddr( uint16 nwkManagerAddr ) { if ( _NIB.nwkManagerAddr != nwkManagerAddr ) { // Update the Network Manager Address _NIB.nwkManagerAddr = nwkManagerAddr; // Our Network Manger Address has been changed -- notify to save info into NV ZDApp_NwkStateUpdateCB(); } } /********************************************************************* * @fn ZDNwkMgr_ReportChannelInterference * * @brief This function builds a Channel Interference detection * message and then forwards it to the Network Manager. * * @param chanInterference * * @return none */ void ZDNwkMgr_ReportChannelInterference( NLME_ChanInterference_t *chanInterference ) { ZDNwkMgr_ChanInterference_t *pChanInterference; // Send Channel Interference message to the Network Manager task pChanInterference = (ZDNwkMgr_ChanInterference_t *)osal_msg_allocate( sizeof( ZDNwkMgr_ChanInterference_t ) ); if ( pChanInterference ) { pChanInterference->hdr.event = NM_CHANNEL_INTERFERE; // Build the structure pChanInterference->totalTransmissions = chanInterference->totalTransmissions; pChanInterference->txFailures = chanInterference->txFailures; osal_msg_send( ZDNwkMgr_TaskID, (uint8 *)pChanInterference ); } } /********************************************************************* * @fn ZDNwkMgr_EDScanConfirmCB * * @brief Handle Energy Scan confirm callback * * @param scannedChannels - scanned channels * @param energyDetectList - measured energy for channels * * @return none */ void ZDNwkMgr_EDScanConfirmCB( NLME_EDScanConfirm_t *EDScanConfirm ) { ZDNwkMgr_EDScanConfirm_t *pEDScanConfirm; // Send ED Confirm to the Network Manager task pEDScanConfirm = (ZDNwkMgr_EDScanConfirm_t *)osal_msg_allocate( sizeof( ZDNwkMgr_EDScanConfirm_t ) ); if ( pEDScanConfirm ) { pEDScanConfirm->hdr.event = NM_ED_SCAN_CONFIRM; // Build the structure pEDScanConfirm->status = EDScanConfirm->status; pEDScanConfirm->scannedChannels = EDScanConfirm->scannedChannels; osal_memcpy( pEDScanConfirm->energyDetectList, EDScanConfirm->energyDetectList, ED_SCAN_MAXCHANNELS ); osal_msg_send( ZDNwkMgr_TaskID, (uint8 *)pEDScanConfirm ); } } /********************************************************************* * @fn ZDNwkMgr_ProcessDataConfirm * * @brief Process received Confirmation for Mgmt NWK Update Notify message * * @param none * * @return none */ void ZDNwkMgr_ProcessDataConfirm( afDataConfirm_t *afDataConfirm ) { if ( ZDNwkMgr_WaitingForNotifyConfirm && ( afDataConfirm->transID == 0 ) && ( afDataConfirm->hdr.status == ZSuccess ) ) { // The Mgmt NWK Update Notify was sent as an APS Unicast with // acknowledgement and once the acknowledgment is received the // total transmit and transmit failure counters are reset to zero. _NIB.nwkTotalTransmissions = 0; nwkTransmissionFailures( TRUE ); ZDNwkMgr_WaitingForNotifyConfirm = FALSE; } } /********************************************************************* * PAN ID Conflict Routines */ #if defined ( NWK_MANAGER ) /********************************************************************* * @fn ZDNwkMgr_NetworkReportCB * * @brief Handle the Network Report Command * * @param srcAddr - Source Address of the message. * @param status - ZSuccess. * @param serverMask - Bit mask of services matching the req serverMask. * @param securityUse - * * @return none */ void ZDNwkMgr_NetworkReportCB( ZDNwkMgr_NetworkReport_t *pReport ) { // Send Network Report message to the Network Manager task osal_msg_send( ZDNwkMgr_TaskID, (uint8 *)pReport ); } /********************************************************************* * @fn ZDNwkMgr_NetworkUpdateCB * * @brief Handle the Network Update Command * * @param srcAddr - Source Address of the message. * @param status - ZSuccess. * @param serverMask - Bit mask of services matching the req serverMask. * @param securityUse - * * @return none */ void ZDNwkMgr_NetworkUpdateCB( ZDNwkMgr_NetworkUpdate_t *pUpdate ) { // Send Network Update message to the Network Manager task osal_msg_send( ZDNwkMgr_TaskID, (uint8 *)pUpdate ); } /********************************************************************* * @fn ZDNwkMgr_ProcessNetworkReport * * @brief Process the incoming Network Report message * * @param pNetworkReport - Structure containing Network Report message * * @return none */ void ZDNwkMgr_ProcessNetworkReport( ZDNwkMgr_NetworkReport_t *pNetworkReport ) { uint8 i; uint16 newPID; uint8 unique = TRUE; if ( pNetworkReport->reportType == NWKREPORT_PANID_CONFLICT ) { if ( ZDNwkMgr_PanIdUpdateInProgress == FALSE ) { do { // select a new PAN ID newPID = (uint16)osal_rand(); // Make sure that the chosen PAN ID is not already in use in the // local neighborhood and also not contained within the Report // Information field of the Network Report Command frame for ( i = 0; i < pNetworkReport->reportInfoCnt; i++ ) { if ( pNetworkReport->panIDs[i] == newPID ) { unique = FALSE; break; } } } while ( !unique ); // Send out a Network Update command. NLME_SendNetworkUpdate( NWK_BROADCAST_SHORTADDR, NWKUPDATE_PANID_UPDATE, _NIB.extendedPANID, _NIB.nwkUpdateId+1, newPID ); ZDNwkMgr_PanIdUpdateInProgress = TRUE; } } } /********************************************************************* * @fn ZDNwkMgr_ProcessNetworkUpdate * * @brief Process the incoming Network Update message * * @param pNetworkReport - Structure containing Network Update message * * @return none */ void ZDNwkMgr_ProcessNetworkUpdate( ZDNwkMgr_NetworkUpdate_t *pNetworkUpdate ) { if ( pNetworkUpdate->updateType == NWKUPDATE_PANID_UPDATE ) { // Our PAN ID has been changed -- notify to save info into NV ZDApp_NwkStateUpdateCB(); ZDNwkMgr_PanIdUpdateInProgress = FALSE; } } #endif // NWK_MANAGER /********************************************************************* *********************************************************************/