zstack定位程序的学习--盲节点程序解读

来源:互联网 发布:ps aux grep nginx 编辑:程序博客网 时间:2024/06/06 18:28


今天来看定位的具体程序,首先是盲节点程序。花了一天时间,把程序看了一个大概,有需要交流的可以加我,我的qq号为982453335,欢迎大家和我一起讨论。

(支持原创,如需转载,请注明地址:http://blog.sina.com.cn/litianping0709 作者:叶雨荫城(阿雨))

Filename:       BlindNode.h
    Revised:        $Date: 2006-11-03 19:11:21 -0700 (Fri, 03 Nov 2006) $
    Revision:       $Revision: 12552 $

    Description:

       This file contains the BlindNode through App definitions.

    Notes:

    Copyright (c) 2011 ltp0709@sina.com.
    All Rights Reserved.  Permission to use, reproduce, copy, prepare
    derivative works, modify, distribute, perform, display or sell this
    software and/or its documentation for any purpose is prohibited
    without the express written consent of Texas Instruments, Inc.
*********************************************************************/

#ifdef __cplusplus
extern "C"
{
#endif

*********************************************************************
* INCLUDES
*/
#include "ZComDef.h"

*********************************************************************
* CONSTANTS
*/

// Blind Node's Events (bit masked)
#define BLINDNODE_BLAST_EVT                0x4000
#define BLINDNODE_FIND_EVT                 0x2000
#define BLINDNODE_WAIT_EVT                 0x1000

* MACROS
*/

*********************************************************************
* GLOBAL VARIABLES
*/
extern byte BlindNode_TaskID;

*********************************************************************
* FUNCTIONS
*/


extern void BlindNode_Init( byte task_id ); 
初始化函数


extern UINT16 BlindNode_ProcessEvent( byte task_id, UINT16 events );
事件处理函数


extern void BlindNode_FindRequest( void ); 
开始广播并计算位置信息。(这个函数名字没取好,盲节点位置请求应该由别的节点发出的,这个函数名取的有歧义。)

*********************************************************************

*********************************************************************/

#ifdef __cplusplus
}
#endif

#endif

来看c文件,c文件里的内容有点多,但没事,慢慢看,心急吃不了热豆腐,^_^^_^!!

 

*********************************************************************
  Filename:       BlindNode.c
  Revised:        $Date: 2007-05-31 13:07:52 -0700 (Thu, 31 May 2007) $
  Revision:       $Revision: 14480 $

  Description: Blind Node for the Z-Stack Location Profile.
               
  Copyright (c) 2006 by Texas Instruments, Inc.
  All Rights Reserved.  Permission to use, reproduce, copy, prepare
  derivative works, modify, distribute, perform, display or sell this
  software and/or its documentation for any purpose is prohibited
  without the express written consent of Texas Instruments, Inc.
*********************************************************************/

*********************************************************************
* INCLUDES
*/

#include "OSAL.h"
#include "OSAL_NV.h"
#include "MTEL.h"
#include "AF.h"
#include "ZDApp.h"

#include "OnBoard.h"
#include "hal_key.h"
#if defined ( LCD_SUPPORTED )
#include "hal_lcd.h"
#endif

#include "LocationProfile.h"
#include "BlindNode.h"
#include "LocationEngine.h"
#include "SampleApp.h"

#include "DebugTrace.h"


#if !defined ( CC2431 )
  #error    // Must be defined
#endif

*********************************************************************
* CONSTANTS
*/

#define BLINDNODE_MAX_REF_NODES    20   最大参考节点数
#define BLINDNODE_MIN_REF_NODES      
最少参考节点数

#define BN_TIME_INCR              100   // Milliseconds

每次增加多少毫秒

#define BLINDNODE_FIND_DELAY       20   // BN_TIME_INCR
在BN_TIME_INC时隙内自动位置寻找的延迟(不知道啥意思?)

#define BLINDNODE_WAIT_TIMEOUT       // BN_TIME_INCR

广播和轮询的间隔 以及在BN_TIME_INCR内轮询的间隔

#define BLINDNODE_BLAST_DELAY      20   // Milliseconds

每次广播的时延
#define BLINDNODE_BLAST_COUNT       8

单跳广播的次数

 zstack定位程序的学习(3)--盲节点程序解读




#define _ED_RF_POWER_MIN_DBM  -81  // TBD - why not directly access MAC defs?
#define _ED_RF_POWER_MAX_DBM   10  // TBD - why not directly access MAC defs?
#define _ED_RF_POWER_DELTA   (_ED_RF_POWER_MAX_DBM - _ED_RF_POWER_MIN_DBM)
#define _MAC_SPEC_ED_MAX      255  // TBD - why not directly access MAC defs?

传输的为绝对值
#define LOC_ENGINE_MIN_DBM  -95
#define LOC_ENGINE_MAX_DBM  -40

#if ( LOC_ENGINE_MIN_DBM < _ED_RF_POWER_MIN_DBM )
  #define BLINDNODE_MIN_DBM  _ED_RF_POWER_MIN_DBM
#else
  #define BLINDNODE_MIN_DBM  LOC_ENGINE_MIN_DBM
#endif

上述的工作室保证定位引擎的值限制在-95dBm到-40dBm。

#define BLINDNODE_MIN_RSSI  (_MAC_SPEC_ED_MAX * (BLINDNODE_MIN_DBM - _ED_RF_POWER_MIN_DBM)) / \
                                                                     _ED_RF_POWER_DELTA

(其中有#define _ED_RF_POWER_DELTA   (_ED_RF_POWER_MAX_DBM - _ED_RF_POWER_MIN_DBM) )

#if ( LOC_ENGINE_MAX_DBM < _ED_RF_POWER_MAX_DBM )
  #define BLINDNODE_MAX_DBM  LOC_ENGINE_MAX_DBM
#else
  #define BLINDNODE_MAX_DBM  _ED_RF_POWER_MAX_DBM
#endif

#define BLINDNODE_MAX_RSSI  (_MAC_SPEC_ED_MAX * (BLINDNODE_MAX_DBM - _ED_RF_POWER_MIN_DBM)) / \
                                                                     _ED_RF_POWER_DELTA

#define BLINDNODE_CONV_RSSI( lqi ) \
st ( \
  if ( lqi <= BLINDNODE_MIN_RSSI ) \
    lqi = 0; \
  else if ( lqi >= BLINDNODE_MAX_RSSI ) \
    lqi = -LOC_ENGINE_MAX_DBM; \
  else \
    lqi = -BLINDNODE_MIN_DBM - ((uint8)(((uint16)(lqi) * _ED_RF_POWER_DELTA) / _MAC_SPEC_ED_MAX)); \
)

// [ Loc = (Loc * (N-1) + New-Calc) / N ]  Set to 1 for no filtering.
#define BLINDNODE_FILTER      2
// If newly calculated pos differs by more than M meters, flush filter and
// restart. 10m * 4 = 40
#define BLINDNODE_FLUSH      40   //
这个常量不知道有什么作用?

*********************************************************************
* TYPEDEFS
*/

typedef struct
{
  uint16 timeout;       // In 100 msec increments - time to collect ref node responses
  uint16 cycle;         // In 100 msec increments - For auto mode
  uint16 dstAddr;       // For auto mode
  uint8  dstEp;         // For auto mode
  uint8  mode;    模式位
  uint8  minRefNodes;   最小参考节点数
  LocDevCfg_t loc; //
定位配置

}BN_Cfg_t;     盲节点配置

typedef enum
{
  eBnIdle,
  eBnBlastOut,
  eBnBlastIn,
  eBnBlastOff
} eBN_States_t;  
和BLAST有关。表示各个状态量

typedef struct
{
  uint16 x;
  uint16 y;
  uint16 addr;
  uint8  ep;
  uint8  rssi;
} RefNode_t; 
收到的参考节点的数据

*********************************************************************
* GLOBAL VARIABLES
*/

uint8 BlindNode_TaskID;   全局变量

*********************************************************************
* LOCAL VARIABLES  局部变量
*/

static const cId_t BlindNode_InputClusterList[] = 盲节点输入簇
{
  LOCATION_XY_RSSI_REQUEST,      XY_RSSI请求
  LOCATION_XY_RSSI_RESPONSE,      XY-RSSI响应
  LOCATION_BLINDNODE_FIND_REQUEST, 定位寻找请求
  LOCATION_BLINDNODE_CONFIG,     盲节点配置
  LOCATION_BLINDNODE_REQUEST_CONFIG  盲节点请求配置
};

static const cId_t BlindNode_OutputClusterList[] =
{
  LOCATION_XY_RSSI_REQUEST,
  LOCATION_XY_RSSI_RESPONSE,
  LOCATION_BLINDNODE_FIND_RESPONSE,
  LOCATION_BLINDNODE_CONFIG,

  LOCATION_RSSI_BLAST    RSSI广播
};

static const SimpleDescriptionFormat_t BlindNode_SimpleDesc =
                    盲节点简单描述符
  LOCATION_BLINDNODE_ENDPOINT,
  LOCATION_PROFID,
  LOCATION_BLINDNODE_DEVICEID,
  LOCATION_DEVICE_VERSION,
  LOCATION_FLAGS,  
  sizeof(BlindNode_InputClusterList),
  (cId_t *)BlindNode_InputClusterList,
  sizeof(BlindNode_OutputClusterList),
  (cId_t *)BlindNode_OutputClusterList
};

static const endPointDesc_t epDesc =
               端点描述符
  LOCATION_BLINDNODE_ENDPOINT,
  &BlindNode_TaskID,
  (SimpleDescriptionFormat_t *)&BlindNode_SimpleDesc,
  noLatencyReqs
};

static BN_Cfg_t config;   盲节点配置
static eBN_States_t state;   状态
static RefNode_t refNodes[BLINDNODE_MAX_REF_NODES]; 最大的参考节点数数组,用于存储参考节点的数据信息。
static uint8 transId; 

static afAddrType_t defAddr;

#if defined( BN_DISPLAY_TEST ) && defined( MT_TASK ) 测试用
  #define PRINTBUFSIZE 80
  uint8 printBuf[PRINTBUFSIZE];
#endif

static uint8 blastCnt;
static uint8 rspCnt;   // Count of unique XY_RSSI_RESPONSE messages after blast.

static uint8 rspMsg[LOCATION_XY_RSSI_LEN]; 响应消息

static uint32 xOld, yOld;

*********************************************************************
* LOCAL FUNCTIONS  本文件处理函数*/
static void processMSGCmd( afIncomingMSGPacket_t *pckt );   消息处理函数
static void parseConfig( uint8 *msg ); 分析配置函数
static afStatus_t sendRsp( void );  发送响应
static afStatus_t sendConfig( afAddrType_t *dstAddr );发送配置
static void finishCollection( void ); 结束收集
static void calcOffsets( RefNode_t *ref, uint16 *xOff, uint16 *yOff );计算偏移
static RefNode_t *findBestRSSI( RefNode_t *ref ); 找出具有最好RSSI的参考节点
static uint8 sortNodes( RefNode_t *ref ); 将参考节点按照RSSI值的大小排序,从小到大(从好到坏)
static void setLogicals( LocRefNode_t *loc, RefNode_t *ref,
                                               uint16 xOff, uint16 yOff );
将找出合适的参考节点并将其值写入用于定位引擎计算的数组

 

****************************

注:

typedef struct
{
  byte x;
  byte y;
  byte rssi;
} LocRefNode_t;

typedef struct
{
  byte  param_a;
  byte  param_n;

  byte  x;
  byte  y;
  byte  min;
} LocDevCfg_t;

**************************

 

static void startBlast( void ); 开始广播

*********************************************************************
* @fn      BlindNode_Init
*
* @brief   Initialization function for the Generic App Task.
*
* @param   task_id - the ID assigned by OSAL.
*
* @return  none
*/
void BlindNode_Init( uint8 task_id )
{
  BlindNode_TaskID = task_id;

  state = eBnIdle;

  config.loc.param_a = LOC_DEFAULT_A;  参数A
  config.loc.param_n = LOC_DEFAULT_N;  参数N
  config.mode = LOC_DEFAULT_MODE; 默认模式为自动模式#define LOC_DEFAULT_MODE    NODE_MODE_AUTO
  config.timeout = BLINDNODE_WAIT_TIMEOUT * BN_TIME_INCR;

这个参数主要表明在收集完参考节点数据之前应该等待多长时间,默认情况下BLINDNODE_WAIT_TIMEOUT为2,BN_TIME_INCR为100ms
  config.cycle = (uint16)((uint16)BLINDNODE_FIND_DELAY * BN_TIME_INCR); 
这个参数只在自动模式下有效,本次数据采集与下一次数据收集之间的时间间隔,默认情况下为BLINDNODE_CYCLE_PERIOD,BLINDNODE_CYCLE_PERIOD = BLINDNODE_WAIT_TIMEOUT * BLINDMODE_REQ_RSPS * 2.

it is recommended that the above is the “minimum auto cycle time” – it is only logical that the Blind Node cannot start the next collection cycle before the first is finished. Since it could collect from up to 16 Reference Nodes, and then passing the best 8 to the location engine, the max cycle time (minimum config.cycle setting) would be BLINDNODE_WAIT_TIMEOUT * MAX_REF_NODES, (1600 ms or 1.6 s).

  config.dstAddr = 0;  

目的地址默认为协调器
  config.dstEp = LOCATION_DONGLE_ENDPOINT;

默认端为配置端点,一般为协调器里的配置端点
  config.minRefNodes = BLINDNODE_MIN_REF_NODES;

最小参考节点数目

  if ( ZSUCCESS == osal_nv_item_init( LOC_NV_BLINDNODE_CONFIG,
                                      sizeof(BN_Cfg_t), &config ) )
  {
    osal_nv_read( LOC_NV_BLINDNODE_CONFIG, 0, sizeof( BN_Cfg_t ), &config );
  }
  else
  {
    osal_nv_write( LOC_NV_BLINDNODE_CONFIG, 0, sizeof( BN_Cfg_t ), &config );
  }

上述主要将相关配置信息写入非易失性存储器中。

  afRegister( (endPointDesc_t *)&epDesc ); 注册端点
  //RegisterForKeys( BlindNode_TaskID );

#if defined ( LCD_SUPPORTED )
  //HalLcdWriteString( "Location-Blind", HAL_LCD_LINE_1 );
    GUI_SetColor(1,0);
    GUI_PutString5_7(0,37,"   Location-Blind    ");
    LCM_Refresh();
#ifdef LCD_SD
#ifdef ZTOOL_PORT
    debug_str( (byte*)"Location-Blind" );
#endif
#endif
#endif

  defAddr.addrMode = afAddrBroadcast;
  defAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVALL;
  defAddr.endPoint = LOCATION_DONGLE_ENDPOINT;

  if ( (config.mode == NODE_MODE_AUTO) && (config.cycle > 0) )
  {
    osal_start_timerEx( BlindNode_TaskID, BLINDNODE_FIND_EVT, config.cycle );
  }
}
启动BLINDNODE_FIND_EVT事件,时间间隔为config.cycle。

*********************************************************************
* @fn      BlindNode_ProcessEvent 
盲节点处理事件函数
*
* @brief   Generic Application Task event processor.
*
* @param   task_id  - The OSAL assigned task ID.
* @param   events - events to process.
*
* @return  none
*/
uint16 BlindNode_ProcessEvent( uint8 task_id, uint16 events )
{
  if ( events & SYS_EVENT_MSG )
  {
    afIncomingMSGPacket_t *MSGpkt;
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( BlindNode_TaskID );

    while( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
      case KEY_CHANGE:
        //handleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
        break; 
处理按键信息

      case AF_DATA_CONFIRM_CMD:
#if !defined( RTR_NWK )  没有路由功能的话就进行编译
        {
        // This message is received as a confirmation of a data packet sent.
        // The status is of ZStatus_t type [defined in ZComDef.h]
        afDataConfirm_t *afDataConfirm = (afDataConfirm_t *)MSGpkt;

        if ( afDataConfirm->hdr.status != ZSuccess )
        {
         
          if ( afDataConfirm->hdr.status == ZMacNoACK )
          {
            SampleApp_NoACK();

   ***************************************

注:

*********************************************************************
* @fn      SampleApp_NoACK
*
* @brief   Sample Application recovery from getting a ZMacNoAck.
*
* @return  none
*/
void SampleApp_NoACK( void )
{
#if defined( POWER_SAVING )
  rejoinPending = TRUE;
  ZDApp_SendEventMsg( ZDO_NWK_JOIN_REQ, 0, NULL );  //发送重新加入请求消息,请求重新加入网络

  SampleApp_Sleep( FALSE );

*****************************

注:

void SampleApp_Sleep( uint8 allow )
{
#if defined( POWER_SAVING )
  if ( allow )
  {
    osal_pwrmgr_task_state( NWK_TaskID, PWRMGR_CONSERVE );
    NLME_SetPollRate( 0 );
  }
  else
  {
    osal_pwrmgr_task_state( NWK_TaskID, PWRMGR_HOLD );

*****************************************

注:

* @fn      osal_pwrmgr_task_state
*
* @brief   This function is called by each task to state whether or
         not this task wants to conserve power.
*这个函数被任务调用用来表示该任务是否需要节能
* @param   task_id - calling task ID.
         state - whether the calling task wants to
         conserve power or not.
*
* @return  ZSUCCESS if task complete

******************************************


    NLME_SetPollRate( 1000 );
  }
#endif
}

******************************
#endif
}

********************************************
          }
          else  // Some other error -- Do something.
          {
          }
        }

        }
#endif
        break;

      case AF_INCOMING_MSG_CMD: 消息处理
        processMSGCmd( MSGpkt ); (见消息处理函数注释)
        break;

      case ZDO_STATE_CHANGE: 设备状态改变
#if defined( RTR_NWK )  定义了路由功能
        NLME_PermitJoiningRequest( 0 );  不允许其他节点加入,为何?
#endif
       
        osal_start_timerEx( BlindNode_TaskID, BLINDNODE_FIND_EVT,
                                              BLINDNODE_FIND_DELAY );  启动盲节点寻找事件。
        break;

      default:
        break;
      }

      osal_msg_deallocate( (uint8 *)MSGpkt );
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( BlindNode_TaskID );
    }

    return ( events ^ SYS_EVENT_MSG );  // Return unprocessed events.
  }

  if ( events & BLINDNODE_BLAST_EVT )  广播
  {
    if ( blastCnt == 0 ) 如果为0
    {
      state = eBnBlastOff; 状态转为关闭状态
      finishCollection();

***************************

注: * @fn      finishCollection
*
* @brief   Sends the next Bind Node Response message
            发送盲节点的响应消息
* @param   none
*
* @return  none
*/

 

****************************
    }
    else
    {
      afAddrType_t dstAddr;
      uint8 stat, delay;

      dstAddr.addrMode = afAddrBroadcast;广播模式
      dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVALL;
      dstAddr.endPoint = LOCATION_REFNODE_ENDPOINT;
端点为参考节点的端点

      if ( --blastCnt == 0 )如果次数为0的话开始发送XY-RSSI请求
      {
        stat = AF_DataRequest( &dstAddr, (endPointDesc_t *)&epDesc,
                                LOCATION_XY_RSSI_REQUEST, 0, NULL,
                               &transId, AF_SKIP_ROUTING, 1 );

        state = eBnBlastIn;
        delay = config.timeout;
      }
      else    次数不为零的话广播定位blast
      {
        stat = AF_DataRequest( &dstAddr, (endPointDesc_t *)&epDesc,
                                LOCATION_RSSI_BLAST, 0, NULL,
                               &transId, AF_SKIP_ROUTING, 1 );
        delay = BLINDNODE_BLAST_DELAY;  
      }
      if ( stat != afStatus_SUCCESS ) 发送不成功的话增加发送次数
      {
        blastCnt++;
      }
      osal_start_timerEx( BlindNode_TaskID, BLINDNODE_BLAST_EVT, delay );延迟一段时间后再次启动该事件 
    }

    return ( events ^ BLINDNODE_BLAST_EVT );
  }

  if ( events & BLINDNODE_FIND_EVT ) 盲节点寻找事件
  {
    BlindNode_FindRequest();  
盲节点寻找请求(名字听着很不习惯) 具体注释见下面函数解析。

    return ( events ^ BLINDNODE_FIND_EVT );
  }

  if ( events & BLINDNODE_WAIT_EVT ) 等待时进入睡眠模式
  {
    SampleApp_Sleep( TRUE );

    return ( events ^ BLINDNODE_WAIT_EVT );
  }

  return 0;  // Discard unknown events.
}

*********************************************************************
* @fn      LocationHandleKeys
*
* @brief   Handles all key events for this device.
*
* @param   keys - bit field for key events. Valid entries:
*
* @return  none
*/
void LocationHandleKeys( uint8 keys )
{
  if ( keys & HAL_KEY_SW_1 )
  {
  }
  if ( keys & HAL_KEY_SW_2 )
  {
  }
  if ( keys & HAL_KEY_SW_3 )
  {
    osal_set_event( BlindNode_TaskID, BLINDNODE_FIND_EVT );
  }
  if ( keys & HAL_KEY_SW_4 )
  {
    if ( state == eBnIdle )
    {
      startBlast();
    }
  }
}

*********************************************************************
* @fn      processMSGCmd
*
* @brief   Data message processor callback.
   数据信息处理函数
* @param   none
*
* @return  none
*/
static void processMSGCmd( afIncomingMSGPacket_t *pkt )
{
  switch ( pkt->clusterId )   选择簇ID
  {
    case LOCATION_XY_RSSI_REQUEST:  如果是LOCATION_XY_RSSI_REQUEST请求
      rspMsg[LOCATION_XY_RSSI_RSSI_IDX] = pkt->LinkQuality;
      pkt->srcAddr.addrMode = afAddr16Bit;
      (void)AF_DataRequest( &pkt->srcAddr, (endPointDesc_t *)&epDesc,
                             LOCATION_XY_RSSI_RESPONSE, LOCATION_XY_RSSI_LEN,
                             rspMsg, &transId, 0, AF_DEFAULT_RADIUS );
      break;

    case LOCATION_BLINDNODE_FIND_REQUEST:盲节点位置请求
      if ( state == eBnIdle )
      {
        defAddr.addrMode = afAddr16Bit;
        defAddr.addr.shortAddr = pkt->srcAddr.addr.shortAddr;
        defAddr.endPoint = pkt->srcAddr.endPoint;保存目标地址
        startBlast(); 开始广播
      }
      break;

    case LOCATION_BLINDNODE_CONFIG:盲节点配置
      if ( state == eBnIdle ) 
      {
        parseConfig( pkt->cmd.Data ); 分解配置信息
      }
      break;

    case LOCATION_BLINDNODE_REQUEST_CONFIG:请求配置
      sendConfig( &(pkt->srcAddr) ); 发送配置信息给源发送命令方
      break;

    case LOCATION_XY_RSSI_RESPONSE:    XY-RSSI响应
      if ( state == eBnBlastIn )
      {
        uint8 idx;

        for ( idx = 0; idx < BLINDNODE_MAX_REF_NODES; idx++ )
         
虽然是个循环 但通过后面的break可以退出。

          if ( (refNodes[idx].addr == INVALID_NODE_ADDR) ||
               (refNodes[idx].addr == pkt->srcAddr.addr.shortAddr) )
          {
如果地址为无效地址或者地址已经存在那么存储这个值然后退出循环,否则索引号加1后继续判断存储。

            refNodes[idx].addr = pkt->srcAddr.addr.shortAddr;存储源地址
            refNodes[idx].ep = pkt->srcAddr.endPoint;源端点
            refNodes[idx].x = BUILD_UINT16(
                                  pkt->cmd.Data[LOCATION_XY_RSSI_X_LO_IDX],
                                  pkt->cmd.Data[LOCATION_XY_RSSI_X_HI_IDX] );

          存储x值
            refNodes[idx].y = BUILD_UINT16(
                                  pkt->cmd.Data[LOCATION_XY_RSSI_Y_LO_IDX],
                                  pkt->cmd.Data[LOCATION_XY_RSSI_Y_HI_IDX] );
            refNodes[idx].rssi =  pkt->cmd.Data[LOCATION_XY_RSSI_RSSI_IDX];

         存储y值

            if ( rspCnt <= idx )    
            {
              rspCnt = idx+1;rspCnt有何作用,应该是参考节点的个数。在后面会用到
            }
            break;

          }
        }
      }
      break;

    default:
      break;
  }
}

*********************************************************************
* @fn      parseConfig
*
* @brief   Parse message and populate the configuration struct
       分析配置消息并且将其赋予配置结构体
* @param   none
*
* @return  none
*/
static void parseConfig( uint8 *msg )
{
  config.loc.param_a = msg[BLINDNODE_CONFIG_A_IDX]; 存储A值
  config.loc.param_n = msg[BLINDNODE_CONFIG_N_IDX]; 存储N值
  if ( (msg[BLINDNODE_CONFIG_MODE_IDX] == NODE_MODE_POLLED) ||
       (msg[BLINDNODE_CONFIG_MODE_IDX] == NODE_MODE_AUTO) )
  {
    config.mode = msg[BLINDNODE_CONFIG_MODE_IDX]; 存储模式
  }

  config.timeout = BN_TIME_INCR * BUILD_UINT16(
                                  msg[BLINDNODE_CONFIG_COLLECT_TIME_LO_IDX],
                                  msg[BLINDNODE_CONFIG_COLLECT_TIME_HI_IDX] );

  config.cycle = BN_TIME_INCR * BUILD_UINT16(
       msg[BLINDNODE_CONFIG_CYCLE_LO_IDX], msg[BLINDNODE_CONFIG_CYCLE_HI_IDX] );

存储相应的时间参数 
  config.dstAddr = BUILD_UINT16( msg[BLINDNODE_CONFIG_REPORT_SADDR_LO_IDX],
                                 msg[BLINDNODE_CONFIG_REPORT_SADDR_HI_IDX] );

存储相应的地址
  config.dstEp = msg[BLINDNODE_CONFIG_REPORT_EP_IDX];

存储相应的端点号
  config.minRefNodes = msg[BLINDNODE_CONFIG_MIN_REFNODES_IDX];

存储最小的节点数

  osal_nv_write( LOC_NV_BLINDNODE_CONFIG, 0, sizeof( BN_Cfg_t ), &config );

写入配置参数

  if ( config.mode == NODE_MODE_AUTO ) 如果是自动的话启动BLINDNODE_FIND_EVT 事件
  {
    osal_set_event( BlindNode_TaskID, BLINDNODE_FIND_EVT );
  }
}

*********************************************************************
* @fn      sendRsp
*
* @brief   Build and send the response message.
      建立和发送响应消息(这个函数最他妈的难整,闹心死我了,搞了一天最后才啃到这个函数)
* @param   None.
*
* @return  status from call to AF_DataRequest().
*/
static afStatus_t sendRsp( void )
{
  uint8 msg[BLINDNODE_RESPONSE_LEN];
消息长度

************************************

响应消息的格式如下:

// LOCATION_BLINDNODE_RESPONSE - message format
#define BLINDNODE_RESPONSE_STATUS_IDX               0
#define BLINDNODE_RESPONSE_X_LO_IDX                 1
#define BLINDNODE_RESPONSE_X_HI_IDX                 2
#define BLINDNODE_RESPONSE_Y_LO_IDX                 3
#define BLINDNODE_RESPONSE_Y_HI_IDX                 4
#define BLINDNODE_RESPONSE_NUMREFNODES_IDX          5
#define BLINDNODE_RESPONSE_REF_SHORTADDR_LO_IDX     6
#define BLINDNODE_RESPONSE_REF_SHORTADDR_HI_IDX     7
#define BLINDNODE_RESPONSE_REF_X_LO_IDX             8
#define BLINDNODE_RESPONSE_REF_X_HI_IDX             9
#define BLINDNODE_RESPONSE_REF_Y_LO_IDX             10
#define BLINDNODE_RESPONSE_REF_Y_HI_IDX             11
#define BLINDNODE_RESPONSE_REF_RSSI                 12

#define BLINDNODE_RESPONSE_LEN                      13

// Values for Blind Node Response Status field
#define BLINDNODE_RSP_STATUS_SUCCESS                0
#define BLINDNODE_RSP_STATUS_NOT_ENOUGH_REFNODES    1

**************************************

LocRefNode_t locNodes[BLINDNODE_MAX_REF_NODES];用于存储经过处理后的参考节点信息,用于定位引擎计算。

*************************

注:

typedef struct
{
  byte x;
  byte y;
  byte rssi;
} LocRefNode_t;

*************************
  uint16 xOff, yOff; 变量表示成这个样子,真他妈的不好看,算我白痴吧,他们表示成这样子有他们的目的。
  uint8 idx, cnt = 0;

  for ( idx = 0; idx < rspCnt; idx++ )
  {
    BLINDNODE_CONV_RSSI( refNodes[idx].rssi ); 将收到的rssi值进行转换,为何进行转换先不管了。但不要用出来混迟早都是要还的来刺激我。O(∩_∩)O~
    if ( refNodes[idx].rssi != 0 )
    {
      cnt++; 收到几个有效参考节点的值,要大于3
    }
  }

  if ( cnt >= config.minRefNodes )
  {
    msg[BLINDNODE_RESPONSE_STATUS_IDX] = BLINDNODE_RSP_STATUS_SUCCESS;
状态位为成功位

    // Sort the ref nodes by RSSI in order to pass the best 16 to loc engine.

挑选最好的节点的RSSI参数传给定位引擎 
   
rspCnt = sortNodes( refNodes );进行挑选,重新挑选出有效参考节点个数  

    calcOffsets( refNodes, &xOff, &yOff ); 计算偏移量

    // Convert to logical coordinates.  
 
  setLogicals( locNodes, refNodes, xOff, yOff );转换,具体转换的过程见这个函数解析

    // Run the location calculation
 
   locationCalculatePosition( locNodes, &(config.loc) );利用定位引擎进行计算 具体过程我转载了阿元的文章,里面有详细介绍。

    // Convert results to real coordinates and average over several samples.

转换成真实坐标,通过加上偏移量,具体为何这样做大家自己好好想想,配套文档里也写的有。
    xOff += config.loc.x;
    yOff += config.loc.y;  
面的过程是一些滤波过程吧

    if ( ((xOff > xOld) && ((xOff - xOld) > BLINDNODE_FLUSH))  ||
         ((xOff < xOld) && ((xOld - xOff) > BLINDNODE_FLUSH))  ||
         ((yOff > yOld) && ((yOff - yOld) > BLINDNODE_FLUSH))  ||
         ((yOff < yOld) && ((yOld - yOff) > BLINDNODE_FLUSH)) )
    {
      xOld = xOff;
      yOld = yOff;
    }
    else
    {
      xOld = ((xOld * (BLINDNODE_FILTER-1)) + xOff) / BLINDNODE_FILTER;
      yOld = ((yOld * (BLINDNODE_FILTER-1)) + yOff) / BLINDNODE_FILTER;
    }

    xOff = (uint16)xOld;
    yOff = (uint16)yOld;
  }
  else
  {
    msg[BLINDNODE_RESPONSE_STATUS_IDX] = BLINDNODE_RSP_STATUS_NOT_ENOUGH_REFNODES;

    xOff = (uint16)xOld;
    yOff = (uint16)yOld;
     
  rspMsg[REFNODE_CONFIG_X_LO_IDX] =
  msg[BLINDNODE_RESPONSE_X_LO_IDX] = LO_UINT16( xOff );
  rspMsg[REFNODE_CONFIG_X_HI_IDX] =
  msg[BLINDNODE_RESPONSE_X_HI_IDX] = HI_UINT16( xOff );
  rspMsg[REFNODE_CONFIG_Y_LO_IDX] =
  msg[BLINDNODE_RESPONSE_Y_LO_IDX] = LO_UINT16( yOff );
  rspMsg[REFNODE_CONFIG_Y_HI_IDX] =
  msg[BLINDNODE_RESPONSE_Y_HI_IDX] = HI_UINT16( yOff );

  msg[BLINDNODE_RESPONSE_NUMREFNODES_IDX] = cnt;

  if ( rspCnt != 0 )
          距离最近的节点的信息
    msg[BLINDNODE_RESPONSE_REF_SHORTADDR_LO_IDX] = LO_UINT16( refNodes->addr );
    msg[BLINDNODE_RESPONSE_REF_SHORTADDR_HI_IDX] = HI_UINT16( refNodes->addr );
    msg[BLINDNODE_RESPONSE_REF_X_LO_IDX] = LO_UINT16( refNodes->x );
    msg[BLINDNODE_RESPONSE_REF_X_HI_IDX] = HI_UINT16( refNodes->x );
    msg[BLINDNODE_RESPONSE_REF_Y_LO_IDX] = LO_UINT16( refNodes->y );
    msg[BLINDNODE_RESPONSE_REF_Y_HI_IDX] = HI_UINT16( refNodes->y );
    msg[BLINDNODE_RESPONSE_REF_RSSI] = refNodes->rssi;
  }
  else
          否则有错
    msg[BLINDNODE_RESPONSE_REF_SHORTADDR_LO_IDX] = LO_UINT16( INVALID_NODE_ADDR );
    msg[BLINDNODE_RESPONSE_REF_SHORTADDR_HI_IDX] = HI_UINT16( INVALID_NODE_ADDR );
    msg[BLINDNODE_RESPONSE_REF_X_LO_IDX] = LO_UINT16( LOC_DEFAULT_X_Y );
    msg[BLINDNODE_RESPONSE_REF_X_HI_IDX] = HI_UINT16( LOC_DEFAULT_X_Y );
    msg[BLINDNODE_RESPONSE_REF_Y_LO_IDX] = LO_UINT16( LOC_DEFAULT_X_Y );
    msg[BLINDNODE_RESPONSE_REF_Y_HI_IDX] = HI_UINT16( LOC_DEFAULT_X_Y );
    msg[BLINDNODE_RESPONSE_REF_RSSI] = 0xFF;
  }

………

………

  osal_start_timerEx( BlindNode_TaskID, BLINDNODE_WAIT_EVT, 1000 );启动等待事件,然后 进入休眠状态

  return ( AF_DataRequest( &defAddr, (endPointDesc_t *)&epDesc,
                           LOCATION_BLINDNODE_FIND_RESPONSE,
                           BLINDNODE_RESPONSE_LEN, msg,
                           &transId, 0, AF_DEFAULT_RADIUS ) );
}

*********************************************************************
* @fn      sendConfig
*
* @brief   Build and send the response message.
* 建立和发送响应消息
* @param   dstAddr - where to send
*
* @return  status from call to AF_DataRequest().
*/
static afStatus_t sendConfig( afAddrType_t *dstAddr )
{
  uint8 msg[BLINDNODE_CONFIG_LEN];
消息长度

  msg[BLINDNODE_CONFIG_A_IDX] = config.loc.param_a;
  msg[BLINDNODE_CONFIG_N_IDX] = config.loc.param_n;
  msg[BLINDNODE_CONFIG_MODE_IDX] = config.mode;
  msg[BLINDNODE_CONFIG_COLLECT_TIME_LO_IDX] = LO_UINT16(
                                       config.timeout / BN_TIME_INCR );
  msg[BLINDNODE_CONFIG_COLLECT_TIME_HI_IDX] = HI_UINT16(
                                       config.timeout / BN_TIME_INCR );
  msg[BLINDNODE_CONFIG_CYCLE_LO_IDX] = LO_UINT16( config.cycle / BN_TIME_INCR );
  msg[BLINDNODE_CONFIG_CYCLE_HI_IDX] = HI_UINT16( config.cycle / BN_TIME_INCR );
  msg[BLINDNODE_CONFIG_REPORT_SADDR_LO_IDX] = LO_UINT16( config.dstAddr );
  msg[BLINDNODE_CONFIG_REPORT_SADDR_HI_IDX] = HI_UINT16( config.dstAddr );
  msg[BLINDNODE_CONFIG_REPORT_EP_IDX] = config.dstEp;
  msg[BLINDNODE_CONFIG_MIN_REFNODES_IDX] = config.minRefNodes;

上述过程和分析配置参数一样只是一个反过程,赋值后发送出去,很简单。

  return ( AF_DataRequest( dstAddr, (endPointDesc_t *)&epDesc,
                           LOCATION_BLINDNODE_CONFIG,
                           BLINDNODE_CONFIG_LEN, msg,
                           &transId, 0, AF_DEFAULT_RADIUS ) );
}

*********************************************************************
* @fn      finishCollection
*
* @brief   Sends the next Bind Node Response message
        发送下一个盲节点响应消息
* @param   none
*
* @return  none
*/
static void finishCollection( void )
{
  if ((ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE) == 0)
  {
    uint8 x;

    // Turn the receiver back off while idle
    x = false;
    ZMacSetReq( ZMacRxOnIdle, &x );  
  }

  // Send the Blind node response
  sendRsp();  
发送盲节点响应

  if ( config.mode == NODE_MODE_AUTO )
  如果是自动模式设置下一次盲节点BLINDNODE_FIND_EVT事件
    // set up next auto response
    osal_start_timerEx( BlindNode_TaskID, BLINDNODE_FIND_EVT, config.cycle );
    defAddr.addrMode = afAddr16Bit;  目标地址改为配置节点地址,一般为协调器
    defAddr.addr.shortAddr = config.dstAddr;
    defAddr.endPoint = config.dstEp;
  }

  state = eBnIdle; 状态初始化
}

*********************************************************************
* @fn      calcOffsets
*
* @brief   Calculates the XY offsets.
           计算XY偏移量(为什么出现偏移量这个东西)
* INPUTS: 
* @param   ref - Array of reference nodes, pre-sorted on RSSI, best to worst.
   
* OUTPUTS:
* @param   xOff - pointer to X offset  
* param    yOff - pointer to Y offset    
*
* @return  none
*/
static void calcOffsets( RefNode_t *ref, uint16 *xOff, uint16 *yOff )
{
  RefNode_t *rnP = ref;   指针
  uint16 xMax = 0;
  uint16 yMax = 0;
  uint8 idx;  
索引

  for ( idx = 0; idx < rspCnt; idx++ )
  {
    if ( xMax < rnP->x )
    {
      xMax = rnP->x;   找出最大的X值
    }
    if ( yMax < rnP->y )
    {
      yMax = rnP->y;  找出最大的Y值
    }

    rnP++;
  }

  // No need for conversion.
  if ( (xMax < 256) && (yMax < 256) )
  {
    *xOff = *yOff = 0;   如果最大值在256的范围内,偏移量为0
  }
  else
  {
    // Force reference node with the best RSSI to sit at logical (32,32).
    *xOff = (ref->x & 0xFFFC) - 128; 否则将最好的RSSI的节点范围限制在(32,,32),这个地方啥意思,没看懂,为何要这样干??我感觉可能是范围超过64*64之后进行定位计算用的。
    *yOff = (ref->y & 0xFFFC) - 128;  

  }
}

*********************************************************************
* @fn      findBestRSSI
*
* @brief   Returns the node with the best rssi.
         寻找最好的RSSI值,并返回相应的节点
* INPUTS:  ref - Array of reference nodes w/ RSSI values converted for
         location engine from 40 (strong) to 95 (weak) & zero = too week.
        
* @return  Ref node entry with best RSSI.
*/
static RefNode_t *findBestRSSI( RefNode_t *ref )
{
  RefNode_t *bestRef = NULL;
  uint8 idx;

  for ( idx = 0; idx < rspCnt; idx++ ) 挑最好的一个出来
  {
    if ( (ref->addr != INVALID_NODE_ADDR) && (ref->rssi != 0) )
    {
      if ( (bestRef == NULL) || (bestRef->rssi > ref->rssi) )
      {
        bestRef = ref;
      }
    }
    ref++;
  }

  return bestRef;
}

*********************************************************************
* @fn      sortNodes
*
* @brief   Sorts the nodes into a list with the best to least RSSI
   将节点分类 从最好的到最少的
* INPUTS:  ref - Array of reference nodes w/ RSSI values converted for
         location engine from 40 (strong) to 95 (weak) & zero = too week.
*参数为 参考节点数组
* OUTPUTS: none
*
* @return  Count of non-zero RSSI entries.
*/
static uint8 sortNodes( RefNode_t *ref )
{
  RefNode_t *workNodes;
  uint8 idx;

  workNodes = osal_mem_alloc( sizeof( RefNode_t ) * rspCnt );分配存储空间

  if ( workNodes == NULL )
  {
    return 0; 如果没有的话返回
  }

  osal_memcpy( workNodes, ref, sizeof( RefNode_t ) * rspCnt );复制相应的信息,防止改变原有的信息,整体赋值和下面的有点区别,下面的数组元素的单个赋值。要注意分清楚。

  for ( idx = 0; idx < rspCnt; idx++ )
   
    RefNode_t *node = findBestRSSI( workNodes );
具体过程见这个findBestRSSI( workNodes )函数解析

    if ( node == NULL )
    {
      break;  没有的话退出
    }
    else
    {
      osal_memcpy( ref, node, sizeof( RefNode_t ) );
如果有的话将进过挑选的值赋给源数组。

      node->addr = INVALID_NODE_ADDR;将找出来的节点地址改成无效地址,在下次寻找时不会再找到本节点

    }

    ref++;  
  }

  osal_mem_free( workNodes );释放空间

  return idx; 返回值为具有有效RSSI值的节点数,并且大小按照从好到坏进行排列。
}

*********************************************************************
* @fn      setLogicals
*
* @brief   Sets the reference node's logical coordinates & RSSI for the
         required number of inputs to the location engine.
*
* INPUTS:   
* @param   ref - array of reference nodes
* @param   offsetX - X offset used to make logical numbers
* param    offsetY - Y offset used to make logical numbers
*
* @return  none
*/
static void setLogicals( LocRefNode_t *loc, RefNode_t *ref,
                                               uint16 xOff, uint16 yOff )
{
  // Rev-B Chip have LocEng Ver 1.0 w/ cap=8, Rev-C have LocEng Ver 2.0 w/ 16.
  const uint8 stop = ( ( CHVER == 0x01 ) ? LOC_ENGINE_NODE_CAPACITY_REVB :
                                          LOC_ENGINE_NODE_CAPACITY_REVC);

            芯片版本的选择吗?
  uint16 xTmp, yTmp;  暂存变量
  uint8 idx; 
索引号

  // Set the logical coordinates
  for ( idx = 0; idx < rspCnt; idx++ )
  {
    xTmp = ref->x - xOff;
    yTmp = ref->y - yOff;

    if ( (xTmp < 256) && (yTmp < 256) )  如果有节点在减去偏移量后处在64*64m的范围内就作为有效值处理,否则就丢弃
    {
      loc->x = (uint8)xTmp;
      loc->y = (uint8)yTmp;
      loc->rssi = ref->rssi;
    }
    else
    {
      // Out of bounds, so feed zero to location engine.
      loc->x = loc->y = loc->rssi = 0;  如果超出范围就不用管了
    }

    loc++;
    ref++;
  }

  for ( ; idx < stop; idx++ )   将剩余的定位引擎的未输入值补零,满足输入要求。
  {
    // Feed zero to location engine to meet the required number of inputs.
    loc->x = loc->y = 0;
    loc->rssi = 0;
    loc++;
  }
}

*********************************************************************
* @fn      startBlast   启动广播
*
* @brief   Start a sequence of blasts and calculate position.
       开始广播并且计算位置
* @param   none
*
* @return  none
*/
static void startBlast( void )
{
  uint8 idx;
  afAddrType_t dstAddr;
  dstAddr.addrMode = afAddrBroadcast; 广播
  dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVALL;
  dstAddr.endPoint = LOCATION_REFNODE_ENDPOINT;
目标端点位参考节点的端点

  if ((ZDO_Config_Node_Descriptor.CapabilityFlags & CAPINFO_RCVR_ON_IDLE) == 0)
        CAPINFO_RCVR_ON_IDLE是什么东西??
    // Turn the receiver on while idle - temporarily.
    idx = true;
    ZMacSetReq( ZMacRxOnIdle, &idx ); //这个函数有何功能?写MAC层PIB属性值
  }
  SampleApp_Sleep( FALSE );
关掉休眠

  for ( idx = 0; idx < BLINDNODE_MAX_REF_NODES; idx++ )
  {
    refNodes[idx].addr = INVALID_NODE_ADDR; 无效地址(这个地址一般用于绑定),为啥在这里要赋这个值呢??猜想:只是一个初始化,没有多大意义。
  }

  (void)AF_DataRequest( &dstAddr, (endPointDesc_t *)&epDesc,
                         LOCATION_RSSI_BLAST, 0,
                         NULL, &transId,
                         AF_SKIP_ROUTING, 1 ); 发送blast消息跳数为1
  rspCnt = 0; 响应参考节点次数
  blastCnt = BLINDNODE_BLAST_COUNT;广播次数默认状态下为8
  state = eBnBlastOut; 状态为发出状态
  osal_start_timerEx( BlindNode_TaskID, BLINDNODE_BLAST_EVT, BLINDNODE_BLAST_DELAY );

延迟一段时间后启动BLINDNODE_BLAST_EVT事件。
}

*********************************************************************
* @fn      BlindNode_FindRequest  盲节点寻找请求
*
* @brief   Start a sequence of blasts and calculate position.
         开始广播并计算位置
* @param   none
*
* @return  none
*/
void BlindNode_FindRequest( void )
{
  if ( state == eBnIdle )  如果状态为空闲状态 则进行广播  (state的状态在初始化函数中定位为 state= eBnIdle)
  {
    startBlast();   启动广播函数
  }
}

*********************************************************************
*********************************************************************/

 

 

 

 

最后将所有的程序整合一下来看一下整个调用流程是怎么回事。

 

初始化 --启动BLINDNODE_FIND_EVT事件--启动广播函数---启动BLINDNODE_BLAST_EVT事件--判断次数--不等于0时发送blast----等于零时发送XY-RSSI请求---调用finishcollection()函数----调用发送响应函数sendRsp()(如果是自动模式设置下一个BLINDNODE_FIND_EVT事件)。

 

     理解有误的地方希望大家指正。希望大家多和我交流。

0 0
原创粉丝点击