CC2431 代码分析③-忍辱负重的CC2430
这节主要分析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
转载于:https://www.cnblogs.com/tuzhuke/p/5918567.html
CC2431 代码分析③-忍辱负重的CC2430相关推荐
- 20145236《网络攻防》Exp4 恶意代码分析
20145236<网络攻防>Exp4 恶意代码分析 一.基础问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些 ...
- C#中类的继承 override virtual new的作用以及代码分析
继承中override virtual new的作用 virtual 父类中需要注明允许重写的方法: override 子类中必须显示声明该方法是重写的父类中的方法: new 子类中忽略父类的已存在的 ...
- 2017.4.18 静态代码分析工具sonarqube+sonar-runner的安装配置及使用
配置成功后的代码分析页面: 可以看到对复杂度.语法使用.重复度等等都做了分析,具体到了每一个方法和每一句代码. 四种使用方式: sonarqube + sonar-runner sonarqube + ...
- lighttpd1.4.18代码分析
lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态 posted @ 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1) 编辑 lig ...
- Device Tree(三):代码分析
2019独角兽企业重金招聘Python工程师标准>>> 一.前言 Device Tree总共有三篇,分别是: 1.为何要引入Device Tree,这个机制是用来解决什么问题的?(请 ...
- 使用Hadoop和ELK进行业务代码分析!分分钟捉到Bug!
大数据是计算领域的新高地,它有望提供一种方法来应对二十一世纪不断增长的数据生成.越来越多的大数据爱好者正在涌现,越来越多的公司正在采用各种大数据平台,并希望提出以客户为中心的解决方案,帮助他们在竞争激 ...
- 20145328 《网络对抗技术》恶意代码分析
20145328 <网络对抗技术>恶意代码分析 ------看到这句话说明还没写完-------- 实践内容: 使用schtasks指令监控系统运行 使用sysmon工具监控系统运行 使用 ...
- starGAN原理代码分析
下载: git clone https://github.com/yunjey/StarGAN.git 1 cd StarGAN/ 1 下载celebA训练数据: bash download.sh 1 ...
- tensorflow笔记:多层CNN代码分析
tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) tensorflow笔记:多层CNN代码分析 (三) tensorflow笔记:多层LSTM代 ...
最新文章
- 强烈推荐8个良心好用的国产软件应用,让你爱不释手
- mysql事务变量_mysql学习四之事务、变量、触发器、函数、存储过程
- Asp.net操作数据库方法
- MySQL常用函数 一
- 20172313 2018-2019-1 《程序设计与数据结构》第六周学习总结
- Sharding-JDBC水平分表(环境搭建)_Sharding-Sphere,Sharding-JDBC分布式_分库分表工作笔记007
- 谁知道怎么编写侧边栏的代码吗?
- 使用Scikit-Learn,XGBoost,LightGBM和CatBoost进行梯度增强
- 计算机网络——局域网网络结构以及 VLAN 划分
- Mac终端查看MD5/SHA1/SHA256
- 智慧路灯杆系统车流量监测解决方案
- SpringBoot整合银联支付
- IDEA 在debug 模式下启动tomcat报错:Application Server was not ..reason:Unable to ping server at localhos:1199
- 11个值得珍藏的4K高清壁纸网站推荐
- 详解JS中的TDZ(暂时性死区)
- 我的互联网创业公司的第一笔收入磨难记
- 变身成为互联网设计师
- MarkDown符号大全
- SAP FICO 批量成本估算
- SpringBoot整合Mybatis3 Dynamic Sql(IDEA)
热门文章
- windows下定期清理超过一定时间的文件
- [Android]使用Kotlin开发Android(二)
- struts2对action的搜索规则
- linux安装vi 插件,Ubuntu上Vim安装NERDTree插件的详细操作步骤
- java cms cpu占用率_cpu使用率过高和jvm old占用过高排查过程
- html服务流程如何实现_朱传燕:美容院如何规范服务流程,提升专业口碑
- SPI、UART、I2C三种串行总线简介
- 人工智能之自然语言的从新思考
- QQ第三方登录报错error=-1
- spring框架使用Quartz执行定时任务实例详解