ZDO(ZDO目录)
ZDApp.c
#include "ZComDef.h"
#include "ZMac.h"
#include "OSAL.h"
#include "OSAL_Tasks.h"
#include "OSAL_PwrMgr.h"
#include "OSAL_Nv.h"
#include "AF.h"
#include "APSMEDE.h"
#include "NLMEDE.h"
#include "AddrMgr.h"
#include "ZDProfile.h"
#include "ZDObject.h"
#include "ZDConfig.h"
#include "ZDSecMgr.h"
#include "ZDApp.h"
#include "DebugTrace.h"
#include "nwk_util.h"
#include "OnBoard.h"
#include "ZGlobals.h"
#include "ZDNwkMgr.h"
#include "rtg.h"
#include "ssp.h"
/* HAL */
#include "hal_led.h"
#include "hal_lcd.h"
#include "hal_key.h"
#if defined( MT_MAC_FUNC ) || defined( MT_MAC_CB_FUNC )
#error "ERROR! MT_MAC functionalities should be disabled on ZDO devices"
#endif
#if !defined( NWK_START_DELAY )
#define NWK_START_DELAY 100 // in milliseconds
#endif
#if !defined( LEAVE_RESET_DELAY )
#define LEAVE_RESET_DELAY 5000 // in milliseconds
#endif
// Init ZDO, but hold and wait for application to start the joining or
// forming network
#define ZDO_INIT_HOLD_NWK_START 0xFFFF
#if !defined( EXTENDED_JOINING_RANDOM_MASK )
#define EXTENDED_JOINING_RANDOM_MASK 0x007F
#endif
#if !defined( BEACON_REQUEST_DELAY )
#define BEACON_REQUEST_DELAY 100 // in milliseconds
#endif
#if !defined( BEACON_REQ_DELAY_MASK )
#define BEACON_REQ_DELAY_MASK 0x007F
#endif
#define MAX_RESUME_RETRY 3
#define MAX_DEVICE_UNAUTH_TIMEOUT 5000 // 5 seconds
// Beacon Order Settings (see NLMEDE.h)
#define DEFAULT_BEACON_ORDER BEACON_ORDER_NO_BEACONS
#define DEFAULT_SUPERFRAME_ORDER DEFAULT_BEACON_ORDER
#if !defined( MAX_NWK_FRAMECOUNTER_CHANGES )
// The number of times the frame counter can change before
// saving to NV
#define MAX_NWK_FRAMECOUNTER_CHANGES 1000
#endif
// Leave control bits
#define ZDAPP_LEAVE_CTRL_INIT 0
#define ZDAPP_LEAVE_CTRL_SET 1
#define ZDAPP_LEAVE_CTRL_RA 2
// Address Manager Stub Implementation
#define ZDApp_NwkWriteNVRequest AddrMgrWriteNVRequest
#if !defined ZDO_NV_SAVE_RFDs
#define ZDO_NV_SAVE_RFDs TRUE
#endif
// Delay time before updating NWK NV data to force fewer writes during high activity.
#if ZDO_NV_SAVE_RFDs
#define ZDAPP_UPDATE_NWK_NV_TIME 700
#else
#define ZDAPP_UPDATE_NWK_NV_TIME 65000
#endif
#if defined( LCD_SUPPORTED )
uint8 MatchRsps = 0;
#endif
uint8 zdoDiscCounter = 1;
zAddrType_t ZDAppNwkAddr;
uint8 zdappMgmtNwkDiscRspTransSeq;
uint8 zdappMgmtNwkDiscReqInProgress = FALSE;
zAddrType_t zdappMgmtNwkDiscRspAddr;
uint8 zdappMgmtNwkDiscStartIndex;
uint8 zdappMgmtSavedNwkState;
uint16 nwkFrameCounterChanges = 0;
uint8 continueJoining = TRUE;
uint8 _tmpRejoinState;
// The extended PanID used in ZDO layer for rejoin.
uint8 ZDO_UseExtendedPANID[Z_EXTADDR_LEN];
pfnZdoCb zdoCBFunc[MAX_ZDO_CB_FUNC];
void ZDApp_NetworkStartEvt( void );
void ZDApp_DeviceAuthEvt( void );
void ZDApp_SaveNetworkStateEvt( void );
uint8 ZDApp_ReadNetworkRestoreState( void );
uint8 ZDApp_RestoreNetworkState( void );
void ZDAppDetermineDeviceType( void );
void ZDApp_InitUserDesc( void );
void ZDAppCheckForHoldKey( void );
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr );
void ZDApp_ProcessNetworkJoin( void );
void ZDApp_SetCoordAddress( uint8 endPoint, uint8 dstEP );
uint8 ZDApp_RestoreNwkKey( void );
networkDesc_t* ZDApp_NwkDescListProcessing(void);
void ZDApp_SecInit( uint8 state );
UINT16 ZDApp_ProcessSecEvent( uint8 task_id, UINT16 events );
void ZDApp_ProcessSecMsg( osal_event_hdr_t *msgPtr );
void ZDApp_SendMsg( uint8 taskID, uint8 cmd, uint8 len, uint8 *buf );
void ZDApp_ResetTimerStart( uint16 delay );
void ZDApp_ResetTimerCancel( void );
void ZDApp_LeaveCtrlInit( void );
void ZDApp_LeaveCtrlSet( uint8 ra );
uint8 ZDApp_LeaveCtrlBypass( void );
void ZDApp_LeaveCtrlStartup( devStates_t* state, uint16* startDelay );
void ZDApp_LeaveUpdate( uint16 nwkAddr, uint8* extAddr,
uint8 removeChildren );
void ZDApp_NodeProfileSync( uint8 stackProfile );
void ZDApp_ProcessMsgCBs( zdoIncomingMsg_t *inMsg );
void ZDApp_RegisterCBs( void );
void ZDApp_InitZdoCBFunc(void);
uint8 ZDAppTaskID;
uint8 nwkStatus;
endPointDesc_t *ZDApp_AutoFindMode_epDesc = (endPointDesc_t *)NULL;
uint8 ZDApp_LeaveCtrl;
#if defined( HOLD_AUTO_START )
devStates_t devState = DEV_HOLD;
#else
devStates_t devState = DEV_INIT;
#endif
#if ( ZG_BUILD_RTRONLY_TYPE ) || ( ZG_BUILD_ENDDEVICE_TYPE )
devStartModes_t devStartMode = MODE_JOIN; // Assume joining
//devStartModes_t devStartMode = MODE_RESUME; // if already "directly joined"
// to parent. Set to make the device do an Orphan scan.
#else
// Set the default to coodinator
devStartModes_t devStartMode = MODE_HARD;
#endif
uint8 retryCnt;
endPointDesc_t ZDApp_epDesc =
{
ZDO_EP,
&ZDAppTaskID,
(SimpleDescriptionFormat_t *)NULL, // No Simple description for ZDO
(afNetworkLatencyReq_t)0 // No Network Latency req
};
uint16 ZDApp_SavedPollRate = POLL_RATE;
void ZDApp_Init( uint8 task_id )
{
// Save the task ID
ZDAppTaskID = task_id;
// Initialize the ZDO global device short address storage
ZDAppNwkAddr.addrMode = Addr16Bit;
ZDAppNwkAddr.addr.shortAddr = INVALID_NODE_ADDR;
(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.
// Check for manual "Hold Auto Start"
ZDAppCheckForHoldKey();
// Initialize ZDO items and setup the device - type of device to create.
ZDO_Init();
// Register the endpoint description with the AF
// This task doesn't have a Simple description, but we still need
// to register the endpoint.
afRegister( (endPointDesc_t *)&ZDApp_epDesc );
#if defined( ZDO_USERDESC_RESPONSE )
ZDApp_InitUserDesc();
#endif // ZDO_USERDESC_RESPONSE
// Start the device?
if ( devState != DEV_HOLD )
{
ZDOInitDevice( 0 );
}
else
{
ZDOInitDevice( ZDO_INIT_HOLD_NWK_START );
// Blink LED to indicate HOLD_START
HalLedBlink ( HAL_LED_4, 0, 50, 500 );
}
// Initialize the ZDO callback function pointers zdoCBFunc[]
ZDApp_InitZdoCBFunc();
ZDApp_RegisterCBs();
} /* ZDApp_Init() */
void ZDApp_SecInit( uint8 state )
{
uint8 zgPreConfigKey[SEC_KEY_LEN];
if ( ZG_SECURE_ENABLED && ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
{
// Set the Trust Center bit
ZDO_Config_Node_Descriptor.ServerMask |= PRIM_TRUST_CENTER;
}
if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
{
ZDO_Config_Node_Descriptor.CapabilityFlags |= CAPINFO_SECURITY_CAPABLE;
}
// Initialize ZigBee Device Security Manager
ZDSecMgrInit(state);
if ( ZG_SECURE_ENABLED )
{
if ( state != ZDO_INITDEV_RESTORED_NETWORK_STATE )
{
nwkFrameCounter = 0;
if( _NIB.nwkKeyLoaded == FALSE )
{
if ( ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE ) ||
( ( zgSecurityMode == ZG_SECURITY_RESIDENTIAL ) && zgPreConfigKeys ) )
{
ZDSecMgrReadKeyFromNv(ZCD_NV_PRECFGKEY, zgPreConfigKey);
SSP_UpdateNwkKey( zgPreConfigKey, 0);
SSP_SwitchNwkKey( 0 );
// clear local copy of key
osal_memset(zgPreConfigKey, 0x00, SEC_KEY_LEN);
}
}
}
}
}
UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events )
{
uint8 *msg_ptr;
if ( events & SYS_EVENT_MSG )
{
while ( (msg_ptr = osal_msg_receive( ZDAppTaskID )) )
{
ZDApp_ProcessOSALMsg( (osal_event_hdr_t *)msg_ptr );
// Release the memory
osal_msg_deallocate( msg_ptr );
}
// Return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
if ( events & ZDO_NETWORK_INIT )
{
// Initialize apps and start the network
devState = DEV_INIT;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
ZDO_StartDevice( (uint8)ZDO_Config_Node_Descriptor.LogicalType, devStartMode,
DEFAULT_BEACON_ORDER, DEFAULT_SUPERFRAME_ORDER );
// Return unprocessed events
return (events ^ ZDO_NETWORK_INIT);
}
if ( ZSTACK_ROUTER_BUILD )
{
if ( events & ZDO_NETWORK_START )
{
ZDApp_NetworkStartEvt();
// Return unprocessed events
return (events ^ ZDO_NETWORK_START);
}
if ( events & ZDO_ROUTER_START )
{
if ( nwkStatus == ZSuccess )
{
if ( devState == DEV_END_DEVICE )
devState = DEV_ROUTER;
osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
}
else
{
// remain as end device!!
}
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
// Return unprocessed events
return (events ^ ZDO_ROUTER_START);
}
}
if ( events & ZDO_STATE_CHANGE_EVT )
{
ZDO_UpdateNwkStatus( devState );
// At start up, do one MTO route discovery if the device is a concentrator
if ( zgConcentratorEnable == TRUE )
{
// Start next event
osal_start_timerEx( NWK_TaskID, NWK_MTO_RTG_REQ_EVT, 100 );
}
// Return unprocessed events
return (events ^ ZDO_STATE_CHANGE_EVT);
}
if ( events & ZDO_COMMAND_CNF )
{
// User defined logic
// Return unprocessed events
return (events ^ ZDO_COMMAND_CNF);
}
if ( events & ZDO_NWK_UPDATE_NV )
{
ZDApp_SaveNetworkStateEvt();
// Return unprocessed events
return (events ^ ZDO_NWK_UPDATE_NV);
}
if ( events & ZDO_DEVICE_RESET )
{
#ifdef ZBA_FALLBACK_NWKKEY
if ( devState == DEV_END_DEVICE_UNAUTH )
{
ZDSecMgrFallbackNwkKey();
}
else
#endif
{
// Set the NV startup option to force a "new" join.
zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );
// The device has been in the UNAUTH state, so reset
// Note: there will be no return from this call
SystemResetSoft();
}
}
if ( ZG_SECURE_ENABLED )
{
return ( ZDApp_ProcessSecEvent( task_id, events ) );
}
else
{
// Discard or make more handlers
return 0;
}
}
UINT16 ZDApp_ProcessSecEvent( uint8 task_id, UINT16 events )
{
(void)task_id; // Intentionally unreferenced parameter
if ( ZSTACK_ROUTER_BUILD )
{
if ( events & ZDO_NEW_DEVICE )
{
// process the new device event
if ( ZDSecMgrNewDeviceEvent() == TRUE )
{
osal_start_timerEx( ZDAppTaskID, ZDO_NEW_DEVICE, 1000 );
}
// Return unprocessed events
return (events ^ ZDO_NEW_DEVICE);
}
}
if ( (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH)
|| (ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD) )
{
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
{
if ( events & ZDO_SECMGR_EVENT )
{
ZDSecMgrEvent();
// Return unprocessed events
return (events ^ ZDO_SECMGR_EVENT);
}
}
}
if ( events & ZDO_DEVICE_AUTH )
{
ZDApp_DeviceAuthEvt();
// Return unprocessed events
return (events ^ ZDO_DEVICE_AUTH);
}
if ( events & ZDO_FRAMECOUNTER_CHANGE )
{
if ( nwkFrameCounterChanges++ > MAX_NWK_FRAMECOUNTER_CHANGES )
{
ZDApp_SaveNwkKey();
}
// Return unprocessed events
return (events ^ ZDO_FRAMECOUNTER_CHANGE);
}
if ( events & ZDO_APS_FRAMECOUNTER_CHANGE )
{
#if defined (NV_RESTORE)
ZDSecMgrSaveApsLinkKey();
#endif // (NV_RESTORE)
// Return unprocessed events
return (events ^ ZDO_APS_FRAMECOUNTER_CHANGE);
}
if ( events & ZDO_TCLK_FRAMECOUNTER_CHANGE )
{
ZDSecMgrSaveTCLinkKey();
// Return unprocessed events
return (events ^ ZDO_TCLK_FRAMECOUNTER_CHANGE);
}
// Discard or make more handlers
return 0;
}
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 been updated.
zgInitItems( FALSE );
}
ZDConfig_InitDescriptors();
//devtag.071807.todo - fix this temporary solution
_NIB.CapabilityFlags = ZDO_Config_Node_Descriptor.CapabilityFlags;
#if defined ( NV_RESTORE )
// Get Keypad directly to see if a reset nv is needed.
// Hold down the SW_BYPASS_NV key (defined in OnBoard.h)
// while booting to skip past NV Restore.
if ( HalKeyRead() == SW_BYPASS_NV )
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
else
{
// Determine if NV should be restored
networkStateNV = ZDApp_ReadNetworkRestoreState();
}
if ( networkStateNV == ZDO_INITDEV_RESTORED_NETWORK_STATE )
{
networkStateNV = ZDApp_RestoreNetworkState();
}
else
{
// Wipe out the network state in NV
NLME_InitNV();
NLME_SetDefaultNV();
// clear NWK key values
ZDSecMgrClearNVKeyValues();
}
#endif
if ( networkStateNV == ZDO_INITDEV_NEW_NETWORK_STATE )
{
ZDAppDetermineDeviceType();
// Only delay if joining network - not restoring network state
extendedDelay = (uint16)((NWK_START_DELAY + startDelay)
+ (osal_rand() & EXTENDED_JOINING_RANDOM_MASK));
}
// Initialize the security for type of device
ZDApp_SecInit( networkStateNV );
if( ZDO_INIT_HOLD_NWK_START != startDelay )
{
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 come back
if ( devState == DEV_HOLD )
{
// Set the NV startup option to force a "new" join.
zgWriteStartupOptions( ZG_STARTUP_SET, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );
// Notify the applications
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
return ( ZDO_INITDEV_LEAVE_NOT_STARTED ); // Don't join - (one time).
}
// Trigger the network start
ZDApp_NetworkInit( extendedDelay );
}
// set broadcast address mask to support broadcast filtering
NLME_SetBroadcastFilter( ZDO_Config_Node_Descriptor.CapabilityFlags );
return ( networkStateNV );
}
uint8 ZDApp_ReadNetworkRestoreState( void )
{
uint8 networkStateNV = ZDO_INITDEV_RESTORED_NETWORK_STATE;
// Look for the New Network State option.
if ( zgReadStartupOptions() & ZCD_STARTOPT_DEFAULT_NETWORK_STATE )
{
networkStateNV = ZDO_INITDEV_NEW_NETWORK_STATE;
}
return ( networkStateNV );
}
void ZDAppDetermineDeviceType( void )
{
if ( zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR )
{
devStartMode = MODE_HARD; // Start as a coordinator
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;
}
else
{
if ( zgDeviceLogicalType == ZG_DEVICETYPE_ROUTER )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER;
else if ( zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICE;
// If AIB_apsUseExtendedPANID is set to a non-zero value by commissioning
// The device shall do rejoin the network. Otherwise, do normal join
if ( nwk_ExtPANIDValid( AIB_apsUseExtendedPANID ) == false )
{
devStartMode = MODE_JOIN; // Assume joining
}
else
{
devStartMode = MODE_REJOIN;
}
}
}
void ZDApp_NetworkStartEvt( void )
{
if ( nwkStatus == ZSuccess )
{
// Successfully started a ZigBee network
if ( devState == DEV_COORD_STARTING )
{
devState = DEV_ZB_COORD;
}
osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
}
else
{
// Try again with a higher energy threshold !!
if ( ( NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT ) < 0xff )
{
NLME_SetEnergyThreshold( (uint8)(NLME_GetEnergyThreshold() + ENERGY_SCAN_INCREMENT) );
osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );
}
else
{
// Failed to start network. Enter a dormant state (until user intervenes)
devState = DEV_INIT;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
}
}
}
void ZDApp_DeviceAuthEvt( void )
{
// received authentication from trust center
if ( devState == DEV_END_DEVICE_UNAUTH )
{
// Stop the reset timer so it doesn't reset
ZDApp_ResetTimerCancel();
devState = DEV_END_DEVICE;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
// Set the Power Manager Device
#if defined ( POWER_SAVING )
osal_pwrmgr_device( PWRMGR_BATTERY );
#endif
if ( ZSTACK_ROUTER_BUILD )
{
if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
// NOTE: first two parameters are not used, see NLMEDE.h for details
NLME_StartRouterRequest( 0, 0, false );
}
}
// Notify to save info into NV
ZDApp_NVUpdate();
// Save off the security
ZDApp_SaveNwkKey();
ZDApp_AnnounceNewAddress();
if ( (ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE) == 0 )
{
NLME_SetPollRate( ZDApp_SavedPollRate );
}
}
else
{
ZDApp_NVUpdate();
}
}
void ZDApp_SaveNetworkStateEvt( void )
{
#if defined ( NV_RESTORE )
#if defined ( NV_TURN_OFF_RADIO )
// Turn off the radio's receiver during an NV update
uint8 RxOnIdle;
uint8 x = false;
ZMacGetReq( ZMacRxOnIdle, &RxOnIdle );
ZMacSetReq( ZMacRxOnIdle, &x );
#endif
// Update the Network State in NV
NLME_UpdateNV( NWK_NV_NIB_ENABLE |
NWK_NV_DEVICELIST_ENABLE |
NWK_NV_BINDING_ENABLE |
NWK_NV_ADDRMGR_ENABLE );
// Reset the NV startup option to resume from NV by
// clearing the "New" join option.
zgWriteStartupOptions( FALSE, ZCD_STARTOPT_DEFAULT_NETWORK_STATE );
#if defined ( NV_TURN_OFF_RADIO )
ZMacSetReq( ZMacRxOnIdle, &RxOnIdle );
#endif
#endif // NV_RESTORE
}
uint8 ZDApp_RestoreNetworkState( void )
{
uint8 nvStat;
// Initialize NWK NV items
nvStat = NLME_InitNV();
if ( nvStat != NV_OPER_FAILED )
{
if ( NLME_RestoreFromNV() )
{
// Are we a coordinator
ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();
if ( ZDAppNwkAddr.addr.shortAddr == 0 )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;
devStartMode = MODE_RESUME;
osal_cpyExtAddr( ZDO_UseExtendedPANID, _NIB.extendedPANID );
}
else
nvStat = NV_ITEM_UNINIT;
if ( ZG_SECURE_ENABLED )
{
nwkFrameCounterChanges = 0;
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
{
ZDApp_RestoreNwkKey();
}
}
// The default for RxOnWhenIdle is true for Routers and false for end devices
// [setup in the NLME_RestoreFromNV()]. Change it here if you want something
// other than default.
}
if ( nvStat == ZSUCCESS )
return ( ZDO_INITDEV_RESTORED_NETWORK_STATE );
else
return ( ZDO_INITDEV_NEW_NETWORK_STATE );
}
void ZDApp_InitUserDesc( void )
{
UserDescriptorFormat_t ZDO_DefaultUserDescriptor;
// Initialize the User Descriptor, the descriptor is read from NV
// when needed. If you want to initialize the User descriptor to something
// other than all zero, do it here.
osal_memset( &ZDO_DefaultUserDescriptor, 0, sizeof( UserDescriptorFormat_t ) );
if ( ZSUCCESS == osal_nv_item_init( ZCD_NV_USERDESC,
sizeof(UserDescriptorFormat_t), (void*)&ZDO_DefaultUserDescriptor ) )
{
if ( ZSUCCESS == osal_nv_read( ZCD_NV_USERDESC, 0,
sizeof(UserDescriptorFormat_t), (void*)&ZDO_DefaultUserDescriptor ) )
{
if ( ZDO_DefaultUserDescriptor.len != 0 )
{
ZDO_Config_Node_Descriptor.UserDescAvail = TRUE;
}
}
}
}
void ZDAppCheckForHoldKey( void )
{
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
// Get Keypad directly to see if a HOLD_START is needed.
// Hold down the SW_BYPASS_START key (see OnBoard.h)
// while booting to avoid starting up the device.
if ( HalKeyRead () == SW_BYPASS_START)
{
// Change the device state to HOLD on start up
devState = DEV_HOLD;
}
#endif // HAL_KEY
}
void ZDApp_ProcessOSALMsg( osal_event_hdr_t *msgPtr )
{
// Data Confirmation message fields
uint8 sentEP; // This should always be 0
uint8 sentStatus;
afDataConfirm_t *afDataConfirm;
uint8 tmp;
switch ( msgPtr->event )
{
// Incoming ZDO Message
case AF_INCOMING_MSG_CMD:
ZDP_IncomingData( (afIncomingMSGPacket_t *)msgPtr );
break;
case ZDO_CB_MSG:
ZDApp_ProcessMsgCBs( (zdoIncomingMsg_t *)msgPtr );
break;
case AF_DATA_CONFIRM_CMD:
// This message is received as a confirmation of a data packet sent.
// The status is of ZStatus_t type [defined in NLMEDE.h]
// The message fields are defined in AF.h
afDataConfirm = (afDataConfirm_t *)msgPtr;
sentEP = afDataConfirm->endpoint;
sentStatus = afDataConfirm->hdr.status;
// Action taken when confirmation is received.
#if defined ( ZIGBEE_FREQ_AGILITY )
if ( pZDNwkMgr_ProcessDataConfirm )
pZDNwkMgr_ProcessDataConfirm( afDataConfirm );
#endif
(void)sentEP;
(void)sentStatus;
break;
case ZDO_NWK_DISC_CNF:
if (devState != DEV_NWK_DISC)
break;
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
// Process the network discovery scan results and choose a parent
// device to join/rejoin itself
networkDesc_t *pChosenNwk;
if ( ( (pChosenNwk = ZDApp_NwkDescListProcessing()) != NULL ) && (zdoDiscCounter > NUM_DISC_ATTEMPTS) )
{
if ( devStartMode == MODE_JOIN )
{
devState = DEV_NWK_JOINING;
ZDApp_NodeProfileSync( pChosenNwk->stackProfile);
if ( NLME_JoinRequest( pChosenNwk->extendedPANID, pChosenNwk->panId,
pChosenNwk->logicalChannel,
ZDO_Config_Node_Descriptor.CapabilityFlags,
pChosenNwk->chosenRouter, pChosenNwk->chosenRouterDepth ) != ZSuccess )
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
} // if ( devStartMode == MODE_JOIN )
else if ( devStartMode == MODE_REJOIN )
{
devState = DEV_NWK_REJOIN;
// Before trying to do rejoin, check if the device has a valid short address
// If not, generate a random short address for itself
if ( _NIB.nwkDevAddress == INVALID_NODE_ADDR )
{
_NIB.nwkDevAddress = osal_rand();
ZMacSetReq( ZMacShortAddress, (byte*)&_NIB.nwkDevAddress );
}
if ( ZG_SECURE_ENABLED )
{
ZDApp_RestoreNwkKey();
}
// Check if the device has a valid PanID, if not, set it to the discovered Pan
if ( _NIB.nwkPanId == INVALID_PAN_ID )
{
_NIB.nwkPanId = pChosenNwk->panId;
ZMacSetReq( ZMacPanId, (byte*)&(_NIB.nwkPanId) );
}
tmp = true;
ZMacSetReq( ZMacRxOnIdle, &tmp ); // Set receiver always on during rejoin
if ( NLME_ReJoinRequest( ZDO_UseExtendedPANID, pChosenNwk->logicalChannel) != ZSuccess )
{
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
} // else if ( devStartMode == MODE_REJOIN )
if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
{
// The receiver is on, turn network layer polling off.
NLME_SetPollRate( 0 );
NLME_SetQueuedPollRate( 0 );
NLME_SetResponseRate( 0 );
}
else
{
if ( (ZG_SECURE_ENABLED) && (devStartMode == MODE_JOIN) )
{
ZDApp_SavedPollRate = zgPollRate;
NLME_SetPollRate( zgRejoinPollRate );
}
}
}
else
{
if ( continueJoining )
{
#if defined ( MANAGED_SCAN )
ZDApp_NetworkInit( MANAGEDSCAN_DELAY_BETWEEN_SCANS );
#else
zdoDiscCounter++;
ZDApp_NetworkInit( (uint16)(BEACON_REQUEST_DELAY
+ ((uint16)(osal_rand()& BEACON_REQ_DELAY_MASK))) );
#endif
}
}
}
break;
case ZDO_NWK_JOIN_IND:
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
ZDApp_ProcessNetworkJoin();
}
break;
case ZDO_NWK_JOIN_REQ:
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
retryCnt = 0;
devStartMode = MODE_RESUME;
_tmpRejoinState = true;
osal_cpyExtAddr( ZDO_UseExtendedPANID, _NIB.extendedPANID );
zgDefaultStartingScanDuration = BEACON_ORDER_60_MSEC;
ZDApp_NetworkInit( 0 );
}
break;
default:
if ( ZG_SECURE_ENABLED )
ZDApp_ProcessSecMsg( msgPtr );
break;
}
}
void ZDApp_ProcessMsgCBs( zdoIncomingMsg_t *inMsg )
{
switch ( inMsg->clusterID )
{
#if defined ( ZDO_NWKADDR_REQUEST ) || defined ( ZDO_IEEEADDR_REQUEST ) || defined ( REFLECTOR )
case NWK_addr_rsp:
case IEEE_addr_rsp:
{
ZDO_NwkIEEEAddrResp_t *pAddrRsp;
pAddrRsp = ZDO_ParseAddrRsp( inMsg );
if ( pAddrRsp )
{
if ( pAddrRsp->status == ZSuccess )
{
ZDO_UpdateAddrManager( pAddrRsp->nwkAddr, pAddrRsp->extAddr );
}
osal_mem_free( pAddrRsp );
}
}
break;
#endif
#if defined ( REFLECTOR )
case Bind_req:
case Unbind_req:
{
ZDO_BindUnbindReq_t bindReq;
ZDO_ParseBindUnbindReq( inMsg, &bindReq );
ZDO_ProcessBindUnbindReq( inMsg, &bindReq );
}
break;
#endif
#if ( ZG_BUILD_COORDINATOR_TYPE )
case Bind_rsp:
case Unbind_rsp:
if (ZG_DEVICE_COORDINATOR_TYPE && matchED)
{
ZDMatchSendState(
(uint8)((inMsg->clusterID == Bind_rsp) ? ZDMATCH_REASON_BIND_RSP : ZDMATCH_REASON_UNBIND_RSP),
ZDO_ParseBindRsp(inMsg), inMsg->TransSeq );
}
break;
case End_Device_Bind_req:
if (ZG_DEVICE_COORDINATOR_TYPE)
{
ZDEndDeviceBind_t bindReq;
ZDO_ParseEndDeviceBindReq( inMsg, &bindReq );
ZDO_MatchEndDeviceBind( &bindReq );
// Freeing the cluster lists - if allocated.
if ( bindReq.numInClusters )
osal_mem_free( bindReq.inClusters );
if ( bindReq.numOutClusters )
osal_mem_free( bindReq.outClusters );
}
break;
#endif
}
}
void ZDApp_RegisterCBs( void )
{
#if defined ( ZDO_IEEEADDR_REQUEST ) || defined ( REFLECTOR )
ZDO_RegisterForZDOMsg( ZDAppTaskID, IEEE_addr_rsp );
#endif
#if defined ( ZDO_NWKADDR_REQUEST ) || defined ( REFLECTOR )
ZDO_RegisterForZDOMsg( ZDAppTaskID, NWK_addr_rsp );
#endif
#if ZG_BUILD_COORDINATOR_TYPE
ZDO_RegisterForZDOMsg( ZDAppTaskID, Bind_rsp );
ZDO_RegisterForZDOMsg( ZDAppTaskID, Unbind_rsp );
ZDO_RegisterForZDOMsg( ZDAppTaskID, End_Device_Bind_req );
#endif
#if defined ( REFLECTOR )
ZDO_RegisterForZDOMsg( ZDAppTaskID, Bind_req );
ZDO_RegisterForZDOMsg( ZDAppTaskID, Unbind_req );
#endif
}
void ZDApp_ProcessSecMsg( osal_event_hdr_t *msgPtr )
{
switch ( msgPtr->event )
{
case ZDO_ESTABLISH_KEY_CFM:
if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
{
ZDSecMgrEstablishKeyCfm( (ZDO_EstablishKeyCfm_t*)msgPtr );
}
break;
case ZDO_ESTABLISH_KEY_IND:
if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
{
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
ZDSecMgrEstablishKeyInd( (ZDO_EstablishKeyInd_t*)msgPtr );
}
}
break;
case ZDO_TRANSPORT_KEY_IND:
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
ZDSecMgrTransportKeyInd( (ZDO_TransportKeyInd_t*)msgPtr );
}
break;
case ZDO_UPDATE_DEVICE_IND:
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
{
ZDSecMgrUpdateDeviceInd( (ZDO_UpdateDeviceInd_t*)msgPtr );
}
break;
case ZDO_REMOVE_DEVICE_IND:
if ( ZG_BUILD_RTRONLY_TYPE && ( zgDeviceLogicalType == ZG_DEVICETYPE_ROUTER ) )
{
ZDSecMgrRemoveDeviceInd( (ZDO_RemoveDeviceInd_t*)msgPtr );
}
break;
case ZDO_REQUEST_KEY_IND:
if (( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH ) ||
( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_SE_STANDARD ))
{
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
{
ZDSecMgrRequestKeyInd( (ZDO_RequestKeyInd_t*)msgPtr );
}
}
break;
case ZDO_SWITCH_KEY_IND:
if ( ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE )
{
ZDSecMgrSwitchKeyInd( (ZDO_SwitchKeyInd_t*)msgPtr );
}
break;
case ZDO_AUTHENTICATE_IND:
if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
{
ZDSecMgrAuthenticateInd( (ZDO_AuthenticateInd_t*)msgPtr );
}
break;
case ZDO_AUTHENTICATE_CFM:
if ( ZG_CHECK_SECURITY_MODE == ZG_SECURITY_PRO_HIGH )
{
ZDSecMgrAuthenticateCfm( (ZDO_AuthenticateCfm_t*)msgPtr );
}
break;
default:
// Unsupported messages
break;
}
}
void ZDApp_ProcessNetworkJoin( void )
{
if ( (devState == DEV_NWK_JOINING) ||
((devState == DEV_NWK_ORPHAN) &&
(ZDO_Config_Node_Descriptor.LogicalType == NODETYPE_ROUTER)) )
{
// Result of a Join attempt by this device.
if ( nwkStatus == ZSuccess )
{
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
#if defined ( POWER_SAVING )
osal_pwrmgr_device( PWRMGR_BATTERY );
#endif
if ( ZG_SECURE_ENABLED && ( ZDApp_RestoreNwkKey() == false ) )
{
// wait for auth from trust center!!
devState = DEV_END_DEVICE_UNAUTH;
// Start the reset timer for MAX UNAUTH time
ZDApp_ResetTimerStart( 10000 );//MAX_DEVICE_UNAUTH_TIMEOUT );
}
else
{
if ( ZSTACK_ROUTER_BUILD )
{
if ( devState == DEV_NWK_ORPHAN
&& ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
// Change NIB state to router for restore
_NIB.nwkState = NWK_ROUTER;
}
}
if ( devState == DEV_NWK_JOINING )
{
ZDApp_AnnounceNewAddress();
}
devState = DEV_END_DEVICE;
if ( ZSTACK_ROUTER_BUILD )
{
// NOTE: first two parameters are not used, see NLMEDE.h for details
if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
NLME_StartRouterRequest( 0, 0, false );
}
}
}
}
else
{
if ( (devStartMode == MODE_RESUME) && (++retryCnt >= MAX_RESUME_RETRY) )
{
if ( _NIB.nwkPanId == 0xFFFF || _NIB.nwkPanId == INVALID_PAN_ID )
devStartMode = MODE_JOIN;
else
{
devStartMode = MODE_REJOIN;
_tmpRejoinState = true;
}
}
if ( (NLME_GetShortAddr() != INVALID_NODE_ADDR) ||
(_NIB.nwkDevAddress != INVALID_NODE_ADDR) )
{
uint16 addr = INVALID_NODE_ADDR;
// Invalidate nwk addr so end device does not use in its data reqs.
_NIB.nwkDevAddress = INVALID_NODE_ADDR;
ZMacSetReq( ZMacShortAddress, (uint8 *)&addr );
}
// Clear the neighbor Table and network discovery tables.
nwkNeighborInitTable();
NLME_NwkDiscTerm();
zdoDiscCounter = 1;
// ZDApp_NetworkInit( (uint16)
// ((NWK_START_DELAY * (osal_rand() & 0x0F)) +
// (NWK_START_DELAY * 5)) );
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ ((uint16)(osal_rand()& EXTENDED_JOINING_RANDOM_MASK))) );
}
}
else if ( devState == DEV_NWK_ORPHAN || devState == DEV_NWK_REJOIN )
{
// results of an orphaning attempt by this device
if (nwkStatus == ZSuccess)
{
if ( ZG_SECURE_ENABLED )
{
ZDApp_RestoreNwkKey();
}
devState = DEV_END_DEVICE;
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
// setup Power Manager Device
#if defined ( POWER_SAVING )
osal_pwrmgr_device( PWRMGR_BATTERY );
#endif
if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE )
{
// The receiver is on, turn network layer polling off.
NLME_SetPollRate( 0 );
NLME_SetQueuedPollRate( 0 );
NLME_SetResponseRate( 0 );
}
if ( ZSTACK_ROUTER_BUILD )
{
// NOTE: first two parameters are not used, see NLMEDE.h for details
if ( ZDO_Config_Node_Descriptor.LogicalType != NODETYPE_DEVICE )
{
NLME_StartRouterRequest( 0, 0, false );
}
}
ZDApp_AnnounceNewAddress();
}
else
{
if ( devStartMode == MODE_RESUME )
{
if ( ++retryCnt <= MAX_RESUME_RETRY )
{
if ( _NIB.nwkPanId == 0xFFFF || _NIB.nwkPanId == INVALID_PAN_ID )
devStartMode = MODE_JOIN;
else
{
devStartMode = MODE_REJOIN;
_tmpRejoinState = true;
}
}
// Do a normal join to the network after certain times of rejoin retries
else if( AIB_apsUseInsecureJoin == true )
{
devStartMode = MODE_JOIN;
}
}
// Clear the neighbor Table and network discovery tables.
nwkNeighborInitTable();
NLME_NwkDiscTerm();
// setup a retry for later...
ZDApp_NetworkInit( (uint16)(NWK_START_DELAY
+ (osal_rand()& EXTENDED_JOINING_RANDOM_MASK)) );
}
}
#if defined ( ZIGBEE_STOCHASTIC_ADDRESSING )
else
{
// Assume from address conflict
if ( _NIB.nwkAddrAlloc == NWK_ADDRESSING_STOCHASTIC )
{
// Notify the network
ZDApp_AnnounceNewAddress();
// Notify apps
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
}
}
#endif
}
void ZDApp_SaveNwkKey( void )
{
nwkActiveKeyItems keyItems;
SSP_ReadNwkActiveKey( &keyItems );
keyItems.frameCounter++;
osal_nv_write( ZCD_NV_NWKKEY, 0, sizeof( nwkActiveKeyItems ),
(void *)&keyItems );
nwkFrameCounterChanges = 0;
// Clear copy in RAM before return.
osal_memset( &keyItems, 0x00, sizeof(keyItems) );
}
void ZDApp_ResetNwkKey( void )
{
nwkActiveKeyItems keyItems;
osal_memset( &keyItems, 0, sizeof( nwkActiveKeyItems ) );
osal_nv_write( ZCD_NV_NWKKEY, 0, sizeof( nwkActiveKeyItems ),
(void *)&keyItems );
}
uint8 ZDApp_RestoreNwkKey( void )
{
nwkActiveKeyItems keyItems;
uint8 ret = false;
if ( osal_nv_read( ZCD_NV_NWKKEY, 0, sizeof(nwkActiveKeyItems), (void*)&keyItems )
== ZSUCCESS )
{
if ( keyItems.frameCounter > 0 )
{
// Restore the key information
keyItems.frameCounter += MAX_NWK_FRAMECOUNTER_CHANGES;
nwkFrameCounter = keyItems.frameCounter;
ret = true;
}
// Force a save for the first frame counter increment
nwkFrameCounterChanges = MAX_NWK_FRAMECOUNTER_CHANGES + 1;
}
// Clear copy in RAM before return.
osal_memset( &keyItems, 0x00, sizeof(keyItems) );
return ( ret );
}
void ZDApp_ResetTimerStart( uint16 delay )
{
// Start the rest timer
osal_start_timerEx( ZDAppTaskID, ZDO_DEVICE_RESET, delay );
}
void ZDApp_ResetTimerCancel( void )
{
// Cancel the reset timer
osal_stop_timerEx( ZDAppTaskID, ZDO_DEVICE_RESET );
}
void ZDApp_LeaveCtrlInit( void )
{
uint8 status;
// Initialize control state
ZDApp_LeaveCtrl = ZDAPP_LEAVE_CTRL_INIT;
status = osal_nv_item_init( ZCD_NV_LEAVE_CTRL,
sizeof(ZDApp_LeaveCtrl),
&ZDApp_LeaveCtrl );
if ( status == ZSUCCESS )
{
// Read saved control
osal_nv_read( ZCD_NV_LEAVE_CTRL,
0,
sizeof( uint8 ),
&ZDApp_LeaveCtrl);
}
}
void ZDApp_LeaveCtrlSet( uint8 ra )
{
ZDApp_LeaveCtrl = ZDAPP_LEAVE_CTRL_SET;
if ( ra == TRUE )
{
ZDApp_LeaveCtrl |= ZDAPP_LEAVE_CTRL_RA;
}
// Write the leave control
osal_nv_write( ZCD_NV_LEAVE_CTRL,
0,
sizeof( uint8 ),
&ZDApp_LeaveCtrl);
}
void ZDApp_LeaveCtrlReset( void )
{
// Set leave control to initialized state
ZDApp_LeaveCtrl = ZDAPP_LEAVE_CTRL_INIT;
// Write initialized control
osal_nv_write( ZCD_NV_LEAVE_CTRL,
0,
sizeof( uint8 ),
&ZDApp_LeaveCtrl);
}
uint8 ZDApp_LeaveCtrlBypass( void )
{
uint8 bypass;
if ( ZDApp_LeaveCtrl & ZDAPP_LEAVE_CTRL_SET )
{
bypass = TRUE;
}
else
{
bypass = FALSE;
}
return bypass;
}
void ZDApp_LeaveCtrlStartup( devStates_t* state, uint16* startDelay )
{
*startDelay = 0;
if ( ZDApp_LeaveCtrl & ZDAPP_LEAVE_CTRL_SET )
{
if ( ZDApp_LeaveCtrl & ZDAPP_LEAVE_CTRL_RA )
{
*startDelay = LEAVE_RESET_DELAY;
}
else
{
*state = DEV_HOLD;
}
// Reset leave control logic
ZDApp_LeaveCtrlReset();
}
}
void ZDApp_LeaveReset( uint8 ra )
{
ZDApp_LeaveCtrlSet( ra );
ZDApp_ResetTimerStart( LEAVE_RESET_DELAY );
}
void ZDApp_LeaveUpdate( uint16 nwkAddr, uint8* extAddr,
uint8 removeChildren )
{
// Remove Apps Key for leaving device
ZDSecMgrDeviceRemoveByExtAddr(extAddr);
// Clear SECURITY bit from Address Manager
ZDSecMgrAddrClear( extAddr );
if ( pbindRemoveDev )
{
zAddrType_t devAddr;
// Remove bind entry and all related data
devAddr.addrMode = Addr64Bit;
osal_memcpy(devAddr.addr.extAddr, extAddr, Z_EXTADDR_LEN);
pbindRemoveDev(&devAddr);
}
// Remove if child
if ( ZSTACK_ROUTER_BUILD )
{
NLME_RemoveChild( extAddr, removeChildren );
}
// Remove Routing table related entry
RTG_RemoveRtgEntry( nwkAddr, 0 );
// Remove entry from neighborTable
nwkNeighborRemove( nwkAddr, _NIB.nwkPanId );
// Schedule to save data to NV
ZDApp_NwkWriteNVRequest();
}
ZStatus_t ZDApp_NetworkDiscoveryReq( uint32 scanChannels, uint8 scanDuration)
{
// Setup optional filters - tbd
// Request NLME network discovery
return NLME_NetworkDiscoveryRequest(scanChannels, scanDuration);
}
ZStatus_t ZDApp_JoinReq( uint8 channel, uint16 panID, uint8 *extendedPanID,
uint16 chosenParent, uint8 parentDepth, uint8 stackProfile )
{
// Sync up the node with the stack profile (In the case where a pro device
// joins a non-pro network, or verse versa)
ZDApp_NodeProfileSync( stackProfile);
// Request NLME Join Request
return NLME_JoinRequest(extendedPanID, panID,channel,
ZDO_Config_Node_Descriptor.CapabilityFlags,
chosenParent, parentDepth);
}
uint8 ZDApp_DeviceConfigured( void )
{
uint16 nwkAddr = INVALID_NODE_ADDR;
osal_nv_read( ZCD_NV_NIB, osal_offsetof( nwkIB_t, nwkDevAddress ),
sizeof( uint16), &nwkAddr );
// Does the NIB have anything more than default?
return ( nwkAddr == INVALID_NODE_ADDR ? FALSE : TRUE );
}
void ZDApp_SendEventMsg( uint8 cmd, uint8 len, uint8 *buf )
{
ZDApp_SendMsg( ZDAppTaskID, cmd, len, buf );
}
void ZDApp_SendMsg( uint8 taskID, uint8 cmd, uint8 len, uint8 *buf )
{
osal_event_hdr_t *msgPtr;
// Send the address to the task
msgPtr = (osal_event_hdr_t *)osal_msg_allocate( len );
if ( msgPtr )
{
if ( (len > 0) && (buf != NULL) )
osal_memcpy( msgPtr, buf, len );
msgPtr->event = cmd;
osal_msg_send( taskID, (uint8 *)msgPtr );
}
}
ZStatus_t ZDO_NetworkDiscoveryConfirmCB(uint8 status)
{
osal_event_hdr_t msg;
// If Scan is initiated by ZDO_MGMT_NWK_DISC_REQ
// Send ZDO_MGMT_NWK_DISC_RSP back
#if defined ( ZDO_MGMT_NWKDISC_RESPONSE )
if ( zdappMgmtNwkDiscReqInProgress )
{
zdappMgmtNwkDiscReqInProgress = false;
ZDO_FinishProcessingMgmtNwkDiscReq();
}
else
#endif
{
// Pass the confirm to another task if it registers the callback
// Otherwise, pass the confirm to ZDApp.
if (zdoCBFunc[ZDO_NWK_DISCOVERY_CNF_CBID] != NULL )
{
zdoCBFunc[ZDO_NWK_DISCOVERY_CNF_CBID]( (void*)&status );
}
else
{
// Otherwise, send scan confirm to ZDApp task to proceed
msg.status = ZDO_SUCCESS;
ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_DISC_CNF, sizeof(osal_event_hdr_t), (uint8 *)&msg );
}
}
return (ZSuccess);
} // ZDO_NetworkDiscoveryConfirmCB
#define STACK_PROFILE_MAX 2
networkDesc_t* ZDApp_NwkDescListProcessing(void)
{
networkDesc_t *pNwkDesc;
uint8 i, ResultCount = 0;
uint8 stackProfile;
uint8 stackProfilePro;
uint8 selected;
// Count the number of nwk descriptors in the list
pNwkDesc = nwk_getNwkDescList();
while (pNwkDesc)
{
ResultCount++;
pNwkDesc = pNwkDesc->nextDesc;
}
// process discovery results
stackProfilePro = FALSE;
selected = FALSE;
for ( stackProfile = 0; stackProfile < STACK_PROFILE_MAX; stackProfile++ )
{
pNwkDesc = nwk_getNwkDescList();
for ( i = 0; i < ResultCount; i++, pNwkDesc = pNwkDesc->nextDesc )
{
if ( zgConfigPANID != 0xFFFF )
{
// PAN Id is preconfigured. check if it matches
if ( pNwkDesc->panId != zgConfigPANID )
continue;
}
if ( nwk_ExtPANIDValid( ZDO_UseExtendedPANID) == true )
{
// If the extended Pan ID is commissioned to a non zero value
// Only join the Pan that has match EPID
if ( osal_ExtAddrEqual( ZDO_UseExtendedPANID, pNwkDesc->extendedPANID) == false )
continue;
}
// check that network is allowing joining
if ( ZSTACK_ROUTER_BUILD )
{
if ( stackProfilePro == FALSE )
{
if ( !pNwkDesc->routerCapacity )
{
continue;
}
}
else
{
if ( !pNwkDesc->deviceCapacity )
{
continue;
}
}
}
else if ( ZSTACK_END_DEVICE_BUILD )
{
if ( !pNwkDesc->deviceCapacity )
{
continue;
}
}
// check version of zigbee protocol
if ( pNwkDesc->version != _NIB.nwkProtocolVersion )
continue;
// check version of stack profile
if ( pNwkDesc->stackProfile != zgStackProfile )
{
if ( ((zgStackProfile == HOME_CONTROLS) && (pNwkDesc->stackProfile == ZIGBEEPRO_PROFILE))
|| ((zgStackProfile == ZIGBEEPRO_PROFILE) && (pNwkDesc->stackProfile == HOME_CONTROLS)) )
{
stackProfilePro = TRUE;
}
if ( stackProfile == 0 )
{
continue;
}
}
break;
}
if (i < ResultCount)
{
selected = TRUE;
break;
}
// break if selected or stack profile pro wasn't found
if ( (selected == TRUE) || (stackProfilePro == FALSE) )
{
break;
}
}
if ( i == ResultCount )
{
return (NULL); // couldn't find appropriate PAN to join !
}
else
{
return (pNwkDesc);
}
}// ZDApp_NwkDescListProcessing()
void ZDO_NetworkFormationConfirmCB( ZStatus_t Status )
{
nwkStatus = (byte)Status;
if ( Status == ZSUCCESS )
{
// LED on shows Coordinator started
HalLedSet ( HAL_LED_3, HAL_LED_MODE_ON );
// LED off forgets HOLD_AUTO_START
HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);
#if defined ( ZBIT )
SIM_SetColor(0xd0ffd0);
#endif
if ( devState == DEV_HOLD )
{
// Began with HOLD_AUTO_START
devState = DEV_COORD_STARTING;
}
}
#if defined(BLINK_LEDS)
else
{
HalLedSet ( HAL_LED_3, HAL_LED_MODE_FLASH ); // Flash LED to show failure
}
#endif
osal_set_event( ZDAppTaskID, ZDO_NETWORK_START );
}
void ZDO_beaconNotifyIndCB( NLME_beaconInd_t *pBeacon )
{
// Pass the beacon Indication to another task if it registers the callback
// Otherwise, process the beacon notification here.
if (zdoCBFunc[ZDO_BEACON_NOTIFY_IND_CBID] != NULL )
{
zdoCBFunc[ZDO_BEACON_NOTIFY_IND_CBID]( (void*)pBeacon );
}
else
{
networkDesc_t *pNwkDesc;
networkDesc_t *pLastNwkDesc;
uint8 found = false;
// Add the network to the Network Descriptor List
pNwkDesc = NwkDescList;
pLastNwkDesc = NwkDescList;
while (pNwkDesc)
{
if ((pNwkDesc->panId == pBeacon->panID) &&
(pNwkDesc->logicalChannel == pBeacon->logicalChannel))
{
found = true;
break;
}
pLastNwkDesc = pNwkDesc;
pNwkDesc = pNwkDesc->nextDesc;
}
// If no existing descriptor found, make a new one and add to the list
if (found == false)
{
pNwkDesc = osal_mem_alloc( sizeof(networkDesc_t) );
if ( !pNwkDesc )
{
// Memory alloc failed, discard this beacon
return;
}
// Clear the network descriptor
osal_memset( pNwkDesc, 0, sizeof(networkDesc_t) );
// Initialize the descriptor
pNwkDesc->chosenRouter = INVALID_NODE_ADDR;
pNwkDesc->chosenRouterDepth = 0xFF;
// Save new entry into the descriptor list
if ( !NwkDescList )
{
NwkDescList = pNwkDesc;
}
else
{
pLastNwkDesc->nextDesc = pNwkDesc;
}
}
// Update the descriptor with the incoming beacon
pNwkDesc->stackProfile = pBeacon->stackProfile;
pNwkDesc->version = pBeacon->protocolVersion;
pNwkDesc->logicalChannel = pBeacon->logicalChannel;
pNwkDesc->panId = pBeacon->panID;
pNwkDesc->updateId = pBeacon->updateID;
// Save the extended PAN ID from the beacon payload only if 1.1 version network
if ( pBeacon->protocolVersion != ZB_PROT_V1_0 )
{
osal_cpyExtAddr( pNwkDesc->extendedPANID, pBeacon->extendedPanID );
}
else
{
osal_memset( pNwkDesc->extendedPANID, 0xFF, Z_EXTADDR_LEN );
}
// check if this device is a better choice to join...
// ...dont bother checking assocPermit flag is doing a rejoin
if ( ( pBeacon->LQI > gMIN_TREE_LINK_COST ) &&
( ( pBeacon->permitJoining == TRUE ) || ( _tmpRejoinState ) ) )
{
uint8 selected = FALSE;
uint8 capacity = FALSE;
if ( _NIB.nwkAddrAlloc == NWK_ADDRESSING_STOCHASTIC )
{
if ( ((pBeacon->LQI > pNwkDesc->chosenRouterLinkQuality) &&
(pBeacon->depth < MAX_NODE_DEPTH)) ||
((pBeacon->LQI == pNwkDesc->chosenRouterLinkQuality) &&
(pBeacon->depth < pNwkDesc->chosenRouterDepth)) )
{
selected = TRUE;
}
}
else
{
if ( pBeacon->depth < pNwkDesc->chosenRouterDepth )
{
selected = TRUE;
}
}
if ( ZSTACK_ROUTER_BUILD )
{
capacity = pBeacon->routerCapacity;
}
else if ( ZSTACK_END_DEVICE_BUILD )
{
capacity = pBeacon->deviceCapacity;
}
if ( (capacity) && (selected) )
{
// this is the new chosen router for joining...
pNwkDesc->chosenRouter = pBeacon->sourceAddr;
pNwkDesc->chosenRouterLinkQuality = pBeacon->LQI;
pNwkDesc->chosenRouterDepth = pBeacon->depth;
}
if ( pBeacon->deviceCapacity )
pNwkDesc->deviceCapacity = 1;
if ( pBeacon->routerCapacity )
pNwkDesc->routerCapacity = 1;
}
}
}
void ZDO_StartRouterConfirmCB( ZStatus_t Status )
{
nwkStatus = (byte)Status;
if ( Status == ZSUCCESS )
{
// LED on shows Router started
HalLedSet ( HAL_LED_3, HAL_LED_MODE_ON );
// LED off forgets HOLD_AUTO_START
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF);
if ( devState == DEV_HOLD )
{
// Began with HOLD_AUTO_START
devState = DEV_END_DEVICE;
}
}
#if defined(BLINK_LEDS)
else
{
HalLedSet( HAL_LED_3, HAL_LED_MODE_FLASH ); // Flash LED to show failure
}
#endif
osal_set_event( ZDAppTaskID, ZDO_ROUTER_START );
}
void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status )
{
(void)PanId; // remove if this parameter is used.
nwkStatus = (byte)Status;
if ( Status == ZSUCCESS )
{
// LED on shows device joined
HalLedSet ( HAL_LED_3, HAL_LED_MODE_ON );
// LED off forgets HOLD_AUTO_START
HalLedSet ( HAL_LED_4, HAL_LED_MODE_OFF);
if ( (devState == DEV_HOLD) )
{
// Began with HOLD_AUTO_START
devState = DEV_NWK_JOINING;
}
if ( !ZG_SECURE_ENABLED )
{
// Notify to save info into NV
ZDApp_NVUpdate();
}
}
else
{
#if defined(BLINK_LEDS)
HalLedSet ( HAL_LED_3, HAL_LED_MODE_FLASH ); // Flash LED to show failure
#endif
}
// Pass the join confirm to higher layer if callback registered
if (zdoCBFunc[ZDO_JOIN_CNF_CBID] != NULL )
{
zdoJoinCnf_t joinCnf;
joinCnf.status = Status;
joinCnf.deviceAddr = _NIB.nwkDevAddress;
joinCnf.parentAddr = _NIB.nwkCoordAddress;
zdoCBFunc[ZDO_JOIN_CNF_CBID]( (void*)&joinCnf );
}
// Notify ZDApp
ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_IND, sizeof(osal_event_hdr_t), (byte*)NULL );
}
void ZDO_AddrChangeIndicationCB( uint16 newAddr )
{
ZDO_AddrChangeInd_t *pZDOAddrChangeMsg;
epList_t *pItem = epList;
// Notify to save info into NV
ZDApp_NVUpdate();
// Notify the applications
osal_set_event( ZDAppTaskID, ZDO_STATE_CHANGE_EVT );
while (pItem != NULL)
{
if (pItem->epDesc->endPoint != ZDO_EP)
{
pZDOAddrChangeMsg = (ZDO_AddrChangeInd_t *)osal_msg_allocate( sizeof( ZDO_AddrChangeInd_t ) );
if (pZDOAddrChangeMsg != NULL)
{
pZDOAddrChangeMsg->hdr.event = ZDO_ADDR_CHANGE_IND;
pZDOAddrChangeMsg->shortAddr = newAddr;
osal_msg_send( *(pItem->epDesc->task_id), (uint8 *)pZDOAddrChangeMsg );
}
}
pItem = pItem->nextDesc;
}
// Send out a device announce
ZDApp_AnnounceNewAddress();
}
ZStatus_t ZDO_JoinIndicationCB(uint16 ShortAddress, uint8 *ExtendedAddress,
uint8 CapabilityFlags, uint8 type)
{
(void)ShortAddress;
(void)ExtendedAddress;
#if ZDO_NV_SAVE_RFDs
(void)CapabilityFlags;
#else // if !ZDO_NV_SAVE_RFDs
if (CapabilityFlags & CAPINFO_DEVICETYPE_FFD)
#endif
{
ZDApp_NVUpdate(); // Notify to save info into NV.
}
if (ZG_SECURE_ENABLED) // Send notification to TC of new device.
{
if (type == NWK_ASSOC_JOIN || type == NWK_ASSOC_REJOIN_UNSECURE)
{
osal_start_timerEx( ZDAppTaskID, ZDO_NEW_DEVICE, 600 );
}
}
return ZSuccess;
}
void ZDO_ConcentratorIndicationCB( uint16 nwkAddr, uint8 *extAddr, uint8 pktCost )
{
zdoConcentratorInd_t conInd;
conInd.nwkAddr = nwkAddr;
conInd.extAddr = extAddr;
conInd.pktCost = pktCost;
if( zdoCBFunc[ZDO_CONCENTRATOR_IND_CBID] != NULL )
{
zdoCBFunc[ZDO_CONCENTRATOR_IND_CBID]( (void*)&conInd );
}
}
void ZDO_LeaveCnf( NLME_LeaveCnf_t* cnf )
{
// Check for this device
if ( osal_ExtAddrEqual( cnf->extAddr,
NLME_GetExtAddr() ) == TRUE )
{
// Pass the leave confirm to higher layer if callback registered
if ( ( zdoCBFunc[ZDO_LEAVE_CNF_CBID] == NULL ) ||
( (*zdoCBFunc[ZDO_LEAVE_CNF_CBID])( cnf ) == NULL ) )
{
// Prepare to leave with reset
ZDApp_LeaveReset( cnf->rejoin );
}
}
else if ( ZSTACK_ROUTER_BUILD )
{
// Remove device address(optionally descendents) from data
ZDApp_LeaveUpdate( cnf->dstAddr,
cnf->extAddr,
cnf->removeChildren );
}
}
void ZDO_LeaveInd( NLME_LeaveInd_t* ind )
{
uint8 leave;
// Parent is requesting the leave - NWK layer filters out illegal
// requests
if ( ind->request == TRUE )
{
// Notify network of leave
if ( ZSTACK_ROUTER_BUILD )
{
NLME_LeaveRsp_t rsp;
rsp.rejoin = ind->rejoin;
rsp.removeChildren = ind->removeChildren;
NLME_LeaveRsp( &rsp );
}
// Prepare to leave with reset
ZDApp_LeaveReset( ind->rejoin );
}
else
{
leave = FALSE;
// Check if this device needs to leave as a child or descendent
if ( ind->srcAddr == NLME_GetCoordShortAddr() )
{
if ( ( ind->removeChildren == TRUE ) ||
( ZDO_Config_Node_Descriptor.LogicalType ==
NODETYPE_DEVICE ) )
{
leave = TRUE;
}
}
else if ( ind->removeChildren == TRUE )
{
// Check NWK address allocation algorithm
//leave = RTG_ANCESTOR(nwkAddr,thisAddr);
}
if ( leave == TRUE )
{
// Prepare to leave with reset
ZDApp_LeaveReset( ind->rejoin );
}
else
{
// Remove device address(optionally descendents) from data
ZDApp_LeaveUpdate( ind->srcAddr,
ind->extAddr,
ind->removeChildren );
}
}
// Pass the leave indication to higher layer if callback registered.
if (zdoCBFunc[ZDO_LEAVE_IND_CBID] != NULL)
{
(void)zdoCBFunc[ZDO_LEAVE_IND_CBID](ind);
}
}
void ZDO_SyncIndicationCB( uint8 type, uint16 shortAddr )
{
(void)shortAddr; // Remove this line if this parameter is used.
if ( ZSTACK_END_DEVICE_BUILD
|| (ZSTACK_ROUTER_BUILD && ((_NIB.CapabilityFlags & ZMAC_ASSOC_CAPINFO_FFD_TYPE) == 0)))
{
if ( type == 1 )
{
// We lost contact with our parent. Clear the neighbor Table.
nwkNeighborInitTable();
// Start the rejoin process.
ZDApp_SendMsg( ZDAppTaskID, ZDO_NWK_JOIN_REQ, sizeof(osal_event_hdr_t), NULL );
}
}
}
void ZDO_ManytoOneFailureIndicationCB()
{
// By default, the concentrator automatically redo many-to-one route
// discovery to update all many-to-one routes in the network
// If you want anything processing other than the default,
// please replace the following code.
RTG_MTORouteReq();
}
void ZDO_PollConfirmCB( uint8 status )
{
(void)status; // Remove this line if this parameter is used.
return;
}
void ZDApp_NwkWriteNVRequest( void )
{
#if defined ( NV_RESTORE )
if ( !osal_get_timeoutEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV ) )
{
// Trigger to save info into NV
ZDApp_NVUpdate();
}
#endif
}
ZStatus_t ZDO_UpdateDeviceIndication( uint8 *extAddr, uint8 status )
{
// can implement a network access policy based on the
// IEEE address of newly joining devices...
(void)extAddr;
(void)status;
return ZSuccess;
}
void ZDApp_InMsgCB( zdoIncomingMsg_t *inMsg )
{
if ( inMsg->clusterID & ZDO_RESPONSE_BIT )
{
// Handle the response message
}
else
{
// Handle the request message by sending a generic "not supported".
// Device Announce doesn't have a response.
if ( !(inMsg->wasBroadcast) && inMsg->clusterID != Device_annce )
{
ZDP_GenericRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZDP_NOT_SUPPORTED, 0,
(uint16)(inMsg->clusterID | ZDO_RESPONSE_BIT), inMsg->SecurityUse );
}
}
}
void ZDApp_ChangeMatchDescRespPermission( uint8 endpoint, uint8 action )
{
// Store the action
afSetMatch( endpoint, action );
}
void ZDApp_NetworkInit( uint16 delay )
{
if ( delay )
{
// Wait awhile before starting the device
osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay );
}
else
{
osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT );
}
}
void ZDApp_NwkStateUpdateCB( void )
{
// Notify to save info into NV
if ( !osal_get_timeoutEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV ) )
{
// Trigger to save info into NV
ZDApp_NVUpdate();
}
}
void ZDApp_NodeProfileSync( uint8 stackProfile )
{
if ( ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_DEVICETYPE_FFD )
{
if ( stackProfile != zgStackProfile )
{
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICE;
ZDO_Config_Node_Descriptor.CapabilityFlags = CAPINFO_DEVICETYPE_RFD | CAPINFO_POWER_AC | CAPINFO_RCVR_ON_IDLE;
NLME_SetBroadcastFilter( ZDO_Config_Node_Descriptor.CapabilityFlags );
}
}
}
uint8 ZDApp_StartJoiningCycle( void )
{
if ( devState == DEV_INIT || devState == DEV_NWK_DISC )
{
continueJoining = TRUE;
ZDApp_NetworkInit( 0 );
return ( TRUE );
}
else
return ( FALSE );
}
uint8 ZDApp_StopJoiningCycle( void )
{
if ( devState == DEV_INIT || devState == DEV_NWK_DISC )
{
continueJoining = FALSE;
return ( TRUE );
}
else
return ( FALSE );
}
void ZDApp_AnnounceNewAddress( void )
{
#if defined ( ZIGBEE_NWK_UNIQUE_ADDR_CHECK )
// Turn off data request hold
APSME_HoldDataRequests( 0 );
#endif
ZDP_DeviceAnnce( NLME_GetShortAddr(), NLME_GetExtAddr(),
ZDO_Config_Node_Descriptor.CapabilityFlags, 0 );
#if defined ( ZIGBEE_NWK_UNIQUE_ADDR_CHECK )
// Setup the timeout
APSME_HoldDataRequests( ZDAPP_HOLD_DATA_REQUESTS_TIMEOUT );
#endif
}
void ZDApp_NVUpdate( void )
{
#if defined ( NV_RESTORE )
osal_start_timerEx( ZDAppTaskID, ZDO_NWK_UPDATE_NV, ZDAPP_UPDATE_NWK_NV_TIME );
#endif
}
uint16 ZDApp_CoordStartPANIDConflictCB( uint16 panid )
{
return ( panid + 1 );
}
void ZDO_SrcRtgIndCB (uint16 srcAddr, uint8 relayCnt, uint16* pRelayList )
{
zdoSrcRtg_t srcRtg;
srcRtg.srcAddr = srcAddr;
srcRtg.relayCnt = relayCnt;
srcRtg.pRelayList = pRelayList;
if( zdoCBFunc[ZDO_SRC_RTG_IND_CBID] != NULL )
{
zdoCBFunc[ZDO_SRC_RTG_IND_CBID]( (void*)&srcRtg );
}
}
void ZDApp_InitZdoCBFunc( void )
{
uint8 i;
for ( i=0; i< MAX_ZDO_CB_FUNC; i++ )
{
zdoCBFunc[i] = NULL;
}
}
ZStatus_t ZDO_RegisterForZdoCB( uint8 indID, pfnZdoCb pFn )
{
// Check the range of the indication ID
if ( indID < MAX_ZDO_CB_FUNC )
{
zdoCBFunc[indID] = pFn;
return ZSuccess;
}
return ZInvalidParameter;
}
ZStatus_t ZDO_DeregisterForZdoCB( uint8 indID )
{
// Check the range of the indication ID
if ( indID < MAX_ZDO_CB_FUNC )
{
zdoCBFunc[indID] = NULL;
return ZSuccess;
}
return ZInvalidParameter;
}
ZDApp.h
#ifndef ZDAPP_H
#define ZDAPP_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "ZComDef.h"
#include "ZMac.h"
#include "NLMEDE.h"
#include "APS.h"
#include "AF.h"
#include "ZDProfile.h"
// Set this value for use in choosing a PAN to join
// modify ZDApp.c to enable this...
#define ZDO_CONFIG_MAX_BO 15
// Task Events
#define ZDO_NETWORK_INIT 0x0001
#define ZDO_NETWORK_START 0x0002
#define ZDO_DEVICE_RESET 0x0004
#define ZDO_COMMAND_CNF 0x0008
#define ZDO_STATE_CHANGE_EVT 0x0010
#define ZDO_ROUTER_START 0x0020
#define ZDO_NEW_DEVICE 0x0040
#define ZDO_DEVICE_AUTH 0x0080
#define ZDO_SECMGR_EVENT 0x0100
#define ZDO_NWK_UPDATE_NV 0x0200
#define ZDO_FRAMECOUNTER_CHANGE 0x0400
#define ZDO_TCLK_FRAMECOUNTER_CHANGE 0x0800
#define ZDO_APS_FRAMECOUNTER_CHANGE 0x1000
// Incoming to ZDO
#define ZDO_NWK_DISC_CNF 0x01
#define ZDO_NWK_JOIN_IND 0x02
#define ZDO_NWK_JOIN_REQ 0x03
#define ZDO_ESTABLISH_KEY_CFM 0x04
#define ZDO_ESTABLISH_KEY_IND 0x05
#define ZDO_TRANSPORT_KEY_IND 0x06
#define ZDO_UPDATE_DEVICE_IND 0x07
#define ZDO_REMOVE_DEVICE_IND 0x08
#define ZDO_REQUEST_KEY_IND 0x09
#define ZDO_SWITCH_KEY_IND 0x0A
#define ZDO_AUTHENTICATE_IND 0x0B
#define ZDO_AUTHENTICATE_CFM 0x0C
// ZDO command message fields
#define ZDO_CMD_ID 0
#define ZDO_CMD_ID_LEN 1
// ZDO security message fields
#define ZDO_ESTABLISH_KEY_CFM_LEN \
((uint8) \
(sizeof(ZDO_EstablishKeyCfm_t) ) )
#define ZDO_ESTABLISH_KEY_IND_LEN \
((uint8) \
(sizeof(ZDO_EstablishKeyInd_t) ) )
#define ZDO_TRANSPORT_KEY_IND_LEN \
((uint8) \
(sizeof(ZDO_TransportKeyInd_t) ) )
#define ZDO_UPDATE_DEVICE_IND_LEN \
((uint8) \
(sizeof(ZDO_UpdateDeviceInd_t) ) )
#define ZDO_REMOVE_DEVICE_IND_LEN \
((uint8) \
(sizeof(ZDO_RemoveDeviceInd_t) ) )
#define ZDO_REQUEST_KEY_IND_LEN \
((uint8) \
(sizeof(ZDO_RequestKeyInd_t) ) )
#define ZDO_SWITCH_KEY_IND_LEN \
((uint8) \
(sizeof(ZDO_SwitchKeyInd_t) ) )
#define ZDO_AUTHENTICATE_IND_LEN \
((uint8) \
(sizeof(ZDO_AuthenticateInd_t) ) )
#define ZDO_AUTHENTICATE_CFM_LEN \
((uint8) \
(sizeof(ZDO_AuthenticateCfm_t) ) )
#define NWK_RETRY_DELAY 1000 // in milliseconds
#define ZDO_MATCH_DESC_ACCEPT_ACTION 1 // Message field
#if !defined NUM_DISC_ATTEMPTS
#define NUM_DISC_ATTEMPTS 2
#endif
// ZDOInitDevice return values
#define ZDO_INITDEV_RESTORED_NETWORK_STATE 0x00
#define ZDO_INITDEV_NEW_NETWORK_STATE 0x01
#define ZDO_INITDEV_LEAVE_NOT_STARTED 0x02
#if defined ( MANAGED_SCAN )
// Only use in a battery powered device
// This is the number of times a channel is scanned at the shortest possible
// scan time (which is 30 MS (2 x 15). The idea is to scan one channel at a
// time (from the channel list), but scan it multiple times.
#define MANAGEDSCAN_TIMES_PRE_CHANNEL 5
#define MANAGEDSCAN_DELAY_BETWEEN_SCANS 150 // milliseconds
extern uint8 zdoDiscCounter;
#endif // MANAGED_SCAN
// Use the following to delay application data request after startup.
#define ZDAPP_HOLD_DATA_REQUESTS_TIMEOUT 0 // in milliseconds
typedef enum
{
DEV_HOLD, // Initialized - not started automatically
DEV_INIT, // Initialized - not connected to anything
DEV_NWK_DISC, // Discovering PAN's to join
DEV_NWK_JOINING, // Joining a PAN
DEV_NWK_REJOIN, // ReJoining a PAN, only for end devices
DEV_END_DEVICE_UNAUTH, // Joined but not yet authenticated by trust center
DEV_END_DEVICE, // Started as device after authentication
DEV_ROUTER, // Device joined, authenticated and is a router
DEV_COORD_STARTING, // Started as Zigbee Coordinator
DEV_ZB_COORD, // Started as Zigbee Coordinator
DEV_NWK_ORPHAN // Device has lost information about its parent..
} devStates_t;
typedef enum
{
ZDO_SUCCESS,
ZDO_FAIL
} zdoStatus_t;
typedef struct
{
osal_event_hdr_t hdr;
uint8 dstAddrDstEP;
zAddrType_t dstAddr;
uint8 dstAddrClusterIDLSB;
uint8 dstAddrClusterIDMSB;
uint8 dstAddrRemove;
uint8 dstAddrEP;
} ZDO_NewDstAddr_t;
// ZDO security message types
typedef struct
{
osal_event_hdr_t hdr;
uint8 partExtAddr[Z_EXTADDR_LEN];
uint8 status;
} ZDO_EstablishKeyCfm_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 initExtAddr[Z_EXTADDR_LEN];
uint8 method;
uint8 apsSecure;
uint8 nwkSecure;
//devtag.0604.todo - remove obsolete
} ZDO_EstablishKeyInd_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 keyType;
uint8 keySeqNum;
uint8 key[SEC_KEY_LEN];
uint8 srcExtAddr[Z_EXTADDR_LEN];
uint8 initiator;
uint8 secure;
} ZDO_TransportKeyInd_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 devExtAddr[Z_EXTADDR_LEN];
uint16 devAddr;
uint8 status;
} ZDO_UpdateDeviceInd_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 childExtAddr[Z_EXTADDR_LEN];
} ZDO_RemoveDeviceInd_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 keyType;
uint8 partExtAddr[Z_EXTADDR_LEN];
} ZDO_RequestKeyInd_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 keySeqNum;
} ZDO_SwitchKeyInd_t;
typedef struct
{
osal_event_hdr_t hdr;
APSME_AuthenticateInd_t aps;
} ZDO_AuthenticateInd_t;
typedef struct
{
osal_event_hdr_t hdr;
APSME_AuthenticateCfm_t aps;
} ZDO_AuthenticateCfm_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 nwkAddr;
uint8 numInClusters;
uint16 *pInClusters;
uint8 numOutClusters;
uint16 *pOutClusters;
} ZDO_MatchDescRspSent_t;
typedef struct
{
osal_event_hdr_t hdr;
uint16 shortAddr;
} ZDO_AddrChangeInd_t;
/* ZDO Indication Callback Registration */
typedef void* (*pfnZdoCb)( void *param );
/* ZDO Indication callback ID */
enum
{
ZDO_SRC_RTG_IND_CBID,
ZDO_CONCENTRATOR_IND_CBID,
ZDO_NWK_DISCOVERY_CNF_CBID,
ZDO_BEACON_NOTIFY_IND_CBID,
ZDO_JOIN_CNF_CBID,
ZDO_LEAVE_CNF_CBID,
ZDO_LEAVE_IND_CBID,
MAX_ZDO_CB_FUNC // Must be at the bottom of the list
};
typedef struct
{
uint16 srcAddr;
uint8 relayCnt;
uint16 *pRelayList;
} zdoSrcRtg_t;
typedef struct
{
uint16 nwkAddr;
uint8 *extAddr;
uint8 pktCost;
} zdoConcentratorInd_t;
/* Keep the same format as NLME_beaconInd_t */
typedef struct
{
uint16 sourceAddr; /* Short address of the device sends the beacon */
uint16 panID;
uint8 logicalChannel;
uint8 permitJoining;
uint8 routerCapacity;
uint8 deviceCapacity;
uint8 protocolVersion;
uint8 stackProfile ;
uint8 LQI ;
uint8 depth ;
uint8 updateID;
uint8 extendedPanID[8];
} zdoBeaconInd_t;
typedef struct
{
uint8 status;
uint16 deviceAddr;
uint16 parentAddr;
} zdoJoinCnf_t;
/*********************************************************************
* GLOBAL VARIABLES
*/
extern uint8 ZDAppTaskID;
extern uint8 nwkStatus;
extern devStates_t devState;
/* Always kept up to date by the network state changed logic, so use this addr
* in function calls the require my network address as one of the parameters.
*/
extern zAddrType_t ZDAppNwkAddr;
extern uint8 saveExtAddr[]; // Loaded with value by ZDApp_Init().
extern uint8 zdappMgmtNwkDiscRspTransSeq;
extern uint8 zdappMgmtNwkDiscReqInProgress;
extern zAddrType_t zdappMgmtNwkDiscRspAddr;
extern uint8 zdappMgmtNwkDiscStartIndex;
extern uint8 zdappMgmtSavedNwkState;
extern uint8 ZDO_UseExtendedPANID[Z_EXTADDR_LEN];
extern void ZDO_AddrChangeIndicationCB( uint16 newAddr );
extern void ZDApp_Init( uint8 task_id );
extern UINT16 ZDApp_event_loop( uint8 task_id, UINT16 events );
extern uint8 ZDOInitDevice( uint16 startDelay );
extern void ZDApp_SendEventMsg( uint8 cmd, uint8 len, uint8 *buf );
extern ZStatus_t ZDApp_EstablishKey( uint8 endPoint,
uint16 nwkAddr,
uint8* extAddr );
extern void ZDApp_NetworkInit( uint16 delay );
extern ZStatus_t ZDApp_NetworkDiscoveryReq( uint32 scanChannels, uint8 scanDuration);
extern ZStatus_t ZDApp_JoinReq( uint8 channel, uint16 panID,
uint8 *extendedPanID, uint16 chosenParent,
uint8 parentDepth, uint8 stackProfile);
extern ZStatus_t ZDO_NetworkDiscoveryConfirmCB( uint8 status );
extern void ZDO_NetworkFormationConfirmCB( ZStatus_t Status );
extern void ZDO_beaconNotifyIndCB( NLME_beaconInd_t *beacon );
extern void ZDO_JoinConfirmCB( uint16 PanId, ZStatus_t Status );
ZStatus_t ZDO_JoinIndicationCB(uint16 ShortAddress, uint8 *ExtendedAddress,
uint8 CapabilityFlags, uint8 type);
extern void ZDO_ConcentratorIndicationCB( uint16 nwkAddr, uint8 *extAddr, uint8 pktCost );
extern void ZDO_StartRouterConfirmCB( ZStatus_t Status );
extern void ZDO_LeaveCnf( NLME_LeaveCnf_t* cnf );
extern void ZDO_LeaveInd( NLME_LeaveInd_t* ind );
extern void ZDO_SyncIndicationCB( uint8 type, uint16 shortAddr );
extern void ZDO_ManytoOneFailureIndicationCB( void );
extern void ZDO_PollConfirmCB( uint8 status );
extern ZStatus_t ZDO_UpdateDeviceIndication( uint8 *extAddr, uint8 status );
extern void ZDApp_InMsgCB( zdoIncomingMsg_t *inMsg );
extern void ZDO_StartRouterConfirm( ZStatus_t Status );
extern void ZDApp_NwkStateUpdateCB( void );
extern void ZDApp_ChangeMatchDescRespPermission( uint8 endpoint, uint8 action );
extern void ZDApp_SaveNwkKey( void );
extern void ZDApp_ResetNwkKey( void );
extern uint8 ZDApp_StartJoiningCycle( void );
extern uint8 ZDApp_StopJoiningCycle( void );
extern void ZDApp_AnnounceNewAddress( void );
extern void ZDApp_NVUpdate( void );
extern uint16 ZDApp_CoordStartPANIDConflictCB( uint16 panid );
extern void ZDApp_LeaveReset( uint8 ra );
extern void ZDApp_LeaveCtrlReset( void );
extern uint8 ZDApp_DeviceConfigured( void );
extern void ZDO_SrcRtgIndCB (uint16 srcAddr, uint8 relayCnt, uint16* pRelayList );
extern ZStatus_t ZDO_RegisterForZdoCB( uint8 indID, pfnZdoCb pFn );
extern ZStatus_t ZDO_DeregisterForZdoCB( uint8 indID );
#ifdef __cplusplus
}
#endif
#endif /* ZDOBJECT_H */
ZDConfig.c
#include "ZComdef.h"
#include "AF.h"
#include "ZDObject.h"
#include "ZDConfig.h"
NodeDescriptorFormat_t ZDO_Config_Node_Descriptor;
NodePowerDescriptorFormat_t ZDO_Config_Power_Descriptor;
void ZDConfig_InitDescriptors( void )
{
ZDConfig_UpdateNodeDescriptor();
ZDConfig_UpdatePowerDescriptor();
}
void ZDConfig_UpdateNodeDescriptor( void )
{
// Build the Node Descriptor
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_COORDINATOR;
else if ( ZSTACK_ROUTER_BUILD )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_ROUTER;
else if ( ZSTACK_END_DEVICE_BUILD )
ZDO_Config_Node_Descriptor.LogicalType = NODETYPE_DEVICE;
ZDO_Config_Node_Descriptor.ComplexDescAvail = FALSE; // set elsewhere
ZDO_Config_Node_Descriptor.UserDescAvail = FALSE; // set elsewhere
ZDO_Config_Node_Descriptor.Reserved = 0; // Reserved
ZDO_Config_Node_Descriptor.APSFlags = 0; // NO APS flags
ZDO_Config_Node_Descriptor.FrequencyBand = NODEFREQ_2400; // Frequency Band
// MAC Capabilities
if ( ZSTACK_ROUTER_BUILD )
{
ZDO_Config_Node_Descriptor.CapabilityFlags
= (CAPINFO_DEVICETYPE_FFD | CAPINFO_POWER_AC | CAPINFO_RCVR_ON_IDLE);
if ( ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
ZDO_Config_Node_Descriptor.CapabilityFlags |= CAPINFO_ALTPANCOORD;
}
else if ( ZSTACK_END_DEVICE_BUILD )
{
ZDO_Config_Node_Descriptor.CapabilityFlags = (CAPINFO_DEVICETYPE_RFD
#if ( RFD_RCVC_ALWAYS_ON == TRUE)
| CAPINFO_RCVR_ON_IDLE
#endif
);
}
// Manufacturer Code - *YOU FILL IN*
ZDO_Config_Node_Descriptor.ManufacturerCode[0] = 0;
ZDO_Config_Node_Descriptor.ManufacturerCode[1] = 0;
// Maximum Buffer Size
ZDO_Config_Node_Descriptor.MaxBufferSize = MAX_BUFFER_SIZE;
// Maximum Incoming Transfer Size Field
ZDO_Config_Node_Descriptor.MaxInTransferSize[0] = LO_UINT16( MAX_TRANSFER_SIZE );
ZDO_Config_Node_Descriptor.MaxInTransferSize[1] = HI_UINT16( MAX_TRANSFER_SIZE );
// Maximum Outgoing Transfer Size Field
ZDO_Config_Node_Descriptor.MaxOutTransferSize[0] = LO_UINT16( MAX_TRANSFER_SIZE );
ZDO_Config_Node_Descriptor.MaxOutTransferSize[1] = HI_UINT16( MAX_TRANSFER_SIZE );
// Server Mask
ZDO_Config_Node_Descriptor.ServerMask = 0;
// Descriptor Capability Field - extended active endpoint list and
// extended simple descriptor are not supported.
ZDO_Config_Node_Descriptor.DescriptorCapability = 0;
}
void ZDConfig_UpdatePowerDescriptor( void )
{
// Build the Power Descriptor
if ( ZSTACK_ROUTER_BUILD )
{
ZDO_Config_Power_Descriptor.PowerMode = NODECURPWR_RCVR_ALWAYS_ON;
ZDO_Config_Power_Descriptor.AvailablePowerSources = NODEAVAILPWR_MAINS;
ZDO_Config_Power_Descriptor.CurrentPowerSource = NODEAVAILPWR_MAINS;
ZDO_Config_Power_Descriptor.CurrentPowerSourceLevel = NODEPOWER_LEVEL_100;
}
else if ( ZSTACK_END_DEVICE_BUILD )
{
if ( zgPollRate )
ZDO_Config_Power_Descriptor.PowerMode = NODECURPWR_RCVR_AUTO;
else
ZDO_Config_Power_Descriptor.PowerMode = NODECURPWR_RCVR_STIM;
ZDO_Config_Power_Descriptor.AvailablePowerSources = NODEAVAILPWR_RECHARGE;
ZDO_Config_Power_Descriptor.CurrentPowerSource = NODEAVAILPWR_RECHARGE;
ZDO_Config_Power_Descriptor.CurrentPowerSourceLevel = NODEPOWER_LEVEL_66;
}
}
ZDConfig.h
#ifndef ZDCONFIG_H
#define ZDCONFIG_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "AF.h"
#if defined ( MT_ZDO_FUNC )
// All of the ZDO functions are enabled for ZTool use.
#define ZDO_NWKADDR_REQUEST
#define ZDO_IEEEADDR_REQUEST
#define ZDO_MATCH_REQUEST
#define ZDO_NODEDESC_REQUEST
#define ZDO_POWERDESC_REQUEST
#define ZDO_SIMPLEDESC_REQUEST
#define ZDO_ACTIVEEP_REQUEST
#define ZDO_COMPLEXDESC_REQUEST
#define ZDO_USERDESC_REQUEST
#define ZDO_USERDESCSET_REQUEST
#define ZDO_ENDDEVICEBIND_REQUEST
#define ZDO_BIND_UNBIND_REQUEST
#define ZDO_SERVERDISC_REQUEST
#define ZDO_NETWORKSTART_REQUEST
#define ZDO_MANUAL_JOIN
#define ZDO_COMPLEXDESC_RESPONSE
#define ZDO_USERDESC_RESPONSE
#define ZDO_USERDESCSET_RESPONSE
#define ZDO_SERVERDISC_RESPONSE
#define ZDO_ENDDEVICE_ANNCE
#if defined ( MT_ZDO_MGMT )
#define ZDO_MGMT_NWKDISC_REQUEST
#define ZDO_MGMT_LQI_REQUEST
#define ZDO_MGMT_RTG_REQUEST
#define ZDO_MGMT_BIND_REQUEST
#define ZDO_MGMT_LEAVE_REQUEST
#define ZDO_MGMT_JOINDIRECT_REQUEST
#define ZDO_MGMT_PERMIT_JOIN_REQUEST
#define ZDO_MGMT_NWKUPDATE_REQUEST
#define ZDO_MGMT_NWKDISC_RESPONSE
#define ZDO_MGMT_LQI_RESPONSE
#define ZDO_MGMT_RTG_RESPONSE
#define ZDO_MGMT_BIND_RESPONSE
#define ZDO_MGMT_LEAVE_RESPONSE
#define ZDO_MGMT_JOINDIRECT_RESPONSE
#define ZDO_MGMT_PERMIT_JOIN_RESPONSE
#define ZDO_MGMT_NWKUPDATE_NOTIFY
#endif
#else // !MT_ZDO_FUNC
// Normal operation and sample apps only use End Device Bind
// and Match Request.
//#define ZDO_NWKADDR_REQUEST
//#define ZDO_IEEEADDR_REQUEST
#define ZDO_MATCH_REQUEST
//#define ZDO_NODEDESC_REQUEST
//#define ZDO_POWERDESC_REQUEST
//#define ZDO_SIMPLEDESC_REQUEST
//#define ZDO_ACTIVEEP_REQUEST
//#define ZDO_COMPLEXDESC_REQUEST
//#define ZDO_USERDESC_REQUEST
//#define ZDO_USERDESCSET_REQUEST
#define ZDO_ENDDEVICEBIND_REQUEST
//#define ZDO_BIND_UNBIND_REQUEST
//#define ZDO_SERVERDISC_REQUEST
//#define ZDO_NETWORKSTART_REQUEST
//#define ZDO_MANUAL_JOIN
//#define ZDO_BIND_UNBIND_RESPONSE
//#define ZDO_COMPLEXDESC_RESPONSE
//#define ZDO_USERDESC_RESPONSE
//#define ZDO_USERDESCSET_RESPONSE
//#define ZDO_SERVERDISC_RESPONSE
#define ZDO_ENDDEVICE_ANNCE
//#define ZDO_MGMT_NWKDISC_REQUEST
//#define ZDO_MGMT_LQI_REQUEST
//#define ZDO_MGMT_RTG_REQUEST
//#define ZDO_MGMT_BIND_REQUEST
//#define ZDO_MGMT_LEAVE_REQUEST
//#define ZDO_MGMT_JOINDIRECT_REQUEST
//#define ZDO_MGMT_PERMIT_JOIN_REQUEST
//#define ZDO_MGMT_NWKDISC_RESPONSE
//#define ZDO_MGMT_LQI_RESPONSE
//#define ZDO_MGMT_RTG_RESPONSE
//#define ZDO_MGMT_BIND_RESPONSE
//#define ZDO_MGMT_LEAVE_RESPONSE
//#define ZDO_MGMT_JOINDIRECT_RESPONSE
//#define ZDO_MGMT_PERMIT_JOIN_RESPONSE
#if defined ( REFLECTOR )
// Binding needs this request to do a 64 to 16 bit conversion
#if !defined(ZDO_NWKADDR_REQUEST)
#define ZDO_NWKADDR_REQUEST
#endif
#if !defined(ZDO_IEEEADDR_REQUEST)
#define ZDO_IEEEADDR_REQUEST
#endif
#define ZDO_BIND_UNBIND_RESPONSE
#endif
#endif // !MT_ZDO_FUNC
#define MAX_BUFFER_SIZE 80
#if defined ( ZIGBEE_FRAGMENTATION )
// The application/profile must fill this field out.
#define MAX_TRANSFER_SIZE 160
#else
#define MAX_TRANSFER_SIZE 80
#endif
#define MAX_ENDPOINTS 240
// Node Description Bitfields
#define ZDOLOGICALTYPE_MASK 0x07
#define ZDOAPSFLAGS_MASK 0x07
#define ZDOFREQUENCYBANDS_MASK 0x1F
#define ZDOAPSFLAGS_BITLEN 3
#define SIMPLE_DESC_DATA_SIZE 7
#define NODE_DESC_DATA_SIZE 10
// Simple Description Bitfields
#define ZDOENDPOINT_BITLEN 5
#define ZDOENDPOINT_MASK 0x1F
#define ZDOINTERFACE_MASK 0x07
#define ZDOAPPFLAGS_MASK 0x0F
#define ZDOAPPDEVVER_MASK 0x0F
#define ZDOAPPDEVVER_BITLEN 4
extern NodeDescriptorFormat_t ZDO_Config_Node_Descriptor;
extern NodePowerDescriptorFormat_t ZDO_Config_Power_Descriptor;
extern void ZDConfig_InitDescriptors( void );
extern void ZDConfig_UpdateNodeDescriptor( void );
extern void ZDConfig_UpdatePowerDescriptor( void );
#ifdef __cplusplus
}
#endif
#endif /* ZDCONFIG_H */
ZDNwkMgr.c
#ifdef __cplusplus
extern "C"
{
#endif
#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"
#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-cur<last fail";
const char NwkMgrStr_3[] = "NM-energy too hi";
const char NwkMgrStr_4[] = "NM-energy not up";
#endif
// Task ID for internal task/event processing. This variable will be
// received when ZDNwkMgr_Init() is called.
uint8 ZDNwkMgr_TaskID = 0;
// Frequency Agility variables
uint8 ZDNwkMgr_MgmtNwkUpdateNotifyTransSeq = 0;
zAddrType_t ZDNwkMgr_MgmtNwkUpdateNotifyAddr;
uint16 ZDNwkMgr_UpdateNotifyTimer = 0;
uint8 ZDNwkMgr_NumUpdateNotifySent = 0;
uint8 ZDNwkMgr_WaitingForNotifyConfirm = FALSE;
uint16 ZDNwkMgr_TotalTransmissions;
uint16 ZDNwkMgr_TxFailures;
ZDO_MgmtNwkUpdateReq_t ZDNwkMgr_MgmtNwkUpdateReq;
#if defined ( NWK_MANAGER )
uint16 ZDNwkMgr_UpdateRequestTimer = 0;
uint8 ZDNwkMgr_LastChannelEnergy = 0;
uint16 ZDNwkMgr_LastChannelFailureRate = 0;
#endif // NWK_MANAGER
uint8 ZDNwkMgr_NewChannel;
// PAN ID Conflict variables
#if defined ( NWK_MANAGER )
uint8 ZDNwkMgr_PanIdUpdateInProgress = FALSE;
#endif // NWK_MANAGER
// Freguency Agility functions
void (*pZDNwkMgr_ReportChannelInterference)( NLME_ChanInterference_t *chanInterference ) = NULL;
void (*pZDNwkMgr_ProcessDataConfirm)( afDataConfirm_t *afDataConfirm ) = NULL;
void (*pZDNwkMgr_EDScanConfirmCB)( NLME_EDScanConfirm_t *EDScanConfirm ) = NULL;
// PAN ID Conflict functions
void (*pZDNwkMgr_NetworkReportCB)( ZDNwkMgr_NetworkReport_t *pReport ) = NULL;
void (*pZDNwkMgr_NetworkUpdateCB)( ZDNwkMgr_NetworkUpdate_t *pUpdate ) = NULL;
void ZDNwkMgr_ProcessServerDiscRsp( zdoIncomingMsg_t *inMsg );
void ZDNwkMgr_SetNwkManagerAddr( uint16 nwkManagerAddr );
// Frequency Agility functions
static void ZDNwkMgr_ProcessMsgCBs( zdoIncomingMsg_t *inMsg );
static void ZDNwkMgr_ProcessMgmtNwkUpdateReq( zdoIncomingMsg_t *inMsg );
static void ZDNwkMgr_ProcessChannelInterference( ZDNwkMgr_ChanInterference_t *pChanInterference );
static void ZDNwkMgr_ProcessEDScanConfirm( ZDNwkMgr_EDScanConfirm_t *pEDScanConfirm );
static void ZDNwkMgr_CheckForChannelInterference( ZDNwkMgr_EDScanConfirm_t *pEDScanConfirm );
static void ZDNwkMgr_BuildAndSendUpdateNotify( uint8 TransSeq, zAddrType_t *dstAddr,
uint16 totalTransmissions, uint16 txFailures,
ZDNwkMgr_EDScanConfirm_t *pEDScanConfirm, uint8 txOptions );
void ZDNwkMgr_EDScanConfirmCB( NLME_EDScanConfirm_t *EDScanConfirm );
void ZDNwkMgr_ProcessDataConfirm( afDataConfirm_t *afDataConfirm );
void ZDNwkMgr_ReportChannelInterference( NLME_ChanInterference_t *chanInterference );
#if defined ( NWK_MANAGER )
static void ZDNwkMgr_ProcessMgmtNwkUpdateNotify( zdoIncomingMsg_t *inMsg );
static void ZDNwkMgr_CheckForChannelChange( ZDO_MgmtNwkUpdateNotify_t *pNotify );
#endif // NWK_MANAGER
// PAN ID Conflict functions
#if defined ( NWK_MANAGER )
void ZDNwkMgr_NetworkReportCB( ZDNwkMgr_NetworkReport_t *pReport );
void ZDNwkMgr_NetworkUpdateCB( ZDNwkMgr_NetworkUpdate_t *pUpdate );
void ZDNwkMgr_ProcessNetworkReport( ZDNwkMgr_NetworkReport_t *pNetworkReport );
void ZDNwkMgr_ProcessNetworkUpdate( ZDNwkMgr_NetworkUpdate_t *pNetworkUpdate );
#endif // NWK_MANAGER
void ZDNwkMgr_Init( byte task_id )
{
// Save the task ID
ZDNwkMgr_TaskID = task_id;
ZDO_RegisterForZDOMsg( ZDNwkMgr_TaskID, Server_Discovery_rsp );
// Frequecy Agility initialization
ZDO_RegisterForZDOMsg( ZDNwkMgr_TaskID, Mgmt_NWK_Update_req );
#if defined ( NWK_MANAGER )
ZDO_RegisterForZDOMsg( ZDNwkMgr_TaskID, Mgmt_NWK_Update_notify );
#endif // NWK_MANAGER
pZDNwkMgr_EDScanConfirmCB = ZDNwkMgr_EDScanConfirmCB;
pZDNwkMgr_ProcessDataConfirm = ZDNwkMgr_ProcessDataConfirm;
pZDNwkMgr_ReportChannelInterference = ZDNwkMgr_ReportChannelInterference;
// PAN ID Conflict initialization
#if defined ( NWK_MANAGER )
pZDNwkMgr_NetworkReportCB = ZDNwkMgr_NetworkReportCB;
pZDNwkMgr_NetworkUpdateCB = ZDNwkMgr_NetworkUpdateCB;
#endif // NWK_MANAGER
ZDNwkMgr_MgmtNwkUpdateNotifyAddr.addrMode = Addr16Bit;
ZDNwkMgr_MgmtNwkUpdateNotifyAddr.addr.shortAddr = INVALID_NODE_ADDR;
}
UINT16 ZDNwkMgr_event_loop( byte task_id, UINT16 events )
{
osal_event_hdr_t *msgPtr;
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )
{
msgPtr = (osal_event_hdr_t *)osal_msg_receive( ZDNwkMgr_TaskID );
while ( msgPtr )
{
switch ( msgPtr->event )
{
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;
}
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;
}
}
#if defined ( NWK_MANAGER )
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 );
}
}
}
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
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 );
}
}
}
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 );
}
}
}
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;
}
}
}
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 );
}
}
}
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
}
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 )
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
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();
}
}
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 );
}
}
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 );
}
}
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;
}
}
#if defined ( NWK_MANAGER )
void ZDNwkMgr_NetworkReportCB( ZDNwkMgr_NetworkReport_t *pReport )
{
// Send Network Report message to the Network Manager task
osal_msg_send( ZDNwkMgr_TaskID, (uint8 *)pReport );
}
void ZDNwkMgr_NetworkUpdateCB( ZDNwkMgr_NetworkUpdate_t *pUpdate )
{
// Send Network Update message to the Network Manager task
osal_msg_send( ZDNwkMgr_TaskID, (uint8 *)pUpdate );
}
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;
}
}
}
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
ZDNwkMgr.h
#ifndef ZDNWKMGR_H
#define ZDNWKMGR_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "ZComDef.h"
#include "nwk_globals.h"
#include "nwk_util.h"
#include "ZDApp.h"
// Network Manager Role
#define ZDNWKMGR_DISABLE 0x00
#define ZDNWKMGR_ENABLE 0x01
// Energy level threshold
#define ZDNWKMGR_ACCEPTABLE_ENERGY_LEVEL 0x1E
// Minimum transmissions attempted for Channel Interference detection
#if !defined ( ZDNWKMGR_MIN_TRANSMISSIONS )
#define ZDNWKMGR_MIN_TRANSMISSIONS 20
#endif
// Minimum transmit failure rate for Channel Interference detection
#define ZDNWKMGR_CI_TX_FAILURE 25
// Minimum transmit failure rate for Channel Change
#define ZDNWKMGR_CC_TX_FAILURE 50
// Min and Max Scan Counts for Update Request
#define ZDNWKMGR_MIN_SCAN_COUNT 0
#define ZDNWKMGR_MAX_SCAN_COUNT 5
// Update Request and Notify timers
#define ZDNWKMGR_UPDATE_NOTIFY_TIMER 60 // 1(h) * 60(m)
#define ZDNWKMGR_UPDATE_REQUEST_TIMER 60 // 1(h) * 60(m)
// Network Manager Events
#define ZDNWKMGR_CHANNEL_CHANGE_EVT 0x0001
#define ZDNWKMGR_UPDATE_NOTIFY_EVT 0x0002
#define ZDNWKMGR_UPDATE_REQUEST_EVT 0x0004
#define ZDNWKMGR_SCAN_REQUEST_EVT 0x0008
#define ZDNWKMGR_BCAST_DELIVERY_TIME ( _NIB.BroadcastDeliveryTime * 100 )
// Used for Management Network Update Request message
typedef struct
{
osal_event_hdr_t hdr;
uint8 transSeq;
uint16 srcAddr;
uint32 channelMask;
uint8 scanDuration;
uint8 scanCount;
int16 nwkManagerAddr;
uint8 wasBroadcast;
} ZDNwkMgr_MgmtNwkUpdateRequest_t;
// Used for Management Network Update Notify command
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 status;
uint32 scannedChannels;
uint16 totalTransmissions;
uint16 txFailures;
uint8 listCount;
uint8 *energyValues;
} ZDNwkMgr_MgmtNwkUpdateNotify_t;
// Used for Channel Interference message
typedef struct
{
osal_event_hdr_t hdr;
uint16 totalTransmissions;
uint16 txFailures;
} ZDNwkMgr_ChanInterference_t;
// Used for ED Scan Confirm message
typedef struct
{
osal_event_hdr_t hdr;
uint8 status;
uint32 scannedChannels;
uint8 energyDetectList[ED_SCAN_MAXCHANNELS];
} ZDNwkMgr_EDScanConfirm_t;
// Used for Network Report command
typedef struct
{
osal_event_hdr_t hdr;
uint16 srcAddr;
uint8 reportType;
uint8 EPID[Z_EXTADDR_LEN];
uint8 reportInfoCnt;
uint16 panIDs[];
} ZDNwkMgr_NetworkReport_t;
// Used for Network Update command
typedef struct
{
osal_event_hdr_t hdr;
uint8 updateType;
uint8 updateInfoCnt;
uint16 newPanID;
} ZDNwkMgr_NetworkUpdate_t;
extern byte ZDNwkMgr_TaskID;
extern void ZDNwkMgr_Init( byte task_id );
extern UINT16 ZDNwkMgr_event_loop( byte task_id, UINT16 events );
// Frequency Agility functions
extern void (*pZDNwkMgr_EDScanConfirmCB)( NLME_EDScanConfirm_t *EDScanConfirm );
extern void (*pZDNwkMgr_ProcessDataConfirm)( afDataConfirm_t *afDataConfirm );
extern void (*pZDNwkMgr_ReportChannelInterference)( NLME_ChanInterference_t *chanInterference );
// PAN ID Conflict functions
extern void (*pZDNwkMgr_NetworkReportCB)( ZDNwkMgr_NetworkReport_t *pReport );
extern void (*pZDNwkMgr_NetworkUpdateCB)( ZDNwkMgr_NetworkUpdate_t *pUpdate );
#if defined ( NWK_MANAGER )
extern void NwkMgr_SetNwkManager( void );
#endif
#ifdef __cplusplus
}
#endif
#endif /* ZDNWKMGR_H */
ZDObject.c
#include "ZComdef.h"
#include "OSAL.h"
#include "OSAL_Nv.h"
#include "rtg.h"
#include "NLMEDE.h"
#include "nwk_globals.h"
#include "APS.h"
#include "APSMEDE.h"
#include "AssocList.h"
#include "BindingTable.h"
#include "AddrMgr.h"
#include "AF.h"
#include "ZDObject.h"
#include "ZDProfile.h"
#include "ZDConfig.h"
#include "ZDSecMgr.h"
#include "ZDApp.h"
#include "nwk_util.h" // NLME_IsAddressBroadcast()
#include "ZGlobals.h"
#if defined MT_ZDO_CB_FUNC
#include "MT.h"
#endif
#if defined( LCD_SUPPORTED )
#include "OnBoard.h"
#endif
#include "hal_lcd.h"
// NLME Stub Implementations
#define ZDO_ProcessMgmtPermitJoinTimeout NLME_PermitJoiningTimeout
// Status fields used by ZDO_ProcessMgmtRtgReq
#define ZDO_MGMT_RTG_ENTRY_ACTIVE 0x00
#define ZDO_MGMT_RTG_ENTRY_DISCOVERY_UNDERWAY 0x01
#define ZDO_MGMT_RTG_ENTRY_DISCOVERY_FAILED 0x02
#define ZDO_MGMT_RTG_ENTRY_INACTIVE 0x03
#if defined ( REFLECTOR )
typedef struct
{
byte SrcTransSeq;
zAddrType_t SrcAddr;
uint16 LocalCoordinator;
byte epIntf;
uint16 ProfileID;
byte numInClusters;
uint16 *inClusters;
byte numOutClusters;
uint16 *outClusters;
byte SecurityUse;
byte status;
} ZDO_EDBind_t;
#endif // defined ( REFLECTOR )
enum
{
ZDMATCH_INIT, // Initialized
ZDMATCH_WAIT_REQ, // Received first request, waiting for second
ZDMATCH_SENDING_BINDS // Received both requests, sending unbind/binds
};
enum
{
ZDMATCH_SENDING_NOT,
ZDMATCH_SENDING_UNBIND,
ZDMATCH_SENDING_BIND
};
static uint16 ZDOBuildBuf[26]; // temp area to build data without allocation
#if defined ( REFLECTOR )
static ZDO_EDBind_t *ZDO_EDBind; // Null when not used
#endif
#if defined ( MANAGED_SCAN )
uint32 managedScanNextChannel = 0;
uint32 managedScanChannelMask = 0;
uint8 managedScanTimesPerChannel = 0;
#endif
ZDMatchEndDeviceBind_t *matchED = (ZDMatchEndDeviceBind_t *)NULL;
uint32 apsChannelMask = 0;
static void ZDODeviceSetup( void );
#if defined ( MANAGED_SCAN )
static void ZDOManagedScan_Next( void );
#endif
#if defined ( REFLECTOR )
static void ZDO_RemoveEndDeviceBind( void );
static void ZDO_SendEDBindRsp( byte TransSeq, zAddrType_t *dstAddr, byte Status, byte secUse );
#endif
static byte ZDO_CompareClusterLists( byte numList1, uint16 *list1,
byte numList2, uint16 *list2, uint16 *pMatches );
static void ZDO_RemoveMatchMemory( void );
static uint8 ZDO_CopyMatchInfo( ZDEndDeviceBind_t *destReq, ZDEndDeviceBind_t *srcReq );
static void ZDO_EndDeviceBindMatchTimeoutCB( void );
uint8 *ZDO_ConvertOTAClusters( uint8 cnt, uint8 *inBuf, uint16 *outList );
static void zdoSendStateChangeMsg(uint8 state, uint8 taskId);
void ZDO_Init( void )
{
// Initialize ZD items
#if defined ( REFLECTOR )
ZDO_EDBind = NULL;
#endif
// Initialize default ZDO_UseExtendedPANID to the APS one.
osal_cpyExtAddr( ZDO_UseExtendedPANID, AIB_apsUseExtendedPANID );
// Setup the device - type of device to create.
ZDODeviceSetup();
}
#if defined ( MANAGED_SCAN )
static void ZDOManagedScan_Next( void )
{
// Is it the first time
if ( managedScanNextChannel == 0 && managedScanTimesPerChannel == 0 )
{
// Setup the defaults
managedScanNextChannel = 1;
while( managedScanNextChannel && (zgDefaultChannelList & managedScanNextChannel) == 0 )
managedScanNextChannel <<= 1;
managedScanChannelMask = managedScanNextChannel;
managedScanTimesPerChannel = MANAGEDSCAN_TIMES_PRE_CHANNEL;
}
else
{
// Do we need to go to the next channel
if ( managedScanTimesPerChannel == 0 )
{
// Find next active channel
managedScanChannelMask = managedScanNextChannel;
managedScanTimesPerChannel = MANAGEDSCAN_TIMES_PRE_CHANNEL;
}
else
{
managedScanTimesPerChannel--;
if ( managedScanTimesPerChannel == 0 )
{
managedScanNextChannel <<= 1;
while( managedScanNextChannel && (zgDefaultChannelList & managedScanNextChannel) == 0 )
managedScanNextChannel <<= 1;
if ( managedScanNextChannel == 0 )
zdoDiscCounter = NUM_DISC_ATTEMPTS + 1; // Stop
}
}
}
}
#endif // MANAGED_SCAN
static void ZDODeviceSetup( void )
{
if ( ZG_BUILD_COORDINATOR_TYPE )
{
NLME_CoordinatorInit();
}
#if defined ( REFLECTOR )
APS_ReflectorInit( (ZG_DEVICE_COORDINATOR_TYPE) ? APS_REFLECTOR_PUBLIC : APS_REFLECTOR_PRIVATE );
#endif
if ( ZG_BUILD_JOINING_TYPE )
{
NLME_DeviceJoiningInit();
}
}
void ZDO_StartDevice( byte logicalType, devStartModes_t startMode, 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 network channel
// change will not be recieved. On these devices or routers that have
// lost the network, an active scan shall be conducted on the Default
// Channel list using the extended PANID to find the network. If the
// extended PANID isn't found using the Default Channel list, an scan
// 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 value via
// application specific means, the device shall conduct an active scan
// on the Default Channel list and join the PAN with the same
// ExtendedPanID. If the PAN is not found, an scan should be completed
// on all channels.
// When devices rejoin the network and the PAN is not found from
zgDefaultChannelList = MAX_CHANNELS_24GHZ;
}
#endif // ZIGBEE_COMMISSIONING
#endif
}
else if ( startMode == MODE_RESUME )
{
if ( logicalType == NODETYPE_ROUTER )
{
ZMacScanCnf_t scanCnf;
devState = DEV_NWK_ORPHAN;
/* if router and nvram is available, fake successful orphan scan */
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 );
}
}
static void zdoSendStateChangeMsg(uint8 state, uint8 taskId)
{
osal_event_hdr_t *pMsg = (osal_event_hdr_t *)osal_msg_find(taskId, ZDO_STATE_CHANGE);
if (NULL == pMsg)
{
if (NULL == (pMsg = (osal_event_hdr_t *)osal_msg_allocate(sizeof(osal_event_hdr_t))))
{
// Upon failure to notify any EndPoint of the state change, re-set the ZDO event to
// try again later when more Heap may be available.
osal_set_event(ZDAppTaskID, ZDO_STATE_CHANGE_EVT);
}
else
{
pMsg->event = ZDO_STATE_CHANGE;
pMsg->status = state;
(void)osal_msg_send(taskId, (uint8 *)pMsg);
}
}
else
{
// Modify in place the status of an existing ZDO_STATE_CHANGE message to the EndPoint.
pMsg->status = state;
}
}
void ZDO_UpdateNwkStatus(devStates_t state)
{
epList_t *pItem = epList;
while (pItem != NULL)
{
if (pItem->epDesc->endPoint != ZDO_EP)
{
zdoSendStateChangeMsg(state, *(pItem->epDesc->task_id));
}
pItem = pItem->nextDesc;
}
#if defined MT_ZDO_CB_FUNC
zdoSendStateChangeMsg(state, MT_TaskID);
#endif
ZDAppNwkAddr.addr.shortAddr = NLME_GetShortAddr();
(void)NLME_GetExtAddr(); // Load the saveExtAddr pointer.
}
#if defined ( REFLECTOR )
static void ZDO_RemoveEndDeviceBind( void )
{
if ( ZDO_EDBind != NULL )
{
// Free the RAM
if ( ZDO_EDBind->inClusters != NULL )
{
osal_mem_free( ZDO_EDBind->inClusters );
}
if ( ZDO_EDBind->outClusters != NULL )
{
osal_mem_free( ZDO_EDBind->outClusters );
}
osal_mem_free( ZDO_EDBind );
ZDO_EDBind = NULL;
}
}
#endif // REFLECTOR
#if defined ( REFLECTOR )
static void ZDO_SendEDBindRsp( byte TransSeq, zAddrType_t *dstAddr, byte Status, byte secUse )
{
ZDP_EndDeviceBindRsp( TransSeq, dstAddr, Status, secUse );
#if defined( LCD_SUPPORTED )
HalLcdWriteString( "End Device Bind", HAL_LCD_LINE_1 );
if ( Status == ZDP_SUCCESS )
{
HalLcdWriteString( "Success Sent", HAL_LCD_LINE_2 );
}
else
{
HalLcdWriteString( "Timeout", HAL_LCD_LINE_2 );
}
#endif
}
#endif // REFLECTOR
static byte ZDO_CompareClusterLists( byte numList1, uint16 *list1,
byte numList2, uint16 *list2, uint16 *pMatches )
{
byte x, y;
uint16 z;
byte numMatches = 0;
// Check the first in against the seconds out
for ( x = 0; x < numList1; x++ )
{
for ( y = 0; y < numList2; y++ )
{
z = list2[y];
if ( list1[x] == z )
{
pMatches[numMatches++] = z;
}
}
}
return ( numMatches );
}
byte ZDO_AnyClusterMatches( byte ACnt, uint16 *AList, byte BCnt, uint16 *BList )
{
byte x, y;
for ( x = 0; x < ACnt; x++ )
{
for ( y = 0; y < BCnt; y++ )
{
if ( AList[x] == BList[y] )
{
return true;
}
}
}
return false;
}
void ZDO_ProcessNodeDescReq( zdoIncomingMsg_t *inMsg )
{
uint16 aoi = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );
NodeDescriptorFormat_t *desc = NULL;
if ( aoi == ZDAppNwkAddr.addr.shortAddr )
{
desc = &ZDO_Config_Node_Descriptor;
}
if ( desc != NULL )
{
ZDP_NodeDescMsg( inMsg, aoi, desc );
}
else
{
ZDP_GenericRsp( inMsg->TransSeq, &(inMsg->srcAddr),
ZDP_INVALID_REQTYPE, aoi, Node_Desc_rsp, inMsg->SecurityUse );
}
}
void ZDO_ProcessPowerDescReq( zdoIncomingMsg_t *inMsg )
{
uint16 aoi = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );
NodePowerDescriptorFormat_t *desc = NULL;
if ( aoi == ZDAppNwkAddr.addr.shortAddr )
{
desc = &ZDO_Config_Power_Descriptor;
}
if ( desc != NULL )
{
ZDP_PowerDescMsg( inMsg, aoi, desc );
}
else
{
ZDP_GenericRsp( inMsg->TransSeq, &(inMsg->srcAddr),
ZDP_INVALID_REQTYPE, aoi, Power_Desc_rsp, inMsg->SecurityUse );
}
}
void ZDO_ProcessSimpleDescReq( zdoIncomingMsg_t *inMsg )
{
SimpleDescriptionFormat_t *sDesc = NULL;
uint16 aoi = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );
byte endPoint = inMsg->asdu[2];
byte free = false;
byte stat = ZDP_SUCCESS;
if ( (endPoint == ZDO_EP) || (endPoint > MAX_ENDPOINTS) )
{
stat = ZDP_INVALID_EP;
}
else if ( aoi == ZDAppNwkAddr.addr.shortAddr )
{
free = afFindSimpleDesc( &sDesc, endPoint );
if ( sDesc == NULL )
{
stat = ZDP_NOT_ACTIVE;
}
}
else
{
if ( ZSTACK_ROUTER_BUILD )
{
stat = ZDP_DEVICE_NOT_FOUND;
}
else if ( ZSTACK_END_DEVICE_BUILD )
{
stat = ZDP_INVALID_REQTYPE;
}
}
ZDP_SimpleDescMsg( inMsg, stat, sDesc );
if ( free && sDesc )
{
osal_mem_free( sDesc );
}
}
void ZDO_ProcessActiveEPReq( zdoIncomingMsg_t *inMsg )
{
byte cnt = 0;
uint16 aoi;
byte stat = ZDP_SUCCESS;
aoi = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );
if ( aoi == NLME_GetShortAddr() )
{
cnt = afNumEndPoints() - 1; // -1 for ZDO endpoint descriptor
afEndPoints( (uint8 *)ZDOBuildBuf, true );
}
else
{
stat = ZDP_INVALID_REQTYPE;
}
ZDP_ActiveEPRsp( inMsg->TransSeq, &(inMsg->srcAddr), stat,
aoi, cnt, (uint8 *)ZDOBuildBuf, inMsg->SecurityUse );
}
uint8 *ZDO_ConvertOTAClusters( uint8 cnt, uint8 *inBuf, uint16 *outList )
{
uint8 x;
for ( x = 0; x < cnt; x++ )
{
// convert ota format to internal
outList[x] = BUILD_UINT16( inBuf[0], inBuf[1] );
inBuf += sizeof( uint16 );
}
return ( inBuf );
}
void ZDO_ProcessMatchDescReq( zdoIncomingMsg_t *inMsg )
{
uint8 epCnt = 0;
uint8 numInClusters;
uint16 *inClusters = NULL;
uint8 numOutClusters;
uint16 *outClusters = NULL;
epList_t *epDesc;
SimpleDescriptionFormat_t *sDesc = NULL;
uint8 allocated;
uint8 *msg;
uint16 aoi;
uint16 profileID;
// Parse the incoming message
msg = inMsg->asdu;
aoi = BUILD_UINT16( msg[0], msg[1] );
profileID = BUILD_UINT16( msg[2], msg[3] );
msg += 4;
if ( ADDR_BCAST_NOT_ME == NLME_IsAddressBroadcast(aoi) )
{
ZDP_MatchDescRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZDP_INVALID_REQTYPE,
ZDAppNwkAddr.addr.shortAddr, 0, NULL, inMsg->SecurityUse );
return;
}
else if ( (ADDR_NOT_BCAST == NLME_IsAddressBroadcast(aoi)) && (aoi != ZDAppNwkAddr.addr.shortAddr) )
{
ZDP_MatchDescRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZDP_INVALID_REQTYPE,
ZDAppNwkAddr.addr.shortAddr, 0, NULL, inMsg->SecurityUse );
return;
}
if ((numInClusters = *msg++) &&
(inClusters = (uint16*)osal_mem_alloc( numInClusters * sizeof( uint16 ) )))
{
msg = ZDO_ConvertOTAClusters( numInClusters, msg, inClusters );
}
else
{
numInClusters = 0;
}
if ((numOutClusters = *msg++) &&
(outClusters = (uint16 *)osal_mem_alloc( numOutClusters * sizeof( uint16 ) )))
{
msg = ZDO_ConvertOTAClusters( numOutClusters, msg, outClusters );
}
else
{
numOutClusters = 0;
}
// First count the number of endpoints that match.
epDesc = epList;
while ( epDesc )
{
// Don't search endpoint 0 and check if response is allowed
if ( epDesc->epDesc->endPoint != ZDO_EP && (epDesc->flags&eEP_AllowMatch) )
{
if ( epDesc->pfnDescCB )
{
sDesc = (SimpleDescriptionFormat_t *)epDesc->pfnDescCB( AF_DESCRIPTOR_SIMPLE, epDesc->epDesc->endPoint );
allocated = TRUE;
}
else
{
sDesc = epDesc->epDesc->simpleDesc;
allocated = FALSE;
}
if ( sDesc && sDesc->AppProfId == profileID )
{
uint8 *uint8Buf = (uint8 *)ZDOBuildBuf;
// Are there matching input clusters?
if ((ZDO_AnyClusterMatches( numInClusters, inClusters,
sDesc->AppNumInClusters, sDesc->pAppInClusterList )) ||
// Are there matching output clusters?
(ZDO_AnyClusterMatches( numOutClusters, outClusters,
sDesc->AppNumOutClusters, sDesc->pAppOutClusterList )))
{
// Notify the endpoint of the match.
uint8 bufLen = sizeof( ZDO_MatchDescRspSent_t ) + (numOutClusters + numInClusters) * sizeof(uint16);
ZDO_MatchDescRspSent_t *pRspSent = (ZDO_MatchDescRspSent_t *) osal_msg_allocate( bufLen );
if (pRspSent)
{
pRspSent->hdr.event = ZDO_MATCH_DESC_RSP_SENT;
pRspSent->nwkAddr = inMsg->srcAddr.addr.shortAddr;
pRspSent->numInClusters = numInClusters;
pRspSent->numOutClusters = numOutClusters;
if (numInClusters)
{
pRspSent->pInClusters = (uint16*) (pRspSent + 1);
osal_memcpy(pRspSent->pInClusters, inClusters, numInClusters * sizeof(uint16));
}
else
{
pRspSent->pInClusters = NULL;
}
if (numOutClusters)
{
pRspSent->pOutClusters = (uint16*)(pRspSent + 1) + numInClusters;
osal_memcpy(pRspSent->pOutClusters, outClusters, numOutClusters * sizeof(uint16));
}
else
{
pRspSent->pOutClusters = NULL;
}
osal_msg_send( *epDesc->epDesc->task_id, (uint8 *)pRspSent );
}
uint8Buf[epCnt++] = sDesc->EndPoint;
}
}
if ( allocated )
{
osal_mem_free( sDesc );
}
}
epDesc = epDesc->nextDesc;
}
if ( epCnt )
{
// Send the message if at least one match found.
if ( ZSuccess == ZDP_MatchDescRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZDP_SUCCESS,
ZDAppNwkAddr.addr.shortAddr, epCnt, (uint8 *)ZDOBuildBuf, inMsg->SecurityUse ) )
{
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "Match Desc Req", "Rsp Sent" );
#endif
}
}
else
{
// No match found
if (ADDR_NOT_BCAST == NLME_IsAddressBroadcast(aoi))
{
// send response message with match length = 0
ZDP_MatchDescRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZDP_SUCCESS,
ZDAppNwkAddr.addr.shortAddr, 0, (uint8 *)ZDOBuildBuf, inMsg->SecurityUse );
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "Match Desc Req", "Rsp Non Matched" );
#endif
}
else
{
// no response mesage for broadcast message
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( "Match Desc Req", "Non Matched" );
#endif
}
}
if ( inClusters != NULL )
{
osal_mem_free( inClusters );
}
if ( outClusters != NULL )
{
osal_mem_free( outClusters );
}
}
void ZDO_ProcessBindUnbindReq( zdoIncomingMsg_t *inMsg, ZDO_BindUnbindReq_t *pReq )
{
zAddrType_t SourceAddr; // Binding Source addres
byte bindStat;
SourceAddr.addrMode = Addr64Bit;
osal_cpyExtAddr( SourceAddr.addr.extAddr, pReq->srcAddress );
// If the local device is not the primary binding cache
// check the src address of the bind request.
// If it is not the local device's extended address
// discard the request.
if ( !osal_ExtAddrEqual( SourceAddr.addr.extAddr, NLME_GetExtAddr()) ||
(pReq->dstAddress.addrMode != Addr64Bit &&
pReq->dstAddress.addrMode != AddrGroup) )
{
bindStat = ZDP_NOT_SUPPORTED;
}
else
{
// Check source & destination endpoints
if ( (pReq->srcEndpoint == 0 || pReq->srcEndpoint > MAX_ENDPOINTS)
|| (( pReq->dstAddress.addrMode == Addr64Bit ) &&
(pReq->dstEndpoint == 0 || pReq->dstEndpoint > MAX_ENDPOINTS)) )
{
bindStat = ZDP_INVALID_EP;
}
else
{
if ( inMsg->clusterID == Bind_req )
{
// Assume the table is full
bindStat = ZDP_TABLE_FULL;
#if defined( APP_TP ) || defined( APP_TP2 )
// For ZigBee Conformance Testing
if ( bindNumOfEntries() < gNWK_MAX_BINDING_ENTRIES )
#endif
{
if ( APSME_BindRequest( pReq->srcEndpoint, pReq->clusterID,
&(pReq->dstAddress), pReq->dstEndpoint ) == ZSuccess )
{
uint16 nwkAddr;
// valid entry
bindStat = ZDP_SUCCESS;
// Notify to save info into NV
ZDApp_NVUpdate();
// Check for the destination address
if ( pReq->dstAddress.addrMode == Addr64Bit )
{
if ( APSME_LookupNwkAddr( pReq->dstAddress.addr.extAddr, &nwkAddr ) == FALSE )
{
ZDP_NwkAddrReq( pReq->dstAddress.addr.extAddr, ZDP_ADDR_REQTYPE_SINGLE, 0, 0 );
}
}
}
}
}
else // Unbind_req
{
if ( APSME_UnBindRequest( pReq->srcEndpoint, pReq->clusterID,
&(pReq->dstAddress), pReq->dstEndpoint ) == ZSuccess )
{
bindStat = ZDP_SUCCESS;
// Notify to save info into NV
ZDApp_NVUpdate();
}
else
bindStat = ZDP_NO_ENTRY;
}
}
}
// Send back a response message
ZDP_SendData( &(inMsg->TransSeq), &(inMsg->srcAddr),
(inMsg->clusterID | ZDO_RESPONSE_BIT), 1, &bindStat,
inMsg->SecurityUse );
}
void ZDO_UpdateAddrManager( uint16 nwkAddr, uint8 *extAddr )
{
AddrMgrEntry_t addrEntry;
// Update the address manager
addrEntry.user = ADDRMGR_USER_DEFAULT;
addrEntry.nwkAddr = nwkAddr;
AddrMgrExtAddrSet( addrEntry.extAddr, extAddr );
AddrMgrEntryUpdate( &addrEntry );
}
void ZDO_ProcessServerDiscReq( zdoIncomingMsg_t *inMsg )
{
uint16 serverMask = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );
uint16 matchMask = serverMask & ZDO_Config_Node_Descriptor.ServerMask;
if ( matchMask )
{
ZDP_ServerDiscRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZSUCCESS,
ZDAppNwkAddr.addr.shortAddr, matchMask, inMsg->SecurityUse );
}
}
void ZDO_EndDeviceTimeoutCB( void )
{
#if defined ( REFLECTOR )
byte stat;
if ( ZDO_EDBind )
{
stat = ZDO_EDBind->status;
// Send the response message to the first sent
ZDO_SendEDBindRsp( ZDO_EDBind->SrcTransSeq, &(ZDO_EDBind->SrcAddr),
stat, ZDO_EDBind->SecurityUse );
ZDO_RemoveEndDeviceBind();
}
#endif // REFLECTOR
}
void ZDO_ProcessMgmtLqiReq( zdoIncomingMsg_t *inMsg )
{
byte x;
byte index;
byte numItems;
byte maxItems;
ZDP_MgmtLqiItem_t* table = NULL;
ZDP_MgmtLqiItem_t* item;
neighborEntry_t entry;
byte aItems;
associated_devices_t *aDevice;
AddrMgrEntry_t nwkEntry;
uint8 StartIndex = inMsg->asdu[0];
// Get the number of neighbor items
NLME_GetRequest( nwkNumNeighborTableEntries, 0, &maxItems );
// Get the number of associated items
aItems = (uint8)AssocCount( PARENT, CHILD_FFD_RX_IDLE );
// Total number of items
maxItems += aItems;
// Start with the supplied index
if ( maxItems > StartIndex )
{
numItems = maxItems - StartIndex;
// limit the size of the list
if ( numItems > ZDO_MAX_LQI_ITEMS )
numItems = ZDO_MAX_LQI_ITEMS;
// Allocate the memory to build the table
table = (ZDP_MgmtLqiItem_t*)osal_mem_alloc( (short)
( numItems * sizeof( ZDP_MgmtLqiItem_t ) ) );
if ( table != NULL )
{
x = 0;
item = table;
index = StartIndex;
// Loop through associated items and build list
for ( ; x < numItems; x++ )
{
if ( index < aItems )
{
// get next associated device
aDevice = AssocFindDevice( index++ );
// set basic fields
item->panID = _NIB.nwkPanId;
osal_cpyExtAddr( item->extPanID, _NIB.extendedPANID );
item->nwkAddr = aDevice->shortAddr;
item->permit = ZDP_MGMT_BOOL_UNKNOWN;
item->depth = 0xFF;
item->lqi = aDevice->linkInfo.rxLqi;
// set extented address
nwkEntry.user = ADDRMGR_USER_DEFAULT;
nwkEntry.nwkAddr = aDevice->shortAddr;
if ( AddrMgrEntryLookupNwk( &nwkEntry ) == TRUE )
{
osal_cpyExtAddr( item->extAddr, nwkEntry.extAddr );
}
else
{
osal_memset( item->extAddr, 0xFF, Z_EXTADDR_LEN );
}
// use association info to set other fields
if ( aDevice->nodeRelation == PARENT )
{
if ( aDevice->shortAddr == 0 )
{
item->devType = ZDP_MGMT_DT_COORD;
item->depth = 0;
}
else
{
item->devType = ZDP_MGMT_DT_ROUTER;
item->depth = _NIB.nodeDepth - 1;
}
item->rxOnIdle = ZDP_MGMT_BOOL_UNKNOWN;
item->relation = ZDP_MGMT_REL_PARENT;
}
else
{
// If not parent, then it's a child
item->depth = _NIB.nodeDepth + 1;
if ( aDevice->nodeRelation < CHILD_FFD )
{
item->devType = ZDP_MGMT_DT_ENDDEV;
if ( aDevice->nodeRelation == CHILD_RFD )
{
item->rxOnIdle = FALSE;
}
else
{
item->rxOnIdle = TRUE;
}
}
else
{
item->devType = ZDP_MGMT_DT_ROUTER;
if ( aDevice->nodeRelation == CHILD_FFD )
{
item->rxOnIdle = FALSE;
}
else
{
item->rxOnIdle = TRUE;
}
}
item->relation = ZDP_MGMT_REL_CHILD;
}
item++;
}
else
{
if ( StartIndex <= aItems )
// Start with 1st neighbor
index = 0;
else
// Start with >1st neighbor
index = StartIndex - aItems;
break;
}
}
// Loop through neighbor items and finish list
for ( ; x < numItems; x++ )
{
// Add next neighbor table item
NLME_GetRequest( nwkNeighborTable, index++, &entry );
// set ZDP_MgmtLqiItem_t fields
item->panID = entry.panId;
osal_cpyExtAddr( item->extPanID, _NIB.extendedPANID );
osal_memset( item->extAddr, 0xFF, Z_EXTADDR_LEN );
item->nwkAddr = entry.neighborAddress;
item->rxOnIdle = ZDP_MGMT_BOOL_UNKNOWN;
item->relation = ZDP_MGMT_REL_UNKNOWN;
item->permit = ZDP_MGMT_BOOL_UNKNOWN;
item->depth = 0xFF;
item->lqi = entry.linkInfo.rxLqi;
if ( item->nwkAddr == 0 )
{
item->devType = ZDP_MGMT_DT_COORD;
}
else
{
item->devType = ZDP_MGMT_DT_ROUTER;
}
item++;
}
}
}
else
{
numItems = 0;
}
// Send response
ZDP_MgmtLqiRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZSuccess, maxItems,
StartIndex, numItems, table, false );
if ( table )
{
osal_mem_free( table );
}
}
void ZDO_ProcessMgmtNwkDiscReq( zdoIncomingMsg_t *inMsg )
{
NLME_ScanFields_t scan;
uint8 index;
uint8 *msg;
msg = inMsg->asdu;
scan.channels = osal_build_uint32( msg, 4 );
msg += 4;
scan.duration = *msg++;
index = *msg;
scan.scanType = ZMAC_ACTIVE_SCAN;
scan.scanApp = NLME_DISC_SCAN;
// Save off the information to be used for the response
zdappMgmtNwkDiscReqInProgress = true;
zdappMgmtNwkDiscRspAddr.addrMode = Addr16Bit;
zdappMgmtNwkDiscRspAddr.addr.shortAddr = inMsg->srcAddr.addr.shortAddr;
zdappMgmtNwkDiscStartIndex = index;
zdappMgmtNwkDiscRspTransSeq = inMsg->TransSeq;
if ( NLME_NwkDiscReq2( &scan ) != ZSuccess )
{
NLME_NwkDiscTerm();
// zdappMgmtNwkDiscReqInProgress will be reset in the confirm callback
}
}
#if defined ( ZDO_MGMT_NWKDISC_RESPONSE )
void ZDO_FinishProcessingMgmtNwkDiscReq( void )
{
byte count, i, ResultCount = 0;
networkDesc_t *newDesc = NULL, *pList, *NetworkList;
NetworkList = nwk_getNwkDescList();
// Count the number of nwk descriptors in the list
pList = nwk_getNwkDescList();
while (pList)
{
ResultCount++;
pList = pList->nextDesc;
}
if ( ZSTACK_ROUTER_BUILD )
{
// Look for my PanID.
pList = nwk_getNwkDescList();
while ( pList )
{
if ( pList->panId == _NIB.nwkPanId )
{
break;
}
if ( !pList->nextDesc )
{
break;
}
pList = pList->nextDesc;
}
// If my Pan not present (query to a star network ZC or an isolated ZR?),
// prepend it.
if ( !pList || (pList->panId != _NIB.nwkPanId) )
{
newDesc = (networkDesc_t *)osal_mem_alloc( sizeof( networkDesc_t ) );
if ( newDesc )
{
byte pJoin;
newDesc->panId = _NIB.nwkPanId;
newDesc->logicalChannel = _NIB.nwkLogicalChannel;
newDesc->version = NLME_GetProtocolVersion();
newDesc->stackProfile = zgStackProfile;
//Extended PanID
osal_cpyExtAddr( newDesc->extendedPANID, _NIB.extendedPANID);
ZMacGetReq( ZMacAssociationPermit, &pJoin );
newDesc->chosenRouter = ((pJoin) ? ZDAppNwkAddr.addr.shortAddr :
INVALID_NODE_ADDR);
newDesc->nextDesc = NetworkList;
NetworkList = newDesc;
ResultCount++;
}
}
}
// Calc the count and apply a max count.
if ( zdappMgmtNwkDiscStartIndex > ResultCount )
{
count = 0;
}
else
{
count = ResultCount - zdappMgmtNwkDiscStartIndex;
if ( count > ZDO_MAX_NWKDISC_ITEMS )
{
count = ZDO_MAX_NWKDISC_ITEMS;
}
// Move the list pointer up to the start index.
for ( i = 0; i < zdappMgmtNwkDiscStartIndex; i++ )
{
NetworkList = NetworkList->nextDesc;
}
}
ZDP_MgmtNwkDiscRsp( zdappMgmtNwkDiscRspTransSeq,
&zdappMgmtNwkDiscRspAddr, ZSuccess, ResultCount,
zdappMgmtNwkDiscStartIndex,
count,
NetworkList,
false );
if ( ZSTACK_ROUTER_BUILD )
{
if ( newDesc != NULL )
{
osal_mem_free( newDesc );
}
}
NLME_NwkDiscTerm();
}
#endif
void ZDO_ProcessMgmtRtgReq( zdoIncomingMsg_t *inMsg )
{
byte x;
byte maxNumItems;
byte numItems = 0;
uint8 *pBuf = NULL;
rtgItem_t *pList;
uint8 StartIndex = inMsg->asdu[0];
// Get the number of table items
NLME_GetRequest( nwkNumRoutingTableEntries, 0, &maxNumItems );
if ( maxNumItems > StartIndex )
{
numItems = maxNumItems - StartIndex; // Start at the passed in index
// limit the size of the list
if ( numItems > ZDO_MAX_RTG_ITEMS )
{
numItems = ZDO_MAX_RTG_ITEMS;
}
// Allocate the memory to build the table
pBuf = osal_mem_alloc( (short)(sizeof( rtgItem_t ) * numItems) );
if ( pBuf != NULL )
{
// Convert buffer to list
pList = (rtgItem_t *)pBuf;
// Loop through items and build list
for ( x = 0; x < numItems; x++ )
{
NLME_GetRequest( nwkRoutingTable, (uint16)(x + StartIndex), (void*)pList );
// Remap the status to the RoutingTableList Record Format defined in the ZigBee spec
switch( pList->status )
{
case RT_ACTIVE:
pList->status = ZDO_MGMT_RTG_ENTRY_ACTIVE;
break;
case RT_DISC:
pList->status = ZDO_MGMT_RTG_ENTRY_DISCOVERY_UNDERWAY;
break;
case RT_LINK_FAIL:
pList->status = ZDO_MGMT_RTG_ENTRY_DISCOVERY_FAILED;
break;
case RT_INIT:
case RT_REPAIR:
default:
pList->status = ZDO_MGMT_RTG_ENTRY_INACTIVE;
break;
}
// Increment pointer to next record
pList++;
}
}
else
{
numItems = 0;
}
}
// Send response
ZDP_MgmtRtgRsp( inMsg->TransSeq, &(inMsg->srcAddr), ZSuccess, maxNumItems, StartIndex, numItems,
(rtgItem_t *)pBuf, false );
if ( pBuf != NULL )
{
osal_mem_free( pBuf );
}
}
void ZDO_ProcessMgmtBindReq( zdoIncomingMsg_t *inMsg )
{
#if defined ( REFLECTOR )
byte x;
uint16 maxNumItems;
uint16 numItems;
uint8 *pBuf = NULL;
apsBindingItem_t *pList;
uint8 StartIndex = inMsg->asdu[0];
uint8 status;
// Get the number of table items
APSME_GetRequest( apsNumBindingTableEntries, 0, (byte*)(&maxNumItems) );
if ( maxNumItems > StartIndex )
{
numItems = maxNumItems - StartIndex; // Start at the passed in index
}
else
{
numItems = 0;
}
// limit the size of the list
if ( numItems > ZDO_MAX_BIND_ITEMS )
{
numItems = ZDO_MAX_BIND_ITEMS;
}
// Allocate the memory to build the table
if ( numItems && (pBuf = osal_mem_alloc( sizeof( apsBindingItem_t ) * numItems )) )
{
status = ZSuccess;
// Convert buffer to list
pList = (apsBindingItem_t *)pBuf;
// Loop through items and build list
for ( x = 0; x < numItems; x++ )
{
APSME_GetRequest( apsBindingTable, (x + StartIndex), (void*)pList );
pList++;
}
}
else
{
status = ZDP_NOT_PERMITTED;
numItems = 0;
}
// Send response
ZDP_MgmtBindRsp( inMsg->TransSeq, &(inMsg->srcAddr), status, (byte)maxNumItems, StartIndex,
(byte)numItems, (apsBindingItem_t *)pBuf, false );
if ( pBuf )
{
osal_mem_free( pBuf );
}
#else
(void)inMsg;
#endif
}
void ZDO_ProcessMgmtDirectJoinReq( zdoIncomingMsg_t *inMsg )
{
uint8 *deviceAddr;
uint8 capInfo;
uint8 stat;
// Parse the message
deviceAddr = inMsg->asdu;
capInfo = inMsg->asdu[Z_EXTADDR_LEN];
stat = (byte) NLME_DirectJoinRequest( deviceAddr, capInfo );
ZDP_MgmtDirectJoinRsp( inMsg->TransSeq, &(inMsg->srcAddr), stat, false );
}
void ZDO_ProcessMgmtLeaveReq( zdoIncomingMsg_t *inMsg )
{
NLME_LeaveReq_t req;
ZStatus_t status;
uint8 option;
uint8 *msg = inMsg->asdu;
if ( ( AddrMgrExtAddrValid( msg ) == FALSE ) ||
( osal_ExtAddrEqual( msg, NLME_GetExtAddr() ) == TRUE ) )
{
// Remove this device
req.extAddr = NULL;
}
else
{
// Remove child device
req.extAddr = msg;
}
option = msg[Z_EXTADDR_LEN];
if ( option & ZDP_MGMT_LEAVE_REQ_RC )
{
req.removeChildren = TRUE;
}
if ( option & ZDP_MGMT_LEAVE_REQ_REJOIN )
{
req.rejoin = TRUE;
}
req.silent = FALSE;
status = NLME_LeaveReq( &req );
ZDP_MgmtLeaveRsp( inMsg->TransSeq, &(inMsg->srcAddr), status, FALSE );
}
void ZDO_ProcessMgmtPermitJoinReq( zdoIncomingMsg_t *inMsg )
{
uint8 stat;
uint8 duration;
uint8 tcsig;
duration = inMsg->asdu[ZDP_MGMT_PERMIT_JOIN_REQ_DURATION];
tcsig = inMsg->asdu[ZDP_MGMT_PERMIT_JOIN_REQ_TC_SIG];
// Set the network layer permit join duration
stat = (byte) NLME_PermitJoiningRequest( duration );
// Handle the Trust Center Significance
if ( ZG_SECURE_ENABLED && ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
{
if ( tcsig == TRUE )
{
ZDSecMgrPermitJoining( duration );
}
}
// Send a response if unicast
if ( !inMsg->wasBroadcast )
{
ZDP_MgmtPermitJoinRsp( inMsg->TransSeq, &(inMsg->srcAddr), stat, false );
}
}
void ZDO_ProcessMgmtPermitJoinTimeout( void )
{
#if defined( ZDO_MGMT_PERMIT_JOIN_RESPONSE )
// Currently, only the ZDSecMgr needs to be notified
if ( ZG_SECURE_ENABLED && ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE )
{
ZDSecMgrPermitJoiningTimeout();
}
#endif
}
void ZDO_ProcessUserDescReq( zdoIncomingMsg_t *inMsg )
{
uint16 aoi = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );
UserDescriptorFormat_t userDesc;
if ( (aoi == ZDAppNwkAddr.addr.shortAddr) && (ZSUCCESS == osal_nv_read(
ZCD_NV_USERDESC, 0, sizeof(UserDescriptorFormat_t), &userDesc )) )
{
ZDP_UserDescRsp( inMsg->TransSeq, &(inMsg->srcAddr), aoi, &userDesc, false );
}
else
{
ZDP_GenericRsp(inMsg->TransSeq, &(inMsg->srcAddr),
ZDP_NOT_SUPPORTED, aoi, User_Desc_rsp, inMsg->SecurityUse );
}
}
void ZDO_ProcessUserDescSet( zdoIncomingMsg_t *inMsg )
{
uint8 *msg;
uint16 aoi;
UserDescriptorFormat_t userDesc;
uint8 outMsg[3];
uint8 status;
msg = inMsg->asdu;
aoi = BUILD_UINT16( msg[0], msg[1] );
if ( aoi == ZDAppNwkAddr.addr.shortAddr )
{
userDesc.len = (msg[2] < AF_MAX_USER_DESCRIPTOR_LEN) ? msg[2] : AF_MAX_USER_DESCRIPTOR_LEN;
msg ++; // increment one for the length field
osal_memcpy( userDesc.desc, &msg[2], userDesc.len );
osal_nv_write( ZCD_NV_USERDESC, 0, sizeof(UserDescriptorFormat_t), &userDesc );
if ( userDesc.len != 0 )
{
ZDO_Config_Node_Descriptor.UserDescAvail = TRUE;
}
else
{
ZDO_Config_Node_Descriptor.UserDescAvail = FALSE;
}
status = ZDP_SUCCESS;
}
else
{
status = ZDP_NOT_SUPPORTED;
}
outMsg[0] = status;
outMsg[1] = LO_UINT16( aoi );
outMsg[2] = LO_UINT16( aoi );
ZDP_SendData( &(inMsg->TransSeq), &(inMsg->srcAddr), User_Desc_conf, 3, outMsg,
inMsg->SecurityUse );
}
void ZDO_ProcessDeviceAnnce( zdoIncomingMsg_t *inMsg )
{
ZDO_DeviceAnnce_t Annce;
AddrMgrEntry_t addrEntry;
uint8 parentExt[Z_EXTADDR_LEN];
// Parse incoming message
ZDO_ParseDeviceAnnce( inMsg, &Annce );
if ( ZSTACK_END_DEVICE_BUILD )
{
// Make sure the message didn't come from myself - end device only
if ( osal_ExtAddrEqual( NLME_GetExtAddr(), Annce.extAddr ) && Annce.nwkAddr == NLME_GetShortAddr() )
{
return;
}
}
#if defined ( ZIGBEE_STOCHASTIC_ADDRESSING )
// Clean up the neighbor table
nwkNeighborRemoveAllStranded();
// If address conflict is detected, no need to update the address manager
if ( NLME_CheckNewAddrSet( Annce.nwkAddr, Annce.extAddr )== ZFailure )
{
return;
}
#endif
#if defined ( ZIGBEE_STOCHASTIC_ADDRESSING )
// Check for parent's address
NLME_GetCoordExtAddr( parentExt );
if ( osal_ExtAddrEqual( parentExt, Annce.extAddr ) )
{
if ( Annce.nwkAddr != NLME_GetCoordShortAddr() )
{
// Set the Parent's MAC's new short address
_NIB.nwkCoordAddress = Annce.nwkAddr;
ZMacSetReq( ZMacCoordShortAddress, (byte*)&(_NIB.nwkCoordAddress) );
}
}
if ( ZSTACK_ROUTER_BUILD )
{
// If the device annce comes from a end device child that has moved
// to another parent, remove it from associated device list
// If the dev annce is coming from other device's children,
// (The dev annce from its own children shall be unicast to itself,
// So check the mac destination address)
// Remove it from the associated device list. If it is not
// a child, no action will be taken in AssocRemove() anyway.
if ( inMsg->macDestAddr != NLME_GetShortAddr() )
{
associated_devices_t *dev_ptr;
// If it's an end device child
dev_ptr = AssocGetWithExt( Annce.extAddr );
if ( dev_ptr )
{
if ( dev_ptr->nodeRelation == CHILD_RFD ||
dev_ptr->nodeRelation == CHILD_RFD_RX_IDLE )
{
AssocRemove( Annce.extAddr );
}
}
}
if ( Annce.nwkAddr != NLME_GetShortAddr() )
{
// If an associated device is found with matched extended Address,
// update its short address
if ( AssocChangeNwkAddr( Annce.nwkAddr, Annce.extAddr ) )
{
// Set event to save NV
ZDApp_NVUpdate();
}
}
}
// Update the neighbor table
nwkNeighborUpdateNwkAddr( Annce.nwkAddr, Annce.extAddr );
// Assume that the device has moved, remove existing routing entries
RTG_RemoveRtgEntry( Annce.nwkAddr, 0 );
#endif // ZIGBEE_STOCHASTIC_ADDRESSING
// Fill in the extended address in address manager if we don't have it already.
addrEntry.user = ADDRMGR_USER_DEFAULT;
addrEntry.nwkAddr = Annce.nwkAddr;
if ( AddrMgrEntryLookupNwk( &addrEntry ) )
{
osal_memset( parentExt, 0, Z_EXTADDR_LEN );
if ( osal_ExtAddrEqual( parentExt, addrEntry.extAddr ) )
{
AddrMgrExtAddrSet( addrEntry.extAddr, Annce.extAddr );
AddrMgrEntryUpdate( &addrEntry );
}
}
// Update the short address in address manager if it's been changed
AddrMgrExtAddrSet( addrEntry.extAddr, Annce.extAddr );
if ( AddrMgrEntryLookupExt( &addrEntry ) )
{
if ( addrEntry.nwkAddr != Annce.nwkAddr )
{
addrEntry.nwkAddr = Annce.nwkAddr;
AddrMgrEntryUpdate( &addrEntry );
}
}
}
void ZDO_BuildSimpleDescBuf( uint8 *buf, SimpleDescriptionFormat_t *desc )
{
byte cnt;
uint16 *ptr;
*buf++ = desc->EndPoint;
*buf++ = HI_UINT16( desc->AppProfId );
*buf++ = LO_UINT16( desc->AppProfId );
*buf++ = HI_UINT16( desc->AppDeviceId );
*buf++ = LO_UINT16( desc->AppDeviceId );
*buf++ = (byte)(desc->AppDevVer << 4);
*buf++ = desc->AppNumInClusters;
ptr = desc->pAppInClusterList;
for ( cnt = 0; cnt < desc->AppNumInClusters; ptr++, cnt++ )
{
*buf++ = HI_UINT16( *ptr );
*buf++ = LO_UINT16( *ptr );
}
*buf++ = desc->AppNumOutClusters;
ptr = desc->pAppOutClusterList;
for ( cnt = 0; cnt < desc->AppNumOutClusters; ptr++, cnt++ )
{
*buf++ = HI_UINT16( *ptr );
*buf++ = LO_UINT16( *ptr );
}
}
void ZDO_MatchEndDeviceBind( ZDEndDeviceBind_t *bindReq )
{
zAddrType_t dstAddr;
uint8 sendRsp = FALSE;
uint8 status;
// Is this the first request?
if ( matchED == NULL )
{
// Create match info structure
matchED = (ZDMatchEndDeviceBind_t *)osal_mem_alloc( sizeof ( ZDMatchEndDeviceBind_t ) );
if ( matchED )
{
// Clear the structure
osal_memset( (uint8 *)matchED, 0, sizeof ( ZDMatchEndDeviceBind_t ) );
// Copy the first request's information
if ( !ZDO_CopyMatchInfo( &(matchED->ed1), bindReq ) )
{
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
}
else
{
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
if ( !sendRsp )
{
// Set into the correct state
matchED->state = ZDMATCH_WAIT_REQ;
// Setup the timeout
APS_SetEndDeviceBindTimeout( AIB_MaxBindingTime, ZDO_EndDeviceBindMatchTimeoutCB );
}
}
else
{
matchED->state = ZDMATCH_SENDING_BINDS;
// Copy the 2nd request's information
if ( !ZDO_CopyMatchInfo( &(matchED->ed2), bindReq ) )
{
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
// Make a source match for ed1
matchED->ed1numMatched = ZDO_CompareClusterLists(
matchED->ed1.numOutClusters, matchED->ed1.outClusters,
matchED->ed2.numInClusters, matchED->ed2.inClusters, ZDOBuildBuf );
if ( matchED->ed1numMatched )
{
// Save the match list
matchED->ed1Matched = osal_mem_alloc( (short)(matchED->ed1numMatched * sizeof ( uint16 )) );
if ( matchED->ed1Matched )
{
osal_memcpy( matchED->ed1Matched, ZDOBuildBuf, (matchED->ed1numMatched * sizeof ( uint16 )) );
}
else
{
// Allocation error, stop
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
}
// Make a source match for ed2
matchED->ed2numMatched = ZDO_CompareClusterLists(
matchED->ed2.numOutClusters, matchED->ed2.outClusters,
matchED->ed1.numInClusters, matchED->ed1.inClusters, ZDOBuildBuf );
if ( matchED->ed2numMatched )
{
// Save the match list
matchED->ed2Matched = osal_mem_alloc( (short)(matchED->ed2numMatched * sizeof ( uint16 )) );
if ( matchED->ed2Matched )
{
osal_memcpy( matchED->ed2Matched, ZDOBuildBuf, (matchED->ed2numMatched * sizeof ( uint16 )) );
}
else
{
// Allocation error, stop
status = ZDP_NO_ENTRY;
sendRsp = TRUE;
}
}
if ( (sendRsp == FALSE) && (matchED->ed1numMatched || matchED->ed2numMatched) )
{
// Do the first unbind/bind state
ZDMatchSendState( ZDMATCH_REASON_START, ZDP_SUCCESS, 0 );
}
else
{
status = ZDP_NO_MATCH;
sendRsp = TRUE;
}
}
if ( sendRsp )
{
// send response to this requester
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = bindReq->srcAddr;
ZDP_EndDeviceBindRsp( bindReq->TransSeq, &dstAddr, status, bindReq->SecurityUse );
if ( matchED->state == ZDMATCH_SENDING_BINDS )
{
// send response to first requester
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = matchED->ed1.srcAddr;
ZDP_EndDeviceBindRsp( matchED->ed1.TransSeq, &dstAddr, status, matchED->ed1.SecurityUse );
}
// Process ended - release memory used
ZDO_RemoveMatchMemory();
}
}
static void ZDO_RemoveMatchMemory( void )
{
if ( matchED != NULL )
{
if ( matchED->ed2Matched != NULL )
{
osal_mem_free( matchED->ed2Matched );
}
if ( matchED->ed1Matched != NULL )
{
osal_mem_free( matchED->ed1Matched );
}
if ( matchED->ed1.inClusters != NULL )
{
osal_mem_free( matchED->ed1.inClusters );
}
if ( matchED->ed1.outClusters != NULL )
{
osal_mem_free( matchED->ed1.outClusters );
}
if ( matchED->ed2.inClusters != NULL )
{
osal_mem_free( matchED->ed2.inClusters );
}
if ( matchED->ed2.outClusters != NULL )
{
osal_mem_free( matchED->ed2.outClusters );
}
osal_mem_free( matchED );
matchED = (ZDMatchEndDeviceBind_t *)NULL;
}
}
static uint8 ZDO_CopyMatchInfo( ZDEndDeviceBind_t *destReq, ZDEndDeviceBind_t *srcReq )
{
uint8 allOK = TRUE;
// Copy bind information into the match info structure
osal_memcpy( (uint8 *)destReq, srcReq, sizeof ( ZDEndDeviceBind_t ) );
// Initialize the destination cluster pointers
destReq->inClusters = NULL;
destReq->outClusters = NULL;
// Copy input cluster IDs
if ( srcReq->numInClusters )
{
destReq->inClusters = osal_mem_alloc( (short)(srcReq->numInClusters * sizeof ( uint16 )) );
if ( destReq->inClusters )
{
// Copy the clusters
osal_memcpy( (uint8*)(destReq->inClusters), (uint8 *)(srcReq->inClusters),
(srcReq->numInClusters * sizeof ( uint16 )) );
}
else
{
allOK = FALSE;
}
}
// Copy output cluster IDs
if ( srcReq->numOutClusters )
{
destReq->outClusters = osal_mem_alloc( (short)(srcReq->numOutClusters * sizeof ( uint16 )) );
if ( destReq->outClusters )
{
// Copy the clusters
osal_memcpy( (uint8 *)(destReq->outClusters), (uint8 *)(srcReq->outClusters),
(srcReq->numOutClusters * sizeof ( uint16 )) );
}
else
{
allOK = FALSE;
}
}
if ( allOK == FALSE )
{
if ( destReq->inClusters != NULL )
{
osal_mem_free( destReq->inClusters );
}
if ( destReq->outClusters != NULL )
{
osal_mem_free( destReq->outClusters );
}
}
return ( allOK );
}
uint8 ZDMatchSendState( uint8 reason, uint8 status, uint8 TransSeq )
{
uint8 *dstIEEEAddr = NULL;
uint8 dstEP = 0xFF;
zAddrType_t dstAddr;
zAddrType_t destinationAddr;
uint16 msgType;
uint16 clusterID = 0xFFFF;
ZDEndDeviceBind_t *ed = NULL;
uint8 rspStatus = ZDP_SUCCESS;
if ( matchED == NULL )
{
return ( FALSE );
}
// Check sequence number
if ( reason == ZDMATCH_REASON_BIND_RSP || reason == ZDMATCH_REASON_UNBIND_RSP )
{
if ( TransSeq != matchED->transSeq )
{
return( FALSE ); // ignore the message
}
}
// turn off timer
APS_SetEndDeviceBindTimeout( 0, ZDO_EndDeviceBindMatchTimeoutCB );
if ( reason == ZDMATCH_REASON_TIMEOUT )
{
rspStatus = ZDP_TIMEOUT; // The process will stop
}
if ( reason == ZDMATCH_REASON_START || reason == ZDMATCH_REASON_BIND_RSP )
{
matchED->sending = ZDMATCH_SENDING_UNBIND;
if ( reason == ZDMATCH_REASON_BIND_RSP && status != ZDP_SUCCESS )
{
rspStatus = status;
}
}
else if ( reason == ZDMATCH_REASON_UNBIND_RSP )
{
if ( status == ZDP_SUCCESS )
{
matchED->sending = ZDMATCH_SENDING_UNBIND;
}
else
{
matchED->sending = ZDMATCH_SENDING_BIND;
}
}
if ( reason != ZDMATCH_REASON_START && matchED->sending == ZDMATCH_SENDING_UNBIND )
{
// Move to the next cluster ID
if ( matchED->ed1numMatched )
{
matchED->ed1numMatched--;
}
else if ( matchED->ed2numMatched )
{
matchED->ed2numMatched--;
}
}
// What message do we send now
if ( matchED->ed1numMatched )
{
ed = &(matchED->ed1);
clusterID = matchED->ed1Matched[matchED->ed1numMatched-1];
dstIEEEAddr = matchED->ed2.ieeeAddr;
dstEP = matchED->ed2.endpoint;
}
else if ( matchED->ed2numMatched )
{
ed = &(matchED->ed2);
clusterID = matchED->ed2Matched[matchED->ed2numMatched-1];
dstIEEEAddr = matchED->ed1.ieeeAddr;
dstEP = matchED->ed1.endpoint;
}
dstAddr.addrMode = Addr16Bit;
// Send the next message
if ( (rspStatus == ZDP_SUCCESS) && ed )
{
// Send unbind/bind message to source
if ( matchED->sending == ZDMATCH_SENDING_UNBIND )
{
msgType = Unbind_req;
}
else
{
msgType = Bind_req;
}
dstAddr.addr.shortAddr = ed->srcAddr;
// Save off the transaction sequence number
matchED->transSeq = ZDP_TransID;
destinationAddr.addrMode = Addr64Bit;
osal_cpyExtAddr( destinationAddr.addr.extAddr, dstIEEEAddr );
ZDP_BindUnbindReq( msgType, &dstAddr, ed->ieeeAddr, ed->endpoint, clusterID,
&destinationAddr, dstEP, ed->SecurityUse );
// Set timeout for response
APS_SetEndDeviceBindTimeout( AIB_MaxBindingTime, ZDO_EndDeviceBindMatchTimeoutCB );
}
else
{
// Send the response messages to requesting devices
// send response to first requester
dstAddr.addr.shortAddr = matchED->ed1.srcAddr;
ZDP_EndDeviceBindRsp( matchED->ed1.TransSeq, &dstAddr, rspStatus, matchED->ed1.SecurityUse );
// send response to second requester
if ( matchED->state == ZDMATCH_SENDING_BINDS )
{
dstAddr.addr.shortAddr = matchED->ed2.srcAddr;
ZDP_EndDeviceBindRsp( matchED->ed2.TransSeq, &dstAddr, rspStatus, matchED->ed2.SecurityUse );
}
// Process ended - release memory used
ZDO_RemoveMatchMemory();
}
return ( TRUE );
}
static void ZDO_EndDeviceBindMatchTimeoutCB( void )
{
ZDMatchSendState( ZDMATCH_REASON_TIMEOUT, ZDP_TIMEOUT, 0 );
}
void ZDO_ParseEndDeviceBindReq( zdoIncomingMsg_t *inMsg, ZDEndDeviceBind_t *bindReq )
{
uint8 *msg;
// Parse the message
bindReq->TransSeq = inMsg->TransSeq;
bindReq->srcAddr = inMsg->srcAddr.addr.shortAddr;
bindReq->SecurityUse = inMsg->SecurityUse;
msg = inMsg->asdu;
bindReq->localCoordinator = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
osal_cpyExtAddr( bindReq->ieeeAddr, msg );
msg += Z_EXTADDR_LEN;
bindReq->endpoint = *msg++;
bindReq->profileID = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
bindReq->inClusters = NULL;
bindReq->outClusters = NULL;
if ((bindReq->numInClusters = *msg++) &&
(bindReq->inClusters = (uint16*)osal_mem_alloc( (bindReq->numInClusters * sizeof( uint16 )))))
{
msg = ZDO_ConvertOTAClusters( bindReq->numInClusters, msg, bindReq->inClusters );
}
else
{
bindReq->numInClusters = 0;
}
if ((bindReq->numOutClusters = *msg++) &&
(bindReq->outClusters = (uint16*)osal_mem_alloc((bindReq->numOutClusters * sizeof(uint16)))))
{
msg = ZDO_ConvertOTAClusters( bindReq->numOutClusters, msg, bindReq->outClusters );
}
else
{
bindReq->numOutClusters = 0;
}
}
void ZDO_ParseBindUnbindReq( zdoIncomingMsg_t *inMsg, ZDO_BindUnbindReq_t *pReq )
{
uint8 *msg;
msg = inMsg->asdu;
osal_cpyExtAddr( pReq->srcAddress, msg );
msg += Z_EXTADDR_LEN;
pReq->srcEndpoint = *msg++;
pReq->clusterID = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
pReq->dstAddress.addrMode = *msg++;
if ( pReq->dstAddress.addrMode == Addr64Bit )
{
osal_cpyExtAddr( pReq->dstAddress.addr.extAddr, msg );
msg += Z_EXTADDR_LEN;
pReq->dstEndpoint = *msg;
}
else
{
// copy group address
pReq->dstAddress.addr.shortAddr = BUILD_UINT16( msg[0], msg[1] );
}
}
ZDO_NwkIEEEAddrResp_t *ZDO_ParseAddrRsp( zdoIncomingMsg_t *inMsg )
{
ZDO_NwkIEEEAddrResp_t *rsp;
uint8 *msg;
byte cnt = 0;
// Calculate the number of items in the list
if ( inMsg->asduLen > (1 + Z_EXTADDR_LEN + 2) )
{
cnt = inMsg->asdu[1 + Z_EXTADDR_LEN + 2];
}
else
{
cnt = 0;
}
// Make buffer
rsp = (ZDO_NwkIEEEAddrResp_t *)osal_mem_alloc( sizeof(ZDO_NwkIEEEAddrResp_t) + (cnt * sizeof ( uint16 )) );
if ( rsp )
{
msg = inMsg->asdu;
rsp->status = *msg++;
if ( rsp->status == ZDO_SUCCESS )
{
osal_cpyExtAddr( rsp->extAddr, msg );
msg += Z_EXTADDR_LEN;
rsp->nwkAddr = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
rsp->numAssocDevs = 0;
// StartIndex field is only present if NumAssocDev field is non-zero.
if ( cnt > 0 )
{
uint16 *pList = &(rsp->devList[0]);
byte n = cnt;
rsp->numAssocDevs = *msg++;
rsp->startIndex = *msg++;
while ( n != 0 )
{
*pList++ = BUILD_UINT16( msg[0], msg[1] );
msg += sizeof( uint16 );
n--;
}
}
}
}
return ( rsp );
}
void ZDO_ParseNodeDescRsp( zdoIncomingMsg_t *inMsg, ZDO_NodeDescRsp_t *pNDRsp )
{
uint8 *msg;
msg = inMsg->asdu;
pNDRsp->status = *msg++;
pNDRsp->nwkAddr = BUILD_UINT16( msg[0], msg[1] );
if ( pNDRsp->status == ZDP_SUCCESS )
{
msg += 2;
pNDRsp->nodeDesc.LogicalType = *msg & 0x07;
pNDRsp->nodeDesc.ComplexDescAvail = ( *msg & 0x08 ) >> 3;
pNDRsp->nodeDesc.UserDescAvail = ( *msg & 0x10 ) >> 4;
msg++; // Reserved bits.
pNDRsp->nodeDesc.FrequencyBand = (*msg >> 3) & 0x1f;
pNDRsp->nodeDesc.APSFlags = *msg++ & 0x07;
pNDRsp->nodeDesc.CapabilityFlags = *msg++;
pNDRsp->nodeDesc.ManufacturerCode[0] = *msg++;
pNDRsp->nodeDesc.ManufacturerCode[1] = *msg++;
pNDRsp->nodeDesc.MaxBufferSize = *msg++;
pNDRsp->nodeDesc.MaxInTransferSize[0] = *msg++;
pNDRsp->nodeDesc.MaxInTransferSize[1] = *msg++;
pNDRsp->nodeDesc.ServerMask = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
pNDRsp->nodeDesc.MaxOutTransferSize[0] = *msg++;
pNDRsp->nodeDesc.MaxOutTransferSize[1] = *msg++;
pNDRsp->nodeDesc.DescriptorCapability = *msg;
}
}
void ZDO_ParsePowerDescRsp( zdoIncomingMsg_t *inMsg, ZDO_PowerRsp_t *pNPRsp )
{
uint8 *msg;
msg = inMsg->asdu;
pNPRsp->status = *msg++;
pNPRsp->nwkAddr = BUILD_UINT16( msg[0], msg[1] );
if ( pNPRsp->status == ZDP_SUCCESS )
{
msg += 2;
pNPRsp->pwrDesc.AvailablePowerSources = *msg >> 4;
pNPRsp->pwrDesc.PowerMode = *msg++ & 0x0F;
pNPRsp->pwrDesc.CurrentPowerSourceLevel = *msg >> 4;
pNPRsp->pwrDesc.CurrentPowerSource = *msg++ & 0x0F;
}
}
void ZDO_ParseSimpleDescRsp( zdoIncomingMsg_t *inMsg, ZDO_SimpleDescRsp_t *pSimpleDescRsp )
{
uint8 *msg;
msg = inMsg->asdu;
pSimpleDescRsp->status = *msg++;
pSimpleDescRsp->nwkAddr = BUILD_UINT16( msg[0], msg[1] );
msg += sizeof ( uint16 );
msg++; // Skip past the length field.
if ( pSimpleDescRsp->status == ZDP_SUCCESS )
{
ZDO_ParseSimpleDescBuf( msg, &(pSimpleDescRsp->simpleDesc) );
}
}
ZDO_ActiveEndpointRsp_t *ZDO_ParseEPListRsp( zdoIncomingMsg_t *inMsg )
{
ZDO_ActiveEndpointRsp_t *pRsp;
uint8 *msg;
uint8 Status;
uint8 cnt;
msg = inMsg->asdu;
Status = *msg++;
cnt = msg[2];
pRsp = (ZDO_ActiveEndpointRsp_t *)osal_mem_alloc( sizeof( ZDO_ActiveEndpointRsp_t ) + cnt );
if ( pRsp )
{
pRsp->status = Status;
pRsp->nwkAddr = BUILD_UINT16( msg[0], msg[1] );
msg += sizeof( uint16 );
pRsp->cnt = cnt;
msg++; // pass cnt
osal_memcpy( pRsp->epList, msg, cnt );
}
return ( pRsp );
}
void ZDO_ParseServerDiscRsp( zdoIncomingMsg_t *inMsg, ZDO_ServerDiscRsp_t *pRsp )
{
pRsp->status = inMsg->asdu[0];
pRsp->serverMask = BUILD_UINT16( inMsg->asdu[1], inMsg->asdu[2] );
}
ZDO_MgmtLqiRsp_t *ZDO_ParseMgmtLqiRsp( zdoIncomingMsg_t *inMsg )
{
ZDO_MgmtLqiRsp_t *pRsp;
uint8 status;
uint8 startIndex = 0;
uint8 neighborLqiCount = 0;
uint8 neighborLqiEntries = 0;
uint8 *msg;
msg = inMsg->asdu;
status = *msg++;
if ( status == ZSuccess )
{
neighborLqiEntries = *msg++;
startIndex = *msg++;
neighborLqiCount = *msg++;
}
// Allocate a buffer big enough to handle the list.
pRsp = (ZDO_MgmtLqiRsp_t *)osal_mem_alloc(
sizeof( ZDO_MgmtLqiRsp_t ) + (neighborLqiCount * sizeof( neighborLqiItem_t )) );
if ( pRsp )
{
uint8 x;
neighborLqiItem_t *pList = pRsp->list;
pRsp->status = status;
pRsp->neighborLqiEntries = neighborLqiEntries;
pRsp->startIndex = startIndex;
pRsp->neighborLqiCount = neighborLqiCount;
for ( x = 0; x < neighborLqiCount; x++ )
{
osal_cpyExtAddr(pList->extPANId, msg); //Copy extended PAN ID
msg += Z_EXTADDR_LEN;
msg += Z_EXTADDR_LEN; // Throwing away IEEE.
pList->nwkAddr = BUILD_UINT16( msg[0], msg[1] );
msg += 2 + 1 + 1 + 1; // Skip DeviceType, RxOnIdle, Rlationship, PermitJoining and Depth
pList->rxLqi = *msg++;
pList->txQuality = 0; // This is not specified OTA by ZigBee 1.1.
pList++;
}
}
return ( pRsp );
}
ZDO_MgmNwkDiscRsp_t *ZDO_ParseMgmNwkDiscRsp( zdoIncomingMsg_t *inMsg )
{
ZDO_MgmNwkDiscRsp_t *pRsp;
uint8 status;
uint8 networkCount = 0;
uint8 startIndex = 0;
uint8 networkListCount = 0;
uint8 *msg;
msg = inMsg->asdu;
status = *msg++;
if ( status == ZSuccess )
{
networkCount = *msg++;
startIndex = *msg++;
networkListCount = *msg++;
}
// Allocate a buffer big enough to handle the list.
pRsp = (ZDO_MgmNwkDiscRsp_t *)osal_mem_alloc( sizeof( ZDO_MgmNwkDiscRsp_t )
+ (networkListCount * sizeof( mgmtNwkDiscItem_t )) );
if ( pRsp )
{
uint8 x;
mgmtNwkDiscItem_t *pList;
pRsp->status = status;
pRsp->networkCount = networkCount;
pRsp->startIndex = startIndex;
pRsp->networkListCount = networkListCount;
pList = pRsp->list;
for ( x = 0; x < networkListCount; x++ )
{
osal_cpyExtAddr(pList->extendedPANID, msg); //Copy extended PAN ID
pList->PANId = BUILD_UINT16( msg[0], msg[1] );
msg += Z_EXTADDR_LEN;
pList->logicalChannel = *msg++;
pList->stackProfile = (*msg) & 0x0F;
pList->version = (*msg++ >> 4) & 0x0F;
pList->beaconOrder = (*msg) & 0x0F;
pList->superFrameOrder = (*msg++ >> 4) & 0x0F;
pList->permitJoining = *msg++;
pList++;
}
}
return ( pRsp );
}
ZDO_MgmtRtgRsp_t *ZDO_ParseMgmtRtgRsp( zdoIncomingMsg_t *inMsg )
{
ZDO_MgmtRtgRsp_t *pRsp;
uint8 status;
uint8 rtgCount = 0;
uint8 startIndex = 0;
uint8 rtgListCount = 0;
uint8 *msg;
msg = inMsg->asdu;
status = *msg++;
if ( status == ZSuccess )
{
rtgCount = *msg++;
startIndex = *msg++;
rtgListCount = *msg++;
}
// Allocate a buffer big enough to handle the list
pRsp = (ZDO_MgmtRtgRsp_t *)osal_mem_alloc(
sizeof( ZDO_MgmtRtgRsp_t ) + (rtgListCount * sizeof( rtgItem_t )) );
if ( pRsp )
{
uint8 x;
rtgItem_t *pList = pRsp->list;
pRsp->status = status;
pRsp->rtgCount = rtgCount;
pRsp->startIndex = startIndex;
pRsp->rtgListCount = rtgListCount;
for ( x = 0; x < rtgListCount; x++ )
{
pList->dstAddress = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
pList->status = *msg++;
pList->nextHopAddress = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
pList++;
}
}
return ( pRsp );
}
ZDO_MgmtBindRsp_t *ZDO_ParseMgmtBindRsp( zdoIncomingMsg_t *inMsg )
{
ZDO_MgmtBindRsp_t *pRsp;
uint8 status;
uint8 bindingCount = 0;
uint8 startIndex = 0;
uint8 bindingListCount = 0;
uint8 *msg;
msg = inMsg->asdu;
status = *msg++;
if ( status == ZSuccess )
{
bindingCount = *msg++;
startIndex = *msg++;
bindingListCount = *msg++;
}
// Allocate a buffer big enough to handle the list
pRsp = (ZDO_MgmtBindRsp_t *)osal_mem_alloc(
(sizeof ( ZDO_MgmtBindRsp_t ) + (bindingListCount * sizeof( apsBindingItem_t ))) );
if ( pRsp )
{
uint8 x;
apsBindingItem_t *pList = pRsp->list;
pRsp->status = status;
pRsp->bindingCount = bindingCount;
pRsp->startIndex = startIndex;
pRsp->bindingListCount = bindingListCount;
for ( x = 0; x < bindingListCount; x++ )
{
osal_cpyExtAddr( pList->srcAddr, msg );
msg += Z_EXTADDR_LEN;
pList->srcEP = *msg++;
// Get the Cluster ID
pList->clusterID = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
pList->dstAddr.addrMode = *msg++;
if ( pList->dstAddr.addrMode == Addr64Bit )
{
osal_cpyExtAddr( pList->dstAddr.addr.extAddr, msg );
msg += Z_EXTADDR_LEN;
pList->dstEP = *msg++;
}
else
{
pList->dstAddr.addr.shortAddr = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
}
pList++;
}
}
return ( pRsp );
}
ZDO_UserDescRsp_t *ZDO_ParseUserDescRsp( zdoIncomingMsg_t *inMsg )
{
ZDO_UserDescRsp_t *pRsp;
uint8 *msg;
uint8 descLen = 0;
msg = inMsg->asdu;
if ( msg[0] == ZSuccess )
{
descLen = msg[3];
}
pRsp = (ZDO_UserDescRsp_t *)osal_mem_alloc( sizeof ( ZDO_UserDescRsp_t ) + descLen );
if ( pRsp )
{
pRsp->status = msg[0];
pRsp->nwkAddr = BUILD_UINT16( msg[1], msg[2] );
pRsp->length = descLen;
if ( descLen )
{
osal_memcpy( pRsp->desc, &msg[4], descLen );
}
}
return ( pRsp );
}
uint8 ZDO_ParseSimpleDescBuf( uint8 *buf, SimpleDescriptionFormat_t *desc )
{
uint8 num, i;
desc->EndPoint = *buf++;
desc->AppProfId = BUILD_UINT16( buf[0], buf[1] );
buf += 2;
desc->AppDeviceId = BUILD_UINT16( buf[0], buf[1] );
buf += 2;
desc->AppDevVer = *buf >> 4;
desc->Reserved = 0;
buf++;
// move in input cluster list (if any). allocate aligned memory.
num = desc->AppNumInClusters = *buf++;
if ( num )
{
if (!(desc->pAppInClusterList = (uint16 *)osal_mem_alloc(num*sizeof(uint16))))
{
// malloc failed. we're done.
return 1;
}
for (i=0; i<num; ++i)
{
desc->pAppInClusterList[i] = BUILD_UINT16( buf[0], buf[1] );
buf += 2;
}
}
// move in output cluster list (if any). allocate aligned memory.
num = desc->AppNumOutClusters = *buf++;
if (num)
{
if (!(desc->pAppOutClusterList = (uint16 *)osal_mem_alloc(num*sizeof(uint16))))
{
// malloc failed. free input cluster list memory if there is any
if ( desc->pAppInClusterList != NULL )
{
osal_mem_free(desc->pAppInClusterList);
desc->pAppInClusterList = NULL;
}
return 1;
}
for (i=0; i<num; ++i)
{
desc->pAppOutClusterList[i] = BUILD_UINT16( buf[0], buf[1] );
buf += 2;
}
}
return 0;
}
void ZDO_ParseDeviceAnnce( zdoIncomingMsg_t *inMsg, ZDO_DeviceAnnce_t *pAnnce )
{
uint8 *msg;
// Parse incoming message
msg = inMsg->asdu;
pAnnce->nwkAddr = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
osal_cpyExtAddr( pAnnce->extAddr, msg );
msg += Z_EXTADDR_LEN;
pAnnce->capabilities = *msg;
}
ZDO_MgmtNwkUpdateNotify_t *ZDO_ParseMgmtNwkUpdateNotify( zdoIncomingMsg_t *inMsg )
{
uint8 status;
uint32 scannedChannels = 0;
uint16 totalTransmissions = 0;
uint16 transmissionFailures = 0;
uint8 listCount = 0;
uint8 *msg = inMsg->asdu;
ZDO_MgmtNwkUpdateNotify_t *pRsp;
status = *msg++;
if ( status == ZSuccess )
{
scannedChannels = osal_build_uint32( msg, 4 );
msg += 4;
totalTransmissions = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
transmissionFailures = BUILD_UINT16( msg[0], msg[1] );
msg += 2;
listCount = *msg++;
}
pRsp = (ZDO_MgmtNwkUpdateNotify_t *)osal_mem_alloc( sizeof ( ZDO_MgmtNwkUpdateNotify_t ) + listCount );
if ( pRsp )
{
pRsp->status = status;
pRsp->scannedChannels = scannedChannels;
pRsp->totalTransmissions = totalTransmissions;
pRsp->transmissionFailures = transmissionFailures;
pRsp->listCount = listCount;
// Allocate a buffer big enough to handle the list.
if ( listCount > 0 )
{
osal_memcpy( pRsp->energyValues, msg, listCount );
}
}
return ( pRsp );
}
void ZDO_ParseMgmtNwkUpdateReq( zdoIncomingMsg_t *inMsg, ZDO_MgmtNwkUpdateReq_t *pReq )
{
uint8 *msg = inMsg->asdu;
pReq->channelMask = osal_build_uint32( msg, 4 );
msg += 4;
pReq->scanDuration = *msg++;
if ( pReq->scanDuration <= 0x05 )
{
// Request is to scan over channelMask
pReq->scanCount = *msg;
}
else if ( ( pReq->scanDuration == 0xFE ) || ( pReq->scanDuration == 0xFF ) )
{
// Request is to change Channel (0xFE) or apsChannelMask and NwkManagerAddr (0xFF)
pReq->nwkUpdateId = *msg++;
if ( pReq->scanDuration == 0xFF )
{
pReq->nwkManagerAddr = BUILD_UINT16( msg[0], msg[1] );
}
}
}
ZDObject.h
#ifndef ZDOBJECT_H
#define ZDOBJECT_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "NLMEDE.h"
#include "ZDApp.h"
#if defined( ZIGBEE_FRAGMENTATION ) || ( SECURE == 0 )
#define ZDO_MAX_LQI_ITEMS 3
#else
#define ZDO_MAX_LQI_ITEMS 2
#endif
#define ZDO_MAX_NWKDISC_ITEMS 5
#define ZDO_MAX_RTG_ITEMS 10
#define ZDO_MAX_BIND_ITEMS 3
typedef enum
{
MODE_JOIN,
MODE_RESUME,
//MODE_SOFT, // Not supported yet
MODE_HARD,
MODE_REJOIN
} devStartModes_t;
typedef struct
{
uint8 status;
uint16 nwkAddr;
uint8 extAddr[Z_EXTADDR_LEN];
uint8 numAssocDevs;
uint8 startIndex;
uint16 devList[];
} ZDO_NwkIEEEAddrResp_t;
typedef struct
{
uint8 status;
uint16 nwkAddr; // Network address of interest
NodeDescriptorFormat_t nodeDesc;
} ZDO_NodeDescRsp_t;
typedef struct
{
uint8 status;
uint16 nwkAddr; // Network address of interest
NodePowerDescriptorFormat_t pwrDesc;
} ZDO_PowerRsp_t;
typedef struct
{
uint8 status;
uint16 nwkAddr; // Network address of interest
SimpleDescriptionFormat_t simpleDesc;
} ZDO_SimpleDescRsp_t;
typedef struct
{
uint8 status;
uint16 nwkAddr; // Network address of interest
uint8 cnt;
uint8 epList[];
} ZDO_ActiveEndpointRsp_t;
typedef ZDO_ActiveEndpointRsp_t ZDO_MatchDescRsp_t;
typedef struct
{
uint8 status;
uint8 networkCount;
uint8 startIndex;
uint8 networkListCount;
mgmtNwkDiscItem_t list[];
} ZDO_MgmNwkDiscRsp_t;
typedef struct
{
uint8 status;
uint8 neighborLqiEntries;
uint8 startIndex;
uint8 neighborLqiCount;
neighborLqiItem_t list[];
} ZDO_MgmtLqiRsp_t;
typedef struct
{
uint8 status;
uint8 rtgCount;
uint8 startIndex;
uint8 rtgListCount;
rtgItem_t list[];
} ZDO_MgmtRtgRsp_t;
typedef struct
{
uint8 status;
uint8 bindingCount;
uint8 startIndex;
uint8 bindingListCount;
apsBindingItem_t list[];
} ZDO_MgmtBindRsp_t;
typedef struct
{
uint8 status;
uint16 nwkAddr; // Address of interest
uint8 length;
uint8 desc[];
} ZDO_UserDescRsp_t;
typedef struct
{
uint8 status;
uint16 serverMask;
} ZDO_ServerDiscRsp_t;
typedef struct
{
uint8 srcAddress[Z_EXTADDR_LEN];
uint8 srcEndpoint;
uint16 clusterID;
zAddrType_t dstAddress;
uint8 dstEndpoint;
} ZDO_BindUnbindReq_t;
typedef struct
{
uint16 nwkAddr;
uint8 extAddr[Z_EXTADDR_LEN];
uint8 capabilities;
} ZDO_DeviceAnnce_t;
typedef struct
{
uint32 channelMask;
uint8 scanDuration;
uint8 scanCount;
uint8 nwkUpdateId;
int16 nwkManagerAddr;
} ZDO_MgmtNwkUpdateReq_t;
typedef struct
{
uint8 status;
uint32 scannedChannels;
uint16 totalTransmissions;
uint16 transmissionFailures;
uint8 listCount;
uint8 energyValues[];
} ZDO_MgmtNwkUpdateNotify_t;
enum
{
ZDMATCH_REASON_START,
ZDMATCH_REASON_TIMEOUT,
ZDMATCH_REASON_UNBIND_RSP,
ZDMATCH_REASON_BIND_RSP
};
typedef struct
{
ZDEndDeviceBind_t ed1;
ZDEndDeviceBind_t ed2;
uint8 state; // One of the above states
uint8 sending; // 0 - not sent, 1 - unbind, 2 bind - expecting response
uint8 transSeq;
uint8 ed1numMatched;
uint16 *ed1Matched;
uint8 ed2numMatched;
uint16 *ed2Matched;
} ZDMatchEndDeviceBind_t;
extern ZDMatchEndDeviceBind_t *matchED;
extern void ZDO_Init( void );
extern void ZDO_StartDevice( byte logicalType, devStartModes_t startMode,
byte beaconOrder, byte superframeOrder );
extern void ZDO_UpdateNwkStatus( devStates_t state );
extern void ZDO_MatchEndDeviceBind( ZDEndDeviceBind_t *bindReq );
extern byte ZDO_AnyClusterMatches(
byte ACnt, uint16 *AList, byte BCnt, uint16 *BList );
extern void ZDO_ProcessNodeDescReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessPowerDescReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessSimpleDescReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessActiveEPReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMatchDescReq( zdoIncomingMsg_t *inMsg );
void ZDO_ProcessServerDiscRsp( zdoIncomingMsg_t *inMsg );
void ZDO_ProcessServerDiscReq( zdoIncomingMsg_t *inMsg );
extern uint8 ZDMatchSendState( uint8 reason, uint8 status, uint8 TransSeq );
extern void ZDO_EndDeviceTimeoutCB( void );
extern void ZDO_ProcessMgmNwkDiscRsp( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMgmtNwkDiscReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_FinishProcessingMgmtNwkDiscReq( void );
extern void ZDO_ParseMgmtNwkUpdateReq( zdoIncomingMsg_t *inMsg, ZDO_MgmtNwkUpdateReq_t *pReq );
extern void ZDO_ProcessMgmtLqiReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMgmtRtgReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMgmtBindReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMgmtBindRsp( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMgmtDirectJoinReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMgmtLeaveReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessMgmtPermitJoinReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessUserDescReq( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessUserDescSet( zdoIncomingMsg_t *inMsg );
extern void ZDO_ProcessDeviceAnnce( zdoIncomingMsg_t *inMsg );
extern void ZDO_BuildSimpleDescBuf( uint8 *buf, SimpleDescriptionFormat_t *desc );
extern uint8 ZDO_ParseSimpleDescBuf( uint8 *buf, SimpleDescriptionFormat_t *desc );
extern void ZDO_UpdateAddrManager( uint16 nwkAddr, uint8 *extAddr );
extern ZDO_NwkIEEEAddrResp_t *ZDO_ParseAddrRsp( zdoIncomingMsg_t *inMsg );
extern void ZDO_ParseNodeDescRsp( zdoIncomingMsg_t *inMsg, ZDO_NodeDescRsp_t *pNDRsp );
extern void ZDO_ParsePowerDescRsp( zdoIncomingMsg_t *inMsg, ZDO_PowerRsp_t *pNPRsp );
extern void ZDO_ParseSimpleDescRsp( zdoIncomingMsg_t *inMsg, ZDO_SimpleDescRsp_t *pSimpleDescRsp );
extern ZDO_ActiveEndpointRsp_t *ZDO_ParseEPListRsp( zdoIncomingMsg_t *inMsg );
#define ZDO_ParseBindRsp(a) ((uint8)(*(a->asdu)))
extern ZDO_MgmNwkDiscRsp_t *ZDO_ParseMgmNwkDiscRsp( zdoIncomingMsg_t *inMsg );
extern ZDO_MgmtLqiRsp_t *ZDO_ParseMgmtLqiRsp( zdoIncomingMsg_t *inMsg );
extern ZDO_MgmtRtgRsp_t *ZDO_ParseMgmtRtgRsp( zdoIncomingMsg_t *inMsg );
extern ZDO_MgmtBindRsp_t *ZDO_ParseMgmtBindRsp( zdoIncomingMsg_t *inMsg );
#define ZDO_ParseMgmtDirectJoinRsp(a) ((uint8)(*(a->asdu)))
#define ZDO_ParseMgmtLeaveRsp(a) ((uint8)(*(a->asdu)))
#define ZDO_ParseMgmtPermitJoinRsp(a) ((uint8)(*(a->asdu)))
extern ZDO_UserDescRsp_t *ZDO_ParseUserDescRsp( zdoIncomingMsg_t *inMsg );
extern void ZDO_ParseServerDiscRsp( zdoIncomingMsg_t *inMsg, ZDO_ServerDiscRsp_t *pRsp );
extern void ZDO_ParseEndDeviceBindReq( zdoIncomingMsg_t *inMsg, ZDEndDeviceBind_t *bindReq );
extern void ZDO_ParseBindUnbindReq( zdoIncomingMsg_t *inMsg, ZDO_BindUnbindReq_t *pReq );
extern void ZDO_ProcessBindUnbindReq( zdoIncomingMsg_t *inMsg, ZDO_BindUnbindReq_t *pReq );
#define ZDO_ParseUserDescConf(a) ((uint8)(*(a->asdu)))
extern void ZDO_ParseDeviceAnnce( zdoIncomingMsg_t *inMsg, ZDO_DeviceAnnce_t *pAnnce );
extern ZDO_MgmtNwkUpdateNotify_t *ZDO_ParseMgmtNwkUpdateNotify( zdoIncomingMsg_t *inMsg );
#ifdef __cplusplus
}
#endif
#endif /* ZDOBJECT_H */
ZDProfile.c
#include "ZComdef.h"
#include "OSAL.h"
#include "AF.h"
#include "NLMEDE.h"
#include "nwk_util.h"
#include "APS.h"
#include "AddrMgr.h"
#include "ZDConfig.h"
#include "ZDProfile.h"
#include "ZDObject.h"
#include "ZDNwkMgr.h"
#if defined( LCD_SUPPORTED )
#include "OnBoard.h"
#endif
#include "nwk_util.h"
#if defined( MT_ZDO_FUNC )
#include "MT_ZDO.h"
#endif
#define ZADDR_TO_AFADDR( pZADDR, AFADDR ) { \
(AFADDR).endPoint = ZDP_AF_ENDPOINT; \
(AFADDR).addrMode = (afAddrMode_t)(pZADDR)->addrMode; \
(AFADDR).addr.shortAddr = (pZADDR)->addr.shortAddr; \
}
#define FillAndSendBuffer( TRANSSEQ, ADDR, ID, LEN, BUF ) { \
afStatus_t stat; \
ZDP_TmpBuf = (BUF)+1; \
stat = fillAndSend( (TRANSSEQ), (ADDR), (ID), (LEN) ); \
osal_mem_free( (BUF) ); \
ZDP_TmpBuf = ZDP_Buf+1; \
return stat; \
}
#define FillAndSendTxOptions( TRANSSEQ, ADDR, ID, LEN, TxO ) { \
afStatus_t stat; \
ZDP_TxOptions = (TxO); \
stat = fillAndSend( (TRANSSEQ), (ADDR), (ID), (LEN) ); \
ZDP_TxOptions = AF_TX_OPTIONS_NONE; \
return stat; \
}
#define FillAndSendBufferTxOptions( TRANSSEQ, ADDR, ID, LEN, BUF, TxO ) { \
afStatus_t stat; \
ZDP_TmpBuf = (BUF)+1; \
ZDP_TxOptions = (TxO); \
stat = fillAndSend( (TRANSSEQ), (ADDR), (ID), (LEN) ); \
osal_mem_free( (BUF) ); \
ZDP_TmpBuf = ZDP_Buf+1; \
ZDP_TxOptions = AF_TX_OPTIONS_NONE; \
return stat; \
}
#define ZDP_BUF_SZ 80
CONST byte ZDP_AF_ENDPOINT = 0;
typedef struct
{
void *next;
uint8 taskID;
uint16 clusterID;
} ZDO_MsgCB_t;
byte ZDP_TransID = 0;
extern endPointDesc_t ZDApp_epDesc;
static afStatus_t fillAndSend( uint8 *transSeq, zAddrType_t *addr, cId_t clusterID, byte len );
uint8 ZDO_SendMsgCBs( zdoIncomingMsg_t *inMsg );
void zdpProcessAddrReq( zdoIncomingMsg_t *inMsg );
static uint8 ZDP_Buf[ ZDP_BUF_SZ ];
static uint8 *ZDP_TmpBuf = ZDP_Buf+1;
byte ZDP_TxOptions = AF_TX_OPTIONS_NONE;
ZDO_MsgCB_t *zdoMsgCBs = (ZDO_MsgCB_t *)NULL;
typedef void (*pfnZDPMsgProcessor)( zdoIncomingMsg_t *inMsg );
typedef struct
{
uint16 clusterID;
pfnZDPMsgProcessor pFn;
} zdpMsgProcItem_t;
CONST zdpMsgProcItem_t zdpMsgProcs[] =
{
#if ( RFD_RCVC_ALWAYS_ON==TRUE ) || ( ZG_BUILD_RTR_TYPE )
// These aren't processed by sleeping end devices.
{ NWK_addr_req, zdpProcessAddrReq },
{ Device_annce, ZDO_ProcessDeviceAnnce },
#endif
{ IEEE_addr_req, zdpProcessAddrReq },
{ Node_Desc_req, ZDO_ProcessNodeDescReq },
{ Power_Desc_req, ZDO_ProcessPowerDescReq },
{ Simple_Desc_req, ZDO_ProcessSimpleDescReq },
{ Active_EP_req, ZDO_ProcessActiveEPReq },
{ Match_Desc_req, ZDO_ProcessMatchDescReq },
#if defined ( ZDO_MGMT_NWKDISC_RESPONSE )
{ Mgmt_NWK_Disc_req, ZDO_ProcessMgmtNwkDiscReq },
#endif
#if defined ( ZDO_MGMT_LQI_RESPONSE ) && ( ZG_BUILD_RTR_TYPE )
{ Mgmt_Lqi_req, ZDO_ProcessMgmtLqiReq },
#endif
#if defined ( ZDO_MGMT_RTG_RESPONSE ) && ( ZG_BUILD_RTR_TYPE )
{ Mgmt_Rtg_req, ZDO_ProcessMgmtRtgReq },
#endif
#if defined ( ZDO_MGMT_BIND_RESPONSE ) && defined ( REFLECTOR )
{ Mgmt_Bind_req, ZDO_ProcessMgmtBindReq },
#endif
#if defined ( ZDO_MGMT_JOINDIRECT_RESPONSE ) && ( ZG_BUILD_RTR_TYPE )
{ Mgmt_Direct_Join_req, ZDO_ProcessMgmtDirectJoinReq },
#endif
#if defined ( ZDO_MGMT_LEAVE_RESPONSE )
{ Mgmt_Leave_req, ZDO_ProcessMgmtLeaveReq },
#endif
#if defined ( ZDO_MGMT_PERMIT_JOIN_RESPONSE ) && ( ZG_BUILD_RTR_TYPE )
{ Mgmt_Permit_Join_req, ZDO_ProcessMgmtPermitJoinReq },
#endif
#if defined ( ZDO_USERDESC_RESPONSE )
{ User_Desc_req, ZDO_ProcessUserDescReq },
#endif
#if defined ( ZDO_USERDESCSET_RESPONSE )
{ User_Desc_set, ZDO_ProcessUserDescSet },
#endif
#if defined ( ZDO_SERVERDISC_RESPONSE )
{ Server_Discovery_req, ZDO_ProcessServerDiscReq },
#endif
{0xFFFF, NULL} // Last
};
static afStatus_t fillAndSend( uint8 *transSeq, zAddrType_t *addr, cId_t clusterID, byte len )
{
afAddrType_t afAddr;
osal_memset( &afAddr, 0, sizeof(afAddrType_t) );
ZADDR_TO_AFADDR( addr, afAddr );
*(ZDP_TmpBuf-1) = *transSeq;
return AF_DataRequest( &afAddr, &ZDApp_epDesc, clusterID,
(uint16)(len+1), (uint8*)(ZDP_TmpBuf-1),
transSeq, ZDP_TxOptions, AF_DEFAULT_RADIUS );
}
afStatus_t ZDP_SendData( uint8 *TransSeq, zAddrType_t *dstAddr, uint16 cmd,
byte len, uint8 *buf, byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte cnt = len;
while ( cnt-- )
{
*pBuf++ = *buf++;
}
FillAndSendTxOptions( TransSeq, dstAddr, cmd, len, ((SecurityEnable) ? AF_EN_SECURITY : 0) );
}
afStatus_t ZDP_NWKAddrOfInterestReq( zAddrType_t *dstAddr, uint16 nwkAddr,
byte cmd, byte SecurityEnable )
{
(void)SecurityEnable; // Intentionally unreferenced parameter
ZDP_TmpBuf[0] = LO_UINT16( nwkAddr );
ZDP_TmpBuf[1] = HI_UINT16( nwkAddr );
return fillAndSend( &ZDP_TransID, dstAddr, cmd, 2 );
}
afStatus_t ZDP_NwkAddrReq( uint8 *IEEEAddress, byte ReqType,
byte StartIndex, byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = Z_EXTADDR_LEN + 1 + 1; // IEEEAddress + ReqType + StartIndex.
zAddrType_t dstAddr;
(void)SecurityEnable; // Intentionally unreferenced parameter
if ( osal_ExtAddrEqual( saveExtAddr, IEEEAddress ) == FALSE )
{
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVRXON;
}
else
{
dstAddr.addrMode = Addr16Bit;
dstAddr.addr.shortAddr = ZDAppNwkAddr.addr.shortAddr;
}
pBuf = osal_cpyExtAddr( pBuf, IEEEAddress );
*pBuf++ = ReqType;
*pBuf++ = StartIndex;
return fillAndSend( &ZDP_TransID, &dstAddr, NWK_addr_req, len );
}
afStatus_t ZDP_IEEEAddrReq( uint16 shortAddr, byte ReqType,
byte StartIndex, byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = 2 + 1 + 1; // shortAddr + ReqType + StartIndex.
zAddrType_t dstAddr;
(void)SecurityEnable; // Intentionally unreferenced parameter
dstAddr.addrMode = (afAddrMode_t)Addr16Bit;
dstAddr.addr.shortAddr = shortAddr;
*pBuf++ = LO_UINT16( shortAddr );
*pBuf++ = HI_UINT16( shortAddr );
*pBuf++ = ReqType;
*pBuf++ = StartIndex;
return fillAndSend( &ZDP_TransID, &dstAddr, IEEE_addr_req, len );
}
afStatus_t ZDP_MatchDescReq( zAddrType_t *dstAddr, uint16 nwkAddr,
uint16 ProfileID,
byte NumInClusters, cId_t *InClusterList,
byte NumOutClusters, cId_t *OutClusterList,
byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
// nwkAddr+ProfileID+NumInClusters+NumOutClusters.
byte i, len = 2 + 2 + 1 + 1; // nwkAddr+ProfileID+NumInClusters+NumOutClusters.
(void)SecurityEnable; // Intentionally unreferenced parameter
len += (NumInClusters + NumOutClusters) * sizeof(uint16);
if ( len >= ZDP_BUF_SZ-1 )
{
return afStatus_MEM_FAIL;
}
// The spec changed in Zigbee 2007 (2.4.3.1.7.1) to not allow sending
// this command to 0xFFFF. So, here we will filter this and replace
// with 0xFFFD to only send to devices with RX ON. This includes the
// network address of interest.
if ( ((dstAddr->addrMode == AddrBroadcast) || (dstAddr->addrMode == Addr16Bit))
&& (dstAddr->addr.shortAddr == NWK_BROADCAST_SHORTADDR_DEVALL) )
{
dstAddr->addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVRXON;
}
if ( nwkAddr == NWK_BROADCAST_SHORTADDR_DEVALL )
{
nwkAddr = NWK_BROADCAST_SHORTADDR_DEVRXON;
}
*pBuf++ = LO_UINT16( nwkAddr ); // NWKAddrOfInterest
*pBuf++ = HI_UINT16( nwkAddr );
*pBuf++ = LO_UINT16( ProfileID ); // Profile ID
*pBuf++ = HI_UINT16( ProfileID );
*pBuf++ = NumInClusters; // Input cluster list
if ( NumInClusters )
{
for (i=0; i<NumInClusters; ++i) {
*pBuf++ = LO_UINT16( InClusterList[i] );
*pBuf++ = HI_UINT16( InClusterList[i] );
}
}
*pBuf++ = NumOutClusters; // Output cluster list
if ( NumOutClusters )
{
for (i=0; i<NumOutClusters; ++i) {
*pBuf++ = LO_UINT16( OutClusterList[i] );
*pBuf++ = HI_UINT16( OutClusterList[i] );
}
}
return fillAndSend( &ZDP_TransID, dstAddr, Match_Desc_req, len );
}
afStatus_t ZDP_SimpleDescReq( zAddrType_t *dstAddr, uint16 nwkAddr,
byte endPoint, byte SecurityEnable )
{
(void)SecurityEnable; // Intentionally unreferenced parameter
ZDP_TmpBuf[0] = LO_UINT16( nwkAddr );
ZDP_TmpBuf[1] = HI_UINT16( nwkAddr );
ZDP_TmpBuf[2] = endPoint;
return fillAndSend( &ZDP_TransID, dstAddr, Simple_Desc_req, 3 );
}
afStatus_t ZDP_UserDescSet( zAddrType_t *dstAddr, uint16 nwkAddr,
UserDescriptorFormat_t *UserDescriptor,
byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = (UserDescriptor->len < AF_MAX_USER_DESCRIPTOR_LEN) ?
UserDescriptor->len : AF_MAX_USER_DESCRIPTOR_LEN;
byte addrLen = 2;
(void)SecurityEnable; // Intentionally unreferenced parameter
*pBuf++ = LO_UINT16( nwkAddr );
*pBuf++ = HI_UINT16( nwkAddr );
*pBuf++ = len;
addrLen = 3;
pBuf = osal_memcpy( pBuf, UserDescriptor->desc, len );
osal_memset( pBuf, AF_USER_DESCRIPTOR_FILL, AF_MAX_USER_DESCRIPTOR_LEN-len );
return fillAndSend( &ZDP_TransID, dstAddr, User_Desc_set, (AF_MAX_USER_DESCRIPTOR_LEN + addrLen) );
}
afStatus_t ZDP_ServerDiscReq( uint16 serverMask, byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
zAddrType_t dstAddr;
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVRXON;
*pBuf++ = LO_UINT16( serverMask );
*pBuf = HI_UINT16( serverMask );
FillAndSendTxOptions( &ZDP_TransID, &dstAddr, Server_Discovery_req, 2,
((SecurityEnable) ? AF_EN_SECURITY : AF_TX_OPTIONS_NONE) );
}
afStatus_t ZDP_DeviceAnnce( uint16 nwkAddr, uint8 *IEEEAddr,
byte capabilities, byte SecurityEnable )
{
zAddrType_t dstAddr;
uint8 len;
(void)SecurityEnable; // Intentionally unreferenced parameter
dstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVRXON;
ZDP_TmpBuf[0] = LO_UINT16( nwkAddr );
ZDP_TmpBuf[1] = HI_UINT16( nwkAddr );
osal_cpyExtAddr( &ZDP_TmpBuf[2], IEEEAddr );
len = 2 + Z_EXTADDR_LEN;
ZDP_TmpBuf[10] = capabilities;
len++;
return fillAndSend( &ZDP_TransID, &dstAddr, Device_annce, len );
}
void zdpProcessAddrReq( zdoIncomingMsg_t *inMsg )
{
associated_devices_t *pAssoc;
uint8 reqType;
uint16 aoi = INVALID_NODE_ADDR;
uint8 *ieee = NULL;
reqType = inMsg->asdu[(inMsg->clusterID == NWK_addr_req) ? Z_EXTADDR_LEN : sizeof( uint16 ) ];
if ( inMsg->clusterID == NWK_addr_req )
{
ieee = inMsg->asdu;
if ( osal_ExtAddrEqual( saveExtAddr, ieee ) )
{
aoi = ZDAppNwkAddr.addr.shortAddr;
}
// Handle response for sleeping end devices
else if ( (ZSTACK_ROUTER_BUILD)
&& (((pAssoc = AssocGetWithExt( ieee )) != NULL)
&& (pAssoc->nodeRelation == CHILD_RFD)) )
{
aoi = pAssoc->shortAddr;
if ( reqType != ZDP_ADDR_REQTYPE_SINGLE )
reqType = 0xFF; // Force Invalid
}
}
else // if ( inMsg->clusterID == IEEE_addr_req )
{
aoi = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );
if ( aoi == ZDAppNwkAddr.addr.shortAddr )
{
ieee = saveExtAddr;
}
else if ( (ZSTACK_ROUTER_BUILD)
&& (((pAssoc = AssocGetWithShort( aoi )) != NULL)
&& (pAssoc->nodeRelation == CHILD_RFD)) )
{
AddrMgrEntry_t addrEntry;
addrEntry.user = ADDRMGR_USER_DEFAULT;
addrEntry.index = pAssoc->addrIdx;
if ( AddrMgrEntryGet( &addrEntry ) )
{
ieee = addrEntry.extAddr;
}
if ( reqType != ZDP_ADDR_REQTYPE_SINGLE )
reqType = 0xFF; // Force Invalid
}
}
if ( ((aoi != INVALID_NODE_ADDR) && (ieee != NULL)) || (inMsg->wasBroadcast == FALSE) )
{
uint8 stat;
uint8 *pBuf = ZDP_TmpBuf;
// Status + IEEE-Addr + Nwk-Addr.
uint8 len = 1 + Z_EXTADDR_LEN + 2;
// If aoi and iee are both setup, we found results
if ( (aoi != INVALID_NODE_ADDR) && (ieee != NULL) )
{
stat = ((reqType == ZDP_ADDR_REQTYPE_SINGLE) || (reqType == ZDP_ADDR_REQTYPE_EXTENDED))
? ZDP_SUCCESS : ZDP_INVALID_REQTYPE;
}
else
{
// not found and the req was unicast to this device
stat = ZDP_DEVICE_NOT_FOUND;
// Fill in the missing field with this device's address
if ( inMsg->clusterID == NWK_addr_req )
{
aoi = ZDAppNwkAddr.addr.shortAddr;
}
else
{
ieee = saveExtAddr;
}
}
*pBuf++ = stat;
pBuf = osal_cpyExtAddr( pBuf, ieee );
*pBuf++ = LO_UINT16( aoi );
*pBuf++ = HI_UINT16( aoi );
if ( ZSTACK_ROUTER_BUILD )
{
if ( (reqType == ZDP_ADDR_REQTYPE_EXTENDED) && (aoi == ZDAppNwkAddr.addr.shortAddr)
&& (stat == ZDP_SUCCESS) )
{
uint8 cnt = 0;
uint16 *list = AssocMakeList( &cnt );
if ( list != NULL )
{
byte idx = inMsg->asdu[(((inMsg->clusterID == NWK_addr_req) ? Z_EXTADDR_LEN : sizeof( uint16 )) + 1)];
uint16 *pList = list + idx;
// NumAssocDev field is only present on success.
if ( cnt > idx )
{
cnt -= idx;
len += (cnt * sizeof( uint16 ));
}
else
{
cnt = 0;
}
*pBuf++ = cnt;
len++;
// StartIndex field is only present if NumAssocDev field is non-zero.
*pBuf++ = idx;
len++;
while ( cnt != 0 )
{
*pBuf++ = LO_UINT16( *pList );
*pBuf++ = HI_UINT16( *pList );
pList++;
cnt--;
}
osal_mem_free( (uint8 *)list );
}
else
{
// NumAssocDev field is only present on success.
*pBuf++ = 0;
len++;
}
}
}
ZDP_TxOptions = AF_MSG_ACK_REQUEST;
fillAndSend( &(inMsg->TransSeq), &(inMsg->srcAddr), (cId_t)(inMsg->clusterID | ZDO_RESPONSE_BIT), len );
ZDP_TxOptions = AF_TX_OPTIONS_NONE;
}
}
afStatus_t ZDP_NodeDescMsg( zdoIncomingMsg_t *inMsg,
uint16 nwkAddr, NodeDescriptorFormat_t *pNodeDesc )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len;
len = 1 + 2 + 13; // Status + nwkAddr + Node descriptor
*pBuf++ = ZDP_SUCCESS;
*pBuf++ = LO_UINT16( nwkAddr );
*pBuf++ = HI_UINT16( nwkAddr );
*pBuf++ = (byte)((pNodeDesc->ComplexDescAvail << 3) |
(pNodeDesc->UserDescAvail << 4) |
(pNodeDesc->LogicalType & 0x07));
*pBuf++ = (byte)((pNodeDesc->FrequencyBand << 3) | (pNodeDesc->APSFlags & 0x07));
*pBuf++ = pNodeDesc->CapabilityFlags;
*pBuf++ = pNodeDesc->ManufacturerCode[0];
*pBuf++ = pNodeDesc->ManufacturerCode[1];
*pBuf++ = pNodeDesc->MaxBufferSize;
*pBuf++ = pNodeDesc->MaxInTransferSize[0];
*pBuf++ = pNodeDesc->MaxInTransferSize[1];
*pBuf++ = LO_UINT16( pNodeDesc->ServerMask );
*pBuf++ = HI_UINT16( pNodeDesc->ServerMask );
*pBuf++ = pNodeDesc->MaxOutTransferSize[0];
*pBuf++ = pNodeDesc->MaxOutTransferSize[1];
*pBuf = pNodeDesc->DescriptorCapability;
return fillAndSend( &(inMsg->TransSeq), &(inMsg->srcAddr), Node_Desc_rsp, len );
}
afStatus_t ZDP_PowerDescMsg( zdoIncomingMsg_t *inMsg,
uint16 nwkAddr, NodePowerDescriptorFormat_t *pPowerDesc )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = 1 + 2 + 2; // Status + nwkAddr + Node Power descriptor.
*pBuf++ = ZDP_SUCCESS;
*pBuf++ = LO_UINT16( nwkAddr );
*pBuf++ = HI_UINT16( nwkAddr );
*pBuf++ = (byte)((pPowerDesc->AvailablePowerSources << 4)
| (pPowerDesc->PowerMode & 0x0F));
*pBuf++ = (byte)((pPowerDesc->CurrentPowerSourceLevel << 4)
| (pPowerDesc->CurrentPowerSource & 0x0F));
return fillAndSend( &(inMsg->TransSeq), &(inMsg->srcAddr), Power_Desc_rsp, len );
}
afStatus_t ZDP_SimpleDescMsg( zdoIncomingMsg_t *inMsg, byte Status,
SimpleDescriptionFormat_t *pSimpleDesc )
{
uint8 *pBuf = ZDP_TmpBuf;
uint8 i, len;
if ( Status == ZDP_SUCCESS && pSimpleDesc )
{
// Status + NWKAddrOfInterest + desc length + empty simple descriptor.
len = 1 + 2 + 1 + 8;
len += (pSimpleDesc->AppNumInClusters + pSimpleDesc->AppNumOutClusters) * sizeof ( uint16 );
}
else
{
len = 1 + 2 + 1; // Status + desc length
}
if ( len >= ZDP_BUF_SZ-1 )
{
return afStatus_MEM_FAIL;
}
*pBuf++ = Status;
*pBuf++ = LO_UINT16( ZDAppNwkAddr.addr.shortAddr );
*pBuf++ = HI_UINT16( ZDAppNwkAddr.addr.shortAddr );
if ( len > 4 )
{
*pBuf++ = len - 4; // Simple descriptor length
*pBuf++ = pSimpleDesc->EndPoint;
*pBuf++ = LO_UINT16( pSimpleDesc->AppProfId );
*pBuf++ = HI_UINT16( pSimpleDesc->AppProfId );
*pBuf++ = LO_UINT16( pSimpleDesc->AppDeviceId );
*pBuf++ = HI_UINT16( pSimpleDesc->AppDeviceId );
*pBuf++ = (byte)(pSimpleDesc->AppDevVer << 4);
*pBuf++ = pSimpleDesc->AppNumInClusters;
if ( pSimpleDesc->AppNumInClusters )
{
for (i=0; i<pSimpleDesc->AppNumInClusters; ++i)
{
*pBuf++ = LO_UINT16( pSimpleDesc->pAppInClusterList[i] );
*pBuf++ = HI_UINT16( pSimpleDesc->pAppInClusterList[i] );
}
}
*pBuf++ = pSimpleDesc->AppNumOutClusters;
if ( pSimpleDesc->AppNumOutClusters )
{
for (i=0; i<pSimpleDesc->AppNumOutClusters; ++i)
{
*pBuf++ = LO_UINT16( pSimpleDesc->pAppOutClusterList[i] );
*pBuf++ = HI_UINT16( pSimpleDesc->pAppOutClusterList[i] );
}
}
}
else
{
*pBuf = 0; // Description Length = 0;
}
return fillAndSend( &(inMsg->TransSeq), &(inMsg->srcAddr), Simple_Desc_rsp, len );
}
afStatus_t ZDP_EPRsp( uint16 MsgType, byte TransSeq, zAddrType_t *dstAddr,
byte Status, uint16 nwkAddr, byte Count,
uint8 *pEPList,
byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = 1 + 2 + 1; // Status + nwkAddr + endpoint/interface count.
byte txOptions;
(void)SecurityEnable; // Intentionally unreferenced parameter
if ( MsgType == Match_Desc_rsp )
txOptions = AF_MSG_ACK_REQUEST;
else
txOptions = 0;
*pBuf++ = Status;
*pBuf++ = LO_UINT16( nwkAddr );
*pBuf++ = HI_UINT16( nwkAddr );
*pBuf++ = Count; // Endpoint/Interface count
if ( Count )
{
len += Count;
osal_memcpy( pBuf, pEPList, Count );
}
FillAndSendTxOptions( &TransSeq, dstAddr, MsgType, len, txOptions );
}
ZStatus_t ZDP_UserDescRsp( byte TransSeq, zAddrType_t *dstAddr,
uint16 nwkAddrOfInterest, UserDescriptorFormat_t *userDesc,
byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = 1 + 2 + 1; // Status + nwkAddr + descriptor length.
(void)SecurityEnable; // Intentionally unreferenced parameter
len += userDesc->len;
*pBuf++ = ZSUCCESS;
*pBuf++ = LO_UINT16( nwkAddrOfInterest );
*pBuf++ = HI_UINT16( nwkAddrOfInterest );
*pBuf++ = userDesc->len;
osal_memcpy( pBuf, userDesc->desc, userDesc->len );
return (ZStatus_t)fillAndSend( &TransSeq, dstAddr, User_Desc_rsp, len );
}
ZStatus_t ZDP_ServerDiscRsp( byte transID, zAddrType_t *dstAddr, byte status,
uint16 aoi, uint16 serverMask, byte SecurityEnable )
{
const byte len = 1 + 2; // status + aoi + mask.
uint8 *pBuf = ZDP_TmpBuf;
ZStatus_t stat;
// Intentionally unreferenced parameters
(void)aoi;
(void)SecurityEnable;
*pBuf++ = status;
*pBuf++ = LO_UINT16( serverMask );
*pBuf++ = HI_UINT16( serverMask );
ZDP_TxOptions = AF_MSG_ACK_REQUEST;
stat = fillAndSend( &transID, dstAddr, Server_Discovery_rsp, len );
ZDP_TxOptions = AF_TX_OPTIONS_NONE;
return ( stat );
}
afStatus_t ZDP_GenericRsp( byte TransSeq, zAddrType_t *dstAddr,
byte status, uint16 aoi, uint16 rspID, byte SecurityEnable )
{
uint8 len;
(void)SecurityEnable; // Intentionally unreferenced parameter
ZDP_TmpBuf[0] = status;
ZDP_TmpBuf[1] = LO_UINT16( aoi );
ZDP_TmpBuf[2] = HI_UINT16( aoi );
// Length byte
ZDP_TmpBuf[3] = 0;
len = 4;
return fillAndSend( &TransSeq, dstAddr, rspID, len );
}
afStatus_t ZDP_EndDeviceBindReq( zAddrType_t *dstAddr,
uint16 LocalCoordinator,
byte endPoint,
uint16 ProfileID,
byte NumInClusters, cId_t *InClusterList,
byte NumOutClusters, cId_t *OutClusterList,
byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
uint8 i, len;
uint8 *ieeeAddr;
(void)SecurityEnable; // Intentionally unreferenced parameter
// LocalCoordinator + SrcExtAddr + ep + ProfileID + NumInClusters + NumOutClusters.
len = 2 + Z_EXTADDR_LEN + 1 + 2 + 1 + 1;
len += (NumInClusters + NumOutClusters) * sizeof ( uint16 );
if ( len >= ZDP_BUF_SZ-1 )
{
return afStatus_MEM_FAIL;
}
if ( LocalCoordinator != NLME_GetShortAddr() )
{
return afStatus_INVALID_PARAMETER;
}
*pBuf++ = LO_UINT16( LocalCoordinator );
*pBuf++ = HI_UINT16( LocalCoordinator );
ieeeAddr = NLME_GetExtAddr();
pBuf = osal_cpyExtAddr( pBuf, ieeeAddr );
*pBuf++ = endPoint;
*pBuf++ = LO_UINT16( ProfileID ); // Profile ID
*pBuf++ = HI_UINT16( ProfileID );
*pBuf++ = NumInClusters; // Input cluster list
for ( i = 0; i < NumInClusters; ++i )
{
*pBuf++ = LO_UINT16(InClusterList[i]);
*pBuf++ = HI_UINT16(InClusterList[i]);
}
*pBuf++ = NumOutClusters; // Output cluster list
for ( i = 0; i < NumOutClusters; ++i )
{
*pBuf++ = LO_UINT16(OutClusterList[i]);
*pBuf++ = HI_UINT16(OutClusterList[i]);
}
return fillAndSend( &ZDP_TransID, dstAddr, End_Device_Bind_req, len );
}
afStatus_t ZDP_BindUnbindReq( uint16 BindOrUnbind, zAddrType_t *dstAddr,
uint8 *SourceAddr, byte SrcEndPoint,
cId_t ClusterID,
zAddrType_t *destinationAddr, byte DstEndPoint,
byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len;
(void)SecurityEnable; // Intentionally unreferenced parameter
// SourceAddr + SrcEPIntf + ClusterID + addrMode.
len = Z_EXTADDR_LEN + 1 + sizeof( cId_t ) + sizeof( uint8 );
if ( destinationAddr->addrMode == Addr64Bit )
len += Z_EXTADDR_LEN + 1; // +1 for DstEPIntf
else if ( destinationAddr->addrMode == AddrGroup )
len += sizeof ( uint16 );
pBuf = osal_cpyExtAddr( pBuf, SourceAddr );
*pBuf++ = SrcEndPoint;
*pBuf++ = LO_UINT16( ClusterID );
*pBuf++ = HI_UINT16( ClusterID );
*pBuf++ = destinationAddr->addrMode;
if ( destinationAddr->addrMode == Addr64Bit )
{
pBuf = osal_cpyExtAddr( pBuf, destinationAddr->addr.extAddr );
*pBuf = DstEndPoint;
}
else if ( destinationAddr->addrMode == AddrGroup )
{
*pBuf++ = LO_UINT16( destinationAddr->addr.shortAddr );
*pBuf++ = HI_UINT16( destinationAddr->addr.shortAddr );
}
FillAndSendTxOptions( &ZDP_TransID, dstAddr, BindOrUnbind, len, AF_MSG_ACK_REQUEST );
}
afStatus_t ZDP_MgmtNwkDiscReq( zAddrType_t *dstAddr,
uint32 ScanChannels,
byte ScanDuration,
byte StartIndex,
byte SecurityEnable )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = sizeof( uint32 )+1+1; // ScanChannels + ScanDuration + StartIndex.
(void)SecurityEnable; // Intentionally unreferenced parameter
pBuf = osal_buffer_uint32( pBuf, ScanChannels );
*pBuf++ = ScanDuration;
*pBuf = StartIndex;
return fillAndSend( &ZDP_TransID, dstAddr, Mgmt_NWK_Disc_req, len );
}
afStatus_t ZDP_MgmtDirectJoinReq( zAddrType_t *dstAddr,
uint8 *deviceAddr,
byte capInfo,
byte SecurityEnable )
{
(void)SecurityEnable; // Intentionally unreferenced parameter
osal_cpyExtAddr( ZDP_TmpBuf, deviceAddr );
ZDP_TmpBuf[Z_EXTADDR_LEN] = capInfo;
return fillAndSend( &ZDP_TransID, dstAddr, Mgmt_Direct_Join_req, (Z_EXTADDR_LEN + 1) );
}
afStatus_t ZDP_MgmtPermitJoinReq( zAddrType_t *dstAddr, byte duration,
byte TcSignificance, byte SecurityEnable )
{
(void)SecurityEnable; // Intentionally unreferenced parameter
// Build buffer
ZDP_TmpBuf[ZDP_MGMT_PERMIT_JOIN_REQ_DURATION] = duration;
ZDP_TmpBuf[ZDP_MGMT_PERMIT_JOIN_REQ_TC_SIG] = TcSignificance;
// Send the message
return fillAndSend( &ZDP_TransID, dstAddr, Mgmt_Permit_Join_req,
ZDP_MGMT_PERMIT_JOIN_REQ_SIZE );
}
afStatus_t ZDP_MgmtLeaveReq( zAddrType_t *dstAddr, uint8 *IEEEAddr, uint8 RemoveChildren,
uint8 Rejoin, uint8 SecurityEnable )
{
(void)SecurityEnable; // Intentionally unreferenced parameter
osal_cpyExtAddr( ZDP_TmpBuf, IEEEAddr );
ZDP_TmpBuf[Z_EXTADDR_LEN] = 0;
if ( RemoveChildren == TRUE )
{
ZDP_TmpBuf[Z_EXTADDR_LEN] |= ZDP_MGMT_LEAVE_REQ_RC;
}
if ( Rejoin == TRUE )
{
ZDP_TmpBuf[Z_EXTADDR_LEN] |= ZDP_MGMT_LEAVE_REQ_REJOIN;
}
return fillAndSend( &ZDP_TransID, dstAddr, Mgmt_Leave_req, (Z_EXTADDR_LEN + 1) );
}
afStatus_t ZDP_MgmtNwkUpdateReq( zAddrType_t *dstAddr,
uint32 ChannelMask,
uint8 ScanDuration,
uint8 ScanCount,
uint8 NwkUpdateId,
uint16 NwkManagerAddr )
{
uint8 *pBuf = ZDP_TmpBuf;
byte len = sizeof( uint32 ) + 1; // ChannelMask + ScanDuration
pBuf = osal_buffer_uint32( pBuf, ChannelMask );
*pBuf++ = ScanDuration;
if ( ScanDuration <= 0x05 )
{
// Request is to scan over channelMask
len += sizeof( uint8 );
*pBuf++ = ScanCount;
}
else if ( ( ScanDuration == 0xFE ) || ( ScanDuration == 0xFF ) )
{
// Request is to change Channel (0xFE) or apsChannelMask and NwkManagerAddr (0xFF)
len += sizeof( uint8 );
*pBuf++ = NwkUpdateId;
if ( ScanDuration == 0xFF )
{
len += sizeof( uint16 );
*pBuf++ = LO_UINT16( NwkManagerAddr );
*pBuf++ = HI_UINT16( NwkManagerAddr );
}
}
return fillAndSend( &ZDP_TransID, dstAddr, Mgmt_NWK_Update_req, len );
}
afStatus_t ZDP_MgmtNwkDiscRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte NetworkCount,
byte StartIndex,
byte NetworkListCount,
networkDesc_t *NetworkList,
byte SecurityEnable )
{
uint8 *buf;
uint8 *pBuf;
byte len = 1+1+1+1; // Status + NetworkCount + StartIndex + NetworkCountList.
byte idx;
(void)SecurityEnable; // Intentionally unreferenced parameter
len += (NetworkListCount * ( ZDP_NETWORK_EXTENDED_DISCRIPTOR_SIZE - 2 ));
buf = osal_mem_alloc( len+1 );
if ( buf == NULL )
{
return afStatus_MEM_FAIL;
}
pBuf = buf+1;
*pBuf++ = Status;
*pBuf++ = NetworkCount;
*pBuf++ = StartIndex;
*pBuf++ = NetworkListCount;
for ( idx = 0; idx < NetworkListCount; idx++ )
{
osal_cpyExtAddr( pBuf, NetworkList->extendedPANID);
pBuf += Z_EXTADDR_LEN;
*pBuf++ = NetworkList->logicalChannel; // LogicalChannel
*pBuf = NetworkList->stackProfile; // Stack profile
*pBuf++ |= (byte)(NetworkList->version << 4); // ZigBee Version
*pBuf = BEACON_ORDER_NO_BEACONS; // Beacon Order
*pBuf++ |= (uint8)(BEACON_ORDER_NO_BEACONS << 4); // Superframe Order
if ( NetworkList->chosenRouter != INVALID_NODE_ADDR )
{
*pBuf++ = TRUE; // Permit Joining
}
else
{
*pBuf++ = FALSE;
}
NetworkList = NetworkList->nextDesc; // Move to next list entry
}
FillAndSendBuffer( &TransSeq, dstAddr, Mgmt_NWK_Disc_rsp, len, buf );
}
ZStatus_t ZDP_MgmtLqiRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte NeighborLqiEntries,
byte StartIndex,
byte NeighborLqiCount,
ZDP_MgmtLqiItem_t* NeighborList,
byte SecurityEnable )
{
ZDP_MgmtLqiItem_t* list = NeighborList;
uint8 *buf, *pBuf;
byte len, x;
(void)SecurityEnable; // Intentionally unreferenced parameter
if ( ZSuccess != Status )
{
ZDP_TmpBuf[0] = Status;
return fillAndSend( &TransSeq, dstAddr, Mgmt_Lqi_rsp, 1 );
}
// (Status + NeighborLqiEntries + StartIndex + NeighborLqiCount) +
// neighbor LQI data.
len = (1 + 1 + 1 + 1) + (NeighborLqiCount * ZDP_MGMTLQI_EXTENDED_SIZE);
buf = osal_mem_alloc( len+1 );
if ( buf == NULL )
{
return afStatus_MEM_FAIL;
}
pBuf = buf+1;
*pBuf++ = Status;
*pBuf++ = NeighborLqiEntries;
*pBuf++ = StartIndex;
*pBuf++ = NeighborLqiCount;
for ( x = 0; x < NeighborLqiCount; x++ )
{
osal_cpyExtAddr( pBuf, list->extPanID); // Extended PanID
pBuf += Z_EXTADDR_LEN;
// EXTADDR
pBuf = osal_cpyExtAddr( pBuf, list->extAddr );
// NWKADDR
*pBuf++ = LO_UINT16( list->nwkAddr );
*pBuf++ = HI_UINT16( list->nwkAddr );
// DEVICETYPE
*pBuf = list->devType;
// RXONIDLE
*pBuf |= (uint8)(list->rxOnIdle << 2);
// RELATIONSHIP
*pBuf++ |= (uint8)(list->relation << 4);
// PERMITJOINING
*pBuf++ = (uint8)(list->permit);
// DEPTH
*pBuf++ = list->depth;
// LQI
*pBuf++ = list->lqi;
list++; // next list entry
}
FillAndSendBuffer( &TransSeq, dstAddr, Mgmt_Lqi_rsp, len, buf );
}
ZStatus_t ZDP_MgmtRtgRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte RoutingTableEntries,
byte StartIndex,
byte RoutingListCount,
rtgItem_t *RoutingTableList,
byte SecurityEnable )
{
uint8 *buf;
uint8 *pBuf;
// Status + RoutingTableEntries + StartIndex + RoutingListCount.
byte len = 1 + 1 + 1 + 1;
byte x;
(void)SecurityEnable; // Intentionally unreferenced parameter
// Add an array for Routing List data
len += (RoutingListCount * ZDP_ROUTINGENTRY_SIZE);
buf = osal_mem_alloc( (short)(len+1) );
if ( buf == NULL )
{
return afStatus_MEM_FAIL;
}
pBuf = buf+1;
*pBuf++ = Status;
*pBuf++ = RoutingTableEntries;
*pBuf++ = StartIndex;
*pBuf++ = RoutingListCount;
for ( x = 0; x < RoutingListCount; x++ )
{
*pBuf++ = LO_UINT16( RoutingTableList->dstAddress ); // Destination Address
*pBuf++ = HI_UINT16( RoutingTableList->dstAddress );
*pBuf++ = RoutingTableList->status;
*pBuf++ = LO_UINT16( RoutingTableList->nextHopAddress ); // Next hop
*pBuf++ = HI_UINT16( RoutingTableList->nextHopAddress );
RoutingTableList++; // Move to next list entry
}
FillAndSendBuffer( &TransSeq, dstAddr, Mgmt_Rtg_rsp, len, buf );
}
ZStatus_t ZDP_MgmtBindRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte BindingTableEntries,
byte StartIndex,
byte BindingTableListCount,
apsBindingItem_t *BindingTableList,
byte SecurityEnable )
{
uint8 *buf;
uint8 *pBuf;
uint8 maxLen; // maxLen is the maximum packet length to allocate enough memory space
uint8 len; // Actual length varies due to different addrMode
uint8 x;
byte extZdpBindEntrySize = ZDP_BINDINGENTRY_SIZE + 1 + 1; // One more byte for cluserID and DstAddrMode
byte shortZdpBindEntrySize = ZDP_BINDINGENTRY_SIZE + 1 + 1 + 2 - 8 - 1; // clusterID + DstAddrMode + shortAddr - ExtAddr - DstEndpoint
(void)SecurityEnable; // Intentionally unreferenced parameter
// Status + BindingTableEntries + StartIndex + BindingTableListCount.
maxLen = 1 + 1 + 1 + 1;
maxLen += (BindingTableListCount * extZdpBindEntrySize ); //max length
buf = osal_mem_alloc( maxLen + 1 ); // +1 for transaction ID
if ( buf == NULL )
{
return afStatus_MEM_FAIL;
}
pBuf = buf+1;
*pBuf++ = Status;
*pBuf++ = BindingTableEntries;
*pBuf++ = StartIndex;
*pBuf++ = BindingTableListCount;
// Initial length = Status + BindingTableEntries + StartIndex + BindingTableListCount.
// length += ZDP_BINDINGENTRY_SIZE -- Version 1.0
// extZdpBindEntrySize -- Version 1.1 extended address mode
// shortZdpBindEntrySize -- Version 1.1 group address mode
len = 1 + 1 + 1 + 1;
for ( x = 0; x < BindingTableListCount; x++ )
{
pBuf = osal_cpyExtAddr( pBuf, BindingTableList->srcAddr );
*pBuf++ = BindingTableList->srcEP;
// Cluster ID
*pBuf++ = LO_UINT16( BindingTableList->clusterID );
*pBuf++ = HI_UINT16( BindingTableList->clusterID );
*pBuf++ = BindingTableList->dstAddr.addrMode;
if ( BindingTableList->dstAddr.addrMode == Addr64Bit )
{
len += extZdpBindEntrySize;
pBuf = osal_cpyExtAddr( pBuf, BindingTableList->dstAddr.addr.extAddr );
*pBuf++ = BindingTableList->dstEP;
}
else
{
len += shortZdpBindEntrySize;
*pBuf++ = LO_UINT16( BindingTableList->dstAddr.addr.shortAddr );
*pBuf++ = HI_UINT16( BindingTableList->dstAddr.addr.shortAddr );
}
BindingTableList++; // Move to next list entry
}
FillAndSendBuffer( &TransSeq, dstAddr, Mgmt_Bind_rsp, len, buf );
}
afStatus_t ZDP_MgmtNwkUpdateNotify( uint8 TransSeq, zAddrType_t *dstAddr,
uint8 status, uint32 scannedChannels,
uint16 totalTransmissions, uint16 transmissionFailures,
uint8 listCount, uint8 *energyValues, uint8 txOptions,
uint8 securityEnable )
{
uint8 *buf;
uint8 *pBuf;
uint8 len;
(void)securityEnable; // Intentionally unreferenced parameter
// Status + ScannedChannels + totalTransmissions + transmissionFailures + ListCount + energyValues
len = 1 + 4 + 2 + 2 + 1 + listCount;
buf = osal_mem_alloc( len+1 ); // +1 for transaction ID
if ( buf == NULL )
{
return afStatus_MEM_FAIL;
}
pBuf = buf+1;
*pBuf++ = status;
pBuf = osal_buffer_uint32( pBuf, scannedChannels );
*pBuf++ = LO_UINT16( totalTransmissions );
*pBuf++ = HI_UINT16( totalTransmissions );
*pBuf++ = LO_UINT16( transmissionFailures );
*pBuf++ = HI_UINT16( transmissionFailures );
*pBuf++ = listCount;
if ( listCount > 0 )
osal_memcpy( pBuf, energyValues, listCount );
FillAndSendBufferTxOptions( &TransSeq, dstAddr, Mgmt_NWK_Update_notify, len, buf, txOptions );
}
ZStatus_t ZDO_RegisterForZDOMsg( uint8 taskID, uint16 clusterID )
{
ZDO_MsgCB_t *pList;
ZDO_MsgCB_t *pLast;
ZDO_MsgCB_t *pNew;
// Look for duplicate
pList = pLast = zdoMsgCBs;
while ( pList )
{
if ( pList->taskID == taskID && pList->clusterID == clusterID )
return ( ZSuccess );
pLast = pList;
pList = (ZDO_MsgCB_t *)pList->next;
}
// Add to the list
pNew = (ZDO_MsgCB_t *)osal_mem_alloc( sizeof ( ZDO_MsgCB_t ) );
if ( pNew )
{
pNew->taskID = taskID;
pNew->clusterID = clusterID;
pNew->next = NULL;
if ( zdoMsgCBs )
{
pLast->next = pNew;
}
else
zdoMsgCBs = pNew;
return ( ZSuccess );
}
else
return ( ZMemError );
}
ZStatus_t ZDO_RemoveRegisteredCB( uint8 taskID, uint16 clusterID )
{
ZDO_MsgCB_t *pList;
ZDO_MsgCB_t *pLast = NULL;
pList = zdoMsgCBs;
while ( pList )
{
if ( pList->taskID == taskID && pList->clusterID == clusterID )
{
if ( pLast )
{
// remove this one from the linked list
pLast->next = pList->next;
}
else if ( pList->next )
{
// remove the first one from the linked list
zdoMsgCBs = pList->next;
}
else
{
// remove the only item from the list
zdoMsgCBs = (ZDO_MsgCB_t *)NULL;
}
osal_mem_free( pList );
return ( ZSuccess );
}
pLast = pList;
pList = pList->next;
}
return ( ZFailure );
}
uint8 ZDO_SendMsgCBs( zdoIncomingMsg_t *inMsg )
{
uint8 ret = FALSE;
ZDO_MsgCB_t *pList = zdoMsgCBs;
while ( pList )
{
if ( pList->clusterID == inMsg->clusterID )
{
zdoIncomingMsg_t *msgPtr;
// Send the address to the task
msgPtr = (zdoIncomingMsg_t *)osal_msg_allocate( sizeof( zdoIncomingMsg_t ) + inMsg->asduLen );
if ( msgPtr )
{
// copy struct
osal_memcpy( msgPtr, inMsg, sizeof( zdoIncomingMsg_t ));
if ( inMsg->asduLen )
{
msgPtr->asdu = (byte*)(((byte*)msgPtr) + sizeof( zdoIncomingMsg_t ));
osal_memcpy( msgPtr->asdu, inMsg->asdu, inMsg->asduLen );
}
msgPtr->hdr.event = ZDO_CB_MSG;
osal_msg_send( pList->taskID, (uint8 *)msgPtr );
ret = TRUE;
}
}
pList = (ZDO_MsgCB_t *)pList->next;
}
return ( ret );
}
void ZDP_IncomingData( afIncomingMSGPacket_t *pData )
{
uint8 x = 0;
uint8 handled;
zdoIncomingMsg_t inMsg;
inMsg.srcAddr.addrMode = Addr16Bit;
inMsg.srcAddr.addr.shortAddr = pData->srcAddr.addr.shortAddr;
inMsg.wasBroadcast = pData->wasBroadcast;
inMsg.clusterID = pData->clusterId;
inMsg.SecurityUse = pData->SecurityUse;
inMsg.asduLen = pData->cmd.DataLength-1;
inMsg.asdu = pData->cmd.Data+1;
inMsg.TransSeq = pData->cmd.Data[0];
inMsg.macDestAddr = pData->macDestAddr;
handled = ZDO_SendMsgCBs( &inMsg );
#if (defined MT_ZDO_CB_FUNC)
#if !defined MT_TASK
if (zgZdoDirectCB)
#endif
{
MT_ZdoDirectCB( pData, &inMsg );
}
#endif
while ( zdpMsgProcs[x].clusterID != 0xFFFF )
{
if ( zdpMsgProcs[x].clusterID == inMsg.clusterID )
{
zdpMsgProcs[x].pFn( &inMsg );
return;
}
x++;
}
// Handle unhandled messages
if ( !handled )
ZDApp_InMsgCB( &inMsg );
}
ZDProfile.h
#ifndef ZDPROFILE_H
#define ZDPROFILE_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "ZComDef.h"
#include "NLMEDE.h"
#include "AF.h"
#include "ZDConfig.h"
#define ZDO_EP 0 // Endpoint of ZDO
#define ZDO_PROFILE_ID 0
// IEEE_addr_req request types
#define ZDP_ADDR_REQTYPE_SINGLE 0
#define ZDP_ADDR_REQTYPE_EXTENDED 1
// ZDO Status Values
#define ZDP_SUCCESS 0x00 // Operation completed successfully
#define ZDP_INVALID_REQTYPE 0x80 // The supplied request type was invalid
#define ZDP_DEVICE_NOT_FOUND 0x81 // Reserved
#define ZDP_INVALID_EP 0x82 // Invalid endpoint value
#define ZDP_NOT_ACTIVE 0x83 // Endpoint not described by a simple desc.
#define ZDP_NOT_SUPPORTED 0x84 // Optional feature not supported
#define ZDP_TIMEOUT 0x85 // Operation has timed out
#define ZDP_NO_MATCH 0x86 // No match for end device bind
#define ZDP_NO_ENTRY 0x88 // Unbind request failed, no entry
#define ZDP_NO_DESCRIPTOR 0x89 // Child descriptor not available
#define ZDP_INSUFFICIENT_SPACE 0x8a // Insufficient space to support operation
#define ZDP_NOT_PERMITTED 0x8b // Not in proper state to support operation
#define ZDP_TABLE_FULL 0x8c // No table space to support operation
#define ZDP_NOT_AUTHORIZED 0x8d // Permissions indicate request not authorized
#define ZDP_BINDING_TABLE_FULL 0x8e // No binding table space to support operation
#define ZDP_NETWORK_DISCRIPTOR_SIZE 8
#define ZDP_NETWORK_EXTENDED_DISCRIPTOR_SIZE 14
#define ZDP_RTG_DISCRIPTOR_SIZE 5
#define ZDP_BIND_DISCRIPTOR_SIZE 19
// Mgmt_Permit_Join_req fields
#define ZDP_MGMT_PERMIT_JOIN_REQ_DURATION 0
#define ZDP_MGMT_PERMIT_JOIN_REQ_TC_SIG 1
#define ZDP_MGMT_PERMIT_JOIN_REQ_SIZE 2
// Mgmt_Leave_req fields
#define ZDP_MGMT_LEAVE_REQ_REJOIN 1 << 7
#define ZDP_MGMT_LEAVE_REQ_RC 1 << 6 // Remove Children
// Mgmt_Lqi_rsp - (neighbor table) device type
#define ZDP_MGMT_DT_COORD 0x0
#define ZDP_MGMT_DT_ROUTER 0x1
#define ZDP_MGMT_DT_ENDDEV 0x2
// Mgmt_Lqi_rsp - (neighbor table) relationship
#define ZDP_MGMT_REL_PARENT 0x0
#define ZDP_MGMT_REL_CHILD 0x1
#define ZDP_MGMT_REL_SIBLING 0x2
#define ZDP_MGMT_REL_UNKNOWN 0x3
// Mgmt_Lqi_rsp - (neighbor table) unknown boolean value
#define ZDP_MGMT_BOOL_UNKNOWN 0x02
// ZDO Cluster IDs
#define ZDO_RESPONSE_BIT_V1_0 ((uint8)0x80)
#define ZDO_RESPONSE_BIT ((uint16)0x8000)
#define NWK_addr_req ((uint16)0x0000)
#define IEEE_addr_req ((uint16)0x0001)
#define Node_Desc_req ((uint16)0x0002)
#define Power_Desc_req ((uint16)0x0003)
#define Simple_Desc_req ((uint16)0x0004)
#define Active_EP_req ((uint16)0x0005)
#define Match_Desc_req ((uint16)0x0006)
#define NWK_addr_rsp (NWK_addr_req | ZDO_RESPONSE_BIT)
#define IEEE_addr_rsp (IEEE_addr_req | ZDO_RESPONSE_BIT)
#define Node_Desc_rsp (Node_Desc_req | ZDO_RESPONSE_BIT)
#define Power_Desc_rsp (Power_Desc_req | ZDO_RESPONSE_BIT)
#define Simple_Desc_rsp (Simple_Desc_req | ZDO_RESPONSE_BIT)
#define Active_EP_rsp (Active_EP_req | ZDO_RESPONSE_BIT)
#define Match_Desc_rsp (Match_Desc_req | ZDO_RESPONSE_BIT)
#define Complex_Desc_req ((uint16)0x0010)
#define User_Desc_req ((uint16)0x0011)
#define Discovery_Cache_req ((uint16)0x0012)
#define Device_annce ((uint16)0x0013)
#define User_Desc_set ((uint16)0x0014)
#define Server_Discovery_req ((uint16)0x0015)
#define Complex_Desc_rsp (Complex_Desc_req | ZDO_RESPONSE_BIT)
#define User_Desc_rsp (User_Desc_req | ZDO_RESPONSE_BIT)
#define Discovery_Cache_rsp (Discovery_Cache_req | ZDO_RESPONSE_BIT)
#define User_Desc_conf (User_Desc_set | ZDO_RESPONSE_BIT)
#define Server_Discovery_rsp (Server_Discovery_req | ZDO_RESPONSE_BIT)
#define End_Device_Bind_req ((uint16)0x0020)
#define Bind_req ((uint16)0x0021)
#define Unbind_req ((uint16)0x0022)
#define Bind_rsp (Bind_req | ZDO_RESPONSE_BIT)
#define End_Device_Bind_rsp (End_Device_Bind_req | ZDO_RESPONSE_BIT)
#define Unbind_rsp (Unbind_req | ZDO_RESPONSE_BIT)
#define Mgmt_NWK_Disc_req ((uint16)0x0030)
#define Mgmt_Lqi_req ((uint16)0x0031)
#define Mgmt_Rtg_req ((uint16)0x0032)
#define Mgmt_Bind_req ((uint16)0x0033)
#define Mgmt_Leave_req ((uint16)0x0034)
#define Mgmt_Direct_Join_req ((uint16)0x0035)
#define Mgmt_Permit_Join_req ((uint16)0x0036)
#define Mgmt_NWK_Update_req ((uint16)0x0038)
#define Mgmt_NWK_Disc_rsp (Mgmt_NWK_Disc_req | ZDO_RESPONSE_BIT)
#define Mgmt_Lqi_rsp (Mgmt_Lqi_req | ZDO_RESPONSE_BIT)
#define Mgmt_Rtg_rsp (Mgmt_Rtg_req | ZDO_RESPONSE_BIT)
#define Mgmt_Bind_rsp (Mgmt_Bind_req | ZDO_RESPONSE_BIT)
#define Mgmt_Leave_rsp (Mgmt_Leave_req | ZDO_RESPONSE_BIT)
#define Mgmt_Direct_Join_rsp (Mgmt_Direct_Join_req | ZDO_RESPONSE_BIT)
#define Mgmt_Permit_Join_rsp (Mgmt_Permit_Join_req | ZDO_RESPONSE_BIT)
#define Mgmt_NWK_Update_notify (Mgmt_NWK_Update_req | ZDO_RESPONSE_BIT)
#define ZDP_BINDINGENTRY_SIZE 19
typedef struct
{
osal_event_hdr_t hdr;
zAddrType_t srcAddr;
uint8 wasBroadcast;
cId_t clusterID;
uint8 SecurityUse;
uint8 TransSeq;
uint8 asduLen;
uint16 macDestAddr;
uint8 *asdu;
} zdoIncomingMsg_t;
// This structure is used to build the Mgmt Network Discover Response
typedef struct
{
uint8 extendedPANID[Z_EXTADDR_LEN]; // The extended PAN ID
uint16 PANId; // The network PAN ID
uint8 logicalChannel; // Network's channel
uint8 stackProfile; // Network's profile
uint8 version; // Network's Zigbee version
uint8 beaconOrder; // Beacon Order
uint8 superFrameOrder;
uint8 permitJoining; // PermitJoining. 1 or 0
} mgmtNwkDiscItem_t;
// This structure is used to build the Mgmt LQI Response
typedef struct
{
uint16 nwkAddr; // device's short address
uint16 PANId; // The neighbor device's PAN ID
uint8 extPANId[Z_EXTADDR_LEN]; // The neighbor device's Extended PanID
uint8 txQuality; // Transmit quality
uint8 rxLqi; // Receive LQI
} neighborLqiItem_t;
#define ZDP_NEIGHBORLQI_SIZE 12
// This structure is used to build the Mgmt_Lqi_rsp
typedef struct
{
uint16 panID; // PAN Id
uint8 extPanID[Z_EXTADDR_LEN];// Extended Pan ID
uint8 extAddr[Z_EXTADDR_LEN]; // Extended address
uint16 nwkAddr; // Network address
uint8 devType; // Device type
uint8 rxOnIdle; // RxOnWhenIdle
uint8 relation; // Relationship
uint8 permit; // Permit joining
uint8 depth; // Depth
uint8 lqi; // LQI
} ZDP_MgmtLqiItem_t;
// devType, rxOnIdle, relation, are all packed into 1 byte: 18-2=16.
#define ZDP_MGMTLQI_SIZE 15
#define ZDP_MGMTLQI_EXTENDED_SIZE 22 // One extra byte for permitJointing, also with extended PanID instead of PanID 15+8-2+1 = 22
// This structure is used to build the Mgmt Routing Response
// NOTICE: this structure must match "rtgEntry_t" in rtg.h
typedef struct
{
uint16 dstAddress; // Destination short address
uint16 nextHopAddress; // next hop short address
uint8 expiryTime; // expiration time - not used for response
uint8 status; // route entry status
uint8 options;
} rtgItem_t;
// expiryTime is not packed & sent OTA.
#define ZDP_ROUTINGENTRY_SIZE 5
typedef struct
{
uint8 TransSeq;
byte SecurityUse;
uint16 srcAddr;
uint16 localCoordinator;
uint8 ieeeAddr[Z_EXTADDR_LEN];
uint8 endpoint;
uint16 profileID;
uint8 numInClusters;
uint16 *inClusters;
uint8 numOutClusters;
uint16 *outClusters;
} ZDEndDeviceBind_t;
extern byte ZDP_TransID;
extern byte ZDP_TxOptions;
extern afStatus_t ZDP_SendData( uint8 *transSeq, zAddrType_t *dstAddr, uint16 cmd, byte len,
uint8 *buf, byte SecurityEnable );
#define ZDP_NodeDescReq( dstAddr, NWKAddrOfInterest, SecurityEnable ) \
ZDP_NWKAddrOfInterestReq( dstAddr, \
NWKAddrOfInterest, Node_Desc_req, SecurityEnable )
#define ZDP_PowerDescReq( dstAddr, NWKAddrOfInterest, SecurityEnable ) \
ZDP_NWKAddrOfInterestReq( dstAddr, \
NWKAddrOfInterest, Power_Desc_req, SecurityEnable )
#define ZDP_ActiveEPReq( dstAddr, NWKAddrOfInterest, SecurityEnable ) \
ZDP_NWKAddrOfInterestReq( dstAddr, \
NWKAddrOfInterest, Active_EP_req, SecurityEnable )
#define ZDP_ComplexDescReq( dstAddr, NWKAddrOfInterest, SecurityEnable ) \
ZDP_NWKAddrOfInterestReq( dstAddr, \
NWKAddrOfInterest, Complex_Desc_req, SecurityEnable )
#define ZDP_UserDescReq( dstAddr, NWKAddrOfInterest, SecurityEnable ) \
ZDP_NWKAddrOfInterestReq( dstAddr, \
NWKAddrOfInterest, User_Desc_req, SecurityEnable )
#define ZDP_BindReq( dstAddr, SourceAddr, SrcEP, \
ClusterID, DestinationAddr, DstEP, SecurityEnable ) \
ZDP_BindUnbindReq( Bind_req, dstAddr, \
SourceAddr, SrcEP, ClusterID, \
DestinationAddr, DstEP, SecurityEnable )
#define ZDP_UnbindReq( dstAddr, SourceAddr, SrcEP, \
ClusterID, DestinationAddr, DstEP, SecurityEnable ) \
ZDP_BindUnbindReq( Unbind_req, dstAddr, \
SourceAddr, SrcEP, ClusterID, \
DestinationAddr, DstEP, SecurityEnable )
#define ZDP_MgmtLqiReq( dstAddr, StartIndex, SecurityEnable ) \
ZDP_SendData( &ZDP_TransID, dstAddr, Mgmt_Lqi_req, 1, &StartIndex, SecurityEnable )
#define ZDP_MgmtRtgReq( dstAddr, StartIndex, SecurityEnable ) \
ZDP_SendData( &ZDP_TransID, dstAddr, Mgmt_Rtg_req, 1, &StartIndex, SecurityEnable )
#define ZDP_MgmtBindReq( dstAddr, StartIndex, SecurityEnable ) \
ZDP_SendData( &ZDP_TransID, dstAddr, Mgmt_Bind_req, 1, &StartIndex, SecurityEnable )
#ifdef REMOVE_BY_LAF
#define ZDP_NWKAddrRsp( TransSeq, dstAddr, Status, IEEEAddrRemoteDev, ReqType, nwkAddr, NumAssocDev, \
StartIndex, NWKAddrAssocDevList, SecurityEnable ) \
ZDP_AddrRsp( NWK_addr_rsp, TransSeq, dstAddr, Status, \
IEEEAddrRemoteDev, ReqType, nwkAddr, NumAssocDev, StartIndex, \
NWKAddrAssocDevList, SecurityEnable )
#define ZDP_IEEEAddrRsp( TransSeq, dstAddr, Status, IEEEAddrRemoteDev, ReqType, nwkAddr, NumAssocDev, \
StartIndex, NWKAddrAssocDevList, SecurityEnable ) \
ZDP_AddrRsp( IEEE_addr_rsp, TransSeq, dstAddr, Status, \
IEEEAddrRemoteDev, ReqType, nwkAddr, NumAssocDev, StartIndex, \
NWKAddrAssocDevList, SecurityEnable )
#endif
#define ZDP_ActiveEPRsp( TransSeq, dstAddr, Status, nwkAddr, Count, \
pEPList, SecurityEnable ) \
ZDP_EPRsp( Active_EP_rsp, TransSeq, dstAddr, Status, \
nwkAddr, Count, pEPList, SecurityEnable )
#define ZDP_MatchDescRsp( TransSeq, dstAddr, Status, nwkAddr, Count, \
pEPList, SecurityEnable ) \
ZDP_EPRsp( Match_Desc_rsp, TransSeq, dstAddr, Status, \
nwkAddr, Count, pEPList, SecurityEnable )
#define ZDP_ComplexDescRsp( dstAddr, SecurityEnable ) \
ZDP_GenericRsp( dstAddr, Complex_Desc_rsp, SecurityEnable )
#define ZDP_UserDescConf( TransSeq, dstAddr, Status, SecurityEnable ) \
ZDP_SendData( &TransSeq, dstAddr, User_Desc_conf, 1, &Status, SecurityEnable )
#define ZDP_EndDeviceBindRsp( TransSeq, dstAddr, Status, SecurityEnable ) \
ZDP_SendData( &TransSeq, dstAddr, End_Device_Bind_rsp, 1, &Status, SecurityEnable )
#define ZDP_BindRsp( TransSeq, dstAddr, Status, SecurityEnable ) \
ZDP_SendData( &TransSeq, dstAddr, Bind_rsp, 1, &Status, SecurityEnable )
#define ZDP_UnbindRsp( TransSeq, dstAddr, Status, SecurityEnable ) \
ZDP_SendData( &TransSeq, dstAddr, Unbind_rsp, 1, &Status, SecurityEnable )
#define ZDP_MgmtLeaveRsp( TransSeq, dstAddr, Status, SecurityEnable ) \
ZDP_SendData( &TransSeq, dstAddr, Mgmt_Leave_rsp, 1, &Status, SecurityEnable )
#define ZDP_MgmtPermitJoinRsp( TransSeq, dstAddr, Status, SecurityEnable ) \
ZDP_SendData( &TransSeq, dstAddr, Mgmt_Permit_Join_rsp, 1, &Status, SecurityEnable )
#define ZDP_MgmtDirectJoinRsp( TransSeq, dstAddr, Status, SecurityEnable ) \
ZDP_SendData( &TransSeq, dstAddr, Mgmt_Direct_Join_rsp, 1, &Status, SecurityEnable )
extern afStatus_t ZDP_NWKAddrOfInterestReq( zAddrType_t *dstAddr,
uint16 nwkAddr, byte cmd, byte SecurityEnable );
extern afStatus_t ZDP_NwkAddrReq( uint8 *IEEEAddress, byte ReqType,
byte StartIndex, byte SecurityEnable );
extern afStatus_t ZDP_IEEEAddrReq( uint16 shortAddr, byte ReqType,
byte StartIndex, byte SecurityEnable );
extern afStatus_t ZDP_MatchDescReq( zAddrType_t *dstAddr, uint16 nwkAddr,
uint16 ProfileID,
byte NumInClusters, uint16 *InClusterList,
byte NumOutClusters, uint16 *OutClusterList,
byte SecurityEnable );
extern afStatus_t ZDP_SimpleDescReq( zAddrType_t *dstAddr, uint16 nwkAddr,
byte ep, byte SecurityEnable );
extern afStatus_t ZDP_UserDescSet( zAddrType_t *dstAddr, uint16 nwkAddr,
UserDescriptorFormat_t *UserDescriptor,
byte SecurityEnable );
afStatus_t ZDP_ServerDiscReq( uint16 serverMask, byte SecurityEnable );
extern afStatus_t ZDP_DeviceAnnce( uint16 nwkAddr, uint8 *IEEEAddr,
byte capabilities, byte SecurityEnable );
extern afStatus_t ZDP_EndDeviceBindReq( zAddrType_t *dstAddr,
uint16 LocalCoordinator,
byte ep,
uint16 ProfileID,
byte NumInClusters, uint16 *InClusterList,
byte NumOutClusters, uint16 *OutClusterList,
byte SecurityEnable );
extern afStatus_t ZDP_BindUnbindReq( uint16 BindOrUnbind, zAddrType_t *dstAddr,
uint8 *SourceAddr, byte SrcEP,
cId_t ClusterID,
zAddrType_t *DestinationAddr, byte DstEP,
byte SecurityEnable );
extern afStatus_t ZDP_MgmtNwkDiscReq( zAddrType_t *dstAddr,
uint32 ScanChannels,
byte ScanDuration,
byte StartIndex,
byte SecurityEnable );
extern afStatus_t ZDP_MgmtDirectJoinReq( zAddrType_t *dstAddr,
uint8 *deviceAddr,
byte capInfo,
byte SecurityEnable );
extern afStatus_t ZDP_MgmtLeaveReq( zAddrType_t *dstAddr,
uint8 *IEEEAddr,
uint8 RemoveChildren,
uint8 Rejoin,
uint8 SecurityEnable );
extern afStatus_t ZDP_MgmtPermitJoinReq( zAddrType_t *dstAddr,
byte duration,
byte TcSignificance,
byte SecurityEnable );
extern afStatus_t ZDP_MgmtNwkUpdateReq( zAddrType_t *dstAddr,
uint32 ChannelMask,
uint8 ScanDuration,
uint8 ScanCount,
uint8 NwkUpdateId,
uint16 NwkManagerAddr );
afStatus_t ZDP_AddrRsp( byte cId, byte seq, zAddrType_t *dst, byte stat,
uint8 *ieee, byte reqType, uint16 nwkAddr, byte devCnt, byte strtIdx,
uint16 *devAddr, byte secOpt );
extern afStatus_t ZDP_NodeDescMsg( zdoIncomingMsg_t *inMsg,
uint16 nwkAddr, NodeDescriptorFormat_t *pNodeDesc );
extern afStatus_t ZDP_PowerDescMsg( zdoIncomingMsg_t *inMsg,
uint16 nwkAddr, NodePowerDescriptorFormat_t *pPowerDesc );
extern afStatus_t ZDP_SimpleDescMsg( zdoIncomingMsg_t *inMsg,
byte Status, SimpleDescriptionFormat_t *pSimpleDesc );
extern afStatus_t ZDP_EPRsp( uint16 MsgType, byte TransSeq, zAddrType_t *dstAddr, byte Status,
uint16 nwkAddr, byte Count, uint8 *pEPList,
byte SecurityEnable );
extern afStatus_t ZDP_GenericRsp( byte TransSeq, zAddrType_t *dstAddr,
byte status, uint16 aoi, uint16 rspID, byte SecurityEnable );
extern afStatus_t ZDP_MgmtNwkDiscRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte NetworkCount,
byte StartIndex,
byte NetworkCountList,
networkDesc_t *NetworkList,
byte SecurityEnable );
extern ZStatus_t ZDP_MgmtLqiRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte NeighborLqiEntries,
byte StartIndex,
byte NeighborLqiCount,
ZDP_MgmtLqiItem_t* NeighborList,
byte SecurityEnable );
extern ZStatus_t ZDP_MgmtRtgRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte RoutingTableEntries,
byte StartIndex,
byte RoutingListCount,
rtgItem_t *RoutingTableList,
byte SecurityEnable );
extern ZStatus_t ZDP_MgmtBindRsp( byte TransSeq, zAddrType_t *dstAddr,
byte Status,
byte BindingTableEntries,
byte StartIndex,
byte BindingTableListCount,
apsBindingItem_t *BindingTableList,
byte SecurityEnable );
extern afStatus_t ZDP_MgmtNwkUpdateNotify( uint8 TransSeq, zAddrType_t *dstAddr,
uint8 status, uint32 scannedChannels,
uint16 totalTransmissions, uint16 transmissionFailures,
uint8 listCount, uint8 *energyValues, uint8 txOptions,
uint8 securityEnable );
extern ZStatus_t ZDP_UserDescRsp( byte TransSeq, zAddrType_t *dstAddr,
uint16 nwkAddrOfInterest, UserDescriptorFormat_t *userDesc,
byte SecurityEnable );
ZStatus_t ZDP_ServerDiscRsp( byte transID, zAddrType_t *dstAddr, byte status,
uint16 aoi, uint16 serverMask, byte SecurityEnable );
extern void ZDP_IncomingData( afIncomingMSGPacket_t *pData );
extern ZStatus_t ZDO_RegisterForZDOMsg( uint8 taskID, uint16 clusterID );
extern ZStatus_t ZDO_RemoveRegisteredCB( uint8 taskID, uint16 clusterID );
#ifdef __cplusplus
}
#endif