Upma Xmac 测试 01

一、本文的目的主要是构建一个Xmac的测试程序,并从上层到下层,从发送到接收,深入调试upma的Xmac协议

二、程序构建:

  1、upma开源包下的  “upma/apps/tests/TestBmac”是对Bmac协议的测试,主要实现的功能就是发送和接收,如果你下载的upma是最终版的(不是最终版有一些问题),只需将文件夹“TestBmac”改成“TestXmac”,并就TestXmac目录下的Makefile中的  “UPMA_MAC = bmac” 改成“UPMA_MAC = xmac”就完成了一个Xmac测试程序的构建,还是很方便的。

  2、代码深入调试(就从Boot.booted()开始分析吧)

    a、upma/apps/tests/TestXmac/SendingC.nc$Boot.booted() 事件是硬件上电后第一个执行的事件,相当于C里面的main,也就是程序入口

    event void Boot.booted()
    {
        call SplitControl.start();      //具体由XmacSplitControlP.SplitControl实现
    }

    从配置组件查找得知,这里的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()的实现代码如下:

    

  /**
   * 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,代码如下:

   

#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是什么时候指定的?没思路。

 

    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;
  }

三、小结:

    upma/apps/tests/TestXmac/SendingC.nc$Boot$booted() 事件主要做的工作就是开启radio。

posted @ 2017-11-19 16:09  XiaoBBai  阅读(213)  评论(0编辑  收藏  举报