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。