理解1:Microchip的Stack使用了Neighbor表,说明它不是利用short mac地址来判断是否自己的叶子节点。(经进一步阅读,这个理解是错的!)
在RouteAlongTree()方法中,对邻居表中的每条记录进行判断,如果该邻居属于本节点的子节点,则判断目的地址是否该节点或该节点的下级节点(通过IsDescendant()方法实现判断)。
邻居记录的currentNeighborRecord.deviceInfo.bits.Relationship属性定义了邻居表中的节点与本节点的关系,一共有4种: NEIGHBOR_IS_PARENT, NEIGHBOR_IS_CHILD, NEIGHBOR_IS_SIBLING(sibling: 兄弟姐妹), NEIGHBOR_IS_NONE
=================
阅读IsDescendant()的实现方式时发现有局限性。子节点的地址分配受PROFILE_nwkMaxChildren、PROFILE_nwkMaxDepth、PROFILE_nwkMaxRouters这些配置参数的限制。那么同一个网内的节点的这些参数是否必须采用相同的取值?
另外,GetCSkipVal()的实现代码只支持9层的层次。
=================
既然有表,就有表中记录的添加、删除、查找、修改,容量达到最大值时的处理,初始化等操作。下面查看对应的代码。
1、Neighbor表的变量:neighborTable (NIB_TABLE.nwkNeighborTable 待分析)
表中的最大记录数:MAX_NEIGHBORS (zMAC_*.c中限制最大255)
定义在zNVM.c:
===============
// Neighbor Table information
NEIGHBOR_RECORD currentNeighborRecord; // Node information.
NEIGHBOR_TABLE_INFO currentNeighborTableInfo; // Info about the neighbor table and the node's children.
#ifdef USE_EXTERNAL_NVM
WORD neighborTableInfo;
WORD neighborTable;
WORD pCurrentNeighborRecord;
#else
ROM NEIGHBOR_TABLE_INFO neighborTableInfo = {0x00}; // Initialize to something other than the valid key.
ROM NEIGHBOR_RECORD neighborTable[MAX_NEIGHBORS] = {0x00}; // Does not need initializing, but the HI-TECH compiler will not place it in ROM memory otherwise
ROM NEIGHBOR_RECORD *pCurrentNeighborRecord;
#endif
================
2、Neighbor记录的结构:
typedef struct _NEIGHBOR_RECORD
{
LONG_ADDR longAddr;
SHORT_ADDR shortAddr;
PAN_ADDR panID;
NEIGHBOR_RECORD_DEVICE_INFO deviceInfo;
BYTE LogicalChannel; // Needed to add for NLME_JOIN_request and other things.
#ifdef I_SUPPORT_SECURITY
BOOL bSecured;
#endif
} NEIGHBOR_RECORD; // 15 bytes long
typedef union _NEIGHBOR_RECORD_DEVICE_INFO
{
struct
{
BYTE LQI : 8;
BYTE Depth : 4;
BYTE StackProfile : 4; // Needed for network discovery
BYTE ZigBeeVersion : 4; // Needed for network discovery
BYTE deviceType : 2;
BYTE Relationship : 2;
BYTE RxOnWhenIdle : 1;
BYTE bInUse : 1;
BYTE PermitJoining : 1;
BYTE PotentialParent : 1;
} bits;
DWORD Val;
} NEIGHBOR_RECORD_DEVICE_INFO;
typedef struct _NEIGHBOR_TABLE_INFO
{
WORD validityKey;
BYTE neighborTableSize;
#ifndef I_AM_COORDINATOR
BYTE parentNeighborTableIndex;
#endif
#ifndef I_AM_END_DEVICE
BYTE depth; // Our depth in the network
SHORT_ADDR cSkip; // Address block size
SHORT_ADDR nextEndDeviceAddr; // Next address available to give to an end device
SHORT_ADDR nextRouterAddr; // Next address available to give to a router
BYTE numChildren; // How many children we have
BYTE numChildRouters; // How many of our children are routers
union _flags
{
BYTE Val;
struct _bits
{
BYTE bChildAddressInfoValid : 1; // Child addressing information is valid
} bits;
}flags;
#endif
} NEIGHBOR_TABLE_INFO;
3、相关方法:
GetNeighborRecord( ¤tNeighborRecord, pCurrentNeighborRecord );
将pCurrentNeighborRecord指向的记录的内容复制到currentNeighborRecord结构中。
(GetNeighborRecord()在zNVM.h中定义,是个指向NVMRead()的宏;NVMRead()在zNVM.c中实现,若邻居表保存在NVM中(eeprom中),通过SPI来取数据,否则调用memcpypgm2ram()方法;memcpypgm2ram()在Common/Compiler.h中定义,根据不同的环境指向不同的系统函数)
PutNeighborRecord(pCurrentNeighborRecord, ¤tNeighborRecord);
将currentNeighborRecord的内容复制到pCurrentNeighborRecord指向的地址。
(PutNeighborRecord()在zNVM.h中定义,是个指向NVMWrite(NVM_ADDR *dest, BYTE *src, BYTE count)的宏;NVMWrite()在zNVM.c中实现,若邻居表保存在NVM中(eeprom中),通过SPI来取数据,否则将数据逐字节写入到程序空间中(ROM),需要按块(block)来写入;)
CanAddNeighborNode( void ):搜索邻居表中有没有空的记录。
NWKClearNeighborTable( void ):清空邻居表,更新currentNeighborTableInfo的相关变量。
NWKLookupNodeByLongAddr( LONG_ADDR *longAddr ):在邻居表中根据长地址查找匹配的节点。
NWKLookupNodeByShortAddrVal( WORD shortAddrVal ):在邻居表中根据短地址查找匹配的节点。
NWKTidyNeighborTable( void ):整理邻居表,删除非子节点的节点。
PutNeighborTableInfo();
===================================================================
RouteAlongTree( SHORT_ADDR destTarget, SHORT_ADDR *destNextHop ):
===================================================================
根据树型结构决定路由下一节点的地址。如果目的地址是本节点的下属(descendants),将消息转发给下级父节点;否则转发给本节点的父节点。
遍历邻居表,判断目的地址是否邻居或邻居的下级(IsDescendant())。如果没找到,根据目的地址判断是否本身的下级,如果不是则发给父节点。
// Get ROM address of neighborTable in RAM. Skip the first entry.
pCurrentNeighborRecord = neighborTable;
for ( i="0"; i < MAX_NEIGHBORS; i++ )
{
GetNeighborRecord(¤tNeighborRecord, pCurrentNeighborRecord );
if ((currentNeighborRecord.deviceInfo.bits.bInUse) &&
(currentNeighborRecord.deviceInfo.bits.Relationship == NEIGHBOR_IS_CHILD))
{
if ((destTarget.Val == currentNeighborRecord.shortAddr.Val) ||
IsDescendant( currentNeighborRecord.shortAddr, destTarget, currentNeighborTableInfo.depth+1 ))
{
// The destination address is either my child or a
// descendant of one of my children. Pass the message
// to that child.
*destNextHop = currentNeighborRecord.shortAddr;
found = TRUE;
break;
}
}
#ifdef USE_EXTERNAL_NVM
pCurrentNeighborRecord += (WORD)sizeof(NEIGHBOR_RECORD);
#else
pCurrentNeighborRecord++;
#endif
}
=============================
IsDescendant( SHORT_ADDR parentAddr, SHORT_ADDR childAddr, BYTE parentDepth )
=============================
if ((parentAddr.Val < childAddr.Val) &&
(childAddr.Val < (parentAddr.Val + GetCSkipVal( parentDepth-1 ))))
return TRUE;
=============================
GetCSkipVal( BYTE depth )
=============================
目前代码定义到depth=0至8。返回值CSKIP_DEPTH_0至CSKIP_DEPTH_8。CSKIP_DEPTH_x由应用的头文件定义。规则为:
//******************************************************************************
// Distributed Address Assignment Constants
//
// These should be calculated manually and placed here. They are calculated by
// the following formulae. CSKIP values should be generated until the max
// depth is reached or until CSKIP equals 0.
//
// Cskip(d) = if PROFILE_nwkMaxRouters is 1 =
// 1 + Cm * (Lm - d - 1)
// otherwise =
// 1 + Cm - Rm - (Cm * Rm^(Lm - d - 1))
// ------------------------------------
// 1 - Rm
// where
// Cm = PROFILE_nwkMaxChildren
// Lm = PROFILE_nwkMaxDepth
// Rm = PROFILE_nwkMaxRouters
// d = depth of node in the network
在zHCLighting.h应用中:
#define PROFILE_nwkMaxChildren 20
#define PROFILE_nwkMaxDepth 5
#define PROFILE_nwkMaxRouters 6
则:
#define CSKIP_DEPTH_0 0x143D
#define CSKIP_DEPTH_1 0x035D
#define CSKIP_DEPTH_2 0x008D
#define CSKIP_DEPTH_3 0x0015
#define CSKIP_DEPTH_4 0x0001
#define CSKIP_DEPTH_5 0x0000
=========================
4、neighborTable的初始化:
如果使用NVM:
zNVM.c:
WORD neighborTableInfo;
WORD neighborTable;
在NVMInit()中:
result |= NVMalloc( sizeof(NEIGHBOR_TABLE_INFO), &neighborTableInfo );
result |= NVMalloc( sizeof(NEIGHBOR_RECORD) * MAX_NEIGHBORS, &neighborTable );
如果不使用NVM:
zNVM.c:
ROM NEIGHBOR_TABLE_INFO neighborTableInfo = {0x00}; // Initialize to something other than the valid key.
ROM NEIGHBOR_RECORD neighborTable[MAX_NEIGHBORS] = {0x00}; // Does not need initializing, but the HI-TECH compiler will not place it in ROM memory
(待更新)
文章评论(0条评论)
登录后参与讨论