这节主要分析CC2430的代码,是参考节点的代码,协调器代码我们放到最后分析。

代码分析的原则是事件为导向,我们从CC2431 盲节点code的分析中发现CC2431 向CC2430参考节点发送的信息包含了两种内容

LOCATION_RSSI_BLAST

LOCATION_XY_RSSI_REQUEST

其中LOCATION_RSSI_BLAST 发送了多次,而最后一次发送的是LOCATION_XY_RSSI_REQUEST,我们现在就开始CC2430 code中找相关的关键字。

PS:CC2430 参考节点code文件RefNode.c

由于CC2430 参考节点的代码实在太过于简单了,我们先把CC2430 参考节点事件Event相关的代码全部先贴上来。

/*********************************************************************
* @fn RefNode_ProcessEvent
*
* @brief Generic Application Task event processor.
*
* @param task_id - The OSAL assigned task ID.
* @param events - Bit map of events to process.
*
* @return none
*/
uint16 RefNode_ProcessEvent( byte task_id, uint16 events )
{
if ( events & SYS_EVENT_MSG )
{
afIncomingMSGPacket_t *MSGpkt; while ((MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(RefNode_TaskID)))
{
switch ( MSGpkt->hdr.event )
{
case KEY_CHANGE:
//LocationHandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break; case AF_DATA_CONFIRM_CMD:
break; case AF_INCOMING_MSG_CMD:
processMSGCmd( MSGpkt );
break; case ZDO_STATE_CHANGE:
osal_start_timerEx( RefNode_TaskID, ANNCE_EVT, ANNCE_DELAY );
break; default:
break;
} osal_msg_deallocate( (uint8 *)MSGpkt );
} // Return unprocessed events.
return ( events ^ SYS_EVENT_MSG );
} if ( events & ANNCE_EVT )
{
/* Broadcast the X,Y location for any passive listeners in order to
* register this node.
*/
afAddrType_t dstAddr; dstAddr.addrMode = afAddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVALL;
dstAddr.endPoint = LOCATION_DONGLE_ENDPOINT; (void)AF_DataRequest( &dstAddr, (endPointDesc_t *)&epDesc,
LOCATION_REFNODE_CONFIG, REFNODE_CONFIG_LEN, rspMsg,
&transId, 0, AF_DEFAULT_RADIUS ); return ( events ^ ANNCE_EVT );
} return 0; // Discard unknown events
}

  

可以看到CC2430参考节点的事件太少了,我们简单说一下

KEY_CHANGE 和 AF_DATA_CONFIRM_CMD 两个是按键触发以及发送完成确认,本来 KEY_CHANGE 还有点作用,但是我们还是可以先去掉这个功能,两个就不用看了。

AF_INCOMING_MSG_CMD 当收到无线信号的时候就会触发这个,所以我们在之前分析CC2431的code时向CC2430参考节点 发送的信息都会触发到这,我们后面详细分析。

ZDO_STATE_CHANGE 这个可以认为是设备启动成功加入网络后触发,在code中定时触发了一个人任务ANNCE_EVT,我们在上面的code中也可以看到这个任务的处理方法

  if ( events & ANNCE_EVT )
{
/* Broadcast the X,Y location for any passive listeners in order to
* register this node.
*/
afAddrType_t dstAddr; dstAddr.addrMode = afAddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR_DEVALL;
dstAddr.endPoint = LOCATION_DONGLE_ENDPOINT; (void)AF_DataRequest( &dstAddr, (endPointDesc_t *)&epDesc,
LOCATION_REFNODE_CONFIG, REFNODE_CONFIG_LEN, rspMsg,
&transId, 0, AF_DEFAULT_RADIUS ); return ( events ^ ANNCE_EVT );
}

由 dstAddr.endPoint = LOCATION_DONGLE_ENDPOINT;可以看到这条信息是发送给协调器的,我们分析协调器的时候再分析这个信息的作用。

那么我们下面就主要分析AF_INCOMING_MSG_CMD 相关的内容

      case AF_INCOMING_MSG_CMD:
processMSGCmd( MSGpkt );
break;

可以看到当接受到无线信息的时候,就会调用   processMSGCmd( MSGpkt ) 这个函数处理,其中MSGpkt 这个是非常复杂庞大的结构体,里面包含了非常非常多的内容,有兴趣可以自己查看这个结构体的定义,后面我们看到的code它有什么我们就确信它就是有什么了。

/*********************************************************************
* @fn processMSGCmd
*
* @brief Data message processor callback.
*
* @param none
*
* @return none
*/
static void processMSGCmd( afIncomingMSGPacket_t *pkt )
{
switch ( pkt->clusterId )
{
case LOCATION_XY_RSSI_REQUEST:
rssiRsp( pkt );
break; case LOCATION_REFNODE_CONFIG:
parseConfig( pkt->cmd.Data );
break; case LOCATION_REFNODE_REQUEST_CONFIG:
pkt->srcAddr.addrMode = afAddr16Bit;
(void)AF_DataRequest( &pkt->srcAddr, (endPointDesc_t *)&epDesc,
LOCATION_REFNODE_CONFIG, REFNODE_CONFIG_LEN, rspMsg,
&transId, 0, AF_DEFAULT_RADIUS );
break; case LOCATION_RSSI_BLAST:
addBlast( pkt->srcAddr.addr.shortAddr, pkt->LinkQuality );
break; default:
break;
}
}

我们可以看到这部分代码是会根据 pkt->clusterId 进行分别处理的,我们在之前分析AF_DataRequest 函数中强调的一个参数是否还记得,我们在CC2431code 分析的时候有两种信息LOCATION_RSSI_BLAST  LOCATION_XY_RSSI_REQUEST,我们至于对应就可以知道,当CC2431 开始发送LOCATION_RSSI_BLAST  的时候CC2430 参考节点是调用

addBlast( pkt->srcAddr.addr.shortAddr, pkt->LinkQuality );处理的。

当发送LOCATION_XY_RSSI_REQUEST 的时候,是调用  rssiRsp( pkt )。

还有一点,我们在CC2431发送信息的时候后当时要留意一个参数叫Endpoint,当时设置LOCATION_REFNODE_ENDPOINT, 为何这里没有看到呢?

其实这个Endpoint是在初始化的时候配置的,我们这里再简单贴一点CC2430 参考节点初始化的代码

void RefNode_Init( byte task_id )
{ // Register the endpoint/interface description with the AF.
afRegister( (endPointDesc_t *)&epDesc ); // Register for all key events - This app will handle all key events.
// RegisterForKeys( RefNode_TaskID );

可以看到有个afRegister( (endPointDesc_t *)&epDesc );其中epDesc 是一个全局变量的结构体,我们在code中找到其定义

static const endPointDesc_t epDesc =
{
LOCATION_REFNODE_ENDPOINT,
&RefNode_TaskID,
(SimpleDescriptionFormat_t *)&RefNode_SimpleDesc,
noLatencyReqs
};

好了,我们终于在CC2430 的参考节点的code中找到了LOCATION_REFNODE_ENDPOINT,这个问题分析到这里。

下面我们在回到 processMSGCmd( MSGpkt ),我们可以到看一种有四种处理方法,也就是一种接收到四种消息,其中两种来源于CC2431盲节点,而另外两种则是来源于CC2430协调器,协调器发送信息配置CC2430参考节点的坐标等信息是一种,另一种是读取CC2430参考节点的坐标信息。 这两种我们在分析CC2430 协调器code的时候再分析。

以事件为导向,我们先分析

  case LOCATION_RSSI_BLAST:
addBlast( pkt->srcAddr.addr.shortAddr, pkt->LinkQuality );

 这个是在CC2431最开始发送信息是需要处理的,也就是CC2431 广播让各个CC2430 参考节点记录自己的RSSI值。我们看addBlast函数,函数名就可以看出”加blast“,就是累加RSSI,后面传输的参数是一个short地址一个信号质量。具体函数如下

/*********************************************************************
* @fn addBlast
*
* @brief Add or initialize an RSSI blast for the given Network Address.
*
* @param uint16 - Network address of the Blind Node blasting.
* byte - RSSI of the blast message received.
*
* @return none
*/
static void addBlast( uint16 addr, byte rssi )
{
blastAcc_t *ptr = blastPtr; while ( ptr )
{
if ( ptr->addr == addr )
{
break;
}
ptr = ptr->next;
} if ( ptr )
{
ptr->acc += rssi;
ptr->cnt++;
}
else
{
ptr = (blastAcc_t *)osal_mem_alloc( sizeof( blastAcc_t ) ); if ( ptr )
{
ptr->next = blastPtr;
blastPtr = ptr; ptr->addr = addr;
ptr->acc = rssi;
ptr->cnt = 1;
}
}
}

 从这个函数的描述  Add or initialize an RSSI blast for the given Network Address.,对一个给定的网络地址初始化其信号质量或者累加信号质量,当一个网络地址第一次发送信息过来时由0到一个值叫初始化,后面再收到这个地址的时候就是累加过程。 还有为何是一个给定的网络地址,我们不是就一个CC2431吗? 其实这个协议栈实现了可以同时多个CC2431盲节点的定位系统,我们一般套件只有一个CC2431盲节点罢了。

这个函数实现很简单,就是一个对指针链表赋值的过程,每次收到信号后累加信号强度,我们稍微看家用到的结构体

typedef struct _blastAcc_t
{
struct _blastAcc_t *next;
uint16 addr;
uint16 acc;
byte cnt;
} blastAcc_t;

从结构体可以看到,包含了addr就是指明了这个结构体内容是哪个CC2431盲节点的,acc 是信号强度的累加,而cnt是一种累加了几次,通过acc 和cnt 就可以求出平均值,在这里我们知道CC2431 一共发送了8次,所以追踪code的时候,如果CC2430参考节点全部接收到信息,那么cnt应该是8.

这个函数的具体内容我们就不解释了。

CC2431在发送blast 信息之后还发送了一个信息,里面的cluster ID是LOCATION_XY_RSSI_REQUEST,我们再看下CC2430参考节点接到这个信息是如何处理的。

  case LOCATION_XY_RSSI_REQUEST:
rssiRsp( pkt );
break;

  先把rssiRsp这个函数全部贴出来

/*********************************************************************
* @fn rssiRsp
*
* @brief Respond to requester with average of their RSSI blasts.
*
* @param uint16 - Network address of the Blind Node requesting.
* byte - Endpoint of the Blind Node requesting.
* byte - RSSI of the blast message received.
*
* @return none
*/
static void rssiRsp( afIncomingMSGPacket_t *pkt )
{
blastAcc_t *ptr = blastPtr;
blastAcc_t *prev = NULL;
byte options, radius; while ( ptr )
{
if ( ptr->addr == pkt->srcAddr.addr.shortAddr )
{
break;
}
prev = ptr;
ptr = ptr->next;
} if ( ptr )
{
rspMsg[LOCATION_XY_RSSI_RSSI_IDX] =
(ptr->acc + pkt->LinkQuality) / (ptr->cnt + 1); if ( prev )
{
prev->next = ptr->next;
}
else
{
blastPtr = ptr->next;
}
osal_mem_free( ptr ); options = AF_SKIP_ROUTING;
radius = 1;
}
else
{
rspMsg[LOCATION_XY_RSSI_RSSI_IDX] = pkt->LinkQuality; options = AF_TX_OPTIONS_NONE;
radius = AF_DEFAULT_RADIUS;
} pkt->srcAddr.addrMode = afAddr16Bit;
(void)AF_DataRequest( &pkt->srcAddr, (endPointDesc_t *)&epDesc,
LOCATION_XY_RSSI_RESPONSE, LOCATION_XY_RSSI_LEN,
rspMsg, &transId, options, radius );
} /*********************************************************************
*********************************************************************/

从函数的描述中Respond to requester with average of their RSSI blasts,我们可以看出这个是返回blast的平均RSSI值,函数可以分为三个部分分析,和上面一样,由于使用了链表,所以需要根据这条信息的短地址进行匹配,上面说过,这个网络中支持多个盲节点的定位。

 if ( ptr )
{
rspMsg[LOCATION_XY_RSSI_RSSI_IDX] =
(ptr->acc + pkt->LinkQuality) / (ptr->cnt + 1); if ( prev )
{
prev->next = ptr->next;
}
else
{
blastPtr = ptr->next;
}
osal_mem_free( ptr ); options = AF_SKIP_ROUTING;
radius = 1;

  上面这段代码的大概意思是匹配到短地址,然后求了一个平均值放到数组 rspMsg[LOCATION_XY_RSSI_RSSI_IDX],

但是也可能没有找到,下面就是没有找到的情况,这种情况出现在类似情形:运动的盲节点在开始发送blast的时候没有发送到这个参考节点,但是发送请求信号的时候正好运动到一个位置把请求信号发送到了这个节点,所以这个参考节点就没有之前的记录。但是得到请求不回复一下不好,所以在这个协议栈的设计是把这个请求信息的RSSI作为平均RSSI回复过去,正如下面的代码所示。

   rspMsg[LOCATION_XY_RSSI_RSSI_IDX] = pkt->LinkQuality;

    options = AF_TX_OPTIONS_NONE;
radius = AF_DEFAULT_RADIUS;

  但是我们可以比较上面的两段code发现两个参数option 和radius 的设定是不一样的,这个是为何呢? 我们留在后面再说。

好了,RSSI的“均值”已经找到,那么就需要一个发送函数将这个RSSI发到CC2431盲节点了。

  pkt->srcAddr.addrMode = afAddr16Bit;
(void)AF_DataRequest( &pkt->srcAddr, (endPointDesc_t *)&epDesc,
LOCATION_XY_RSSI_RESPONSE, LOCATION_XY_RSSI_LEN,
rspMsg, &transId, options, radius );

 上面发送的数据是rspMsg,发送长度是 LOCATION_XY_RSSI_LEN, 数据不仅仅包括了RSSI,还有这个参考节点的X Y坐标等信息,具体这个数据可自行查看代码,我们在后期解释节点配置的时候会再次说明。

好了,CC2430 参考节点在定位中充当的角色就这些,CC2430 盲节点发送blast 和request,CC2430 收集RSSI并将均值RSSI返回给盲节点。我们追到这里后面需要再返回到CC2431 了,因为CC2430这段代码执行的时机是在 

if ( events & BLINDNODE_BLAST_EVT )
{
if ( blastCnt == 0 )
{
state = eBnBlastOff;
finishCollection();
}

之前完成的,下面我们将接着分析CC2431 的finishCollection(); 具体参见下节分析。

CC2431定位套餐推荐:https://item.taobao.com/item.htm?id=527836022363

CC2431 代码分析③-忍辱负重的CC2430的更多相关文章

  1. CC2431 代码分析②-CC2431狂轰滥炸

    CC2431 code review : CC2431 狂轰滥炸 在上一篇中的最后我们分析到CC2431 开始喊出第一声,这里我们逐步分析从第一声到后面的狂轰滥炸! 上代码 /************ ...

  2. CC2431 代码分析④-衣锦还乡的CC2431

    我们在第二节就分析到了 finishCollection( void ),但是当我们分析完第三节后,整个系统才真正执行到这里,我们依然像第二节一样把这个函数全部贴出来 /*************** ...

  3. CC2431 代码分析①-CC2431 喊出第一声

    CC2431 是一款可以基于RSSI 定位的 芯片. 定位原理,通过RSSI 强度换算距离. 可以打个类似的比方,一个人站在群山之间,每个山头都有一个地理坐标,然后大喊一声,各个方向会返回回声,通过回 ...

  4. Android代码分析工具lint学习

    1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...

  5. pmd静态代码分析

    在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...

  6. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

  7. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)

    Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...

  8. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  9. STM32启动代码分析 IAR 比较好

    stm32启动代码分析 (2012-06-12 09:43:31) 转载▼     最近开始使用ST的stm32w108芯片(也是一款zigbee芯片).开始看他的启动代码看的晕晕呼呼呼的. 还好在c ...

随机推荐

  1. 右键菜单添加打开CMD选项

    转载: https://www.cnblogs.com/mkdd/p/8649139.html#undefined 目前用的win7sp1系统,平时打开CMD窗口通常用三种方法:1.win+R然后输入 ...

  2. Python字符串编码转换

    使用encode()方法编码 str.encode([encoding="utf-8"][,errors="strict"]) str:表示需要转换的字符串 e ...

  3. truncate table时存在外键约束的解决办法

    以前在使用truncate命令时遇到表存在外键引用时无法执行命令的情况都是用delete来代替,今天又遇到这个问题,于是在网上搜了一把,可以通过如下方式解决: 1.基本思路:先关闭mysql的外键约束 ...

  4. ORACLE EHCC(exadata hybrid columnar compression)

    目录: 1. 简介 2. 压缩方式及压缩比 3. 压缩哪些数据 4. 可能有用的脚本 一.简介 EHCC(Exadata Hybrid Columnar Compression),是Oralce 数据 ...

  5. Duplicate 复制数据库 搭建Dataguard

    1 操作系统环境 此处隐藏具体信息 System IP-address db_name db_version Comment         Target DB         Auxiliary D ...

  6. Vue.js货币格式化函数

    函数: const digitsRE = /(\d{3})(?=\d)/g export function currency (value, currency, decimals) { value = ...

  7. js中匿名函数和回调函数

    匿名函数: 通过这种方式定义的函数:(没有名字的函数) 作用:当它不被赋值给变量单独使用的时候 1.将匿名函数作为参数传递给其他函数 2.定义某个匿名函数来执行某些一次性任务 var f = func ...

  8. gradle repo conf - maven-central.storage-download.googleapis.com

    repositories { google() jcenter() maven { // The google mirror is less flaky than mavenCentral() url ...

  9. 上传文件---未能找到路径“D:\MyProject\Files\”的一部分

    C# 使用控件FileUpload 上传文件,简单实例: protected void btnUpload_Click(object sender, EventArgs e) { string pat ...

  10. javascript小例子:實現四方向文本无缝滚动效果

    实现一个文本无缝滚动的效果: <!DOCTYPE html> <!--[if lt IE 7 ]> <html lang="zh-CN" class= ...