[Tinyos-contrib-commits] CVS: tinyos-1.x/contrib/rincon/tos/lib/CC1000Radio/core crc.h, NONE, 1.1 CC1000SquelchM.nc, NONE, 1.1 BusyWaitM.nc, NONE, 1.1 RandomMlcgM.nc, NONE, 1.1 CC1000SendReceiveM.nc, NONE, 1.1 CC1000SendReceiveC.nc, NONE, 1.1 BaseTOSMsg.java, NONE, 1.1 CC1000CsmaC.nc, NONE, 1.1 CC1000RssiC.nc, NONE, 1.1 CC1000ControlM.nc, NONE, 1.1 CC1000CsmaM.nc, NONE, 1.1 AM.h, NONE, 1.1 RandomC.nc, NONE, 1.1 CC1000Const.h, NONE, 1.1 PacketM.nc, NONE, 1.1 CC1000ControlC.nc, NONE, 1.1 RadioCRCPacket.nc, NONE, 1.1 CC1000RssiM.nc, NONE, 1.1

dmm rincon at users.sourceforge.net
Thu Jul 27 16:39:00 PDT 2006


Update of /cvsroot/tinyos/tinyos-1.x/contrib/rincon/tos/lib/CC1000Radio/core
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv18810/contrib/rincon/tos/lib/CC1000Radio/core

Added Files:
	crc.h CC1000SquelchM.nc BusyWaitM.nc RandomMlcgM.nc 
	CC1000SendReceiveM.nc CC1000SendReceiveC.nc BaseTOSMsg.java 
	CC1000CsmaC.nc CC1000RssiC.nc CC1000ControlM.nc CC1000CsmaM.nc 
	AM.h RandomC.nc CC1000Const.h PacketM.nc CC1000ControlC.nc 
	RadioCRCPacket.nc CC1000RssiM.nc 
Log Message:
Added the latest rev. of the CC1000Radio stack, backported from TinyOS 2.0 with modifications.

--- NEW FILE: crc.h ---
// $Id: crc.h,v 1.1.2.4 2006/01/27 23:13:23 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

#ifndef CRC_H
#define CRC_H

/*
 * Default CRC function. Some microcontrollers may provide more efficient
 * implementations.
 *
 * This CRC-16 function produces a 16-bit running CRC that adheres to the
 * ITU-T CRC standard.
 *
 * The ITU-T polynomial is: G_16(x) = x^16 + x^12 + x^5 + 1
 * @param crc Running CRC value
 * @param b Byte to "add" to the CRC
 * @return New CRC value
 *
 */
uint16_t crcByte(uint16_t crc, uint8_t b)
{
  uint8_t i;
  
  crc = crc ^ b << 8;
  i = 8;
  do {
    if (crc & 0x8000) {
      crc = crc << 1 ^ 0x1021;
    
    } else {
      crc = crc << 1;
    }
  } while (--i);

  return crc;
}

#endif

--- NEW FILE: CC1000SquelchM.nc ---
/* $Id: CC1000SquelchP.nc,v 1.1.2.1 2005/08/07 22:42:34 scipio Exp $
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2005 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
 
/**
 * Clear threshold estimation based on RSSI measurements.
 *
 * @author Philip Buonadonna
 * @author Jaein Jeong
 * @author Joe Polastre
 * @author David Gay
 * @author David Moss
 */
  
includes CC1000Const;

module CC1000SquelchM {
  provides {
    interface StdControl;
    interface CC1000Squelch;
  }
}

implementation {

  uint16_t clearThreshold = CC1K_SquelchInit;
  
  uint16_t squelchTable[CC1K_SquelchTableSize];
  
  uint8_t squelchIndex;
  
  uint8_t squelchCount;

  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    uint8_t i;

    for (i = 0; i < CC1K_SquelchTableSize; i++) {
      squelchTable[i] = CC1K_SquelchInit;
    }

    return SUCCESS;
  }

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

  /***************** CC1000 Squelch Commands ****************/
  async command void CC1000Squelch.adjust(uint16_t data) {
    atomic {
      uint16_t squelchTab[CC1K_SquelchTableSize];
      uint16_t lastMinValue;
      uint8_t i;
      uint8_t j;
      uint8_t minIndex;

      squelchTable[squelchIndex++] = data;
      if (squelchIndex >= CC1K_SquelchTableSize) {
        squelchIndex = 0;
      }
    
      if (squelchCount <= CC1K_SquelchCount) {
        squelchCount++;  
      }
    
      /*
       * Order the entries in our squelch table from quietest
       * to loudest.  If there is a jump from being quiet
       * to being loud, the "loudest" quiet value is our 
       * squelch threshold.  Testing showed there is a difference
       * of around 25-50 in the RSSI value between a quiet and loud
       * threshold.  This is characterized with the (lastMinValue >> 3) 
       * condition, which keeps the threshold between quiet and loud 
       * into proportion.
       */
      memcpy(squelchTab, squelchTable, sizeof(squelchTable));
      lastMinValue = 0;
      for (j = 0; j < CC1K_SquelchTableSize - 1; j++) {
        minIndex = 0;
        for (i = 0; i < CC1K_SquelchTableSize - 1; i++) {
          if (squelchTab[i] > squelchTab[minIndex]) {
            minIndex = i;
          }
        }

        if(j != 0 && squelchTab[minIndex] < lastMinValue - (lastMinValue >> 3)) {
          break;
          
        } else {
          lastMinValue = squelchTab[minIndex];
        }
        
        squelchTab[minIndex] = 0;
      }
      
      clearThreshold = (clearThreshold + lastMinValue) / 2;
    }
  }

  async command uint16_t CC1000Squelch.get() {
    return clearThreshold;
  }

  command bool CC1000Squelch.settled() {
    return squelchCount > CC1K_SquelchCount;
  }
}

--- NEW FILE: BusyWaitM.nc ---
/**
 * Busy wait component as per TEP102. Supports waiting for at least some
 * number of microseconds. This functionality should be used sparingly,
 * when the overhead of posting a Timer or Alarm is greater than simply
 * busy waiting.
 *
 * Mica2 compatible
 *
 * @author David Gay
 */

module BusyWaitM {
  provides {
    interface BusyWait;
  }
}

implementation {
  inline async command void BusyWait.wait(uint16_t dt) {
    if (dt) {
      /* loop takes 8 cycles. this is 1uS if running on an internal 8MHz
         clock, and 1.09uS if running on the external crystal. */
      asm volatile (
        "1: sbiw    %0,1\n"
        "   adiw    %0,1\n"
        "   sbiw    %0,1\n"
        "   brne    1b" : "+w" (dt));
    }
  }
}

--- NEW FILE: RandomMlcgM.nc ---
/*
 * "Copyright (c) 2002-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 */


/** 
 * This code is a fast implementation of the Park-Miller Minimal Standard 
 * Generator for pseudo-random numbers.  It uses the 32 bit multiplicative 
 * linear congruential generator, 
 *
 *           S' = (A x S) mod (2^31 - 1) 
 *
 * for A = 16807.
 *
 *
 * @author Barbara Hohlt 
 * @author David Moss
 */

module RandomMlcgM {
  provides {
    interface StdControl;
    interface Random;
  }
}

implementation {
  
  uint32_t seed;

  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    atomic seed = (uint32_t)(TOS_LOCAL_ADDRESS + 1);
    return SUCCESS;
  }

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

  /***************** Random Commands ****************/
  /* Return the next 32 bit random number */
  async command uint32_t Random.rand32() {
    uint32_t mlcg,p,q;
    uint64_t tmpseed;
    atomic {
      tmpseed =  (uint64_t)33614U * (uint64_t)seed;
      q = tmpseed;       /* low */
      q = q >> 1;
      p = tmpseed >> 32 ;            /* hi */
      mlcg = p + q;
        if (mlcg & 0x80000000) { 
        mlcg = mlcg & 0x7FFFFFFF;
        mlcg++;
      }
      seed = mlcg;
    }
    return mlcg; 
  }

  /* Return low 16 bits of next 32 bit random number */
  async command uint16_t Random.rand16() {
    return call Random.rand32();
  }
}

--- NEW FILE: CC1000SendReceiveM.nc ---
/*                                                      tab:4
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2005 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
 
/**
 * A rewrite of the low-power-listening CC1000 radio stack.
 * This file contains the send and receive logic for the CC1000 radio.
 * It does not do any media-access control. It requests the channel
 * via the ready-to-send event (rts) and starts transmission on reception
 * of the clear-to-send command (cts). It listens for packets if the
 * listen() command is called, and stops listening when off() is called.
 *
 * This code has some degree of platform-independence, via the
 * CC1000Control, RSSIADC and SpiByteFifo interfaces which must be provided
 * by the platform. However, these interfaces may still reflect some
 * particularities of the mica2 hardware implementation.
 *
 * @author Philip Buonadonna
 * @author Jaein Jeong
 * @author Joe Polastre
 * @author David Gay
 * @author David Moss
 */

includes crc;
includes CC1000Const;

module CC1000SendReceiveM {
  provides {
    interface StdControl;
    interface BareSendMsg as Send;
    interface ReceiveMsg as Receive;
    interface RadioTimeStamping;
    interface ByteRadio;
    interface PacketAcknowledgements;
    interface MacControl;
  }
  
  uses {
    interface CC1000Control;
    interface SpiByteFifo;
    interface Rssi as RssiRx;
  }
}

implementation {

  norace uint8_t radioState;
  
  norace uint16_t count;

  uint16_t runningCrc;

  uint16_t rxShiftBuf;

  TOS_Msg rxBuf;

  TOS_Msg *rxBufPtr = &rxBuf;

  uint16_t preambleLength;

  TOS_Msg *txBufPtr;

  uint8_t nextTxByte;

  /** Flags */
  struct {
    bool ack : 1;
    bool txBusy : 1;
    uint8_t rxBitOffset : 3;
  } f; // f for flags
  
  
  /**
   * States
   */
  enum {
    /** Off */
    S_INACTIVE,

    /* Listening for packets */
    S_LISTEN,  

    /* Reception states */
    S_SYNC,
    S_RX,
    S_RECEIVED,
    S_SENDACK,

    /* Transmission states */
    S_TXPREAMBLE,
    S_TXSYNC,
    S_TXDATA,
    S_TXCRC,
    S_TXFLUSH,
    S_TXWAITFORACK,
    S_TXREADACK,
    S_TXDONE,
  };

  /**
   * Sync and Ack bytes
   */
  enum {
    SYNC_BYTE1 = 0x33,
    SYNC_BYTE2 = 0xCC,
    SYNC_WORD = SYNC_BYTE1 << 8 | SYNC_BYTE2,
    ACK_BYTE1 = 0xBA,
    ACK_BYTE2 = 0x83,
    ACK_WORD = ACK_BYTE1 << 8 | ACK_BYTE2,
    ACK_LENGTH = 16,
    MAX_ACK_WAIT = 18,
  };

  const uint8_t ackCode[5] = {0xAB, 
                              ACK_BYTE1, 
                              ACK_BYTE2, 
                              0xAA, 
                              0xAA};
  
  
  /***************** State Prototypes ****************/
  void enterInactiveState();
  void enterListenState();
  void enterSyncState();
  void enterRxState();
  void enterReceiveState();
  void enterAckState();
  void enterTxPreambleState();
  void enterTxSyncState();
  void enterTxDataState();
  void enterTxCrcState();
  void enterTxFlushState();
  void enterTxWaitForAckState();
  void enterTxReadAckState();
  void enterTxDoneState();
  
  
  /***************** Tx Prototypes ****************/
  void sendNextByte();
  void txPreamble();
  void txSync();
  void txData();
  void txCrc();
  void txFlush();
  void txWaitForAck();
  void txReadAck(uint8_t in);
  void txDone();
  
  task void signalPacketSent();


  /***************** Rx Prototypes ****************/
  void packetReceived();
  void packetReceiveDone();
  void listenData(uint8_t in);
  void syncData(uint8_t in);
  void rxData(uint8_t in);
  void ackData(uint8_t in);
  
  task void signalPacketReceived();
  
  
  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    call SpiByteFifo.initSlave();
    call ByteRadio.setAck(TRUE);
    return SUCCESS;
  }

  command result_t StdControl.start() {
    atomic {
      f.ack = TRUE;
      f.txBusy = FALSE;
    }
    return SUCCESS;
  }

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


  /***************** Send Commands ****************/
  command result_t Send.send(TOS_Msg *msg) {
    atomic {
      if(f.txBusy) {
        return FAIL;
      
      } else {
        f.txBusy = TRUE;
        txBufPtr = msg;
        call ByteRadio.setAck(txBufPtr->ack);
      }
    }

    signal ByteRadio.rts();

    return SUCCESS;
  }

  /***************** ByteRadio Commands ****************/
  async command void ByteRadio.cts() {
    // We're set to go! Start with our exciting preamble...
    enterTxPreambleState();
    call SpiByteFifo.writeByte(0xAA);
    call CC1000Control.txMode();
    call SpiByteFifo.txMode();
  }

  async command void ByteRadio.listen() {
    enterListenState();
    call CC1000Control.rxMode();
    call SpiByteFifo.rxMode();
    call SpiByteFifo.enableIntr();
  }

  async command void ByteRadio.off() {
    enterInactiveState();
    call SpiByteFifo.disableIntr();
  }

  async command bool ByteRadio.isFree() {
    return (radioState == S_INACTIVE 
        || radioState == S_LISTEN 
        || radioState == S_SYNC);
  }

  async command void ByteRadio.setAck(bool on) {
    atomic f.ack = on;
  }

  async command void ByteRadio.setPreambleLength(uint16_t bytes) {
    atomic preambleLength = bytes;
  }

  async command uint16_t ByteRadio.getPreambleLength() {
    atomic return preambleLength;
  }

  async command TOS_Msg *ByteRadio.getTxMessage() {
    return txBufPtr;
  }

  async command bool ByteRadio.syncing() {
    return radioState == S_SYNC;
  }

  /***************** PacketAcknowledgements Commands ****************/
  async command result_t PacketAcknowledgements.requestAck(TOS_Msg *msg) {
    msg->ack = TRUE;
    return SUCCESS;
  }

  async command result_t PacketAcknowledgements.noAck(TOS_Msg *msg) {
    msg->ack = FALSE;
    return SUCCESS;
  }

  async command bool PacketAcknowledgements.wasAcked(TOS_Msg *msg) {
    return msg->ack;
  }
  
  
  /***************** MacControl Commands ****************/
  /**
   * Enable acknowledgmenets (backwards compatibility)
   */
  async command void MacControl.enableAck() {
    call ByteRadio.setAck(TRUE);
  }
  
  /**
   * Disable acknowledgements (backwards compatibility)
   */
  async command void MacControl.disableAck() {
    call ByteRadio.setAck(FALSE);
  }
  
  
  /***************** RssiRx Events ***********************/
  async event void RssiRx.readDone(result_t result, uint16_t data) {
    if(result != SUCCESS) {
      rxBufPtr->strength = 0;
    
    } else {
      rxBufPtr->strength = data;
    }
  }
  
  /***************** SpiByteFifo Events ****************/
  async event result_t SpiByteFifo.dataReady(uint8_t data) {
    // Invert the data because the LO is high
    data = ~data;

    switch (radioState) {
      case S_TXPREAMBLE: txPreamble(); break;
      case S_TXSYNC: txSync(); break;
      case S_TXDATA: txData(); break;
      case S_TXCRC: txCrc(); break;
      case S_TXFLUSH: txFlush(); break;
      case S_TXWAITFORACK: txWaitForAck(); break;
      case S_TXREADACK: txReadAck(data); break;
      case S_TXDONE: txDone(); break;

      case S_LISTEN: listenData(data); break;
      case S_SYNC: syncData(data); break;
      case S_RX: rxData(data); break;
      case S_SENDACK: ackData(data); break;
    
      default: break;
    }
  
    return SUCCESS;
  }


  /***************** State Functions ****************/
  void enterInactiveState() {
    radioState = S_INACTIVE;
  }

  void enterListenState() {
    radioState = S_LISTEN;
    count = 0;
  }

  void enterSyncState() {
    radioState = S_SYNC;
    count = 0;
    rxShiftBuf = 0;
  }

  void enterRxState() {
    radioState = S_RX;
    rxBufPtr->length = sizeof rxBufPtr->data;
    count = 0;
    runningCrc = 0;
  }

  void enterReceivedState() {
    radioState = S_RECEIVED;
  }

  void enterAckState() {
    radioState = S_SENDACK;
    count = 0;
  }
  
  void enterTxPreambleState() {
    radioState = S_TXPREAMBLE;
    count = 0;
    runningCrc = 0;
    nextTxByte = 0xAA;
  }

  void enterTxSyncState() {
    radioState = S_TXSYNC;
  }

  void enterTxDataState() {
    radioState = S_TXDATA;
    // The count increment happens before the first byte is read from the
    // packet, so we subtract one from the real packet start point to
    // compensate.
    count = -1; 
  }

  void enterTxCrcState() {
    radioState = S_TXCRC;
  }
    
  void enterTxFlushState() {
    radioState = S_TXFLUSH;
    count = 0;
  }
    
  void enterTxWaitForAckState() {
    radioState = S_TXWAITFORACK;
    count = 0;
  }
    
  void enterTxReadAckState() {
    radioState = S_TXREADACK;
    rxShiftBuf = 0;
    count = 0;
  }
    
  void enterTxDoneState() {
    radioState = S_TXDONE;
  }
  
  
  /***************** Tx Functions ****************/
  void sendNextByte() {
    call SpiByteFifo.writeByte(nextTxByte);
    count++;
  }

  void txPreamble() {
    sendNextByte();
    if(count >= preambleLength) {
      nextTxByte = SYNC_BYTE1;
      enterTxSyncState();
    }
  }
  
  void txSync() {
    sendNextByte();
    nextTxByte = SYNC_BYTE2;
    enterTxDataState();
    signal RadioTimeStamping.transmittedSFD(0, txBufPtr); 
  }

  void txData() {
    sendNextByte();
    
    if(count < offsetof(TOS_Msg, data) + txBufPtr->length) {
      nextTxByte = ((uint8_t *)txBufPtr)[count];
      runningCrc = crcByte(runningCrc, nextTxByte);
      
    } else {
      nextTxByte = runningCrc;
      enterTxCrcState();
    }
  }

  void txCrc() {
    sendNextByte();
    nextTxByte = runningCrc >> 8;
    enterTxFlushState();
  }

  void txFlush() {
    sendNextByte();
    if(count > 3) {
      if(f.ack) {
        enterTxWaitForAckState();
      
      } else {
        call SpiByteFifo.rxMode();
        call CC1000Control.rxMode();
        enterTxDoneState();
      }
    }
  }

  void txWaitForAck() {
    sendNextByte();
    if(count == 1) {
      call SpiByteFifo.rxMode();
      call CC1000Control.rxMode();
    
    } else if(count > 3) {
      enterTxReadAckState();
    }
  }

  void txReadAck(uint8_t in) {
    uint8_t i;

    sendNextByte();

    for (i = 0; i < 8; i++) {
      rxShiftBuf <<= 1;
      if(in & 0x80) {
        rxShiftBuf |=  0x1;
      }
      in <<= 1;

      if(rxShiftBuf == ACK_WORD) {
        txBufPtr->ack = 1;
        enterTxDoneState();
        return;
      }
    }
    
    if(count >= MAX_ACK_WAIT) {
      txBufPtr->ack = 0;
      enterTxDoneState();
    }
  }
  
  void txDone() {
    post signalPacketSent();
    signal ByteRadio.sendDone();
  }
  
  
  task void signalPacketSent() {
    TOS_Msg *pBuf;

    atomic {
      pBuf = txBufPtr;
      f.txBusy = FALSE;
      enterListenState();
    }
    
    signal Send.sendDone(pBuf, SUCCESS);
  }
  
  
  /***************** Rx Functions ****************/
  /**
   * Listen for preamble bytes 
   */
  void listenData(uint8_t in) {
    bool preamble = (in == 0xAA || in == 0x55);

    if(preamble) {
      count++;
      if(count > CC1K_ValidPrecursor) {
        enterSyncState();
      }
      
    } else {
      count = 0;
    }
    
    signal ByteRadio.idleByte(preamble);
  }

  void syncData(uint8_t in) {
    // draw in the preamble bytes and look for a sync byte
    // save the data in a short with last byte received as msbyte
    //    and current byte received as the lsbyte.
    // use a bit shift compare to find the byte boundary for the sync byte
    // retain the shift value and use it to collect all of the packet data
    // check for data inversion, and restore proper polarity 
    // XXX-PB: Don't do this.

    if(in == 0xAA || in == 0x55) {
      // It is actually possible to have the LAST BIT of the incoming
      // data be part of the Sync Byte.  SO, we need to store that
      // However, the next byte should definitely not have this pattern.
      rxShiftBuf = in << 8;
      
    } else if(count++ == 0) {
      rxShiftBuf |= in;
      
    } else if(count <= 6) {
      uint16_t tmp;
      uint8_t i;

      // bit shift the data in with previous sample to find sync
      tmp = rxShiftBuf;
      rxShiftBuf = rxShiftBuf << 8 | in;

      for(i = 0; i < 8; i++) {
        tmp <<= 1;
        if(in & 0x80) {
          tmp  |=  0x1;
        }
          
        in <<= 1;
        // check for sync bytes
        if(tmp == SYNC_WORD) {
          enterRxState();
          signal ByteRadio.rx();
          f.rxBitOffset = 7 - i;
          signal RadioTimeStamping.receivedSFD(0);
          call RssiRx.read();
        }
      }
        
    } else {
      // We didn't find it after a reasonable number of tries, so....
      enterListenState();
    }
  }
  
  void rxData(uint8_t in) {
    uint8_t nextByte;

    // rxLength is the offset into a TOS_Msg at which the packet
    // data ends: it is NOT equal to the number of bytes received,
    // as there may be padding in the TOS_Msg before the packet.
    uint8_t rxLength = rxBufPtr->length + offsetof(TOS_Msg, data);

    // Reject invalid length packets
    if(rxLength > TOSH_DATA_LENGTH + offsetof(TOS_Msg, data)) {
      // The packet's screwed up, so just dump it
      enterListenState();
      signal ByteRadio.rxDone();
      return;
    }

    rxShiftBuf = rxShiftBuf << 8 | in;
    nextByte = rxShiftBuf >> f.rxBitOffset;
    ((uint8_t *)rxBufPtr)[count++] = nextByte;

    if(count <= rxLength) {
      runningCrc = crcByte(runningCrc, nextByte);
    }
    
    // Jump to CRC when we reach the end of data
    if(count == rxLength) {
      count = offsetof(TOS_Msg, crc);
    }

    if(count == (offsetof(TOS_Msg, crc) + sizeof(rxBufPtr->crc))) {
      packetReceived();
    }
  }

  void packetReceived() {
    rxBufPtr->crc = (rxBufPtr->crc == runningCrc);

    if(f.ack
           && rxBufPtr->crc 
           && (rxBufPtr->addr == TOS_LOCAL_ADDRESS 
               || rxBufPtr->addr == TOS_BCAST_ADDR)) {
      
      enterAckState();
      call CC1000Control.txMode();
      call SpiByteFifo.txMode();
      call SpiByteFifo.writeByte(0xAA);
      
    } else {
      packetReceiveDone();
    }
  }

  void ackData(uint8_t in) {
    if(++count >= ACK_LENGTH) { 
      call CC1000Control.rxMode();
      call SpiByteFifo.rxMode();
      packetReceiveDone();
    
    } else if(count >= ACK_LENGTH - sizeof(ackCode)) {
      call SpiByteFifo.writeByte(ackCode[count + sizeof(ackCode) - ACK_LENGTH]);
    }
  }
  
  void packetReceiveDone() {
    enterReceivedState();
    post signalPacketReceived();
  }
  
  
  task void signalPacketReceived() {
    TOS_Msg *pBuf;
    atomic {
      pBuf = rxBufPtr;
    }
    
    pBuf = signal Receive.receive(pBuf);
    
    atomic {
      if(pBuf) {
        rxBufPtr = pBuf;
      
      } else {
        rxBufPtr = &rxBuf;
      }
      
      enterListenState();
      signal ByteRadio.rxDone();
    }
  }
  
  /***************** Defaults ****************/
  default async event void RadioTimeStamping.transmittedSFD(uint16_t time, TOS_Msg* msgBuff) {
  }
  
  default async event void RadioTimeStamping.receivedSFD(uint16_t time) {
  }
}

--- NEW FILE: CC1000SendReceiveC.nc ---

/**
 * CC1000 Send/Receive Configuration
 * Implements a byte radio to transmit and receive packets
 *
 * @author David Moss
 */
 
configuration CC1000SendReceiveC {
  provides {
    interface StdControl;
    interface BareSendMsg as Send;
    interface ReceiveMsg as Receive;
    interface ByteRadio;
    interface Packet;
    interface PacketAcknowledgements;
    interface MacControl;
  }
}

implementation {
  components CC1000SendReceiveM, CC1000ControlC, CC1000RssiC, HplSpiC;
  components PacketM;
  
  StdControl = CC1000SendReceiveM;
  Send = CC1000SendReceiveM;
  Receive = CC1000SendReceiveM;
  ByteRadio = CC1000SendReceiveM;
  PacketAcknowledgements = CC1000SendReceiveM;
  MacControl = CC1000SendReceiveM;
  
  Packet = PacketM;
  
  CC1000SendReceiveM.CC1000Control -> CC1000ControlC;
  CC1000SendReceiveM.SpiByteFifo -> HplSpiC;
  CC1000SendReceiveM.RssiRx -> CC1000RssiC.Rssi[unique("Rssi")];

}


--- NEW FILE: BaseTOSMsg.java ---
// $Id: BaseTOSMsg.java,v 1.1 2006/07/27 23:38:58 rincon Exp $

/**
 * This class is automatically generated by mig. DO NOT EDIT THIS FILE.
 * This class implements a Java interface to the 'BaseTOSMsg'
 * message type.
 */

package net.tinyos.message.avrmote;

public class BaseTOSMsg extends net.tinyos.message.TOSMsg {

    /** The default size of this message type in bytes. */
    public static final int DEFAULT_MESSAGE_SIZE = 41;

    /** The Active Message type associated with this message. */
    public static final int AM_TYPE = -1;

    /** Create a new BaseTOSMsg of size 41. */
    public BaseTOSMsg() {
        super(DEFAULT_MESSAGE_SIZE);
        amTypeSet(AM_TYPE);
    }

    /** Create a new BaseTOSMsg of the given data_length. */
    public BaseTOSMsg(int data_length) {
        super(data_length);
        amTypeSet(AM_TYPE);
    }

    /**
     * Create a new BaseTOSMsg with the given data_length
     * and base offset.
     */
    public BaseTOSMsg(int data_length, int base_offset) {
        super(data_length, base_offset);
        amTypeSet(AM_TYPE);
    }

    /**
     * Create a new BaseTOSMsg using the given byte array
     * as backing store.
     */
    public BaseTOSMsg(byte[] data) {
        super(data);
        amTypeSet(AM_TYPE);
    }

    /**
     * Create a new BaseTOSMsg using the given byte array
     * as backing store, with the given base offset.
     */
    public BaseTOSMsg(byte[] data, int base_offset) {
        super(data, base_offset);
        amTypeSet(AM_TYPE);
    }

    /**
     * Create a new BaseTOSMsg using the given byte array
     * as backing store, with the given base offset and data length.
     */
    public BaseTOSMsg(byte[] data, int base_offset, int data_length) {
        super(data, base_offset, data_length);
        amTypeSet(AM_TYPE);
    }

    /**
     * Create a new BaseTOSMsg embedded in the given message
     * at the given base offset.
     */
    public BaseTOSMsg(net.tinyos.message.Message msg, int base_offset) {
        super(msg, base_offset, DEFAULT_MESSAGE_SIZE);
        amTypeSet(AM_TYPE);
    }

    /**
     * Create a new BaseTOSMsg embedded in the given message
     * at the given base offset and length.
     */
    public BaseTOSMsg(net.tinyos.message.Message msg, int base_offset, int data_length) {
        super(msg, base_offset, data_length);
        amTypeSet(AM_TYPE);
    }

    /**
    /* Return a String representation of this message. Includes the
     * message type name and the non-indexed field values.
     */
    public String toString() {
      String s = "Message <BaseTOSMsg> \n";
      try {
        s += "  [addr=0x"+Long.toHexString(get_addr())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [type=0x"+Long.toHexString(get_type())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [group=0x"+Long.toHexString(get_group())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [length=0x"+Long.toHexString(get_length())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [data=";
        for (int i = 0; i < 29; i++) {
          s += "0x"+Long.toHexString(getElement_data(i) & 0xff)+" ";
        }
        s += "]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [crc=0x"+Long.toHexString(get_crc())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [strength=0x"+Long.toHexString(get_strength())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [ack=0x"+Long.toHexString(get_ack())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      try {
        s += "  [time=0x"+Long.toHexString(get_time())+"]\n";
      } catch (ArrayIndexOutOfBoundsException aioobe) { /* Skip field */ }
      return s;
    }

    // Message-type-specific access methods appear below.

    /////////////////////////////////////////////////////////
    // Accessor methods for field: addr
    //   Field type: int, unsigned
    //   Offset (bits): 0
    //   Size (bits): 16
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'addr' is signed (false).
     */
    public static boolean isSigned_addr() {
        return false;
    }

    /**
     * Return whether the field 'addr' is an array (false).
     */
    public static boolean isArray_addr() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'addr'
     */
    public static int offset_addr() {
        return (0 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'addr'
     */
    public static int offsetBits_addr() {
        return 0;
    }

    /**
     * Return the value (as a int) of the field 'addr'
     */
    public int get_addr() {
        return (int)getUIntElement(offsetBits_addr(), 16);
    }

    /**
     * Set the value of the field 'addr'
     */
    public void set_addr(int value) {
        setUIntElement(offsetBits_addr(), 16, value);
    }

    /**
     * Return the size, in bytes, of the field 'addr'
     */
    public static int size_addr() {
        return (16 / 8);
    }

    /**
     * Return the size, in bits, of the field 'addr'
     */
    public static int sizeBits_addr() {
        return 16;
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: type
    //   Field type: short, unsigned
    //   Offset (bits): 16
    //   Size (bits): 8
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'type' is signed (false).
     */
    public static boolean isSigned_type() {
        return false;
    }

    /**
     * Return whether the field 'type' is an array (false).
     */
    public static boolean isArray_type() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'type'
     */
    public static int offset_type() {
        return (16 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'type'
     */
    public static int offsetBits_type() {
        return 16;
    }

    /**
     * Return the value (as a short) of the field 'type'
     */
    public short get_type() {
        return (short)getUIntElement(offsetBits_type(), 8);
    }

    /**
     * Set the value of the field 'type'
     */
    public void set_type(short value) {
        setUIntElement(offsetBits_type(), 8, value);
    }

    /**
     * Return the size, in bytes, of the field 'type'
     */
    public static int size_type() {
        return (8 / 8);
    }

    /**
     * Return the size, in bits, of the field 'type'
     */
    public static int sizeBits_type() {
        return 8;
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: group
    //   Field type: short, unsigned
    //   Offset (bits): 24
    //   Size (bits): 8
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'group' is signed (false).
     */
    public static boolean isSigned_group() {
        return false;
    }

    /**
     * Return whether the field 'group' is an array (false).
     */
    public static boolean isArray_group() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'group'
     */
    public static int offset_group() {
        return (24 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'group'
     */
    public static int offsetBits_group() {
        return 24;
    }

    /**
     * Return the value (as a short) of the field 'group'
     */
    public short get_group() {
        return (short)getUIntElement(offsetBits_group(), 8);
    }

    /**
     * Set the value of the field 'group'
     */
    public void set_group(short value) {
        setUIntElement(offsetBits_group(), 8, value);
    }

    /**
     * Return the size, in bytes, of the field 'group'
     */
    public static int size_group() {
        return (8 / 8);
    }

    /**
     * Return the size, in bits, of the field 'group'
     */
    public static int sizeBits_group() {
        return 8;
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: length
    //   Field type: short, unsigned
    //   Offset (bits): 32
    //   Size (bits): 8
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'length' is signed (false).
     */
    public static boolean isSigned_length() {
        return false;
    }

    /**
     * Return whether the field 'length' is an array (false).
     */
    public static boolean isArray_length() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'length'
     */
    public int offset_length() {
        return (32 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'length'
     */
    public static int offsetBits_length() {
        return 32;
    }

    /**
     * Return the value (as a short) of the field 'length'
     */
    public short get_length() {
        return (short)getUIntElement(offsetBits_length(), 8);
    }

    /**
     * Set the value of the field 'length'
     */
    public void set_length(short value) {
        setUIntElement(offsetBits_length(), 8, value);
    }

    /**
     * Return the size, in bytes, of the field 'length'
     */
    public static int size_length() {
        return (8 / 8);
    }

    /**
     * Return the size, in bits, of the field 'length'
     */
    public static int sizeBits_length() {
        return 8;
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: data
    //   Field type: byte[], unsigned
    //   Offset (bits): 40
    //   Size of each element (bits): 8
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'data' is signed (false).
     */
    public static boolean isSigned_data() {
        return false;
    }

    /**
     * Return whether the field 'data' is an array (true).
     */
    public static boolean isArray_data() {
        return true;
    }

    /**
     * Return the offset (in bytes) of the field 'data'
     */
    public  int offset_data(int index1) {
        int offset = 40;
        if (index1 < 0 || index1 >= 29) throw new ArrayIndexOutOfBoundsException();
        offset += 0 + index1 * 8;
        return (offset / 8);
    }

    /**
     * Return the offset (in bits) of the field 'data'
     */
    public static int offsetBits_data(int index1) {
        int offset = 40;
        if (index1 < 0 || index1 >= 29) throw new ArrayIndexOutOfBoundsException();
        offset += 0 + index1 * 8;
        return offset;
    }

    /**
     * Return the entire array 'data' as a byte[]
     */
    public byte[] get_data() {
        byte[] tmp = new byte[29];
        for (int index0 = 0; index0 < numElements_data(0); index0++) {
            tmp[index0] = getElement_data(index0);
        }
        return tmp;
    }

    /**
     * Set the contents of the array 'data' from the given byte[]
     */
    public void set_data(byte[] value) {
        for (int index0 = 0; index0 < value.length; index0++) {
            setElement_data(index0, value[index0]);
        }
    }

    /**
     * Return an element (as a byte) of the array 'data'
     */
    public byte getElement_data(int index1) {
        return (byte)getSIntElement(offsetBits_data(index1), 8);
    }

    /**
     * Set an element of the array 'data'
     */
    public void setElement_data(int index1, byte value) {
        setSIntElement(offsetBits_data(index1), 8, value);
    }

    /**
     * Return the total size, in bytes, of the array 'data'
     */
    public int totalSize_data() {
        return (232 / 8);
    }

    /**
     * Return the total size, in bits, of the array 'data'
     */
    public int totalSizeBits_data() {
        return 232;
    }

    /**
     * Return the size, in bytes, of each element of the array 'data'
     */
    public static int elementSize_data() {
        return (8 / 8);
    }

    /**
     * Return the size, in bits, of each element of the array 'data'
     */
    public static int elementSizeBits_data() {
        return 8;
    }

    /**
     * Return the number of dimensions in the array 'data'
     */
    public static int numDimensions_data() {
        return 1;
    }

    /**
     * Return the number of elements in the array 'data'
     */
    public int numElements_data() {
        return 29;
    }

    /**
     * Return the number of elements in the array 'data'
     * for the given dimension.
     */
    public int numElements_data(int dimension) {
      int array_dims[] = { 29,  };
        if (dimension < 0 || dimension >= 1) throw new ArrayIndexOutOfBoundsException();
        if (array_dims[dimension] == 0) throw new IllegalArgumentException("Array dimension "+dimension+" has unknown size");
        return array_dims[dimension];
    }

    /**
     * Fill in the array 'data' with a String
     */
    public void setString_data(String s) { 
         int len = s.length();
         int i;
         for (i = 0; i < len; i++) {
             setElement_data(i, (byte)s.charAt(i));
         }
         setElement_data(i, (byte)0); //null terminate
    }

    /**
     * Read the array 'data' as a String
     */
    public String getString_data() { 
         char carr[] = new char[Math.min(net.tinyos.message.Message.MAX_CONVERTED_STRING_LENGTH,29)];
         int i;
         for (i = 0; i < carr.length; i++) {
             if ((char)getElement_data(i) == (char)0) break;
             carr[i] = (char)getElement_data(i);
         }
         return new String(carr,0,i);
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: crc
    //   Field type: int, unsigned
    //   Offset (bits): 272
    //   Size (bits): 16
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'crc' is signed (false).
     */
    public static boolean isSigned_crc() {
        return false;
    }

    /**
     * Return whether the field 'crc' is an array (false).
     */
    public static boolean isArray_crc() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'crc'
     */
    public int offset_crc() {
        return (272 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'crc'
     */
    public int offsetBits_crc() {
        return 272;
    }

    /**
     * Return the value (as a int) of the field 'crc'
     */
    public int get_crc() {
        return (int)getUIntElement(offsetBits_crc(), 16);
    }

    /**
     * Set the value of the field 'crc'
     */
    public void set_crc(int value) {
        setUIntElement(offsetBits_crc(), 16, value);
    }

    /**
     * Return the size, in bytes, of the field 'crc'
     */
    public static int size_crc() {
        return (16 / 8);
    }

    /**
     * Return the size, in bits, of the field 'crc'
     */
    public static int sizeBits_crc() {
        return 16;
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: strength
    //   Field type: int, unsigned
    //   Offset (bits): 288
    //   Size (bits): 16
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'strength' is signed (false).
     */
    public static boolean isSigned_strength() {
        return false;
    }

    /**
     * Return whether the field 'strength' is an array (false).
     */
    public static boolean isArray_strength() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'strength'
     */
    public static int offset_strength() {
        return (288 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'strength'
     */
    public static int offsetBits_strength() {
        return 288;
    }

    /**
     * Return the value (as a int) of the field 'strength'
     */
    public int get_strength() {
        return (int)getUIntElement(offsetBits_strength(), 16);
    }

    /**
     * Set the value of the field 'strength'
     */
    public void set_strength(int value) {
        setUIntElement(offsetBits_strength(), 16, value);
    }

    /**
     * Return the size, in bytes, of the field 'strength'
     */
    public static int size_strength() {
        return (16 / 8);
    }

    /**
     * Return the size, in bits, of the field 'strength'
     */
    public static int sizeBits_strength() {
        return 16;
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: ack
    //   Field type: short, unsigned
    //   Offset (bits): 304
    //   Size (bits): 8
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'ack' is signed (false).
     */
    public static boolean isSigned_ack() {
        return false;
    }

    /**
     * Return whether the field 'ack' is an array (false).
     */
    public static boolean isArray_ack() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'ack'
     */
    public static int offset_ack() {
        return (304 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'ack'
     */
    public static int offsetBits_ack() {
        return 304;
    }

    /**
     * Return the value (as a short) of the field 'ack'
     */
    public short get_ack() {
        return (short)getUIntElement(offsetBits_ack(), 8);
    }

    /**
     * Set the value of the field 'ack'
     */
    public void set_ack(short value) {
        setUIntElement(offsetBits_ack(), 8, value);
    }

    /**
     * Return the size, in bytes, of the field 'ack'
     */
    public static int size_ack() {
        return (8 / 8);
    }

    /**
     * Return the size, in bits, of the field 'ack'
     */
    public static int sizeBits_ack() {
        return 8;
    }

    /////////////////////////////////////////////////////////
    // Accessor methods for field: time
    //   Field type: int, unsigned
    //   Offset (bits): 312
    //   Size (bits): 16
    /////////////////////////////////////////////////////////

    /**
     * Return whether the field 'time' is signed (false).
     */
    public static boolean isSigned_time() {
        return false;
    }

    /**
     * Return whether the field 'time' is an array (false).
     */
    public static boolean isArray_time() {
        return false;
    }

    /**
     * Return the offset (in bytes) of the field 'time'
     */
    public static int offset_time() {
        return (312 / 8);
    }

    /**
     * Return the offset (in bits) of the field 'time'
     */
    public static int offsetBits_time() {
        return 312;
    }

    /**
     * Return the value (as a int) of the field 'time'
     */
    public int get_time() {
        return (int)getUIntElement(offsetBits_time(), 16);
    }

    /**
     * Set the value of the field 'time'
     */
    public void set_time(int value) {
        setUIntElement(offsetBits_time(), 16, value);
    }

    /**
     * Return the size, in bytes, of the field 'time'
     */
    public static int size_time() {
        return (16 / 8);
    }

    /**
     * Return the size, in bits, of the field 'time'
     */
    public static int sizeBits_time() {
        return 16;
    }

}

--- NEW FILE: CC1000CsmaC.nc ---

/**
 * CC1000 CSMA Configuration
 * Provides the low power listening functionality for the CC1000 radio
 * 
 * @author David Moss
 */

configuration CC1000CsmaC {
  provides {
    interface StdControl;
    interface LowPowerListening;
  }
}

implementation {
  components CC1000CsmaM, CC1000ControlC, RandomC, TimerC, BusyWaitM;
  components CC1000SquelchM, CC1000SendReceiveC, CC1000RssiC;

  StdControl = CC1000CsmaM;
  LowPowerListening = CC1000CsmaM;
  
  CC1000CsmaM.CC1000Control -> CC1000ControlC;
  CC1000CsmaM.Random -> RandomC;
  CC1000CsmaM.CC1000Squelch -> CC1000SquelchM;
  CC1000CsmaM.WakeupTimer -> TimerC.Timer[unique("Timer")];
  CC1000CsmaM.RssiNoiseFloor -> CC1000RssiC.Rssi[unique("Rssi")];
  CC1000CsmaM.RssiCheckChannel -> CC1000RssiC.Rssi[unique("Rssi")];
  CC1000CsmaM.RssiPulseCheck -> CC1000RssiC.Rssi[unique("Rssi")];
  CC1000CsmaM.BusyWait -> BusyWaitM;
  CC1000CsmaM.ByteRadio -> CC1000SendReceiveC;
  CC1000CsmaM.ByteRadioControl -> CC1000SendReceiveC.StdControl;

}



--- NEW FILE: CC1000RssiC.nc ---

/**
 * CC1000 RSSI readings
 * Use unique("Rssi") when connecting to one of the parameterized interfaces
 *
 * @author David Moss
 */

configuration CC1000RssiC {
  provides {
    interface StdControl;
    interface Rssi[uint8_t id];
  }
}

implementation {
  components CC1000RssiM, ADCC;
  
  StdControl = CC1000RssiM;
  Rssi = CC1000RssiM;
  
  CC1000RssiM.ADC -> ADCC.ADC[TOS_ADC_CC_RSSI_PORT];
  CC1000RssiM.ADCControl -> ADCC;
}


--- NEW FILE: CC1000ControlM.nc ---
/*
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2005 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
 
/**
 * This module provides the CONTROL functionality for the Chipcon1000
 * series radio.  It exports a custom interface to control CC1000
 * operation.
 *
 * @author Philip Buonadonna
 * @author Jaein Jeong
 * @author David Gay
 * @author David Moss
 */

includes CC1000Const;

module CC1000ControlM {
  provides {
    interface CC1000Control;
    interface StdControl;
  }
  
  uses {
    interface Timer as RecalibrationTimer;
    interface HPLCC1000;
    interface BusyWait;
    interface ByteRadio;
  }
}

implementation {

  norace uint8_t txCurrent;
  
  norace uint8_t rxCurrent;
  
  norace uint8_t power;

  /** The number of hours before an auto recalibration of the radio */
  uint8_t recalibrationHours;
  
  /** TRUE if the radio is being calibrated */
  bool calibrating;
  
  enum {
    IF = 150000,
    FREQ_MIN = 4194304,
    FREQ_MAX = 16751615
  };

  const uint32_t fRefTbl[9] = {
                   2457600,
                   2106514,
                   1843200,
                   1638400,
                   1474560,
                   1340509,
                   1228800,
                   1134277,
                   1053257};
  
  const uint16_t corTbl[9] = {
                  1213,
                  1416,
                  1618,
                  1820,
                  2022,
                  2224,
                  2427,
                  2629,
                  2831};
  
  const uint16_t fsepTbl[9] = {
                   0x1AA,
                   0x1F1,
                   0x238,
                   0x280,
                   0x2C7,
                   0x30E,
                   0x355,
                   0x39C,
                   0x3E3};
  
  enum {
    DEFAULT_RECALIBRATION_HOURS = 8,
  };
  
  /***************** Prototypes ****************/
  void calibrateNow();
  
  void singleCalibration();
  
  uint32_t calculateFrequency(uint32_t desiredFreq);
  
  task void attemptCalibration();
  
  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    call HPLCC1000.init();

    recalibrationHours = DEFAULT_RECALIBRATION_HOURS;
    
    // wake up xtal and reset unit
    call HPLCC1000.write(CC1K_MAIN,
          1 << CC1K_RX_PD | 1 << CC1K_TX_PD | 
          1 << CC1K_FS_PD | 1 << CC1K_BIAS_PD);
          
    // clear reset.
    call CC1000Control.coreOn();
    call BusyWait.wait(2000);

    // Set default parameter values
    // POWER: 0dbm (~900MHz), 6dbm (~430MHz)
    power = 8 << CC1K_PA_HIGHPOWER | 0 << CC1K_PA_LOWPOWER;
    call HPLCC1000.write(CC1K_PA_POW, power);

    // select Manchester Violation for CHP_OUT
    call HPLCC1000.write(CC1K_LOCK_SELECT, 9 << CC1K_LOCK_SELECT);

    // Default modem values = 19.2 Kbps (38.4 kBaud), Manchester encoded
    call HPLCC1000.write(CC1K_MODEM2, 0);
    
    call HPLCC1000.write(CC1K_MODEM1, 
          3 << CC1K_MLIMIT |
          1 << CC1K_LOCK_AVG_MODE | 
          3 << CC1K_SETTLING |
          1 << CC1K_MODEM_RESET_N);
          
    call CC1000Control.doubleBaudRate(FALSE);

    call HPLCC1000.write(CC1K_FSCTRL, 1 << CC1K_FS_RESET_N);

#ifdef CC1K_DEF_FREQ
    call CC1000Control.tuneManual(CC1K_DEF_FREQ);
#else
    call CC1000Control.tunePreset(CC1K_DEF_PRESET);
#endif

    call CC1000Control.off();
    
    return SUCCESS;
  }

  command result_t StdControl.start() {
    call RecalibrationTimer.start(TIMER_REPEAT, recalibrationHours*3600*1024);
    return SUCCESS;
  }
  
  command result_t StdControl.stop() {
    return SUCCESS;
  }
  
  /***************** CC1000Control Commands ****************/
  /**
   * Tune the radio to one of the frequencies available in the CC1K_Params
   * table.  Calling Tune will allso reset the rfpower and LockVal
   * selections to the table values.
   * 
   * @param freq The index into the CC1K_Params table that holds the
   * desired preset frequency parameters.
   */
  command void CC1000Control.tunePreset(uint8_t freq) {
    int i;

    // FREQA, FREQB, FSEP, CURRENT(RX), FRONT_END, POWER, PLL
    for (i = CC1K_FREQ_2A; i <= CC1K_PLL; i++) {
      call HPLCC1000.write(i, PRG_RDB(&CC1K_Params[freq][i]));
    }
    
    call HPLCC1000.write(CC1K_MATCH, PRG_RDB(&CC1K_Params[freq][CC1K_MATCH]));
    rxCurrent = PRG_RDB(&CC1K_Params[freq][CC1K_CURRENT]);
    txCurrent = PRG_RDB(&CC1K_Params[freq][CC1K_MATCH + 1]);
    power = PRG_RDB(&CC1K_Params[freq][CC1K_PA_POW]);

    post attemptCalibration();
  }
  
  /**
   * Tune the radio to a given frequency. Since the CC1000 uses a digital
   * frequency synthesizer, it cannot tune to just an arbitrary frequency.
   * This routine will determine the closest achievable channel, compute
   * the necessary parameters and tune the radio.
   * 
   * @param The desired channel frequency, in Hz.
   * 
   * @return The actual computed channel frequency, in Hz.  A return value
   * of '0' indicates that no frequency was computed and the radio was not
   * tuned.
   */
  command uint32_t CC1000Control.tuneManual(uint32_t freqHz) {
    uint32_t actualFreq = calculateFrequency(freqHz);
    post attemptCalibration();
    return actualFreq;
  }

  /**
   * Set the baud rate to 76.8 kBaud or 38.4 kBaud.
   * The default is 38.4 kBaud, compatible across all motes.
   * If your network does not contain any mica2dot motes, 
   * you should double the baud rate - saving power when communicating
   * by increasing throughput.
   *
   * @param doubleBaud - TRUE to double the default baud rate to 76.8 kBaud,
   *     FALSE to set the baud rate to 38.4 kBaud.
   */
  command void CC1000Control.doubleBaudRate(bool doubleBaud) {
    if(doubleBaud) {
      call HPLCC1000.write(CC1K_MODEM0, 
          5 << CC1K_BAUDRATE |
          1 << CC1K_DATA_FORMAT | 
          0 << CC1K_XOSC_FREQ);
          
    } else {
      call HPLCC1000.write(CC1K_MODEM0, 
          5 << CC1K_BAUDRATE |
          1 << CC1K_DATA_FORMAT | 
          1 << CC1K_XOSC_FREQ);
    }
  }
  
  /** 
   * Auto-Recalibration is on by default.
   *
   * Enable or disable the automatic recalibrations. Temperature and
   * voltage variations will cause the frequency to drift over time.
   * Recalibrating the radio frequencies every few hours will prevent this
   * @param on - TRUE if recalibration should be on, FALSE if it shouldn't
   * @param hours - The delay, in hours, after which to auto recalibrate
   */
  command void CC1000Control.setAutoRecalibration(bool on, uint8_t hours) {
    if(hours == 0) {
      recalibrationHours = DEFAULT_RECALIBRATION_HOURS;
    } else {
      recalibrationHours = hours;
    }
      
    if(on) {
      call RecalibrationTimer.start(TIMER_REPEAT, recalibrationHours*3600*1024);
      
    } else {
      call RecalibrationTimer.stop();
    }
  }
  
  /**
   * Shift the CC1000 Radio into transmit mode.
   */
  async command void CC1000Control.txMode() {
    // MAIN register to TX mode
    call HPLCC1000.write(CC1K_MAIN,
          1 << CC1K_RXTX |
          1 << CC1K_F_REG |
          1 << CC1K_RX_PD | 
          1 << CC1K_RESET_N);
          
    // Set the TX mode VCO Current
    call HPLCC1000.write(CC1K_CURRENT, txCurrent);
    call BusyWait.wait(250);
    call HPLCC1000.write(CC1K_PA_POW, power);
    call BusyWait.wait(20);
  }

  /**
   * Shift the CC1000 Radio in receive mode.
   */
  async command void CC1000Control.rxMode() {
    // MAIN register to RX mode
    // Powerup Freqency Synthesizer and Receiver
    call HPLCC1000.write(CC1K_CURRENT, rxCurrent);
    call HPLCC1000.write(CC1K_PA_POW, 0); // turn off power amp
    call HPLCC1000.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);
    call BusyWait.wait(125);
  }

  /**
   * Turn off the bias power on the CC1000 radio, but leave the core and
   * crystal oscillator powered.  This will result in approximately a 750
   * uA power savings.
   */
  async command void CC1000Control.coreOn() {
    // MAIN register to SLEEP mode
    call HPLCC1000.write(CC1K_MAIN,
          1 << CC1K_RX_PD |
          1 << CC1K_TX_PD | 
          1 << CC1K_FS_PD |
          1 << CC1K_BIAS_PD |
          1 << CC1K_RESET_N);
  }

  /**
   * Turn the bias power on. This function must be followed by a call to
   * either rxMode() or txMode() to place the radio in a recieve/transmit
   * state respectively. There is approximately a 200us delay when
   * restoring bias power.
   */
  async command void CC1000Control.biasOn() {
    call HPLCC1000.write(CC1K_MAIN,
          1 << CC1K_RX_PD |
          1 << CC1K_TX_PD | 
          1 << CC1K_FS_PD | 
          1 << CC1K_RESET_N);
  }

  /**
   * Turn the CC1000 off
   */
  async command void CC1000Control.off() {
    // MAIN register to power down mode. Shut everything off
    call HPLCC1000.write(CC1K_MAIN,
          1 << CC1K_RX_PD |
          1 << CC1K_TX_PD | 
          1 << CC1K_FS_PD |
          1 << CC1K_CORE_PD |
          1 << CC1K_BIAS_PD |
          1 << CC1K_RESET_N);
          
    // Turn off rf amp
    call HPLCC1000.write(CC1K_PA_POW, 0);
  }

  /**
   * Set the transmit RF power value.  The input value is simply an
   * arbitrary index that is programmed into the CC1000 registers.  Consult
   * the CC1000 datasheet for the resulting power output/current
   * consumption values.
   *
   * @param power A power index between 1 and 255.
   */
  command void CC1000Control.setRFPower(uint8_t newPower) {
    power = newPower;
  }

  /**
   * Get the present RF power index.
   *
   * @return The power index value.
   */
  command uint8_t CC1000Control.getRFPower() {
    return power;
  }

  /** 
   * Select the signal to monitor at the CHP_OUT pin of the CC1000.  See
   * the CC1000 data sheet for the available signals.
   * 
   * @param LockVal The index of the signal to monitor at the CHP_OUT pin
   */
  command void CC1000Control.selectLock(uint8_t fn) {
    // Select function of CHP_OUT pin (readable via getLock)
    call HPLCC1000.write(CC1K_LOCK, fn << CC1K_LOCK_SELECT);
  }

  /**
   * Get the binary value from the CHP_OUT pin.  Analog signals cannot be
   * read using function.
   *
   * @return 1 - Pin is high or 0 - Pin is low
   */
  command uint8_t CC1000Control.getLock() {
    return call HPLCC1000.GetLOCK(); 
  }
  
  
  /***************** RecalibrationTimer Events ****************/
  /**
   * Time to recalibrate the radio
   */
  event result_t RecalibrationTimer.fired() {
    post attemptCalibration();
    return SUCCESS;
  }
  
  /***************** Empty ByteRadio Events ****************/
  /**
   * SendReceive wants to send a packet.
   */
  event void ByteRadio.rts() {
  }
  
  /**
   * SendReceive signals this event for every radio-byte-time while
   * listening is enabled and a message isn't being received or
   * transmitted.
   * @param preamble TRUE if a message preamble byte has been received
   */
  async event void ByteRadio.idleByte(bool preamble) {
  }

  /**
   * A message is being received
   */
  async event void ByteRadio.rx() {
  }

  /**
   * Message reception is complete.
   */
  async event void ByteRadio.rxDone() {
  }
  
  /**
   * Transmission complete.
   */
  async event void ByteRadio.sendDone() {
  }
  
  
  /***************** Tasks ****************/
  task void attemptCalibration() {
    if(call ByteRadio.isFree()) {
      call ByteRadio.off();
      singleCalibration();
      call ByteRadio.listen();
      
    } else {
      post attemptCalibration();
    }
  }
  
  
  /***************** Functions ****************/
  /**
   * Run the single calibration algorithm, involving two individual 
   * calibrations.
   */
  void singleCalibration() {
    call HPLCC1000.write(CC1K_PA_POW, 0x00);  // turn off rf amp
    call HPLCC1000.write(CC1K_TEST4, 0x3f);   // chip rate >= 38.4kb

    // RX - configure main freq A
    call HPLCC1000.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);

    calibrateNow();

    // TX - configure main freq B
    call HPLCC1000.write(CC1K_MAIN,
          1 << CC1K_RXTX |
          1 << CC1K_F_REG |
          1 << CC1K_RX_PD | 
          1 << CC1K_RESET_N);
          
    // Set TX current
    call HPLCC1000.write(CC1K_CURRENT, txCurrent);
    call HPLCC1000.write(CC1K_PA_POW, 0);

    calibrateNow();

    call CC1000Control.rxMode();
  }

  /**
   * Perform a calibration on the pre-selected frequency register
   */
  void calibrateNow() {
    // start cal
    call HPLCC1000.write(CC1K_CAL,
          1 << CC1K_CAL_START |
          1 << CC1K_CAL_WAIT |
          6 << CC1K_CAL_ITERATE);
   
    while ((call HPLCC1000.read(CC1K_CAL) & 1 << CC1K_CAL_COMPLETE) == 0)
      ;

    //exit cal mode
    call HPLCC1000.write(CC1K_CAL, 1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE);
  }

  /**
   * Compute an achievable frequency and the necessary CC1K parameters from
   * a given desired frequency (Hz). The function returns the actual achieved
   * channel frequency in Hz.
   *
   * This routine assumes the following:
   *  - Crystal Freq: 14.7456 MHz
   *  - LO Injection: High
   *  - Separation: 64 KHz
   *  - IF: 150 KHz
   * 
   */
  uint32_t calculateFrequency(uint32_t desiredFreq) {
    uint32_t actualFrequency = 0;
    uint32_t rxFreq = 0;
    uint32_t txFreq = 0;
    uint32_t nRef;
    uint32_t fRef;
    uint32_t frequency;
    uint32_t rxCalc;
    uint32_t txCalc;
    int32_t diff;
    int32_t offset = 0x7fffffff;
    uint16_t fsep = 0;
    uint8_t refDiv = 0;
    uint8_t i;
    uint8_t match;
    uint8_t frontend;
    
    for (i = 0; i < 9; i++) {
      nRef = desiredFreq + IF;
      fRef = fRefTbl[i];
      frequency = 0;
      rxCalc = 0;
      txCalc = 0;

      nRef = ((desiredFreq + IF)  <<  2) / fRef;
      if (nRef & 0x1) {
        nRef++;
      }

      if (nRef & 0x2) {
        rxCalc = 16384 >> 1;
        frequency = fRef >> 1;
      }

      nRef >>= 2;

      rxCalc += (nRef * 16384) - 8192;
      if ((rxCalc < FREQ_MIN) || (rxCalc > FREQ_MAX)) {
        continue;
      }
    
      txCalc = rxCalc - corTbl[i];
      if (txCalc < FREQ_MIN || txCalc > FREQ_MAX) {
        continue;
      }
      
      frequency += nRef * fRef;
      frequency -= IF;
      diff = frequency - desiredFreq;
      
      if (diff < 0) {
        diff = -diff;
      }

      if (diff < offset) {
        rxFreq = rxCalc;
        txFreq = txCalc;
        actualFrequency = frequency;
        fsep = fsepTbl[i];
        refDiv = i + 6;
        offset = diff;
      }
    }

    if (refDiv != 0) {
      call HPLCC1000.write(CC1K_FREQ_0A, rxFreq);
      call HPLCC1000.write(CC1K_FREQ_1A, rxFreq >> 8);
      call HPLCC1000.write(CC1K_FREQ_2A, rxFreq >> 16);

      call HPLCC1000.write(CC1K_FREQ_0B, txFreq);
      call HPLCC1000.write(CC1K_FREQ_1B, txFreq >> 8);
      call HPLCC1000.write(CC1K_FREQ_2B, txFreq >> 16);

      call HPLCC1000.write(CC1K_FSEP0, fsep);
      call HPLCC1000.write(CC1K_FSEP1, fsep >> 8);

      if (actualFrequency < 500000000) {
          if (actualFrequency < 400000000) {
            rxCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;
            txCurrent = 9 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;
            
          } else {
            rxCurrent = 4 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;
            txCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;
          }
          
          frontend = 1 << CC1K_IF_RSSI;
          match = 7 << CC1K_RX_MATCH;
          
      } else {
          rxCurrent = 8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE;
          txCurrent = 15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE;
          
          frontend = 1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | 1 << CC1K_IF_RSSI;
          match = 2 << CC1K_RX_MATCH;
      }
      
      call HPLCC1000.write(CC1K_CURRENT, rxCurrent);
      call HPLCC1000.write(CC1K_MATCH, match);
      call HPLCC1000.write(CC1K_FRONT_END, frontend);
      call HPLCC1000.write(CC1K_PLL, refDiv << CC1K_REFDIV);
    }

    return actualFrequency;
  }
  
}

--- NEW FILE: CC1000CsmaM.nc ---
/*                                                      tab:4
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2005 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 * A rewrite of the low-power-listening CC1000 radio stack.
 * This file contains the CSMA and low-power listening logic. Actual
 * packet transmission and reception is in SendReceive.
 *
 * This code has some degree of platform-independence, via the
 * CC1000Control, RSSIADC and SpiByteFifo interfaces which must be provided
 * by the platform. However, these interfaces may still reflect some
 * particularities of the mica2 hardware implementation.
 *
 * @author Philip Buonadonna
 * @author Jaein Jeong
 * @author Joe Polastre
 * @author David Gay
 * @author David Moss
 */

includes crc;
includes CC1000Const;

module CC1000CsmaM {
  provides {
    interface StdControl;
    interface CsmaControl;
    interface CsmaBackoff;
    interface LowPowerListening;
  }
  
  uses {
    interface StdControl as ByteRadioControl;
    interface ByteRadio;

    interface CC1000Control;
    interface CC1000Squelch;
    interface Random;
    interface Timer as WakeupTimer;
    interface BusyWait;

    interface Rssi as RssiNoiseFloor;
    interface Rssi as RssiCheckChannel;
    interface Rssi as RssiPulseCheck;
  }
}

implementation {
  
  norace uint8_t radioState;
  
  uint8_t count;

  int16_t macDelay;

  uint8_t lplTxPower;
  
  uint8_t lplRxPower;

  uint16_t sleepTime;

  uint16_t rssiForSquelch;

  enum {
    TIME_AFTER_CHECK =  128,
  };
  
  /** Flags */
  struct {
    uint8_t ccaOff : 1;
    uint8_t txPending : 1;
  } f;

  enum {
    DISABLED_STATE,
    IDLE_STATE,
    RX_STATE,
    TX_STATE,
    POWERDOWN_STATE,
    PULSECHECK_STATE
  };

  /***************** Prototypes ****************/  
  task void setWakeupTask();
  task void adjustSquelch();
  task void sleepCheck();
  
  void enterIdleState();
  void enterIdleStateSetWakeup();
  void enterDisabledState();
  void enterPowerDownState();
  void enterRxState();
  void enterTxState();
  void radioOn();
  void radioOff();
  void setPreambleLength();
  void setSleepTime();
  void setWakeup();
  void congestion();
  
  
  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    radioState = DISABLED_STATE;
    call ByteRadioControl.init();
    return SUCCESS;
  }

  command result_t StdControl.start() {
    atomic {
      if (radioState == DISABLED_STATE) {
        call ByteRadioControl.start();
        enterIdleStateSetWakeup();
        f.txPending = FALSE;
        setPreambleLength();
        setSleepTime();
        
      } else {
        return SUCCESS;
      }
    }
    
    radioOn();

    return SUCCESS;
  }

  command result_t StdControl.stop() {
    atomic {
      call ByteRadioControl.stop();
      enterDisabledState();
      radioOff();
    }
    
    call WakeupTimer.stop();
    
    return SUCCESS;
  }

  /***************** CsmaControl Commands ****************/
  /**
   * Enable congestion control.
   * @return SUCCESS if congestion control enabled, FAIL otherwise.
   */
  async command result_t CsmaControl.enableCca() {
    atomic f.ccaOff = FALSE;
    return SUCCESS;
  }

  /**
   * Disable congestion control.
   * @return SUCCESS if congestion control disabled, FAIL otherwise.
   */
  async command result_t CsmaControl.disableCca() {
    atomic f.ccaOff = TRUE;
    return SUCCESS;
  }

  /***************** LowPowerListening Commands ****************/
  /**
   * Set the current Low Power Listening mode.
   * Setting the LPL mode sets both the check interval and preamble length.
   * The listening mode can only be set while the radio is stopped.
   *
   * Modes include:
   *  0 = Radio fully on
   *  1 = 10ms check interval
   *  2 = 25ms check interval
   *  3 = 50ms check interval
   *  4 = 100ms check interval (recommended)
   *  5 = 200ms check interval
   *  6 = 400ms check interval
   *  7 = 800ms check interval
   *  8 = 1600ms check interval
   *
   * @param mode the mode number
   * @return SUCCESS if the mode was successfully changed, FAIL otherwise
   */
  async command result_t LowPowerListening.setListeningMode(uint8_t power) {
    if (power >= CC1K_LPL_STATES) {
      return FAIL;
    }

    atomic {
      if (radioState != DISABLED_STATE) {
        return FAIL;
      }
      
      lplTxPower = power;
      lplRxPower = power;
    }
    
    return SUCCESS;
  }

  /**
   * Get the current Low Power Listening mode
   * @return mode number (see SetListeningMode)
   */
  async command uint8_t LowPowerListening.getListeningMode() {
    atomic return lplRxPower;
  }

  /**
   * Set the transmit mode.  This allows for hybrid schemes where
   * the transmit mode is different than the receive mode.
   * Use SetListeningMode first, then change the mode with SetTransmitMode.
   *
   * @param mode mode number (see SetListeningMode)
   * @return SUCCESS if the mode was successfully changed, FAIL otherwise
   */
  async command result_t LowPowerListening.setTransmitMode(uint8_t power) {
    if (power >= CC1K_LPL_STATES) {
      return FAIL;
    }

    atomic {
      lplTxPower = power;
      setPreambleLength();
    }
    
    return SUCCESS;
  }

  /**
   * Get the current Low Power Listening transmit mode
   * @return mode number (see SetListeningMode)
   */
  async command uint8_t LowPowerListening.getTransmitMode() {
    atomic return lplTxPower;
  }

  /**
   * Set the preamble length of outgoing packets. Note that this overrides
   * the value set by setListeningMode or setTransmitMode.
   *
   * @param bytes length of the preamble in bytes
   * @return SUCCESS if the preamble length was successfully changed, FAIL
   *   otherwise
   */
  async command result_t LowPowerListening.setPreambleLength(uint16_t bytes) {
    call ByteRadio.setPreambleLength(bytes);
    return SUCCESS;
  }

  /**
   * Get the preamble length of outgoing packets
   *
   * @return length of the preamble in bytes
   */
  async command uint16_t LowPowerListening.getPreambleLength() {
    return call ByteRadio.getPreambleLength();
  }

  /**
   * Set the check interval (time between waking up and sampling
   * the radio for activity in low power listening). The sleep time
   * can only be changed if low-power-listening is enabled 
   * (setListeningMode called with a non-zero value).
   *
   * @param ms check interval in milliseconds
   * @return SUCCESS if the check interval was successfully changed,
   *   FAIL otherwise.
   */
  async command result_t LowPowerListening.setCheckInterval(uint16_t ms) {
    atomic {
      if (lplRxPower == 0) {
        return FAIL;
      }

      sleepTime = ms;
    }
    
    return SUCCESS;
  }

  /**
   * Get the check interval currently used by low power listening
   *
   * @return length of the check interval in milliseconds
   */
  async command uint16_t LowPowerListening.getCheckInterval() {
    atomic return sleepTime;
  }


  /***************** WakeupTimer Events ****************/
  event result_t WakeupTimer.fired() {
    atomic {
      switch (radioState) {
        case IDLE_STATE:
          /* 
           * If we appear to be receiving a packet we don't check the
           * noise floor. For LPL, this means that going to sleep will
           * be delayed by another TIME_AFTER_CHECK ms. 
           */
          if (!call ByteRadio.syncing()) {
            call RssiNoiseFloor.cancel();  // Cancel all RSSI tasks
            call RssiNoiseFloor.read();
          }
          break;

        case POWERDOWN_STATE:
          radioState = PULSECHECK_STATE;
          count = 0;
          call RssiPulseCheck.read();
          call BusyWait.wait(80);
          return SUCCESS;
          /** Returned, don't set wakeup */
        
        default:
          break;
      }
  
      setWakeup();
    }
      
    return SUCCESS;
  }


  /***************** ByteRadio Events ****************/
  async event void ByteRadio.rx() {
    enterRxState();
  }

  async event void ByteRadio.rxDone() {
    call RssiNoiseFloor.cancel();
    enterIdleStateSetWakeup();
  }
  
  event void ByteRadio.rts() {
    atomic {
      f.txPending = TRUE;

      if (radioState == POWERDOWN_STATE) {
        post sleepCheck();
      }
      
      if (!f.ccaOff) {
        macDelay = signal CsmaBackoff.initial();
      } else {
        macDelay = 1;
      }
    }
  }

  async event void ByteRadio.sendDone() {
    f.txPending = FALSE;
    enterIdleStateSetWakeup();
  }

  async event void ByteRadio.idleByte(bool preamble) {
    if (f.txPending) {
      if (!f.ccaOff && preamble) {
        congestion();
    
      } else if (macDelay && !--macDelay) {
        call RssiCheckChannel.cancel();
        count = 0;
        call RssiCheckChannel.read();
      }
    }
  }
  
  /***************** RssiNoiseFloor Events ****************/
  async event void RssiNoiseFloor.readDone(result_t result, uint16_t data) {
    if (result != SUCCESS) {
      /* We just ignore failed noise floor measurements */
      post sleepCheck();
      return;
    }

    rssiForSquelch = data;
    post adjustSquelch();
    post sleepCheck();
  }
  
  
  /***************** RssiCheckChannel Events ****************/
  async event void RssiCheckChannel.readDone(result_t result, uint16_t data) {
    if (result != SUCCESS) {
      /* We'll retry the transmission at the next SPI event. */
      atomic macDelay = 1;
      return;
    }
    
    count++;
    
    if ((data > call CC1000Squelch.get() - CC1K_SquelchBuffer) || f.ccaOff) {
      enterTxState();
      call ByteRadio.cts();

    } else if (count == CC1K_MaxRSSISamples) {
      congestion();
   
    } else {
      call RssiCheckChannel.read();
      call BusyWait.wait(80);
    }
  }
  
  
  /***************** RssiPulseCheck Events ****************/
  async event void RssiPulseCheck.readDone(result_t result, uint16_t data) {
    
    if(count == 0) {
      // The microcontroller has woken up. Enable the radio and read.
      count++;
      call CC1000Control.biasOn();
      call CC1000Control.rxMode();
      call BusyWait.wait(800);
      call RssiPulseCheck.read();
      return;
    }
    
    /*
     * We got some RSSI data for our LPL check. Decide whether to:
     *  - go back to sleep (quiet)
     *  - wake up (channel active)
     *  - get more RSSI data
     */
    if (data > call CC1000Squelch.get() - (call CC1000Squelch.get() >> 2)) {
      radioOff();
      post sleepCheck();
      
      // don't be too agressive (ignore really quiet thresholds).
      if (data < call CC1000Squelch.get() + (call CC1000Squelch.get() >> 3)) {
          // adjust the noise floor level, go back to sleep.
          rssiForSquelch = data;
          post adjustSquelch();
      }
      
    } else if (count++ > 5) {
      //go to the idle state since no outliers were found
      enterIdleStateSetWakeup();
      call ByteRadio.listen();
      
    } else {
      // The current reading looked good, take a few more to verify
      call RssiPulseCheck.read();
    }
  }
  
  /***************** Tasks ****************/
  /**
   * Should we go to sleep, or turn the radio fully on? 
   */
  task void sleepCheck() {
    bool turnOn = FALSE;

    atomic {
      if (f.txPending) {
        if (radioState == PULSECHECK_STATE || radioState == POWERDOWN_STATE) {
            enterIdleStateSetWakeup();
            turnOn = TRUE;
        }
      
      } else if (lplRxPower > 0 && call CC1000Squelch.settled() && !call ByteRadio.syncing()) {
        radioOff();
        enterPowerDownState();
        setWakeup();
      }
    }

    if (turnOn) {
      radioOn();
    }
  }
  
  task void adjustSquelch() {
    uint16_t squelchData;

    atomic squelchData = rssiForSquelch;
    call CC1000Squelch.adjust(squelchData);
  }

  task void setWakeupTask() {
    atomic setWakeup();
  }
  
  
  /***************** Functions ****************/
  /**
   * Set the length of time before the WakeupTimer is fired
   */
  void setWakeup() {
    switch (radioState) {
      case IDLE_STATE:
        if (call CC1000Squelch.settled()) {
          if (lplRxPower == 0 || f.txPending) {
            call WakeupTimer.start(TIMER_ONE_SHOT, CC1K_SquelchIntervalSlow);
            
          } else {
            // timeout for receiving a message after an lpl check
            // indicates channel activity.
            call WakeupTimer.start(TIMER_ONE_SHOT, TIME_AFTER_CHECK);
          } 
            
        } else {
          call WakeupTimer.start(TIMER_ONE_SHOT, CC1K_SquelchIntervalFast);
        } 

        break;
        
      case PULSECHECK_STATE:
        // Radio warm-up time.
        call WakeupTimer.start(TIMER_ONE_SHOT, 1);
        break;
     
      case POWERDOWN_STATE:
        // low-power listening check interval
        call WakeupTimer.start(TIMER_ONE_SHOT, sleepTime);
        break;
       
      default:
        break;
    }
  }

  void enterIdleState() {
    call RssiNoiseFloor.cancel();
    radioState = IDLE_STATE;
  }

  void enterIdleStateSetWakeup() {
    enterIdleState();
    post setWakeupTask();
  }

  void enterDisabledState() {
    call RssiNoiseFloor.cancel();
    radioState = DISABLED_STATE;
  }

  void enterPowerDownState() {
    call RssiNoiseFloor.cancel();
    radioState = POWERDOWN_STATE;
  }

  void enterRxState() {
    call RssiNoiseFloor.cancel();
    radioState = RX_STATE;
  }

  void enterTxState() {
    radioState = TX_STATE;
  }


  void radioOn() {
    call CC1000Control.coreOn();
    call BusyWait.wait(2000);
    call CC1000Control.biasOn();
    call BusyWait.wait(200);
    atomic call ByteRadio.listen();
  }

  void radioOff() {
    call ByteRadio.off();
    call CC1000Control.off();
  }

  void setPreambleLength() {
    uint16_t len =
      (uint16_t)PRG_RDB(&CC1K_LPL_PreambleLength[lplTxPower * 2]) << 8
      | PRG_RDB(&CC1K_LPL_PreambleLength[lplTxPower * 2 + 1]);
    call ByteRadio.setPreambleLength(len);
  }

  void setSleepTime() {
    sleepTime =
      (uint16_t)PRG_RDB(&CC1K_LPL_SleepTime[lplRxPower *2 ]) << 8 |
      PRG_RDB(&CC1K_LPL_SleepTime[lplRxPower * 2 + 1]);
  }
  
  void congestion() {
    macDelay = signal CsmaBackoff.congestion();
  }
  
  
  /***************** Defaults ****************/
  default async event uint16_t CsmaBackoff.initial() { 
    // initially back off [1,32] bytes (approx 2/3 packet)
    return (call Random.rand16() & 0x1F) + 1;
  }

  default async event uint16_t CsmaBackoff.congestion() { 
    return (call Random.rand16() & 0xF) + 1;
  }
}

--- NEW FILE: AM.h ---
// $Id: AM.h,v 1.4 2003/11/30 21:24:24 ckarlof Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
/*
 *
 * Authors:		Jason Hill, David Gay, Philip Levis, Chris Karlof
 * Date last modified:  6/25/02
 *
 */

// Message format


/**
 * @author Jason Hill
 * @author David Gay
 * @author Philip Levis
 * @author Chris Karlof
 */
#ifndef AM_H_INCLUDED
#define AM_H_INCLUDED
enum {
  TOS_BCAST_ADDR = 0xffff,
  TOS_UART_ADDR = 0x007e,
};

#ifndef DEF_TOS_AM_GROUP
#define DEF_TOS_AM_GROUP 0x7d
#endif

enum {
  TOS_DEFAULT_AM_GROUP = DEF_TOS_AM_GROUP
};

// wtf mate:
#ifndef TOS_AM_GROUP
#define TOS_AM_GROUP TOS_DEFAULT_AM_GROUP
#endif

#ifndef TOSH_DATA_LENGTH
#define TOSH_DATA_LENGTH 28
#endif

#ifndef TOSH_AM_LENGTH
#define TOSH_AM_LENGTH 1
#endif

#ifndef TINYSEC_MAC_LENGTH
#define TINYSEC_MAC_LENGTH 4
#endif

#ifndef TINYSEC_IV_LENGTH
#define TINYSEC_IV_LENGTH 4
#endif

#ifndef TINYSEC_ACK_LENGTH
#define TINYSEC_ACK_LENGTH 1
#endif

typedef struct TOS_Msg
{
  /* The following fields are transmitted/received on the radio. */
  uint16_t addr;
  uint8_t type;
  uint8_t group;
  uint8_t length;
  int8_t data[TOSH_DATA_LENGTH];
  uint16_t crc;

  /* The following fields are not actually transmitted or received 
   * on the radio! They are used for internal accounting only.
   * The reason they are in this structure is that the AM interface
   * requires them to be part of the TOS_Msg that is passed to
   * send/receive operations.
   */
  uint16_t strength;
  uint8_t ack;
  uint16_t time;
  uint8_t sendSecurityMode;
  uint8_t receiveSecurityMode;  
} TOS_Msg;

typedef struct TOS_Msg_TinySecCompat
{
  /* The following fields are transmitted/received on the radio. */
  uint16_t addr;
  uint8_t type;
  // length and group bytes are swapped
  uint8_t length;
  uint8_t group;
  int8_t data[TOSH_DATA_LENGTH];
  uint16_t crc;

  /* The following fields are not actually transmitted or received 
   * on the radio! They are used for internal accounting only.
   * The reason they are in this structure is that the AM interface
   * requires them to be part of the TOS_Msg that is passed to
   * send/receive operations.
   */
  uint16_t strength;
  uint8_t ack;
  uint16_t time;
  uint8_t sendSecurityMode;
  uint8_t receiveSecurityMode;  
} TOS_Msg_TinySecCompat;

typedef struct TinySec_Msg
{ 
  uint16_t addr;
  uint8_t type;
  uint8_t length;
  // encryption iv
  uint8_t iv[TINYSEC_IV_LENGTH];
  // encrypted data
  uint8_t enc[TOSH_DATA_LENGTH];
  // message authentication code
  uint8_t mac[TINYSEC_MAC_LENGTH];

  // not transmitted - used only by MHSRTinySec
  uint8_t calc_mac[TINYSEC_MAC_LENGTH];
  uint8_t ack_byte;
  bool cryptoDone;
  bool receiveDone;
  // indicates whether the calc_mac field has been computed
  bool MACcomputed;
} __attribute__((packed)) TinySec_Msg;



enum {
  MSG_DATA_SIZE = offsetof(struct TOS_Msg, crc) + sizeof(uint16_t), // 36 by default
  TINYSEC_MSG_DATA_SIZE = offsetof(struct TinySec_Msg, mac) + TINYSEC_MAC_LENGTH, // 41 by default
  DATA_LENGTH = TOSH_DATA_LENGTH,
  LENGTH_BYTE_NUMBER = offsetof(struct TOS_Msg, length) + 1,
  TINYSEC_NODE_ID_SIZE = sizeof(uint16_t)
};

enum {
  TINYSEC_AUTH_ONLY = 1,
  TINYSEC_ENCRYPT_AND_AUTH = 2,
  TINYSEC_DISABLED = 3,
  TINYSEC_RECEIVE_AUTHENTICATED = 4,
  TINYSEC_RECEIVE_CRC = 5,
  TINYSEC_RECEIVE_ANY = 6,
  TINYSEC_ENABLED_BIT = 128,
  TINYSEC_ENCRYPT_ENABLED_BIT = 64
} __attribute__((packed));


typedef TOS_Msg *TOS_MsgPtr;

uint8_t TOS_MsgLength(uint8_t type)
{
#if 0
  uint8_t i;

  for (i = 0; i < MSGLEN_TABLE_SIZE; i++)
    if (msgTable[i].handler == type)
      return msgTable[i].length;
#endif

  return offsetof(TOS_Msg, strength);
}
#endif

--- NEW FILE: RandomC.nc ---
/*
 * "Copyright (c) 2002-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 */

/**
 * The standard TinyOS random number generator. If your system requires a 
 * specific random number generator, it should wire to that component
 * directly. 
 *
 * @author Barbara Hohlt 
 * @author Phil Levis 
 * @author David Moss
 */

configuration RandomC {
  provides {
    interface StdControl;
    interface Random;
  }
}

implementation {
  components RandomMlcgM;
  
  StdControl = RandomMlcgM;
  Random = RandomMlcgM;
} 

--- NEW FILE: CC1000Const.h ---
// $Id: CC1000Const.h,v 1.1.2.5 2006/01/27 18:46:00 idgay Exp $

/* -*- Mode: C; c-basic-indent: 2; indent-tabs-mode: nil -*- */ 
/*                                    tab:4
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.  By
 *  downloading, copying, installing or using the software you agree to
 *  this license.  If you do not agree to this license, do not download,
 *  install, copy or use the software.
 *
 *  Intel Open Source License 
 *
 *  Copyright (c) 2002 Intel Corporation 
 *  All rights reserved. 
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 * 
 *    Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *    Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *      Neither the name of the Intel Corporation nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * 
 */

/**
 * @author Phil Buonadonna
 */

#ifndef CC1000CONST_H
#define CC1000CONST_H

/* Constants defined for CC1K */
/* Register addresses */

enum {
  CC1K_MAIN =           0x00,
  CC1K_FREQ_2A =        0x01,
  CC1K_FREQ_1A =        0x02,
  CC1K_FREQ_0A =        0x03,
  CC1K_FREQ_2B =        0x04,
  CC1K_FREQ_1B =        0x05,
  CC1K_FREQ_0B =        0x06,
  CC1K_FSEP1 =          0x07,
  CC1K_FSEP0 =          0x08,
  CC1K_CURRENT =        0x09,
  CC1K_FRONT_END =      0x0A, //10
  CC1K_PA_POW =         0x0B, //11
  CC1K_PLL =            0x0C, //12
  CC1K_LOCK =           0x0D, //13
  CC1K_CAL =            0x0E, //14
  CC1K_MODEM2 =         0x0F, //15
  CC1K_MODEM1 =         0x10, //16
  CC1K_MODEM0 =         0x11, //17
  CC1K_MATCH =          0x12, //18
  CC1K_FSCTRL =         0x13, //19
  CC1K_FSHAPE7 =        0x14, //20
  CC1K_FSHAPE6 =        0x15, //21
  CC1K_FSHAPE5 =        0x16, //22
  CC1K_FSHAPE4 =        0x17, //23
  CC1K_FSHAPE3 =        0x18, //24
  CC1K_FSHAPE2 =        0x19, //25
  CC1K_FSHAPE1 =        0x1A, //26
  CC1K_FSDELAY =        0x1B, //27
  CC1K_PRESCALER =      0x1C, //28
  CC1K_TEST6 =          0x40, //64
  CC1K_TEST5 =          0x41, //66
  CC1K_TEST4 =          0x42, //67
  CC1K_TEST3 =          0x43, //68
  CC1K_TEST2 =          0x44, //69
  CC1K_TEST1 =          0x45, //70
  CC1K_TEST0 =          0x46, //71

  // MAIN Register Bit Posititions
  CC1K_RXTX =        7,
  CC1K_F_REG =        6,
  CC1K_RX_PD =        5,
  CC1K_TX_PD =        4,
  CC1K_FS_PD =        3,
  CC1K_CORE_PD =    2,
  CC1K_BIAS_PD =    1,
  CC1K_RESET_N =    0,

  // CURRENT Register Bit Positions
  CC1K_VCO_CURRENT =    4,
  CC1K_LO_DRIVE =    2,
  CC1K_PA_DRIVE =    0,

  // FRONT_END Register Bit Positions
  CC1K_BUF_CURRENT =    5,
  CC1K_LNA_CURRENT =    3,
  CC1K_IF_RSSI =    1,
  CC1K_XOSC_BYPASS =    0,

  // PA_POW Register Bit Positions
  CC1K_PA_HIGHPOWER =    4,
  CC1K_PA_LOWPOWER =    0,

  // PLL Register Bit Positions
  CC1K_EXT_FILTER =    7,
  CC1K_REFDIV =        3,
  CC1K_ALARM_DISABLE =    2,
  CC1K_ALARM_H =    1,
  CC1K_ALARM_L =    0,

  // LOCK Register Bit Positions
  CC1K_LOCK_SELECT =        4,
  CC1K_PLL_LOCK_ACCURACY =    3,
  CC1K_PLL_LOCK_LENGTH =    2,
  CC1K_LOCK_INSTANT =        1,
  CC1K_LOCK_CONTINUOUS =    0,

  // CAL Register Bit Positions
  CC1K_CAL_START =    7,
  CC1K_CAL_DUAL =    6,
  CC1K_CAL_WAIT =    5,
  CC1K_CAL_CURRENT =    4,
  CC1K_CAL_COMPLETE =    3,
  CC1K_CAL_ITERATE =    0,

  // MODEM2 Register Bit Positions
  CC1K_PEAKDETECT =        7,
  CC1K_PEAK_LEVEL_OFFSET =    0,

  // MODEM1 Register Bit Positions
  CC1K_MLIMIT =        5,
  CC1K_LOCK_AVG_IN =    4,
  CC1K_LOCK_AVG_MODE =    3,
  CC1K_SETTLING =    1,
  CC1K_MODEM_RESET_N =    0,

  // MODEM0 Register Bit Positions
  CC1K_BAUDRATE =    4,
  CC1K_DATA_FORMAT =    2,
  CC1K_XOSC_FREQ =    0,

  // MATCH Register Bit Positions
  CC1K_RX_MATCH =    4,
  CC1K_TX_MATCH =    0,

  // FSCTLR Register Bit Positions
  CC1K_DITHER1 =    3,
  CC1K_DITHER0 =    2,
  CC1K_SHAPE =        1,
  CC1K_FS_RESET_N =    0,

  // PRESCALER Register Bit Positions
  CC1K_PRE_SWING =    6,
  CC1K_PRE_CURRENT =    4,
  CC1K_IF_INPUT =    3,
  CC1K_IF_FRONT =    2,

  // TEST6 Register Bit Positions
  CC1K_LOOPFILTER_TP1 =    7,
  CC1K_LOOPFILTER_TP2 =    6,
  CC1K_CHP_OVERRIDE =    5,
  CC1K_CHP_CO =        0,

  // TEST5 Register Bit Positions
  CC1K_CHP_DISABLE =    5,
  CC1K_VCO_OVERRIDE =    4,
  CC1K_VCO_AO =        0,

  // TEST3 Register Bit Positions
  CC1K_BREAK_LOOP =    4,
  CC1K_CAL_DAC_OPEN =    0,


  /* 
   * CC1K Register Parameters Table
   *
   * This table follows the same format order as the CC1K register 
   * set EXCEPT for the last entry in the table which is the 
   * CURRENT register value for TX mode.
   *  
   * NOTE: To save RAM space, this table resides in program memory (flash). 
   * This has two important implications:
   *    1) You can't write to it (duh!)
   *    2) You must read it using the PRG_RDB(addr) macro. IT CANNOT BE ACCESSED AS AN ORDINARY C ARRAY.  
   * 
   * Add/remove individual entries below to suit your RF tastes.
   * 
   */
  CC1K_915_998_MHZ =    0x00,
  CC1K_914_077_MHZ =    0x01,

  //#define CC1K_SquelchInit        0x02F8 // 0.90V using the bandgap reference
  CC1K_SquelchInit =        288,
  CC1K_SquelchTableSize =   9,
  CC1K_MaxRSSISamples =     15,
  CC1K_Settling =           1,
  CC1K_ValidPrecursor =     2,
  CC1K_SquelchIntervalFast = 128,
  CC1K_SquelchIntervalSlow = 2560,
  CC1K_SquelchCount =       30,
  CC1K_SquelchBuffer =      10,

  CC1K_LPL_STATES =         9,

  CC1K_LPL_PACKET_TIME =    16
};

#ifdef CC1K_DEFAULT_FREQ
#define CC1K_DEF_PRESET (CC1K_DEFAULT_FREQ)
#endif

#ifdef CC1K_MANUAL_FREQ
#define CC1K_DEF_FREQ (CC1K_MANUAL_FREQ)
#endif

#ifndef CC1K_DEF_PRESET
#define CC1K_DEF_PRESET    (CC1K_914_077_MHZ)
#endif 


static const prog_uchar CC1K_LPL_PreambleLength[CC1K_LPL_STATES*2] = {
    0, 6,       // Always on, 6 byte preamble
    0x0, 48,    // 10ms check interval
    0x0, 60,    // 25ms 
    0x0, 144,   // 50ms 
    0x1, 0x0f,  // 100ms
    0x1, 0xf8,  // 200ms
    0x3, 0xd9,  // 400ms
    0x7, 0x9b,  // 800ms
    //0xf, 0x06,  // 1600ms
    0xA, 0x5E,
};

static const prog_uchar CC1K_LPL_SleepTime[CC1K_LPL_STATES*2] = {
    0, 0,       //0
    0x0, 10,    // 10ms
    0x0, 25,    // 25ms
    0x0, 50,    // 50ms
    0x0, 100,   // 100ms
    0x0, 200,   // 200ms
    0x1, 0x90,  // 400ms
    0x3, 0x20,  // 800ms
    //0x6, 0x40,  // 1600ms
    0x4, 0x3D,
};


static const prog_uchar CC1K_Params[2][20] = {

  // 0 915.9988 MHz channel, 19.2 Kbps data, Manchester Encoding, High Side LO
  { // MAIN   0x00 
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x7c,0x00,0x00,                    
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x7b,0xf9,0xae,                    
    // FSEP1, FSEP0     0x07-0x8
    0x02,0x38,
    // CURRENT RX MODE VALUE   0x09 also see below
    8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE,
    //0x8C,    
    // FRONT_END  0x0a
    1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | 1 << CC1K_IF_RSSI,
    //0x32,
    // PA_POW  0x0b
    0x8 << CC1K_PA_HIGHPOWER | 0x0 << CC1K_PA_LOWPOWER, 
    //0xff,
    // PLL  0xc
    8 << CC1K_REFDIV,        
    //0x40,
    // LOCK  0xd
    0x1 << CC1K_LOCK_SELECT,
    //0x10,
    // CAL  0xe
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,    
    //0x26,
    // MODEM2  0xf
    1 << CC1K_PEAKDETECT | 33 << CC1K_PEAK_LEVEL_OFFSET,
    //0xA1,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N, 
    //0x6f, 
    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 1 << CC1K_XOSC_FREQ,
    //0x55,
    // MATCH 0x12
    0x1 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE,
  },

 
  // 1 914.077 MHz channel, 19.2 Kbps data, Manchester Encoding, High Side LO
  { // MAIN   0x00 
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x5c,0xe0,0x00,                    
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x5c,0xdb,0x42,                    
    // FSEP1, FSEP0     0x07-0x8
    0x01,0xAA,
    // CURRENT RX MODE VALUE   0x09 also see below
    8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE,
    //0x8C,    
    // FRONT_END  0x0a
    1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | 1 << CC1K_IF_RSSI,
    //0x32,
    // PA_POW  0x0b
    0x8 << CC1K_PA_HIGHPOWER | 0x0 << CC1K_PA_LOWPOWER, 
    //0xff,
    // PLL  0xc
    6 << CC1K_REFDIV,        
    //0x40,
    // LOCK  0xd
    0x1 << CC1K_LOCK_SELECT,
    //0x10,
    // CAL  0xe
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,    
    //0x26,
    // MODEM2  0xf
    1 << CC1K_PEAKDETECT | 33 << CC1K_PEAK_LEVEL_OFFSET,
    //0xA1,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N, 
    //0x6f, 
    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 1 << CC1K_XOSC_FREQ,
    //0x55,
    // MATCH 0x12
    0x1 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE,
  },


};

#endif /* CC1000CONST_H */

--- NEW FILE: PacketM.nc ---
/*
 * Copyright (c) 2004-2006 Rincon Research Corporation.  
 * All rights reserved.
 * 
 * Rincon Research will permit distribution and use by others subject to
 * the restrictions of a licensing agreement which contains (among other things)
 * the following restrictions:
 * 
 *  1. No credit will be taken for the Work of others.
 *  2. It will not be resold for a price in excess of reproduction and 
 *      distribution costs.
 *  3. Others are not restricted from copying it or using it except as 
 *      set forward in the licensing agreement.
 *  4. Commented source code of any modifications or additions will be 
 *      made available to Rincon Research on the same terms.
 *  5. This notice will remain intact and displayed prominently.
 * 
 * Copies of the complete licensing agreement may be obtained by contacting 
 * Rincon Research, 101 N. Wilmot, Suite 101, Tucson, AZ 85711.
 * 
 * There is no warranty with this product, either expressed or implied.  
 * Use at your own risk.  Rincon Research is not liable or responsible for 
 * damage or loss incurred or resulting from the use or misuse of this software.
 */

/**
 * This module provides the Packet interface 
 * with default packet information.
 * 
 * The packet interface can be overridden by
 * comm layers higher up in the stack, such as security
 * or bcast.  This allows application components that sit on
 * top to know how much of the payload belongs to them and
 * where it starts.
 *
 * @author David Moss - dmm at rincon.com
 */
 
module PacketM {
  provides {
    interface Packet;
  }
}

implementation {


  /***************** Packet Commands ****************/
  /**
    * Clear out this packet.  Note that this is a deep operation and
    * total operation: calling clear() on any layer will completely
    * clear the packet for reuse.
    *
    * Note that the Transceiver relies on the AM type to
    * be present throughout the lifetime of an allocated
    * packet. This means we cannot clear the entire
    * packet, or we'd erase the AM type and the allocated
    * message would never get sent.
    */
  command void Packet.clear(TOS_MsgPtr msg) {
    memset(msg->data, 0, sizeof(msg->data));
  }

  /**
    * Return the length of the payload of msg. This value may be less
    * than what maxPayloadLength() returns, if the packet is smaller than
    * the MTU. If a communication component does not support variably
    * sized data regions, then payloadLength() will always return
    * the same value as maxPayloadLength(). 
    */

  command uint8_t Packet.payloadLength(TOS_MsgPtr msg) {
    return TOSH_DATA_LENGTH;
  }

  /**
   * Set the length of the payload in this packet
   */
  command void Packet.setPayloadLength(TOS_Msg *msg, uint8_t len) {
    msg->length  = len;
  }
  
 /**
   * Return the maximum payload length that this communication layer
   * can provide. Note that, depending on protocol fields, a
   * given request to send a packet may not be able to send the
   * maximum payload length (e.g., if there are variable length
   * fields). Protocols may provide specialized interfaces
   * for these circumstances.
   */
  command uint8_t Packet.maxPayloadLength() {
    return TOSH_DATA_LENGTH;
  }

 /**
   * Return point to a protocol's payload region in a packet.
   * If len is not NULL, getPayload will return the length of
   * the payload in it, which is the same as the return value
   * from payloadLength(). If a protocol does not support
   * variable length packets, then *len is equal to 
   * maxPayloadLength().
   */
  command void* Packet.getPayload(TOS_MsgPtr msg, uint8_t* len) {
    if(len != NULL) {
      *len = TOSH_DATA_LENGTH;
    }
    return msg->data;
  }
}


--- NEW FILE: CC1000ControlC.nc ---

/**
 * CC1000Control Configuration
 * The CC1000Control will set the state of the CC1000 radio chip, 
 * turn it on and off, configure it, etc.
 *
 * @author David Moss
 */
configuration CC1000ControlC {
  provides {
    interface StdControl;
    interface CC1000Control;
  }
}

implementation {
  components CC1000ControlM, HPLCC1000M, BusyWaitM, TimerC, CC1000SendReceiveC;
  
  StdControl = CC1000ControlM;
  CC1000Control = CC1000ControlM;
  
  CC1000ControlM.RecalibrationTimer -> TimerC.Timer[unique("Timer")];
  CC1000ControlM.HPLCC1000 -> HPLCC1000M;
  CC1000ControlM.BusyWait -> BusyWaitM;
  CC1000ControlM.ByteRadio -> CC1000SendReceiveC;
}


--- NEW FILE: RadioCRCPacket.nc ---
// $Id: RadioCRCPacket.nc,v 1.3 2003/10/07 21:46:30 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2003 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */
 
/**
 * This configuration connects the application level with
 * the correct radio stack, allowing application platform
 * independance.
 *
 */
configuration RadioCRCPacket {
  provides {
    interface StdControl as Control;
    interface BareSendMsg as Send;
    interface ReceiveMsg as Receive;
  }
}
implementation {
  components CC1000RadioC; 

  Control = CC1000RadioC;
  Send = CC1000RadioC;
  Receive = CC1000RadioC;
}




--- NEW FILE: CC1000RssiM.nc ---
/*
 * "Copyright (c) 2000-2005 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 * Copyright (c) 2002-2005 Intel Corporation
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE     
 * file. If you do not find these files, copies can be found by writing to
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, 
 * 94704.  Attention:  Intel License Inquiry.
 */

/**
 *   RSSI fun. It's used for lots of things, and a request to read it
 *   for one purpose may have to be discarded if conditions change. For
 *   example, if we've initiated a noise-floor measure, but start 
 *   receiving a packet, we have to:
 *   - cancel the noise-floor measure (we don't know if the value will
 *     reflect the received packet or the previous idle state)
 *   - start an RSSI measurement so that we can report signal strength
 *     to the application
 *
 *   This module hides the complexities of cancellation from the rest of
 *   the stack.
 * 
 * @author 
 * @author David Moss
 */

module CC1000RssiM {
  provides {
    interface StdControl;
    interface Rssi[uint8_t id];
  }
  
  uses { 
    interface ADCControl;
    interface ADC;
  }
}

implementation {

  /** The client that made the current request */
  uint8_t currentClient;

  /** The next client in line for a request */
  uint8_t nextClient;
  
  enum {
    EMPTY = unique("Rssi"),
  };

  /***************** Prototypes ****************/
  task void startNextClient();
  
  /***************** StdControl Commands ****************/
  command result_t StdControl.init() {
    call ADCControl.bindPort(TOS_ADC_CC_RSSI_PORT, TOSH_ACTUAL_CC_RSSI_PORT);
    call ADCControl.init();

    atomic currentClient = EMPTY;
    atomic nextClient = EMPTY;
    return SUCCESS;
  }
  
  command result_t StdControl.start() {
    return SUCCESS;
  }
  
  command result_t StdControl.stop() {
    return SUCCESS;
  }
  

  /***************** RSSI Commands ****************/
  /**
   * Read the RSSI value
   */
  async command result_t Rssi.read[uint8_t id]() {
    atomic {
      nextClient = id;
      post startNextClient();
    }
    return SUCCESS;
  }

  /**
   * Cancel all current RSSI requests
   */
  async command void Rssi.cancel[uint8_t id]() {
    currentClient = EMPTY;
    nextClient = EMPTY;
  }

  /***************** ADC Events ****************/
  async event result_t ADC.dataReady(uint16_t data) {
    atomic {
      if(currentClient != EMPTY) {
        signal Rssi.readDone[currentClient](SUCCESS, data);
      }
      
      currentClient = EMPTY;
      
      post startNextClient();
    }
    return SUCCESS; 
  }

  /***************** Tasks ****************/
  task void startNextClient() {
    atomic {
      if (nextClient != EMPTY) {
        currentClient = nextClient;
        nextClient = EMPTY;
        call ADC.getData();
      }
    }
  }

  /**************** Defaults ****************/
  default async event void Rssi.readDone[uint8_t id](result_t result, uint16_t data) { 
  }
}



More information about the Tinyos-contrib-commits mailing list