1074 lines
27 KiB
C
1074 lines
27 KiB
C
|
/**************************************************************************************************
|
|||
|
Filename: BindingTable.c
|
|||
|
Revised: $Date: 2012-03-28 15:40:50 -0700 (Wed, 28 Mar 2012) $
|
|||
|
Revision: $Revision: 29930 $
|
|||
|
|
|||
|
Description: Device binding table functions.
|
|||
|
|
|||
|
|
|||
|
Copyright 2004-2012 Texas Instruments Incorporated. All rights reserved.
|
|||
|
|
|||
|
IMPORTANT: Your use of this Software is limited to those specific rights
|
|||
|
granted under the terms of a software license agreement between the user
|
|||
|
who downloaded the software, his/her employer (which must be your employer)
|
|||
|
and Texas Instruments Incorporated (the "License"). You may not use this
|
|||
|
Software unless you agree to abide by the terms of the License. The License
|
|||
|
limits your use, and you acknowledge, that the Software may not be modified,
|
|||
|
copied or distributed unless embedded on a Texas Instruments microcontroller
|
|||
|
or used solely and exclusively in conjunction with a Texas Instruments radio
|
|||
|
frequency transceiver, which is integrated into your product. Other than for
|
|||
|
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
|
|||
|
works of, modify, distribute, perform, display or sell this Software and/or
|
|||
|
its documentation for any purpose.
|
|||
|
|
|||
|
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
|
|||
|
PROVIDED <EFBFBD>AS IS<EFBFBD> WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
|||
|
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
|
|||
|
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
|
|||
|
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
|
|||
|
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
|
|||
|
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
|
|||
|
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
|
|||
|
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
|
|||
|
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
|
|||
|
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
|
|||
|
|
|||
|
Should you have any questions regarding your right to use this Software,
|
|||
|
contact Texas Instruments Incorporated at www.TI.com.
|
|||
|
**************************************************************************************************/
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* INCLUDES
|
|||
|
*/
|
|||
|
#include "ZComDef.h"
|
|||
|
#include "OSAL.h"
|
|||
|
#include "OSAL_Nv.h"
|
|||
|
#include "nwk_globals.h"
|
|||
|
#include "AddrMgr.h"
|
|||
|
#include "BindingTable.h"
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* MACROS
|
|||
|
*/
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* CONSTANTS
|
|||
|
*/
|
|||
|
#define NV_BIND_EMPTY 0xFF
|
|||
|
#define NV_BIND_REC_SIZE (gBIND_REC_SIZE)
|
|||
|
#define NV_BIND_ITEM_SIZE (gBIND_REC_SIZE * gNWK_MAX_BINDING_ENTRIES)
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* TYPEDEFS
|
|||
|
*/
|
|||
|
typedef struct
|
|||
|
{
|
|||
|
uint8 srcEP;
|
|||
|
uint16 srcIndex;
|
|||
|
uint16 dstIndex;
|
|||
|
uint8 dstEP;
|
|||
|
uint8 dstAddrMode;
|
|||
|
uint8 clusterIDs;
|
|||
|
uint16* clusterIDList;
|
|||
|
} bindFields_t;
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* GLOBAL VARIABLES
|
|||
|
*/
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* LOCAL FUNCTIONS
|
|||
|
*/
|
|||
|
void BindAddrMgrCB( uint8 update, AddrMgrEntry_t *entryOld,
|
|||
|
AddrMgrEntry_t *entryNew );
|
|||
|
BindingEntry_t *bindFindEmpty( void );
|
|||
|
uint16 bindingAddrMgsHelperFind( zAddrType_t *addr );
|
|||
|
uint8 bindingAddrMgsHelperConvert( uint16 idx, zAddrType_t *addr );
|
|||
|
void bindAddrMgrLocalLoad( void );
|
|||
|
uint16 bindAddrIndexGet( zAddrType_t* addr );
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* LOCAL VARIABLES
|
|||
|
*/
|
|||
|
static uint8 bindAddrMgrLocalLoaded = FALSE;
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* Function Pointers
|
|||
|
*/
|
|||
|
|
|||
|
BindingEntry_t *(*pbindAddEntry)( byte srcEpInt,
|
|||
|
zAddrType_t *dstAddr, byte dstEpInt,
|
|||
|
byte numClusterIds, uint16 *clusterIds ) = (void*)NULL;
|
|||
|
uint16 (*pbindNumOfEntries)( void ) = (void*)NULL;
|
|||
|
void (*pbindRemoveDev)( zAddrType_t *Addr ) = (void*)NULL;
|
|||
|
byte (*pBindInitNV)( void ) = (void*)NULL;
|
|||
|
void (*pBindSetDefaultNV)( void ) = (void*)NULL;
|
|||
|
uint16 (*pBindRestoreFromNV)( void ) = (void*)NULL;
|
|||
|
void (*pBindWriteNV)( void ) = (void*)NULL;
|
|||
|
|
|||
|
#if ( ADDRMGR_CALLBACK_ENABLED == 1 )
|
|||
|
/*********************************************************************
|
|||
|
* @fn BindAddrMgrCB()
|
|||
|
*
|
|||
|
* @brief Address Manager Callback function
|
|||
|
*
|
|||
|
* @param update -
|
|||
|
* @param entry -
|
|||
|
*
|
|||
|
* @return pointer to
|
|||
|
*/
|
|||
|
void BindAddrMgrCB( uint8 update, AddrMgrEntry_t *entryNew,
|
|||
|
AddrMgrEntry_t *entryOld )
|
|||
|
{
|
|||
|
// Check for either deleted items or changed Extended (Duplicate) addresses
|
|||
|
}
|
|||
|
#endif // ( ADDRMGR_CALLBACK_ENABLED == 1 )
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn InitBindingTable()
|
|||
|
*
|
|||
|
* @brief
|
|||
|
*
|
|||
|
* This function is used to initialise the binding table
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void InitBindingTable( void )
|
|||
|
{
|
|||
|
osal_memset( BindingTable, 0xFF, gBIND_REC_SIZE * gNWK_MAX_BINDING_ENTRIES );
|
|||
|
|
|||
|
pbindAddEntry = bindAddEntry;
|
|||
|
pbindNumOfEntries = bindNumOfEntries;
|
|||
|
pbindRemoveDev = bindRemoveDev;
|
|||
|
pBindInitNV = BindInitNV;
|
|||
|
pBindSetDefaultNV = BindSetDefaultNV;
|
|||
|
pBindRestoreFromNV = BindRestoreFromNV;
|
|||
|
pBindWriteNV = BindWriteNV;
|
|||
|
|
|||
|
bindAddrMgrLocalLoaded = FALSE;
|
|||
|
|
|||
|
#if ( ADDRMGR_CALLBACK_ENABLED == 1 )
|
|||
|
// Register with the address manager
|
|||
|
AddrMgrRegister( ADDRMGR_REG_BINDING, BindAddrMgrCB );
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindFindEmpty()
|
|||
|
*
|
|||
|
* @brief This function returns a pointer to an empty binding slot
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return pointer to binding table entry, NULL if not added
|
|||
|
*/
|
|||
|
BindingEntry_t *bindFindEmpty( void )
|
|||
|
{
|
|||
|
uint16 x;
|
|||
|
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
// It's empty if the index is "Not Found"
|
|||
|
if ( BindingTable[x].srcEP == NV_BIND_EMPTY )
|
|||
|
{
|
|||
|
return ( &BindingTable[x] );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( (BindingEntry_t *)NULL );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindNumOfEntries()
|
|||
|
*
|
|||
|
* @brief This function returns the number of binding table entries.
|
|||
|
* The return for this is the number of clusters in the
|
|||
|
* table NOT the number of entries.
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return number of entries
|
|||
|
*/
|
|||
|
uint16 bindNumOfEntries( void )
|
|||
|
{
|
|||
|
uint16 x;
|
|||
|
uint16 found;
|
|||
|
|
|||
|
for ( found = 0, x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
// It's empty if the index is "Not Found"
|
|||
|
if ( BindingTable[x].srcEP != NV_BIND_EMPTY )
|
|||
|
{
|
|||
|
found += BindingTable[x].numClusterIds;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( found );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindCapacity()
|
|||
|
*
|
|||
|
* @brief This function returns the number of binding entries
|
|||
|
* possible and used.
|
|||
|
*
|
|||
|
* @param maxEntries - pointer to a place to put the max entries
|
|||
|
* @param usedEntries - pointer to a place to put the number
|
|||
|
* of used entries
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void bindCapacity( uint16 *maxEntries, uint16 *usedEntries )
|
|||
|
{
|
|||
|
uint16 x;
|
|||
|
uint16 used;
|
|||
|
|
|||
|
for ( used = 0, x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
// It's empty if the index is "Not Found"
|
|||
|
if ( BindingTable[x].srcEP != NV_BIND_EMPTY )
|
|||
|
{
|
|||
|
used++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*maxEntries = gNWK_MAX_BINDING_ENTRIES;
|
|||
|
*usedEntries = used;
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindAddEntry()
|
|||
|
*
|
|||
|
* @brief This function is used to Add an entry to the binding table
|
|||
|
*
|
|||
|
* @param srcAddr - source Address
|
|||
|
* @param srcEpInt - source endpoint
|
|||
|
* @param dstAddr - destination Address
|
|||
|
* @param dstEpInt - destination endpoint
|
|||
|
* @param numClusterIds - number of cluster Ids in the list
|
|||
|
* @param clusterIds - pointer to the Object ID list
|
|||
|
*
|
|||
|
* @return pointer to binding table entry, NULL if not added
|
|||
|
*/
|
|||
|
BindingEntry_t *bindAddEntry( byte srcEpInt,
|
|||
|
zAddrType_t *dstAddr, byte dstEpInt,
|
|||
|
byte numClusterIds, uint16 *clusterIds )
|
|||
|
{
|
|||
|
uint8 index;
|
|||
|
BindingEntry_t* entry;
|
|||
|
bindFields_t fields;
|
|||
|
|
|||
|
// initialize results
|
|||
|
entry = NULL;
|
|||
|
|
|||
|
// make sure local addresses have been loaded
|
|||
|
bindAddrMgrLocalLoad();
|
|||
|
|
|||
|
// setup fields
|
|||
|
fields.dstIndex = bindAddrIndexGet( dstAddr );
|
|||
|
fields.srcEP = srcEpInt;
|
|||
|
|
|||
|
if ( dstAddr->addrMode == AddrGroup )
|
|||
|
{
|
|||
|
fields.dstAddrMode = DSTGROUPMODE_GROUP;
|
|||
|
fields.dstEP = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fields.dstAddrMode = DSTGROUPMODE_ADDR;
|
|||
|
fields.dstEP = dstEpInt;
|
|||
|
}
|
|||
|
|
|||
|
if ( fields.dstIndex != INVALID_NODE_ADDR )
|
|||
|
{
|
|||
|
for ( index = 0; index < gNWK_MAX_BINDING_ENTRIES; index++ )
|
|||
|
{
|
|||
|
if ( ( fields.srcEP == BindingTable[index].srcEP ) &&
|
|||
|
( fields.dstAddrMode == BindingTable[index].dstGroupMode ) &&
|
|||
|
( fields.dstIndex == BindingTable[index].dstIdx ) &&
|
|||
|
( fields.dstEP == BindingTable[index].dstEP ) )
|
|||
|
{
|
|||
|
entry = &BindingTable[index];
|
|||
|
|
|||
|
// break from loop
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( entry != NULL )
|
|||
|
{
|
|||
|
// Loop through the cluster IDs
|
|||
|
for ( index = 0; index < numClusterIds; index++ )
|
|||
|
{
|
|||
|
// Found - is the cluster already defined?
|
|||
|
if ( bindIsClusterIDinList( entry, clusterIds[index] ) == FALSE )
|
|||
|
{
|
|||
|
// Nope, add this cluster
|
|||
|
if ( bindAddClusterIdToList( entry, clusterIds[index] ) == FALSE )
|
|||
|
{
|
|||
|
// Indicate error if cluster list was full
|
|||
|
entry = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Find an empty slot
|
|||
|
entry = bindFindEmpty();
|
|||
|
|
|||
|
// Check against the maximum number allowed
|
|||
|
if ( entry != NULL )
|
|||
|
{
|
|||
|
// Add new entry
|
|||
|
entry->srcEP = fields.srcEP;
|
|||
|
entry->dstGroupMode = fields.dstAddrMode;
|
|||
|
entry->dstIdx = fields.dstIndex;
|
|||
|
entry->dstEP = fields.dstEP;
|
|||
|
|
|||
|
if ( numClusterIds > gMAX_BINDING_CLUSTER_IDS )
|
|||
|
{
|
|||
|
numClusterIds = gMAX_BINDING_CLUSTER_IDS;
|
|||
|
}
|
|||
|
|
|||
|
entry->numClusterIds = numClusterIds;
|
|||
|
|
|||
|
osal_memcpy( entry->clusterIdList,
|
|||
|
clusterIds,
|
|||
|
numClusterIds * sizeof(uint16) );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return entry;
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindRemoveEntry
|
|||
|
*
|
|||
|
* @brief Removes a binding table entry.
|
|||
|
*
|
|||
|
* @param pBind - pointer to binding table entry to delete
|
|||
|
*
|
|||
|
* @return TRUE if Removed, FALSE if not
|
|||
|
*/
|
|||
|
byte bindRemoveEntry( BindingEntry_t *pBind )
|
|||
|
{
|
|||
|
osal_memset( pBind, 0xFF, gBIND_REC_SIZE );
|
|||
|
return ( TRUE );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindIsClusterIDinList()
|
|||
|
*
|
|||
|
* @brief Is the clusterID in the clusterID list?
|
|||
|
*
|
|||
|
* @param enter - binding table entry
|
|||
|
* @param clusterId - Cluster ID to look for
|
|||
|
*
|
|||
|
* @return TRUE if found, FALSE if not found
|
|||
|
*/
|
|||
|
byte bindIsClusterIDinList( BindingEntry_t *entry, uint16 clusterId )
|
|||
|
{
|
|||
|
uint8 x;
|
|||
|
|
|||
|
if ( entry != NULL )
|
|||
|
{
|
|||
|
for ( x = 0; x < entry->numClusterIds; x++ )
|
|||
|
{
|
|||
|
if ( entry->clusterIdList[x] == clusterId )
|
|||
|
{
|
|||
|
return ( TRUE );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindRemoveClusterIdFromList()
|
|||
|
*
|
|||
|
* @brief Removes a ClusterID from a list of ClusterIDs.
|
|||
|
*
|
|||
|
* @param enter - binding table entry
|
|||
|
* @param clusterId - Cluster ID to look for
|
|||
|
*
|
|||
|
* @return TRUE if there are at least 1 clusterID left, FALSE if none
|
|||
|
*/
|
|||
|
byte bindRemoveClusterIdFromList( BindingEntry_t *entry, uint16 clusterId )
|
|||
|
{
|
|||
|
byte x;
|
|||
|
uint16 *listPtr;
|
|||
|
byte numIds;
|
|||
|
|
|||
|
if ( entry )
|
|||
|
{
|
|||
|
if ( entry->numClusterIds > 0 )
|
|||
|
{
|
|||
|
listPtr = entry->clusterIdList;
|
|||
|
numIds = entry->numClusterIds;
|
|||
|
|
|||
|
// Copy the new list over
|
|||
|
for ( x = 0; x < numIds; x++ )
|
|||
|
{
|
|||
|
if ( entry->clusterIdList[x] != clusterId )
|
|||
|
{
|
|||
|
*listPtr++ = entry->clusterIdList[x];
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
entry->numClusterIds--;
|
|||
|
if ( entry->numClusterIds == 0 )
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( entry && (entry->numClusterIds > 0) )
|
|||
|
{
|
|||
|
return ( TRUE );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return ( FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindAddClusterIdToList()
|
|||
|
*
|
|||
|
* @brief Adds a ClusterID to a list of ClusterIDs.
|
|||
|
*
|
|||
|
* @param enter - binding table entry
|
|||
|
* @param clusterId - Cluster ID to Add
|
|||
|
*
|
|||
|
* @return TRUE if Added, FALSE if not
|
|||
|
*/
|
|||
|
byte bindAddClusterIdToList( BindingEntry_t *entry, uint16 clusterId )
|
|||
|
{
|
|||
|
if ( entry && entry->numClusterIds < gMAX_BINDING_CLUSTER_IDS )
|
|||
|
{
|
|||
|
// Add the new one
|
|||
|
entry->clusterIdList[entry->numClusterIds] = clusterId;
|
|||
|
entry->numClusterIds++;
|
|||
|
return ( TRUE );
|
|||
|
}
|
|||
|
return ( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindFindExisting
|
|||
|
*
|
|||
|
* @brief Finds an existing src/epint to dst/epint bind record
|
|||
|
*
|
|||
|
* @param srcAddr - Source address
|
|||
|
* @param srcEpInt - Source Endpoint/Interface
|
|||
|
* @param dstAddr - Destination address
|
|||
|
* @param dstEpInt - Destination Endpoint/Interface
|
|||
|
*
|
|||
|
* @return pointer to existing entry or NULL
|
|||
|
*/
|
|||
|
BindingEntry_t *bindFindExisting( byte srcEpInt,
|
|||
|
zAddrType_t *dstAddr, byte dstEpInt )
|
|||
|
{
|
|||
|
uint16 dstIdx;
|
|||
|
uint16 x;
|
|||
|
|
|||
|
// Find the records in the assoc list
|
|||
|
if ( dstAddr->addrMode == AddrGroup )
|
|||
|
{
|
|||
|
dstIdx = dstAddr->addr.shortAddr;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
dstIdx = bindingAddrMgsHelperFind( dstAddr );
|
|||
|
}
|
|||
|
|
|||
|
if ( dstIdx == INVALID_NODE_ADDR )
|
|||
|
{
|
|||
|
return ( (BindingEntry_t *)NULL );
|
|||
|
}
|
|||
|
|
|||
|
// Start at the beginning
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
if ( (BindingTable[x].srcEP == srcEpInt) )
|
|||
|
{
|
|||
|
if ( ((dstAddr->addrMode == AddrGroup)
|
|||
|
&& (BindingTable[x].dstGroupMode == DSTGROUPMODE_GROUP)
|
|||
|
&& (dstIdx == BindingTable[x].dstIdx))
|
|||
|
|| ((dstAddr->addrMode != AddrGroup)
|
|||
|
&& (BindingTable[x].dstGroupMode == DSTGROUPMODE_ADDR)
|
|||
|
&& (dstIdx == BindingTable[x].dstIdx) && (BindingTable[x].dstEP == dstEpInt)) )
|
|||
|
{
|
|||
|
return ( &BindingTable[x] );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( (BindingEntry_t *)NULL );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindRemoveDev()
|
|||
|
*
|
|||
|
* @brief
|
|||
|
*
|
|||
|
* Remove all bind(s) entries associated to a device address (destination).
|
|||
|
* Updates binding table.
|
|||
|
*
|
|||
|
* @param Addr - address of device to be removed from Binding Table
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void bindRemoveDev( zAddrType_t *Addr )
|
|||
|
{
|
|||
|
uint16 idx;
|
|||
|
uint16 x;
|
|||
|
|
|||
|
if ( Addr->addrMode == AddrGroup )
|
|||
|
{
|
|||
|
idx = Addr->addr.shortAddr;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
idx = bindingAddrMgsHelperFind( Addr );
|
|||
|
}
|
|||
|
|
|||
|
if ( idx == INVALID_NODE_ADDR )
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Removes all the entries that match the destination Address/Index
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
if ( ( (Addr->addrMode == AddrGroup) && (BindingTable[x].dstGroupMode == DSTGROUPMODE_GROUP)
|
|||
|
&& (BindingTable[x].dstIdx == idx) ) ||
|
|||
|
( (Addr->addrMode != AddrGroup) && (BindingTable[x].dstGroupMode == DSTGROUPMODE_ADDR)
|
|||
|
&& (BindingTable[x].dstIdx == idx) ) )
|
|||
|
{
|
|||
|
bindRemoveEntry( &BindingTable[x] );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindRemoveSrcDev()
|
|||
|
*
|
|||
|
* @brief
|
|||
|
*
|
|||
|
* Remove binds(s) associated to device address (source).
|
|||
|
* Updates binding table.
|
|||
|
*
|
|||
|
* @param srcAddr - address of device
|
|||
|
* @param ep - endpoint to remove, 0xFF is all endpoints
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void bindRemoveSrcDev( uint8 ep )
|
|||
|
{
|
|||
|
uint16 x;
|
|||
|
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
if ( (ep == 0xFF) || (ep == BindingTable[x].srcEP) )
|
|||
|
{
|
|||
|
bindRemoveEntry( &BindingTable[x] );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindNumBoundTo
|
|||
|
*
|
|||
|
* @brief Calculate the number items this device is bound to.
|
|||
|
* When srcMode is set to TRUE, discard what value devAddr
|
|||
|
* has, it returns number count bound to the local dev.
|
|||
|
*
|
|||
|
* @param devAddr - device Address
|
|||
|
* @param devEP - endpoint
|
|||
|
* @param srcMode - TRUE - assume devHandle is a source address
|
|||
|
* FALSE - destination address
|
|||
|
*
|
|||
|
* @return status
|
|||
|
*/
|
|||
|
byte bindNumBoundTo( zAddrType_t *devAddr, byte devEpInt, byte srcMode )
|
|||
|
{
|
|||
|
BindingEntry_t *pBind;
|
|||
|
uint16 idx;
|
|||
|
byte num;
|
|||
|
uint16 x;
|
|||
|
|
|||
|
// Init
|
|||
|
num = 0;
|
|||
|
|
|||
|
if ( devAddr->addrMode == AddrGroup )
|
|||
|
{
|
|||
|
idx = devAddr->addr.shortAddr;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
idx = bindingAddrMgsHelperFind( devAddr );
|
|||
|
}
|
|||
|
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
pBind = &BindingTable[x];
|
|||
|
if ( srcMode )
|
|||
|
{
|
|||
|
if ( pBind->srcEP == devEpInt )
|
|||
|
{
|
|||
|
num++;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if ( ((devAddr->addrMode == AddrGroup)
|
|||
|
&& (pBind->dstGroupMode == DSTGROUPMODE_GROUP) && (pBind->dstIdx == idx))
|
|||
|
|| ((devAddr->addrMode != AddrGroup) && (pBind->dstGroupMode == DSTGROUPMODE_ADDR)
|
|||
|
&& (pBind->dstIdx == idx) && (pBind->dstEP == devEpInt)) )
|
|||
|
{
|
|||
|
num++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return num;
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindNumReflections
|
|||
|
*
|
|||
|
* @brief Counts the number of reflections needed for a
|
|||
|
* endpoint and cluster ID combo.
|
|||
|
*
|
|||
|
* @param ep - source endpoint
|
|||
|
* @param clusterID - matching clusterID
|
|||
|
*
|
|||
|
* @return number of reflections needed.
|
|||
|
*/
|
|||
|
uint16 bindNumReflections( uint8 ep, uint16 clusterID )
|
|||
|
{
|
|||
|
uint16 x;
|
|||
|
BindingEntry_t *pBind;
|
|||
|
uint16 cnt = 0;
|
|||
|
uint8 bindEP;
|
|||
|
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
pBind = &BindingTable[x];
|
|||
|
bindEP = pBind->srcEP;
|
|||
|
|
|||
|
if ( (bindEP == ep) && (bindIsClusterIDinList( pBind, clusterID )) )
|
|||
|
{
|
|||
|
cnt++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( cnt );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindFind
|
|||
|
*
|
|||
|
* @brief Finds the binding entry for the source address, endpoint
|
|||
|
* and cluster ID passed in as a parameter.
|
|||
|
*
|
|||
|
* @param ep - source endpoint
|
|||
|
* @param clusterID - matching clusterID
|
|||
|
* @param skip - number of matches to skip before returning
|
|||
|
*
|
|||
|
* @return pointer to the binding table entry, NULL if not found
|
|||
|
*/
|
|||
|
BindingEntry_t *bindFind( uint8 ep, uint16 clusterID, uint8 skipping )
|
|||
|
{
|
|||
|
BindingEntry_t *pBind;
|
|||
|
byte skipped = 0;
|
|||
|
uint16 x;
|
|||
|
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
pBind = &BindingTable[x];
|
|||
|
|
|||
|
if ( ( pBind->srcEP == ep) && bindIsClusterIDinList( pBind, clusterID ))
|
|||
|
{
|
|||
|
if ( skipped < skipping )
|
|||
|
{
|
|||
|
skipped++;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return ( pBind );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return ( (BindingEntry_t *)NULL );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn BindInitNV
|
|||
|
*
|
|||
|
* @brief Initialize the Binding NV Item
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return ZSUCCESS if successful, NV_ITEM_UNINIT if item did not
|
|||
|
* exist in NV, NV_OPER_FAILED if failure.
|
|||
|
*/
|
|||
|
byte BindInitNV( void )
|
|||
|
{
|
|||
|
byte ret;
|
|||
|
|
|||
|
// Initialize the device list
|
|||
|
ret = osal_nv_item_init( ZCD_NV_BINDING_TABLE,
|
|||
|
(uint16)(gBIND_REC_SIZE + NV_BIND_ITEM_SIZE), NULL );
|
|||
|
|
|||
|
if ( ret != ZSUCCESS )
|
|||
|
{
|
|||
|
BindSetDefaultNV();
|
|||
|
}
|
|||
|
|
|||
|
return ( ret );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn BindSetDefaultNV
|
|||
|
*
|
|||
|
* @brief Write the defaults to NV
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void BindSetDefaultNV( void )
|
|||
|
{
|
|||
|
nvBindingHdr_t hdr;
|
|||
|
|
|||
|
// Initialize the header
|
|||
|
hdr.numRecs = 0;
|
|||
|
|
|||
|
// Save off the header
|
|||
|
osal_nv_write( ZCD_NV_BINDING_TABLE, 0, sizeof( nvBindingHdr_t ), &hdr );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn BindRestoreFromNV
|
|||
|
*
|
|||
|
* @brief Restore the binding table from NV
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return Number of entries restored
|
|||
|
*/
|
|||
|
uint16 BindRestoreFromNV( void )
|
|||
|
{
|
|||
|
nvBindingHdr_t hdr;
|
|||
|
uint16 numAdded = 0;
|
|||
|
|
|||
|
if ( osal_nv_read( ZCD_NV_BINDING_TABLE, 0, sizeof(nvBindingHdr_t), &hdr ) == ZSuccess )
|
|||
|
{
|
|||
|
if (hdr.numRecs > 0)
|
|||
|
{
|
|||
|
// Read the whole table at once
|
|||
|
if ( osal_nv_read( ZCD_NV_BINDING_TABLE,
|
|||
|
(uint16)(sizeof(nvBindingHdr_t)),
|
|||
|
(NV_BIND_REC_SIZE * gNWK_MAX_BINDING_ENTRIES), BindingTable ) == ZSUCCESS )
|
|||
|
{
|
|||
|
numAdded = gNWK_MAX_BINDING_ENTRIES;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return ( numAdded );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn BindWriteNV
|
|||
|
*
|
|||
|
* @brief Save the Binding Table in NV
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void BindWriteNV( void )
|
|||
|
{
|
|||
|
BindingEntry_t *pBind;
|
|||
|
BindingEntry_t bind;
|
|||
|
nvBindingHdr_t hdr;
|
|||
|
uint16 x;
|
|||
|
|
|||
|
hdr.numRecs = 0;
|
|||
|
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
pBind = &BindingTable[x];
|
|||
|
|
|||
|
osal_memcpy( &bind, pBind, gBIND_REC_SIZE );
|
|||
|
|
|||
|
// Save the record to NV
|
|||
|
osal_nv_write( ZCD_NV_BINDING_TABLE,
|
|||
|
(uint16)((sizeof(nvBindingHdr_t)) + (x * NV_BIND_REC_SIZE)),
|
|||
|
NV_BIND_REC_SIZE, &bind );
|
|||
|
|
|||
|
if ( pBind->srcEP != NV_BIND_EMPTY )
|
|||
|
{
|
|||
|
hdr.numRecs++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Save off the header
|
|||
|
osal_nv_write( ZCD_NV_BINDING_TABLE, 0, sizeof(nvBindingHdr_t), &hdr );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindUpdateAddr
|
|||
|
*
|
|||
|
* @brief Update the network address in the binding table.
|
|||
|
*
|
|||
|
* @param oldAddr - old network address
|
|||
|
* @param newAddr - new network address
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void bindUpdateAddr( uint16 oldAddr, uint16 newAddr )
|
|||
|
{
|
|||
|
uint16 oldIdx;
|
|||
|
uint16 newIdx;
|
|||
|
zAddrType_t addr;
|
|||
|
uint16 x;
|
|||
|
BindingEntry_t *pBind;
|
|||
|
|
|||
|
addr.addrMode = Addr16Bit;
|
|||
|
addr.addr.shortAddr = oldAddr;
|
|||
|
oldIdx = bindingAddrMgsHelperFind( &addr );
|
|||
|
addr.addr.shortAddr = newAddr;
|
|||
|
newIdx = bindingAddrMgsHelperFind( &addr );
|
|||
|
|
|||
|
for ( x = 0; x < gNWK_MAX_BINDING_ENTRIES; x++ )
|
|||
|
{
|
|||
|
pBind = &BindingTable[x];
|
|||
|
|
|||
|
if ( pBind->dstIdx == oldIdx )
|
|||
|
{
|
|||
|
pBind->dstIdx = newIdx;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindingAddrMgsHelperFind
|
|||
|
*
|
|||
|
* @brief Turns an zAddrType_t to an Addr Manager index
|
|||
|
*
|
|||
|
* @param addr - zAddrType_t
|
|||
|
*
|
|||
|
* @return INVALID_NODE_ADDR if not found, otherwise an index
|
|||
|
*/
|
|||
|
uint16 bindingAddrMgsHelperFind( zAddrType_t *addr )
|
|||
|
{
|
|||
|
AddrMgrEntry_t entry;
|
|||
|
|
|||
|
// Resolve addresses with the address manager
|
|||
|
entry.user = ADDRMGR_USER_BINDING;
|
|||
|
if ( addr->addrMode == Addr16Bit )
|
|||
|
{
|
|||
|
entry.nwkAddr = addr->addr.shortAddr;
|
|||
|
AddrMgrEntryLookupNwk( &entry );
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
AddrMgrExtAddrSet( entry.extAddr, addr->addr.extAddr );
|
|||
|
AddrMgrEntryLookupExt( &entry );
|
|||
|
}
|
|||
|
|
|||
|
return ( entry.index );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindingAddrMgsHelperConvert
|
|||
|
*
|
|||
|
* @brief Convert an index into an zAddrType_t
|
|||
|
*
|
|||
|
* @param idx -
|
|||
|
* @param addr - zAddrType_t
|
|||
|
*
|
|||
|
* @return TRUE if found, FALSE if not
|
|||
|
*/
|
|||
|
uint8 bindingAddrMgsHelperConvert( uint16 idx, zAddrType_t *addr )
|
|||
|
{
|
|||
|
AddrMgrEntry_t entry;
|
|||
|
uint8 stat;
|
|||
|
|
|||
|
// Resolve addresses with the address manager
|
|||
|
entry.user = ADDRMGR_USER_BINDING;
|
|||
|
entry.index = idx;
|
|||
|
stat = AddrMgrEntryGet( &entry );
|
|||
|
if ( stat )
|
|||
|
{
|
|||
|
addr->addrMode = Addr64Bit;
|
|||
|
osal_cpyExtAddr( addr->addr.extAddr, entry.extAddr );
|
|||
|
}
|
|||
|
|
|||
|
return ( stat );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindingAddrMgsHelperConvertShort
|
|||
|
*
|
|||
|
* @brief Convert an index into a short address
|
|||
|
*
|
|||
|
* @param idx -
|
|||
|
*
|
|||
|
* @return INVALID_NODE_ADDR if not available, otherwise the short address
|
|||
|
*/
|
|||
|
uint16 bindingAddrMgsHelperConvertShort( uint16 idx )
|
|||
|
{
|
|||
|
AddrMgrEntry_t entry;
|
|||
|
|
|||
|
// Resolve addresses with the address manager
|
|||
|
entry.user = ADDRMGR_USER_BINDING;
|
|||
|
entry.index = idx;
|
|||
|
AddrMgrEntryGet( &entry );
|
|||
|
|
|||
|
return ( entry.nwkAddr );
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindAddrMgrLocalLoad
|
|||
|
*
|
|||
|
* @brief Load local(self and parent) address information into
|
|||
|
* Address Manager
|
|||
|
*
|
|||
|
* @param none
|
|||
|
*
|
|||
|
* @return none
|
|||
|
*/
|
|||
|
void bindAddrMgrLocalLoad( void )
|
|||
|
{
|
|||
|
AddrMgrEntry_t entry;
|
|||
|
uint16 parent;
|
|||
|
|
|||
|
// add "local"(self and parent) address informtion into the Address
|
|||
|
// Manager
|
|||
|
if ( bindAddrMgrLocalLoaded == FALSE )
|
|||
|
{
|
|||
|
// add the device's address information
|
|||
|
entry.user = ADDRMGR_USER_BINDING;
|
|||
|
entry.nwkAddr = _NIB.nwkDevAddress;
|
|||
|
AddrMgrExtAddrSet( entry.extAddr, NLME_GetExtAddr() );
|
|||
|
AddrMgrEntryUpdate( &entry );
|
|||
|
|
|||
|
// make sure parent address is valid
|
|||
|
parent = NLME_GetCoordShortAddr();
|
|||
|
if ( ( parent != entry.nwkAddr ) &&
|
|||
|
( parent != INVALID_NODE_ADDR ) )
|
|||
|
{
|
|||
|
// add the parent's address information
|
|||
|
entry.nwkAddr = parent;
|
|||
|
NLME_GetCoordExtAddr( entry.extAddr );
|
|||
|
AddrMgrEntryUpdate( &entry );
|
|||
|
}
|
|||
|
|
|||
|
bindAddrMgrLocalLoaded = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn bindAddrIndexGet
|
|||
|
*
|
|||
|
* @brief Get bind address index.
|
|||
|
*
|
|||
|
* @param addr - <zAddrType_t>
|
|||
|
*
|
|||
|
* @return (uint16) address index
|
|||
|
*/
|
|||
|
uint16 bindAddrIndexGet( zAddrType_t* addr )
|
|||
|
{
|
|||
|
AddrMgrEntry_t entry;
|
|||
|
uint8 update;
|
|||
|
|
|||
|
update = FALSE;
|
|||
|
|
|||
|
// sync binding addresses with the address manager
|
|||
|
entry.user = ADDRMGR_USER_BINDING;
|
|||
|
|
|||
|
if ( addr->addrMode == Addr16Bit )
|
|||
|
{
|
|||
|
entry.nwkAddr = addr->addr.shortAddr;
|
|||
|
|
|||
|
if ( AddrMgrEntryLookupNwk( &entry ) == FALSE )
|
|||
|
{
|
|||
|
update = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( addr->addrMode == Addr64Bit )
|
|||
|
{
|
|||
|
AddrMgrExtAddrSet( entry.extAddr, addr->addr.extAddr );
|
|||
|
|
|||
|
if ( AddrMgrEntryLookupExt( &entry ) == FALSE )
|
|||
|
{
|
|||
|
update = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( addr->addrMode == AddrGroup )
|
|||
|
{
|
|||
|
entry.index = addr->addr.shortAddr;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
entry.index = INVALID_NODE_ADDR;
|
|||
|
}
|
|||
|
|
|||
|
if ( update )
|
|||
|
{
|
|||
|
AddrMgrEntryUpdate( &entry );
|
|||
|
}
|
|||
|
|
|||
|
return entry.index;
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
* @fn GetBindingTableEntry
|
|||
|
*
|
|||
|
* @brief Get a pointer to the Nth valid binding table entry.
|
|||
|
*
|
|||
|
* @param Nth valid entry being requested.
|
|||
|
*
|
|||
|
* @return The Nth valid binding table entry.
|
|||
|
*/
|
|||
|
BindingEntry_t *GetBindingTableEntry( uint16 Nth )
|
|||
|
{
|
|||
|
BindingEntry_t *rtrn = NULL;
|
|||
|
|
|||
|
#if defined ( REFLECTOR )
|
|||
|
uint16 idx, cnt = 0;
|
|||
|
|
|||
|
for ( idx = 0; idx < gNWK_MAX_BINDING_ENTRIES; idx++ )
|
|||
|
{
|
|||
|
if ( BindingTable[idx].srcEP != NV_BIND_EMPTY )
|
|||
|
{
|
|||
|
if ( cnt++ == Nth )
|
|||
|
{
|
|||
|
rtrn = BindingTable+idx;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#else
|
|||
|
(void)Nth;
|
|||
|
#endif
|
|||
|
|
|||
|
return rtrn;
|
|||
|
}
|
|||
|
|
|||
|
/*********************************************************************
|
|||
|
*********************************************************************/
|