Upma Xmac 测试 02
一、接上 Upma Xmac 测试 01
二、程序调试分析:
1、跳到upma/apps/tests/TestXmac/SendingC$SplitControl$startDone事件,代码如下:
event void SplitControl.startDone(error_t err) { uint8_t * nodeId; call LowPowerListening.setLocalWakeupInterval(interval); nodeId = (uint8_t *)call Packet.getPayload(&packet, sizeof(uint8_t)); *nodeId = TOS_NODE_ID; call SendTimer.startPeriodic(8000); }
LowPowerListening接口实际是由BmacLplPacketP组件实现的,源码如下:
command void LowPowerListening.setLocalWakeupInterval(uint16_t ms) { call ChannelPoller.setWakeupInterval(ms); }
ChannelPoller.setWakeupInterval命令是由ChannelPollerP.setWakeupInterval实现的,源码如下:
async command void ChannelPoller.setWakeupInterval(uint16_t ms)
{ atomic ms_ = ms; if(running_) //初始值 bool running_ = FALSE;经调试不知道在什么时候变为了true. call Alarm.start(ms); // // Save the sleep interval, and reset the alarm if the poller is active }
Alarm.fired()实现代码如下:
async event void Alarm.fired() { // If the channel poller is active if(running_) { call Alarm.start(ms_); // Restart the timer call State.forceState(S_CHECKING); // Move into the busy state call ChannelMonitor.check(); // Do a CCA check } }
call Alarm.start(ms_);就是ms_之后在触发一次Alarm,Alarm也是一类定时器,只不过更为准确。
call State.forceState(S_CHECKING); 就是将State的状态设为S_CHECKING,表示正在进行信道检测
ChannelMonitor.check()由PowerCycleP组件实现,代码如下:
async command void ChannelMonitor.check() { post startRadio(); }
可以看出,信道检测是通过一个任务来实现的,startRadio()的代码如下:
task void startRadio() { error_t err; err = call RadioPowerControl.start(); if(err == EALREADY) { post getCca(); } else if (err != SUCCESS) { post startRadio(); }
经调试,第一次err=9=EALREADY,进行CCA检测。getCca() task的实现代码如下
task void getCca() { uint8_t detects = 0; #ifdef OLDCCA ////使用的不是old cca,下面不用看了 uint16_t ccaChecks; atomic { for(ccaChecks = 0; ccaChecks < MAX_LPL_CCA_CHECKS; ccaChecks++) { if(call PacketIndicator.isReceiving()) { detected++; signal ChannelMonitor.busy(); return; } if(call EnergyIndicator.isReceiving()) { detects++; if(detects > MIN_SAMPLES_BEFORE_DETECT) { detected++; signal ChannelMonitor.busy(); return; } // Leave the radio on for upper layers to perform some transaction } } free++; signal ChannelMonitor.free(); } #else local_time16_t startAt, endAt, length, now; uint16_t count = 0; length.mticks = 0; length.sticks = ccaCheckLength; startAt = call Time.getNow(); endAt = call Time.add(&startAt, &length); //endAt.sticks=startAt.sticks+8*32; while(TRUE) { count++; if(count % 32 == 0) { now = call Time.getNow(); //每检测32次,看一下CCA的时间长度是否超过预定的长度 if(!call Time.lessThan(&now, &endAt)) { //now是否<endAt break; } } if(call PacketIndicator.isReceiving()) { //是否接收到数据包,如果接收到数据包,直接认为信道忙 detects = MIN_SAMPLES_BEFORE_DETECT + 1; //避免多余的检测 #define MIN_SAMPLES_BEFORE_DETECT 3 break; } if(call EnergyIndicator.isReceiving()) { //信道检测其实就是检测能量,当信道的功率大于某个值一定次数,也认为信道忙 detects++; if(detects > MIN_SAMPLES_BEFORE_DETECT) { //避免多余的检测 break; } // Leave the radio on for upper layers to perform some transaction } } if(detects > MIN_SAMPLES_BEFORE_DETECT) { //说明信道忙 detected++; signal ChannelMonitor.busy(); } else { free++; signal ChannelMonitor.free(); } #endif }
从上诉代码可以看出,CCA检测其实就是检测有没收到packet或者信道中的功率是不是大于某个阈值一定次数。
小结:call LowPowerListening.setLocalWakeupInterval(interval); 就是设置本地节点listen的间隔,而listen也就是CCA。
继续分析upma/apps/tests/TestXmac/SendingC$SplitControl$startDone事件,代码如下:
nodeId = (uint8_t *)call Packet.getPayload(&packet, sizeof(uint8_t)); *nodeId = TOS_NODE_ID; call SendTimer.startPeriodic(8000);
packet之前并没有填充,由此也可见我的这个upma并非最终版本,里面是随机值。
call SendTimer.startPeriodic(8000); 每隔8s触发一次SendTimer,跳到 event void SendTimer.fired()事件:
event void SendTimer.fired() { if(sends) { call Leds.led2On(); call AMSender.send(AM_BROADCAST_ADDR, &packet, 2 * sizeof(uint8_t)); } }
触发后就以广播方式发送一次数据。
总结:
upma/apps/tests/TestXmac/SendingC$SplitControl$startDone事件主要:设置本地节点的唤醒间隔,并启动发送packet定时器。