1、本文的目的主要是构建一个Xmac的测试程序,并从上层到下层,从发送到接收,深刻调试upma的Xmac协议数组
2、程序构建:app
一、upma开源包下的 “upma/apps/tests/TestBmac”是对Bmac协议的测试,主要实现的功能就是发送和接收,若是你下载的upma是最终版的(不是最终版有一些问题),只需将文件夹“TestBmac”改为“TestXmac”,并就TestXmac目录下的Makefile中的 “UPMA_MAC = bmac” 改为“UPMA_MAC = xmac”就完成了一个Xmac测试程序的构建,仍是很方便的。less
二、代码深刻调试(就从Boot.booted()开始分析吧)async
a、upma/apps/tests/TestXmac/SendingC.nc$Boot.booted() 事件是硬件上电后第一个执行的事件,至关于C里面的main,也就是程序入口ide
从配置组件查找得知,这里的SplitControl接口实际是由XmacSplitControlP提供的,跳到upma/lib/macs/xmac/XmacSplitControlP.nc文件,找到SplitControl.start() 命令的实现代码以下:测试
command error_t SplitControl.start() { if(call State.getState() != S_STOPPED) return FAIL; // Make sure we're off call State.forceState(S_STARTING); return call RadioPowerControl.start(); // Turn on the radio }
而State接口由/tinyos-2.1.2/tos/system/StateImplP提供,跳到/tinyos-2.1.2/tos/system.nc文件,找到State.getState()的实现代码以下:ui
/** * Get the current state */ async command uint8_t State.getState[uint8_t id]() { uint8_t theState; atomic theState = state[id]; return theState; }
这里的id相似于AMReceiverC组件中的id,代码以下:atom
#include "AM.h" generic configuration AMReceiverC(am_id_t amId) { provides { interface Receive; interface Packet; interface AMPacket; } } implementation { components ActiveMessageC; Receive = ActiveMessageC.Receive[amId]; Packet = ActiveMessageC; AMPacket = ActiveMessageC; }
只不过这里的id是用来区分不一样组件的,不一样组件拥有不一样的状态机,而AMReceiverC中的id是用来区别不一样的receiver的。State的id是何时指定的?没思路。spa
state[id]的定义以下:调试
/** Each component's state - uniqueCount("State") of them */ uint8_t state[uniqueCount(UQ_STATE)];
是一个uint8_t数组,这里的state[id]应该表明radio相对于State组件而言当前的状态,能够经过调用State.requestState,State.forceState,State.toIdle命令改变。
经调试,State组件的id值为5,而state[id]=state[5]=0,也就是S_IDLE状态。
回到upma/lib/macs/xmac/XmacSplitControlP.nc中SplitControl.start() 命令的实现代码,第一行代码 “ if(call State.getState() != S_STOPPED) ”的意思就是判断radio是否处于空闲状态(从这里能够看出,
S_STOPPED也就是radio的IDLE状态)。
upma/lib/macs/xmac/XmacSplitControlP.nc中SplitControl.start() 第二行代码 “ call State.forceState(S_STARTING) ;“的实现代码以下:
/** * Force the state machine to go into a certain state, * regardless of the current state it's in. */ async command void State.forceState[uint8_t id](uint8_t reqState) { atomic state[id] = reqState; }
不管是从命令名仍是实现代码能够看出,就是强制将state[id]的值置为一个指定值。 “ call State.forceState(S_STARTING) ;“的做用应该是将radio的状态机置为”正在开启“状态,也就是说S_STARTING
对应radio的正在开启状态。
upma/lib/macs/xmac/XmacSplitControlP.nc中SplitControl.start() 命令的实现代码,第三行代码
return call RadioPowerControl.start(); //RadioPowerControl接口的提供者是在哪里指定的
老实说,我在SendingAppC.nc,XmacSplitControlC.nc和MacC都没有找到RadioPowerControl提供的组件,只能用搜索方法,找到了/upma/chips/cc2420/CC2420CsmaP.nc文件,上述命令的实现代码以下:
async command error_t RadioPowerControl.start() { if(call SplitControlState.requestState(S_STARTING) == SUCCESS) { //SplitControlState的id号为1,在上面的过程当中 //咱们已经将radio的状态设为S_STARTING #ifdef CC2420_ACCOUNTING //没有定义,下面两行代码忽略 call Alarm.start(1024UL); vRegStartedAt = call Counter.get(); #endif call CC2420Power.startVReg(); return SUCCESS; } else if(call SplitControlState.isState(S_STARTED)) { return EALREADY; } else if(call SplitControlState.isState(S_STARTING)) { return SUCCESS; } return EBUSY; }
这个命令主要是启动radio时对radio进行稳压操做,看了一下内部实现代码,没看懂,下面是 ”call CC2420Power.startVReg();“的实现代码
/***************** CC2420Power Commands ****************/ async command error_t CC2420Power.startVReg() { atomic { if ( m_state != S_VREG_STOPPED ) { //m_state的初始值是0,S_VREG_STOPPED是枚举值,也是0 return FAIL; } m_state = S_VREG_STARTING; //S_VREG_STARTING=1 } call VREN.set(); //并无找到这个命令的实现 call StartupTimer.start( CC2420_TIME_VREN ); //CC2420_TIME_VREN = 20,这里启动一个定时器,应该是us级的 return SUCCESS; }
3、小结:
upma/apps/tests/TestXmac/SendingC.nc$Boot$booted() 事件主要作的工做就是开启radio。