原创 zigbee协议栈路由协议学习(3):Neighbor表

2008-9-17 11:13 5416 10 10 分类: MCU/ 嵌入式

理解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( &currentNeighborRecord, pCurrentNeighborRecord );
将pCurrentNeighborRecord指向的记录的内容复制到currentNeighborRecord结构中。
(GetNeighborRecord()在zNVM.h中定义,是个指向NVMRead()的宏;NVMRead()在zNVM.c中实现,若邻居表保存在NVM中(eeprom中),通过SPI来取数据,否则调用memcpypgm2ram()方法;memcpypgm2ram()在Common/Compiler.h中定义,根据不同的环境指向不同的系统函数)



PutNeighborRecord(pCurrentNeighborRecord, &currentNeighborRecord);
将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(&currentNeighborRecord, 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
 
(待更新)

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
10
关闭 站长推荐上一条 /1 下一条