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