No subject


Sun Apr 27 08:38:55 PDT 2008


This page describes how to set up and use TOSNIC (the successor to
Hostmote/MoteNIC) with SCP-MAC as the MAC layer. So far this has only
been tested with Mica2 motes.
Contents


    * 1 Basic EmStar Setup
    * 2 Compiling SCPBase
    * 3 Running TOSNIC
    * 4 Interpreting LEDs


Basic EmStar Setup

You will first need to do the following (which are not specific to this
application):

    * Download and compile EmStar
    * Download and unpack the latest version of SCP-MAC into a
    * subdirectory of the EmStar tos-contrib directory
    * Insert the fusd.ko kernel module
    * Run fusdd as root 


Compiling SCPBase

SCPBase is the mote-side application which communicates with the TOSNIC
application on the host side. You will find it in I-LENSE CVS under
ilense/tos/commstack/apps/SCPBase. If SCPMAC_ROOT is where you placed
scp-mac in the EmStar tos-contrib directory, then SCPBase will be in
SCPMAC_ROOT/apps/SCPBase.

Currently, due to a bug in SCP-MAC, you will have to perform a small
workaround to get serial communications working properly with
SCPBase. Find the file
SCPMAC_ROOT/tos/platform/mica2/HPLUART0M.nc. Rename this file to
something else (like HPLUART0M.nc.bak). Renaming this file prevents you
from using SCP-MAC UART debugging, but you can't do that an TOSNIC at
the same time anyway - just remember to put it back if you need
something else with UART debugging in the future.

Next, look at the Makefile in SCPMAC_ROOT/apps/SCPBase. Make sure that
SCPMAC_ROOT and TOSNIC_ROOT are pointing to the right directories (they
should be by default). Then, look at the config.h file and modify any
SCP-MAC settings that you wish to customize. Then, simply make mica2,
and make install.<id>, and your mote is ready.

Running TOSNIC

Once you have compiled EmStar, the tosnicd application is found in
emstar/obj.<platform>/mote/. Tosnicd requires the fusd module to be
inserted and fusdd to be running. Run tosnicd (as root or using sudo)
with the following options:

 ./tosnicd --port <device> --tosbase 512 --node_id <id>

where <device> is replaced by the serial port that the mote is attached
to, and <id> is the id that you passed to make install (this can be
omitted if /etc/id exists).

After this is running, the /dev/link/mote devices are available for use
by TOSNIC-aware applications.

Interpreting LEDs

SCPBase toggles the three LEDs for status information:

    * Yellow: Serial communication
    * Green: Radio communication
    * Red: Errors 

If an application attempts to send multiple packets before SCP-MAC has
acquired a schedule, you may see rapid blinking of the red and yellow
lights until the schedule is acquired and the packets are sent. Red LED
errors are usually not fatal - the most common red LED event indicates
that a packet failed to send and will be retried. 
--- NEW FILE: SCPBase.nc ---
includes AM;
includes Timer;
includes config;   
includes protocols;
includes AM_emstar;
includes ScpMsg;
includes SCPBaseMsg;

configuration SCPBase { 
}

implementation
{
#include "PlatformConstants.h"

   components Main, SCPBaseM,
       Scp as Mac, UART,
       FramerM, LedsC, NoLeds, TOSMsgTranslateM;
   
   Main.StdControl -> SCPBaseM;

   SCPBaseM.UARTControl -> FramerM;

   SCPBaseM.Framer -> FramerM.Framer[unique("Framer")];
   SCPBaseM.FramerSendDone -> FramerM.Framer[unique("Framer")];
   SCPBaseM.FramerStatus -> FramerM.Framer[unique("Framer")];

   SCPBaseM.Leds -> LedsC;

   SCPBaseM.TOSMsgTranslate -> TOSMsgTranslateM;      

   SCPBaseM.MacMsg -> Mac;
   SCPBaseM.MacStdControl -> Mac;
#ifdef RADIO_TX_POWER
   SCPBaseM.RadioTxPower -> Mac;
#endif

   FramerM.ByteControl -> UART;
   FramerM.ByteComm -> UART;
   FramerM.Leds -> NoLeds;
}

--- NEW FILE: SCPBaseM.nc ---
includes SCPBaseMsg;

/* Led indicators:
 *
 * Green = radio activity
 * Yellow = serial activity
 * Red = error activity
 *
 */

module SCPBaseM {
  provides interface StdControl;

  uses {
    interface StdControl as UARTControl;
    interface Framer;
    interface Framer as FramerSendDone;
    interface Framer as FramerStatus;
    
    interface Leds;
    interface TOSMsgTranslate;

    interface StdControl as MacStdControl;
    interface MacMsg;
#ifdef RADIO_TX_POWER
    interface GetSetU8 as RadioTxPower;
#endif
  }
}

implementation 
{

#include "PlatformConstants.h"
    
  typedef struct {
    uint16_t radioRxPkts;
    uint16_t radioCRCFail;
    uint16_t radioQDropFail;
    uint16_t radioTxPkts;
    uint16_t uartDataRxPkts;
    uint16_t uartDataTxPkts;
    uint16_t uartSendDoneTxPkts;

    uint16_t radioRxBytes;
    uint16_t radioTxBytes;
    uint16_t uartDataRxBytes;
    uint16_t uartDataTxBytes;
    uint16_t uartSendDoneTxBytes;

    uint16_t radioTxAckedPkts;

    uint16_t radioTxFailPkts;
    uint16_t uartDataRxFailPkts;
    uint16_t uartDataTxFailPkts;
    uint16_t uartSendDoneTxFailPkts;
  } emstar_base_stats_t;

  typedef struct {
    bool hwAcksEnabled;
    uint8_t reserved;
    uint32_t baudrate;
  } emstar_base_config_t;

  typedef struct {
    emstar_base_config_t config;
    emstar_base_stats_t stats;
  } emstar_base_status_msg_t;

  enum {
    OUTBOUND_IDLE=0,    
    OUTBOUND_SENDING,
    OUTBOUND_ACKING
  };

  enum {
    INBOUND_IDLE=0,    
    INBOUND_SENDING
  };

  enum {
    CONF_MAX=20,
    INBOUND_QUEUE_MAX=4
  };


  uint8_t conf_request[CONF_MAX];

  TOS_Msg_emstar_t gRecvBuffer, gSendBuffer; // for the Framer
  send_done_msg_t gSendDoneBuffer;

  emstar_base_stats_t stats;
  emstar_base_config_t config;
  
  SCPBasePkt outbound_pkt;
  uint8_t outbound_state;
  uint8_t outbound_seqno;
  uint8_t outbound_retval;
  
  uint8_t inbound_state;
  void* inbound_queue[INBOUND_QUEUE_MAX];
  uint8_t inbound_head;
  uint8_t inbound_count;
  
  /* INITIALIZATION */
    
  command result_t StdControl.init()
  {
      call UARTControl.init();
      call MacStdControl.init();
#ifdef RADIO_TX_POWER
      call RadioTxPower.set(RADIO_TX_POWER);
#endif
      
      call Leds.init();
      return SUCCESS;
  }

  command result_t StdControl.start()
  {      
      call Framer.register_client(TOSNIC_DATA_PACKET, (uint8_t *)&gRecvBuffer,
                                  sizeof(gRecvBuffer));
      call FramerSendDone.register_client(TOSNIC_UNKNOWN_PACKET, NULL, 0);
      call FramerStatus.register_client(TOSNIC_STATUS_PACKET,
                                        (uint8_t *)&conf_request,
                                        sizeof(conf_request));


      call UARTControl.start();
      call MacStdControl.start();

      outbound_state = OUTBOUND_IDLE;
      inbound_state = INBOUND_IDLE;

      return SUCCESS;
  }
  
  command result_t StdControl.stop()
  {

      call MacStdControl.stop();
      call UARTControl.stop();

      return SUCCESS;
  }

  /* CRC */

  uint16_t update_crc(uint8_t data, uint16_t crc)
   {
      uint8_t i;
      uint16_t tmp;
      tmp = (uint16_t)(data);
      crc = crc ^ (tmp << 8);
      for (i = 0; i < 8; i++) {
         if (crc & 0x8000)
            crc = crc << 1 ^ 0x1021;  // << is done before ^
         else
            crc = crc << 1;
         }
      return crc;
   }
    
  /* QUEUEING */

  uint8_t iq_empty() {
    return inbound_count == 0;
  }

  uint8_t iq_full() {
    return inbound_count >= INBOUND_QUEUE_MAX;
  }
  
  void* iq_pop() {
    void* retval = NULL;
    if (inbound_count > 0) {
      retval = inbound_queue[inbound_head];
      inbound_count--;
      inbound_head++;
      if (inbound_head >= INBOUND_QUEUE_MAX)
	inbound_head = 0;
    }
    return retval;
  }

  uint8_t iq_get_tail() {
    uint8_t tail = (inbound_head + inbound_count);
    if (tail >= INBOUND_QUEUE_MAX)
      tail -= INBOUND_QUEUE_MAX;
    return tail;
  }

  void* iq_swap_push(void* msg) {
    void* retval = NULL;
    if (!iq_full()) {
      uint8_t tail = iq_get_tail();
      retval = inbound_queue[tail];
      inbound_queue[tail] = msg;
      inbound_count++;
    }
    return retval;
  }

  /* SEND / RECV TASKS */
  
  void run_rx() {

      void* msg = NULL;
      Mini_TOS_Msg *mtos_msgptr;
      TOS_Msg tmp_tos_msg;
      
      if (inbound_state == INBOUND_IDLE && !iq_empty()) {
        
        /* dequeue */
        msg = iq_pop();

        mtos_msgptr = (Mini_TOS_Msg*)msg;
        
        if (msg == NULL || mtos_msgptr == NULL) {
            call Leds.redToggle();
            return;
        }
        
        /* translate */

        tmp_tos_msg.addr = mtos_msgptr->addr;
        tmp_tos_msg.type = mtos_msgptr->type;
        tmp_tos_msg.group = mtos_msgptr->group;
        tmp_tos_msg.length = mtos_msgptr->length;
        
        memcpy(tmp_tos_msg.data, mtos_msgptr->data,
               tmp_tos_msg.length);
        
        tmp_tos_msg.crc = mtos_msgptr->crc;
        
        call TOSMsgTranslate.moteToHost(&tmp_tos_msg, &gSendBuffer);
        
        /* push to framer */
        if (call Framer.send(TOSNIC_DATA_PACKET, (uint8_t *)&gSendBuffer,
                             gSendBuffer.hdr.length + 
                             sizeof(TOS_Msg_emstar_hdr_t), 
                             TOSNIC_PRIORITY_MEDIUM) == FAIL) {
            call Leds.redToggle();
        } else {
            /* sending mode */
            
            stats.uartDataTxPkts++;
            stats.uartDataTxBytes += 
                gSendBuffer.hdr.length + sizeof(TOS_Msg_emstar_hdr_t);
            inbound_state = INBOUND_SENDING;
        }
    }
  }
          
  task void send_done_task(){

    if (outbound_state != OUTBOUND_SENDING) {
        call Leds.redToggle();
        return;
    }

    outbound_state = OUTBOUND_ACKING;
    gSendDoneBuffer.seqno = outbound_seqno;
    gSendDoneBuffer.result = outbound_retval;
    if ((call FramerSendDone.send
	 (TOSNIC_SEND_DONE_PACKET, (uint8_t*)&gSendDoneBuffer,
	  sizeof(send_done_msg_t), TOSNIC_PRIORITY_HIGH)) != SUCCESS) {
        call Leds.redToggle();
    }

  }

  
  /* SERIAL COMMUNICATION */
  

  /* Status Packets */

  event result_t FramerStatus.receive(uint8_t *data, uint16_t length,
                                      uint8_t token)
  {
      // nothing to do
      return SUCCESS;
  }

  event void FramerStatus.sendDone(uint8_t *data, result_t success)
  {
      // nothing to do
  }

  /* Unknown packets */
  
  event result_t FramerSendDone.receive(uint8_t *data, uint16_t length,
                                        uint8_t token)
  {
      // should not reach this point; indicate error
      call Leds.redToggle(); 
      return SUCCESS;
  }
  
  event void FramerSendDone.sendDone(uint8_t *data, result_t success)
  {
      // not sure exactly what we're supposed to be doing here..
      
      if (outbound_state != OUTBOUND_ACKING) {
          // confused state -> error
          call Leds.redToggle();
          outbound_state = OUTBOUND_IDLE;
          return;
      }
      
      if (success == FAIL) {
          // transmission failure -> error
          call Leds.redToggle();
          stats.uartSendDoneTxFailPkts++;
      }

      outbound_state = OUTBOUND_IDLE;
  }


 /* Data packets */
  
  event result_t Framer.receive(uint8_t *data, uint16_t length,
                                uint8_t token)
  {
      // got a message from host, direct to radio
      TOS_Msg_emstar_t *e = (TOS_Msg_emstar_t *)data;
      TOS_Msg tmp_tos_msg;
      int i;
      uint8_t *tmsg_itr = NULL;

      call Leds.yellowToggle();
      
      if (length <= sizeof(TOS_Msg_emstar_hdr_t)) {
          // packet too small -> error
          call Leds.redToggle();
          return FAIL;
      }

      if (outbound_state != OUTBOUND_IDLE) {
          // radio busy -> error
          call Leds.redToggle();
          return FAIL;
      }

    
      outbound_seqno = e->hdr.seq_num;    
      call TOSMsgTranslate.hostToMote(&tmp_tos_msg,e);
      outbound_state = OUTBOUND_SENDING;

      outbound_pkt.tos_msg.addr = tmp_tos_msg.addr;
      outbound_pkt.tos_msg.type = tmp_tos_msg.type;
      outbound_pkt.tos_msg.group = tmp_tos_msg.group;
      outbound_pkt.tos_msg.length = tmp_tos_msg.length;

      for (i = 0; i < TOSH_DATA_LENGTH; i++) {
          outbound_pkt.tos_msg.data[i] = 0;
      }
      memcpy(outbound_pkt.tos_msg.data, tmp_tos_msg.data, tmp_tos_msg.length);

      outbound_pkt.tos_msg.crc = 0;
      
      for (tmsg_itr = (uint8_t*)(&(outbound_pkt.tos_msg));
           tmsg_itr < (uint8_t*)(&(outbound_pkt.tos_msg)) + offsetof(Mini_TOS_Msg, crc);
           tmsg_itr++) {
          outbound_pkt.tos_msg.crc = update_crc(*tmsg_itr, outbound_pkt.tos_msg.crc);
      }

      stats.uartDataRxPkts++;
      stats.uartDataRxBytes+=length;

      if (call MacMsg.send(&(outbound_pkt),
                           sizeof(outbound_pkt),
/*                           outbound_pkt.tos_msg.addr) != SUCCESS) { */
                           0xFFFF) != SUCCESS) {
          // failed to send ->
          call Leds.redToggle();
      } 

      return SUCCESS;
  }

  event void Framer.sendDone(uint8_t *data, result_t success)
  {
      // finished sending message to host

      call Leds.yellowToggle();
      
      if (success == FAIL) {
          // failed to send -> error
          call Leds.redToggle();
          stats.uartDataTxFailPkts++;
      }
      inbound_state = INBOUND_IDLE;
      run_rx();
  }


  /* RADIO COMMUNICATION */

  event void MacMsg.sendDone(void* msg, result_t result)
  {
      // finished sending message over radio
      
      call Leds.greenToggle();

      atomic {
          if (outbound_state != OUTBOUND_SENDING) {
              // confused state -> error
              call Leds.redToggle();
            outbound_state = OUTBOUND_SENDING;
          } 

          if (result != SUCCESS) {
              // failed send -> error
//              call Leds.redToggle();
              outbound_retval = SEND_DONE_FAILED_TRANSMISSION;
          } else {
              outbound_retval = SEND_DONE_SUCCESS;
          }
              
          if ((post send_done_task()) != SUCCESS) {
              // task failed -> error
              call Leds.redToggle();
          }
      }   
  }
  
  event void* MacMsg.receiveDone(void* msg)
  {
      // got a message from radio, direct to host    

      SCPBasePkt* pkt;
      TOS_MsgPtr retval;
      
      pkt = (SCPBasePkt*)msg;
      call Leds.greenToggle();

      stats.radioRxPkts++;
      stats.radioRxBytes += (sizeof(ScpHeader) + ((PhyPktBuf*)msg)->hdr.length);
      retval = iq_swap_push((void*)(&(pkt->tos_msg)));
      run_rx();

      return msg;
  }
  
}

--- NEW FILE: SCPBaseMsg.h ---
#ifndef _SCPBASE_MSG_H_
#define _SCPBASE_MSG_H_

// Defines a TOS message encapsulated within an SCP packet

typedef ScpHeader SCPBaseHeader;

#define PAYLOAD_LEN (PHY_MAX_PKT_LEN - sizeof(SCPBaseHeader) - 2)

typedef struct {
    
    uint8_t type;
    uint16_t addr;
    int8_t  data[TOSH_DATA_LENGTH - 5];
    uint16_t crc;

} __attribute__ ((packed)) TOSNIC_Encap;

typedef struct {
    
    uint16_t addr;
    uint8_t type;
    uint8_t group;
    uint8_t length;
    int8_t data[TOSH_DATA_LENGTH];
    uint16_t crc;

} __attribute__ ((packed)) Mini_TOS_Msg;

typedef struct {

    SCPBaseHeader hdr;
    Mini_TOS_Msg tos_msg;
    int16_t crc;
    
} __attribute__ ((packed)) SCPBasePkt;


#endif

--- NEW FILE: config.h ---
#ifndef _SCPBASE_CONFIG_
#define _SCPBASE_CONFIG_

/* The following is REQUIRED for this application to work */

#define DISABLE_CPU_SLEEP

/* The following are optional SCP-MAC parameters */

// Configure Physical layer. Definitions here override default values
// Default values are defined in PhyMsg.h and PhyConst.h
// --------------------------------------------------------------
#define PHY_MAX_PKT_LEN 250       // max: 250 (bytes), default: 100

// configure radio transmission power (0x01--0xff)
// Following sample values are for 433MHz mica2: 0x0f=0dBm (TinyOS default)
// 0x0B = -3dBm, 0x08 = -6dBm, 0x05 = -9dBm, 0x03 = -14dBm 0x01 = -20dBm
// 0x0f =  0dBm, 0x50 =  3dBm, 0x80 =  6dBm, 0xe0 =  9dBm, 0xff =  10dBm
//#define RADIO_TX_POWER 0x03

// tell PHY to measure radio energy usage, only for performace analysis
//#define RADIO_MEASURE_ENERGY

// Configure CSMA, look for CsmaConst.h for details
// -----------------------------------------------
//#define CSMA_CW 32              // contention window size, must be 2^n
//#define CSMA_BACKOFF_TIME 20
#define CSMA_RTS_THRESHOLD 101
//#define CSMA_BACKOFF_LIMIT 7
//#define CSMA_RETX_LIMIT 3
//#define CSMA_ENABLE_OVERHEARING  // overhearing is disabled by default

// Configure LPL, look for LplConst.h for details
// ----------------------------------------------
// LPL specific configuration (binary ms)
//#define LPL_POLL_PERIOD 512

// Configure SCP, look for ScpConst.h for details
// ----------------------------------------------
// SCP specific configuration (binary ms)
#define SCP_POLL_PERIOD 1024

// only one master node starts a schedule in the network
// the master node will broadcast it schedule after it starts
// slave nodes only performs LPL and wait to synchronize with master schedule
//

// adaptive listen is enabled by default 
// define the following macro to disable it
//#define SCP_DISABLE_ADAPTIVE_LISTEN

// debugging with LEDs
//#define SCP_LED_DEBUG
//#define LPL_LED_DEBUG
//#define CSMA_LED_DEBUG
//#define PHY_LED_DEBUG



// include MAC message and header definitions
#include "ScpMsg.h"
typedef ScpHeader MacHeader;

#endif  // CONFIG



More information about the Tinyos-contrib-commits mailing list