]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
Update of the default CC2420 to the low power listening stack. The "acknowledgement...
authorrincon <rincon>
Thu, 12 Apr 2007 17:11:11 +0000 (17:11 +0000)
committerrincon <rincon>
Thu, 12 Apr 2007 17:11:11 +0000 (17:11 +0000)
43 files changed:
tos/chips/cc2420/CC2420.h
tos/chips/cc2420/CC2420AckLpl.h [new file with mode: 0644]
tos/chips/cc2420/CC2420AckLplC.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420AckLplP.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420ActiveMessageC.nc
tos/chips/cc2420/CC2420ActiveMessageP.nc
tos/chips/cc2420/CC2420Cca.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420Config.nc
tos/chips/cc2420/CC2420ControlC.nc
tos/chips/cc2420/CC2420ControlP.nc
tos/chips/cc2420/CC2420CsmaC.nc
tos/chips/cc2420/CC2420CsmaP.nc
tos/chips/cc2420/CC2420DutyCycle.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420DutyCycleC.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420DutyCycleP.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420LplDummyC.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420LplDummyP.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420NoAckLpl.h [new file with mode: 0644]
tos/chips/cc2420/CC2420NoAckLplC.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420NoAckLplP.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420Packet.nc
tos/chips/cc2420/CC2420PacketC.nc
tos/chips/cc2420/CC2420ReceiveC.nc
tos/chips/cc2420/CC2420ReceiveP.nc
tos/chips/cc2420/CC2420SpiC.nc
tos/chips/cc2420/CC2420SpiImplP.nc
tos/chips/cc2420/CC2420TinyosNetworkC.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420TinyosNetworkP.nc [new file with mode: 0644]
tos/chips/cc2420/CC2420Transmit.nc
tos/chips/cc2420/CC2420TransmitC.nc
tos/chips/cc2420/CC2420TransmitP.nc
tos/chips/cc2420/PacketLink.nc [new file with mode: 0644]
tos/chips/cc2420/PacketLinkC.nc [new file with mode: 0644]
tos/chips/cc2420/PacketLinkDummyC.nc [new file with mode: 0644]
tos/chips/cc2420/PacketLinkDummyP.nc [new file with mode: 0644]
tos/chips/cc2420/PacketLinkP.nc [new file with mode: 0644]
tos/chips/cc2420/README.txt [new file with mode: 0644]
tos/chips/cc2420/RadioBackoff.nc [new file with mode: 0644]
tos/chips/cc2420/UniqueReceiveC.nc [new file with mode: 0644]
tos/chips/cc2420/UniqueReceiveP.nc [new file with mode: 0644]
tos/chips/cc2420/UniqueSendC.nc [new file with mode: 0644]
tos/chips/cc2420/UniqueSendP.nc [new file with mode: 0644]
tos/interfaces/LowPowerListening.nc [new file with mode: 0644]

index 788b700cf56abc583e54570dd28fc39d213e77bc..91665102d5bd0e5c9a0ca706dc7642b18603702c 100644 (file)
  * OF THE POSSIBILITY OF SUCH DAMAGE
  *
  * @author Jonathan Hui <jhui@archrock.com>
+ * @author David Moss
  * @version $Revision$ $Date$
  */
 
 #ifndef __CC2420_H__
 #define __CC2420_H__
 
-//#include "message.h"
-
 typedef uint8_t cc2420_status_t;
 
+/**
+ * CC2420 header.  An I-frame (interoperability frame) header has an 
+ * extra network byte specified by 6LowPAN
+ */
 typedef nx_struct cc2420_header_t {
   nxle_uint8_t length;
   nxle_uint16_t fcf;
@@ -46,12 +49,25 @@ typedef nx_struct cc2420_header_t {
   nxle_uint16_t destpan;
   nxle_uint16_t dest;
   nxle_uint16_t src;
+  
+  /** I-Frame 6LowPAN interoperability byte */
+#ifdef CC2420_IFRAME_TYPE
+  nxle_uint8_t network;
+#endif
+
   nxle_uint8_t type;
 } cc2420_header_t;
-
+  
+/**
+ * CC2420 Packet Footer
+ */
 typedef nx_struct cc2420_footer_t {
 } cc2420_footer_t;
 
+/**
+ * CC2420 Packet metadata. Contains extra information about the message
+ * that will not be transmitted
+ */
 typedef nx_struct cc2420_metadata_t {
   nx_uint8_t tx_power;
   nx_uint8_t rssi;
@@ -59,13 +75,23 @@ typedef nx_struct cc2420_metadata_t {
   nx_bool crc;
   nx_bool ack;
   nx_uint16_t time;
+  nx_uint16_t rxInterval;
+
+  /** Packet Link Metadata */
+#ifdef PACKET_LINK
+  nx_uint16_t maxRetries;
+  nx_uint16_t retryDelay;
+#endif
+
 } cc2420_metadata_t;
 
+
 typedef nx_struct cc2420_packet_t {
   cc2420_header_t packet;
   nx_uint8_t data[];
 } cc2420_packet_t;
 
+
 #ifndef TOSH_DATA_LENGTH
 #define TOSH_DATA_LENGTH 28
 #endif
@@ -78,6 +104,22 @@ typedef nx_struct cc2420_packet_t {
 #define CC2420_DEF_RFPOWER 31
 #endif
 
+/**
+ * Ideally, your receive history size should be equal to the number of
+ * RF neighbors your node will have
+ */
+#ifndef RECEIVE_HISTORY_SIZE
+#define RECEIVE_HISTORY_SIZE 4
+#endif
+
+/** 
+ * The 6LowPAN ID has yet to be defined for a TinyOS network.
+ */
+#ifndef TINYOS_6LOWPAN_NETWORK_ID
+#define TINYOS_6LOWPAN_NETWORK_ID 0x0
+#endif
+
+
 enum {
   // size of the header not including the length byte
   MAC_HEADER_SIZE = sizeof( cc2420_header_t ) - 1,
@@ -92,6 +134,7 @@ enum cc2420_enums {
   CC2420_TIME_VREN = 20,          // jiffies
   CC2420_TIME_SYMBOL = 2,         // 2 symbols / jiffy
   CC2420_BACKOFF_PERIOD = ( 20 / CC2420_TIME_SYMBOL ), // symbols
+  CC2420_MIN_BACKOFF = ( 20 / CC2420_TIME_SYMBOL ),  // platform specific?
   CC2420_ACK_WAIT_DELAY = 128,    // jiffies
 };
 
diff --git a/tos/chips/cc2420/CC2420AckLpl.h b/tos/chips/cc2420/CC2420AckLpl.h
new file mode 100644 (file)
index 0000000..0ff05f0
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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 David Moss
+  */
+#ifndef CC2420ACKLPL_H
+#define CC2420ACKLPL_H
+
+/**
+ * Low Power Listening Send States
+ */
+typedef enum {
+  S_LPL_NOT_SENDING,    // DEFAULT
+  S_LPL_FIRST_MESSAGE,  // 1. Sending the first message
+  S_LPL_SENDING,        // 2. Sending all other messages
+  S_LPL_CLEAN_UP,       // 3. Clean up the transmission
+} lpl_sendstate_t;
+
+
+/**
+ * Amount of time, in milliseconds, to keep the radio on after
+ * a successful receive addressed to this node
+ * You don't want this too fast, or the off timer can accidentally
+ * fire due to delays in the system.  The radio would shut off and
+ * possibly need to turn back on again immediately, which can lock up
+ * the CC2420 if it's in the middle of doing something.
+ */
+#ifndef DELAY_AFTER_RECEIVE
+#define DELAY_AFTER_RECEIVE 100
+#endif
+
+/**
+ * This is a measured value of the time in ms the radio is actually on
+ * We round this up to err on the side of better performance ratios
+ */
+#ifndef DUTY_ON_TIME
+#define DUTY_ON_TIME 5 
+#endif
+
+/**
+ * The maximum number of CCA checks performed on each wakeup.
+ * If there are too few, the receiver may wake up between messages
+ * and not detect the transmitter.
+ *
+ * The on-time had to increase from the original version to allow multiple
+ * transmitters to co-exist.  This is due to using ack's, which then requires us
+ * to extend the backoff period.  In networks that transmit frequently, possibly
+ * with multiple transmitters, this power scheme makes sense.  
+ *
+ * In networks that transmit very infrequently or without multiple transmitters,
+ * it makes more sense to go with no acks and no backoffs and make the
+ * receive check as short as possible.
+ */
+#ifndef MAX_LPL_CCA_CHECKS
+
+#if defined(PLATFORM_TELOSB) || defined(PLATFORM_TMOTE)
+#define MAX_LPL_CCA_CHECKS 500
+#else
+#define MAX_LPL_CCA_CHECKS 400
+#endif
+
+#endif
+
+/**
+ * The minimum number of samples that must be taken in CC2420DutyCycleP
+ * that show the channel is not clear before a detection event is issued
+ */
+#ifndef MIN_SAMPLES_BEFORE_DETECT
+#define MIN_SAMPLES_BEFORE_DETECT 3
+#endif
+
+#endif
+
diff --git a/tos/chips/cc2420/CC2420AckLplC.nc b/tos/chips/cc2420/CC2420AckLplC.nc
new file mode 100644 (file)
index 0000000..a737bd5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Low Power Listening for the CC2420
+ * @author David Moss
+ */
+
+
+#include "CC2420AckLpl.h"
+#warning "*** USING ACK LOW POWER LISTENING LAYER"
+
+configuration CC2420AckLplC {
+  provides {
+    interface LowPowerListening;
+    interface Send;
+    interface Receive;
+    interface SplitControl;
+    interface State as SendState;
+  }
+  
+  uses { 
+    interface Send as SubSend;
+    interface Receive as SubReceive;
+    interface SplitControl as SubControl;
+  }
+}
+
+implementation {
+  components MainC,
+      CC2420AckLplP,
+      CC2420DutyCycleC,
+      CC2420ActiveMessageC,
+      CC2420CsmaC,
+      CC2420TransmitC,
+      CC2420PacketC,
+      RandomC,
+      LedsC,
+      new StateC() as SendStateC,
+      new StateC() as RadioStateC,
+      new TimerMilliC() as OffTimerC,
+      new TimerMilliC() as SendDoneTimerC;
+  
+  LowPowerListening = CC2420AckLplP;
+  Send = CC2420AckLplP;
+  Receive = CC2420AckLplP;
+  SplitControl = CC2420DutyCycleC;
+  SendState = SendStateC;
+  
+  SubControl = CC2420AckLplP.SubControl;
+  SubReceive = CC2420AckLplP.SubReceive;
+  SubSend = CC2420AckLplP.SubSend;
+  
+  
+  MainC.SoftwareInit -> CC2420AckLplP;
+  
+  CC2420AckLplP.Random -> RandomC;
+  CC2420AckLplP.SendState -> SendStateC;
+  CC2420AckLplP.RadioState -> RadioStateC;
+  CC2420AckLplP.SplitControlState -> CC2420DutyCycleC;
+  CC2420AckLplP.OffTimer -> OffTimerC;
+  CC2420AckLplP.SendDoneTimer -> SendDoneTimerC;
+  CC2420AckLplP.CC2420DutyCycle -> CC2420DutyCycleC;
+  CC2420AckLplP.Resend -> CC2420TransmitC;
+  CC2420AckLplP.PacketAcknowledgements -> CC2420ActiveMessageC;
+  CC2420AckLplP.AMPacket -> CC2420ActiveMessageC;
+  CC2420AckLplP.CC2420Packet -> CC2420PacketC;
+  CC2420AckLplP.Leds -> LedsC;
+  
+}
diff --git a/tos/chips/cc2420/CC2420AckLplP.nc b/tos/chips/cc2420/CC2420AckLplP.nc
new file mode 100644 (file)
index 0000000..e35ca47
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Low Power Listening for the CC2420.  This component is responsible for
+ * delivery of an LPL packet, and for turning off the radio when the radio
+ * has run out of tasks.
+ *
+ * The CC2420DutyCycle component is responsible for duty cycling the radio
+ * and performing receive detections.
+ *
+ * @author David Moss
+ */
+
+#include "CC2420AckLpl.h"
+
+module CC2420AckLplP {
+  provides {
+    interface Init;
+    interface LowPowerListening;
+    interface Send;
+    interface Receive;
+  }
+  
+  uses {
+    interface Send as SubSend;
+    interface CC2420Transmit as Resend;
+    interface Receive as SubReceive;
+    interface AMPacket;
+    interface SplitControl as SubControl;
+    interface CC2420DutyCycle;
+    interface CC2420Packet;
+    interface PacketAcknowledgements;
+    interface State as SendState;
+    interface State as RadioState;
+    interface State as SplitControlState;
+    interface Random;
+    interface Timer<TMilli> as OffTimer;
+    interface Timer<TMilli> as SendDoneTimer;
+    interface Leds;
+  }
+}
+
+implementation {
+  
+  /** The message currently being sent */
+  message_t *currentSendMsg;
+  
+  /** The length of the current send message */
+  uint8_t currentSendLen;
+  
+  /** TRUE if the radio is duty cycling and not always on */
+  bool dutyCycling;
+
+  /**
+   * Radio State
+   */
+  enum {
+    S_OFF,
+    S_ON,
+  };
+  
+  /**
+   * Send States
+   */
+  enum {
+    S_IDLE,
+    S_SENDING,
+  };
+  
+  enum {
+    ONE_MESSAGE = 0,
+  };
+  
+  /***************** Prototypes ***************/
+  task void send();
+  task void resend();
+  task void startRadio();
+  task void stopRadio();
+  
+  void initializeSend();
+  void startOffTimer();
+  uint16_t getActualDutyCycle(uint16_t dutyCycle);
+  
+  /***************** Init Commands ***************/
+  command error_t Init.init() {
+    dutyCycling = FALSE;
+    return SUCCESS;
+  }
+  
+  /***************** LowPowerListening Commands ***************/
+  /**
+   * Set this this node's radio sleep interval, in milliseconds.
+   * Once every interval, the node will sleep and perform an Rx check 
+   * on the radio.  Setting the sleep interval to 0 will keep the radio
+   * always on.
+   *
+   * This is the equivalent of setting the local duty cycle rate.
+   *
+   * @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
+   */
+  command void LowPowerListening.setLocalSleepInterval(
+      uint16_t sleepIntervalMs) {
+    call CC2420DutyCycle.setSleepInterval(sleepIntervalMs);
+  }
+  
+  /**
+   * @return the local node's sleep interval, in [ms]
+   */
+  command uint16_t LowPowerListening.getLocalSleepInterval() {
+    return call CC2420DutyCycle.getSleepInterval();
+  }
+  
+  /**
+   * Set this node's radio duty cycle rate, in units of [percentage*100].
+   * For example, to get a 0.05% duty cycle,
+   * <code>
+   *   call LowPowerListening.setDutyCycle(5);
+   * </code>
+   *
+   * For a 100% duty cycle (always on),
+   * <code>
+   *   call LowPowerListening.setDutyCycle(10000);
+   * </code>
+   *
+   * This is the equivalent of setting the local sleep interval explicitly.
+   * 
+   * @param dutyCycle The duty cycle percentage, in units of [percentage*100]
+   */
+  command void LowPowerListening.setLocalDutyCycle(uint16_t dutyCycle) {
+    call CC2420DutyCycle.setSleepInterval(
+        call LowPowerListening.dutyCycleToSleepInterval(dutyCycle));
+  }
+  
+  /**
+   * @return this node's radio duty cycle rate, in units of [percentage*100]
+   */
+  command uint16_t LowPowerListening.getLocalDutyCycle() {
+    return call LowPowerListening.sleepIntervalToDutyCycle(
+        call CC2420DutyCycle.getSleepInterval());
+  }
+  
+  
+  /**
+   * Configure this outgoing message so it can be transmitted to a neighbor mote
+   * with the specified Rx sleep interval.
+   * @param msg Pointer to the message that will be sent
+   * @param sleepInterval The receiving node's sleep interval, in [ms]
+   */
+  command void LowPowerListening.setRxSleepInterval(message_t *msg, 
+      uint16_t sleepIntervalMs) {
+    (call CC2420Packet.getMetadata(msg))->rxInterval = sleepIntervalMs;
+  }
+  
+  /**
+   * @return the destination node's sleep interval configured in this message
+   */
+  command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg) {
+    return (call CC2420Packet.getMetadata(msg))->rxInterval;
+  }
+  
+  /**
+   * Configure this outgoing message so it can be transmitted to a neighbor mote
+   * with the specified Rx duty cycle rate.
+   * Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25.
+   * 
+   * @param msg Pointer to the message that will be sent
+   * @param dutyCycle The duty cycle of the receiving mote, in units of 
+   *     [percentage*100]
+   */
+  command void LowPowerListening.setRxDutyCycle(message_t *msg, 
+      uint16_t dutyCycle) {
+    (call CC2420Packet.getMetadata(msg))->rxInterval =
+        call LowPowerListening.dutyCycleToSleepInterval(dutyCycle);
+  }
+  
+    
+  /**
+   * @return the destination node's duty cycle configured in this message
+   *     in units of [percentage*100]
+   */
+  command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg) {
+    return call LowPowerListening.sleepIntervalToDutyCycle(
+        (call CC2420Packet.getMetadata(msg))->rxInterval);
+  }
+  
+  /**
+   * Convert a duty cycle, in units of [percentage*100], to
+   * the sleep interval of the mote in milliseconds
+   * @param dutyCycle The duty cycle in units of [percentage*100]
+   * @return The equivalent sleep interval, in units of [ms]
+   */
+  command uint16_t LowPowerListening.dutyCycleToSleepInterval(
+      uint16_t dutyCycle) {
+    dutyCycle = getActualDutyCycle(dutyCycle);
+    
+    if(dutyCycle == 10000) {
+      return 0;
+    }
+    
+    return (DUTY_ON_TIME * (10000 - dutyCycle)) / dutyCycle;
+  }
+  
+  /**
+   * Convert a sleep interval, in units of [ms], to a duty cycle
+   * in units of [percentage*100]
+   * @param sleepInterval The sleep interval in units of [ms]
+   * @return The duty cycle in units of [percentage*100]
+   */
+  command uint16_t LowPowerListening.sleepIntervalToDutyCycle(
+      uint16_t sleepInterval) {
+    if(sleepInterval == 0) {
+      return 10000;
+    }
+    
+    return getActualDutyCycle((DUTY_ON_TIME * 10000) 
+        / (sleepInterval + DUTY_ON_TIME));
+  }
+
+  
+  /***************** Send Commands ***************/
+  /**
+   * Each call to this send command gives the message a single
+   * DSN that does not change for every copy of the message
+   * sent out.  For messages that are not acknowledged, such as
+   * a broadcast address message, the receiving end does not
+   * signal receive() more than once for that message.
+   */
+  command error_t Send.send(message_t *msg, uint8_t len) {
+    if(call SplitControlState.getState() == S_OFF) {
+      // Everything is off right now, start SplitControl and try again
+      return EOFF;
+    }
+    
+    if(call SendState.requestState(S_LPL_SENDING) == SUCCESS) {
+      currentSendMsg = msg;
+      currentSendLen = len;
+      
+      // In case our off timer is running...
+      call OffTimer.stop();
+      call SendDoneTimer.stop();
+      
+      if(call RadioState.getState() == S_ON) {
+        initializeSend();
+        return SUCCESS;
+        
+      } else {
+        post startRadio();
+      }
+      
+      return SUCCESS;
+    }
+    
+    return FAIL;
+  }
+
+  command error_t Send.cancel(message_t *msg) {
+    if(currentSendMsg == msg) {
+      call SendState.toIdle();
+      call SendDoneTimer.stop();
+      startOffTimer();
+      return call SubSend.cancel(msg);
+    }
+    
+    return FAIL;
+  }
+  
+  
+  command uint8_t Send.maxPayloadLength() {
+    return call SubSend.maxPayloadLength();
+  }
+
+  command void *Send.getPayload(message_t* msg) {
+    return call SubSend.getPayload(msg);
+  }
+  
+  /***************** Receive Commands ***************/
+  command void *Receive.getPayload(message_t* msg, uint8_t* len) {
+    return call SubReceive.getPayload(msg, len);
+  }
+
+  command uint8_t Receive.payloadLength(message_t* msg) {
+    return call SubReceive.payloadLength(msg);
+  }
+
+
+  /***************** DutyCycle Events ***************/
+  /**
+   * A transmitter was detected.  You must now take action to
+   * turn the radio off when the transaction is complete.
+   */
+  event void CC2420DutyCycle.detected() {
+    // At this point, the duty cycling has been disabled temporary
+    // and it will be this component's job to turn the radio back off
+    // Wait long enough to see if we actually receive a packet, which is
+    // just a little longer in case there is more than one lpl transmitter on
+    // the channel.
+    
+    if(call SendState.isIdle()) {
+      startOffTimer();
+    }
+  }
+  
+  
+  /***************** SubControl Events ***************/
+  event void SubControl.startDone(error_t error) {
+    if(!error) {
+      call RadioState.forceState(S_ON);
+      
+      if(call SendState.getState() == S_LPL_FIRST_MESSAGE
+          || call SendState.getState() == S_LPL_SENDING) {
+        initializeSend();
+      }
+    }
+  }
+    
+  event void SubControl.stopDone(error_t error) {
+    if(!error) {
+      call RadioState.forceState(S_OFF);
+
+      if(call SendState.getState() == S_LPL_FIRST_MESSAGE
+          || call SendState.getState() == S_LPL_SENDING) {
+        // We're in the middle of sending a message; start the radio back up
+        post startRadio();
+        
+      } else {        
+        call OffTimer.stop();
+        call SendDoneTimer.stop();
+      }
+    }
+  }
+  
+  /***************** SubSend Events ***************/
+  event void SubSend.sendDone(message_t* msg, error_t error) {
+   
+    switch(call SendState.getState()) {
+    case S_LPL_SENDING:
+      if(call SendDoneTimer.isRunning()) {
+        if(!call PacketAcknowledgements.wasAcked(msg)) {
+          post resend();
+          return;
+        }
+      }
+      break;
+      
+    case S_LPL_CLEAN_UP:
+      /**
+       * We include this state so upper layers can't send a different message
+       * before the last message gets done sending
+       */
+      break;
+      
+    default:
+      break;
+    }  
+    
+    call SendState.toIdle();
+    call SendDoneTimer.stop();
+    startOffTimer();
+    signal Send.sendDone(msg, error);
+  }
+  
+  /***************** SubReceive Events ***************/
+  /**
+   * If the received message is new, we signal the receive event and
+   * start the off timer.  If the last message we received had the same
+   * DSN as this message, then the chances are pretty good
+   * that this message should be ignored, especially if the destination address
+   * as the broadcast address
+   */
+  event message_t *SubReceive.receive(message_t* msg, void* payload, 
+      uint8_t len) {
+    
+    call CC2420DutyCycle.forceDetected();
+    startOffTimer();
+    return signal Receive.receive(msg, payload, len);
+  }
+  
+  /***************** Timer Events ****************/
+  event void OffTimer.fired() {
+    /*
+     * Only stop the radio if the radio is supposed to be off permanently
+     * or if the duty cycle is on and our sleep interval is not 0
+     */
+    if(call SplitControlState.getState() == S_OFF
+        || (call CC2420DutyCycle.getSleepInterval() > 0
+            && call SplitControlState.getState() == S_ON
+                && call SendState.getState() == S_LPL_NOT_SENDING)) { 
+      post stopRadio();
+    }
+  }
+  
+  /**
+   * When this timer is running, that means we're sending repeating messages
+   * to a node that is receive check duty cycling.
+   */
+  event void SendDoneTimer.fired() {
+    if(call SendState.getState() == S_LPL_SENDING) {
+      // The next time SubSend.sendDone is signaled, send is complete.
+      call SendState.forceState(S_LPL_CLEAN_UP);
+    }
+  }
+  
+  /***************** Resend Events ****************/
+  /**
+   * Signal that a message has been sent
+   *
+   * @param p_msg message to send.
+   * @param error notifaction of how the operation went.
+   */
+  async event void Resend.sendDone( message_t* p_msg, error_t error ) {
+    // This is actually caught by SubSend.sendDone
+  }
+  
+  
+  /***************** Tasks ***************/
+  task void send() {
+    if(call SubSend.send(currentSendMsg, currentSendLen) != SUCCESS) {
+      post send();
+    }
+  }
+  
+  task void resend() {
+    if(call Resend.resend(TRUE) != SUCCESS) {
+      post resend();
+    }
+  }
+  
+  task void startRadio() {
+    if(call SubControl.start() != SUCCESS) {
+      post startRadio();
+    }
+  }
+  
+  task void stopRadio() {
+    if(call SendState.getState() == S_LPL_NOT_SENDING) {
+      if(call SubControl.stop() != SUCCESS) {
+        post stopRadio();
+      }
+    }
+  }
+  
+  /***************** Functions ***************/
+  void initializeSend() {
+    if(call LowPowerListening.getRxSleepInterval(currentSendMsg) 
+      > ONE_MESSAGE) {
+    
+      if(call AMPacket.destination(currentSendMsg) == AM_BROADCAST_ADDR) {
+        call PacketAcknowledgements.noAck(currentSendMsg);
+      } else {
+        // Send it repetitively within our transmit window
+        call PacketAcknowledgements.requestAck(currentSendMsg);
+      }
+
+      call SendDoneTimer.startOneShot(
+          call LowPowerListening.getRxSleepInterval(currentSendMsg) + 20);
+    }
+        
+    post send();
+  }
+  
+  
+  void startOffTimer() {
+    call OffTimer.startOneShot(DELAY_AFTER_RECEIVE);
+  }
+  
+  /**
+   * Check the bounds on a given duty cycle
+   * We're never over 100%, and we're never at 0%
+   */
+  uint16_t getActualDutyCycle(uint16_t dutyCycle) {
+    if(dutyCycle > 10000) {
+      return 10000;
+    } else if(dutyCycle == 0) {
+      return 1;
+    }
+    
+    return dutyCycle;
+  }  
+}
+
index ef78e86e83e59a3a75a9eb82d7af3967e8b79ac3..31e90766e7f2db0ba8456a8a957deb39edd8cc04 100644 (file)
 /**
  * The Active Message layer for the CC2420 radio. This configuration
  * just layers the AM dispatch (CC2420ActiveMessageM) on top of the
- * underlying CC2420 radio packet (CC2420CsmaRadioC), which is
+ * underlying CC2420 radio packet (CC2420CsmaCsmaCC), which is
  * inherently an AM packet (acknowledgements based on AM destination
  * addr and group). Note that snooping may not work, due to CC2420
  * early packet rejection if acknowledgements are enabled.
  *
  * @author Philip Levis
+ * @author David Moss
  * @version $Revision$ $Date$
  */
 
@@ -45,30 +46,66 @@ configuration CC2420ActiveMessageC {
     interface Packet;
     interface CC2420Packet;
     interface PacketAcknowledgements;
+    interface RadioBackoff[am_id_t amId];
+    interface LowPowerListening;
+    interface PacketLink;
   }
 }
 implementation {
 
   components CC2420ActiveMessageP as AM;
-  components CC2420CsmaC as Radio;
+  components CC2420CsmaC as CsmaC;
   components ActiveMessageAddressC as Address;
+  components UniqueSendC;
+  components UniqueReceiveC;
+  components CC2420TinyosNetworkC;
+  components CC2420PacketC;
   
-  SplitControl = Radio;
-  Packet       = AM;
+#if defined(LOW_POWER_LISTENING) || defined(ACK_LOW_POWER_LISTENING)
+  components CC2420AckLplC as LplC;
+#elif defined(NOACK_LOW_POWER_LISTENING)
+  components CC2420NoAckLplC as LplC;
+#else
+  components CC2420LplDummyC as LplC;
+#endif
 
+#if defined(PACKET_LINK)
+  components PacketLinkC as LinkC;
+#else
+  components PacketLinkDummyC as LinkC;
+#endif
+
+  
+  RadioBackoff = CsmaC;
+  Packet       = AM;
   AMSend   = AM;
   Receive  = AM.Receive;
   Snoop    = AM.Snoop;
   AMPacket = AM;
-  
-  AM.SubSend    -> Radio.Send;
-  AM.SubReceive -> Radio.Receive;
-  AM.amAddress -> Address;
-  Radio.AMPacket -> AM;
-
-  components CC2420PacketC;
+  PacketLink = LinkC;
+  LowPowerListening = LplC;
   CC2420Packet = CC2420PacketC;
   PacketAcknowledgements = CC2420PacketC;
+  
+  
+  // SplitControl Layers
+  SplitControl = LplC;
+  LplC.SubControl -> CsmaC;
+  
+  // Send Layers
+  AM.SubSend -> UniqueSendC;
+  UniqueSendC.SubSend -> LinkC;
+  LinkC.SubSend -> LplC.Send;
+  LplC.SubSend -> CC2420TinyosNetworkC.Send;
+  CC2420TinyosNetworkC.SubSend -> CsmaC;
+  
+  // Receive Layers
+  AM.SubReceive -> LplC;
+  LplC.SubReceive -> UniqueReceiveC.Receive;
+  UniqueReceiveC.SubReceive -> CC2420TinyosNetworkC.Receive;
+  CC2420TinyosNetworkC.SubReceive -> CsmaC;
 
-
+  AM.amAddress -> Address;
+  AM.CC2420Packet -> CC2420PacketC;
+  
 }
index 6f6694faf2b1e5a93852be341e915686c52973d9..45a245f49288b17f35d0f4f3e10e007bf1fcd28e 100644 (file)
@@ -31,6 +31,8 @@
  * @author Philip Levis
  * @version $Revision$ $Date$
  */
+#include "CC2420.h"
 
 module CC2420ActiveMessageP {
   provides {
@@ -43,6 +45,7 @@ module CC2420ActiveMessageP {
   uses {
     interface Send as SubSend;
     interface Receive as SubReceive;
+    interface CC2420Packet;
     command am_addr_t amAddress();
   }
 }
@@ -52,14 +55,11 @@ implementation {
     CC2420_SIZE = MAC_HEADER_SIZE + MAC_FOOTER_SIZE,
   };
   
-  cc2420_header_t* getHeader( message_t* msg ) {
-    return (cc2420_header_t*)( msg->data - sizeof(cc2420_header_t) );
-  }
   
   command error_t AMSend.send[am_id_t id](am_addr_t addr,
                                          message_t* msg,
                                          uint8_t len) {
-    cc2420_header_t* header = getHeader( msg );
+    cc2420_header_t* header = call CC2420Packet.getHeader( msg );
     header->type = id;
     header->dest = addr;
     header->destpan = TOS_AM_GROUP;
@@ -115,22 +115,22 @@ implementation {
   }
  
   command am_addr_t AMPacket.destination(message_t* amsg) {
-    cc2420_header_t* header = getHeader(amsg);
+    cc2420_header_t* header = call CC2420Packet.getHeader(amsg);
     return header->dest;
   }
  
   command am_addr_t AMPacket.source(message_t* amsg) {
-    cc2420_header_t* header = getHeader(amsg);
+    cc2420_header_t* header = call CC2420Packet.getHeader(amsg);
     return header->src;
   }
 
   command void AMPacket.setDestination(message_t* amsg, am_addr_t addr) {
-    cc2420_header_t* header = getHeader(amsg);
+    cc2420_header_t* header = call CC2420Packet.getHeader(amsg);
     header->dest = addr;
   }
 
   command void AMPacket.setSource(message_t* amsg, am_addr_t addr) {
-    cc2420_header_t* header = getHeader(amsg);
+    cc2420_header_t* header = call CC2420Packet.getHeader(amsg);
     header->src = addr;
   }
 
@@ -140,12 +140,12 @@ implementation {
   }
 
   command am_id_t AMPacket.type(message_t* amsg) {
-    cc2420_header_t* header = getHeader(amsg);
+    cc2420_header_t* header = call CC2420Packet.getHeader(amsg);
     return header->type;
   }
 
   command void AMPacket.setType(message_t* amsg, am_id_t type) {
-    cc2420_header_t* header = getHeader(amsg);
+    cc2420_header_t* header = call CC2420Packet.getHeader(amsg);
     header->type = type;
   }
 
@@ -165,12 +165,12 @@ implementation {
  command void Packet.clear(message_t* msg) {}
  
  command uint8_t Packet.payloadLength(message_t* msg) {
-   return getHeader(msg)->length - CC2420_SIZE;
+   return (call CC2420Packet.getHeader(msg))->length - CC2420_SIZE;
  }
 
 
  command void Packet.setPayloadLength(message_t* msg, uint8_t len) {
-   getHeader(msg)->length  = len + CC2420_SIZE;
+   (call CC2420Packet.getHeader(msg))->length  = len + CC2420_SIZE;
  }
 
  command uint8_t Packet.maxPayloadLength() {
diff --git a/tos/chips/cc2420/CC2420Cca.nc b/tos/chips/cc2420/CC2420Cca.nc
new file mode 100644 (file)
index 0000000..059c9fe
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Interface to obtain a CCA reading from the CC2420 radio
+ * to determine if a neighbor is transmitting
+ * @author David Moss
+ */
+interface CC2420Cca {
+  
+  /**
+   * @return TRUE if the CCA pin shows a clear channel
+   */
+  command bool isChannelClear();
+  
+}
+
index 2d935888dbb364e523dfbd141fb09232ce7922ed..90308c3844369aa82f9ef492b854c654d2079a1b 100644 (file)
@@ -53,7 +53,7 @@ interface CC2420Config {
   event void syncDone( error_t error );
 
   /**
-   * Change the channel of the radio.
+   * Change the channel of the radio, between 11 and 26
    */
   command uint8_t getChannel();
   command void setChannel( uint8_t channel );
index 04de72efad0dd27e22321691291b1827e267d8e6..1657bcf9c362fe0d952ca8e3ccb5f699549a1f07 100644 (file)
 
 configuration CC2420ControlC {
 
-  provides interface Init;
   provides interface Resource;
   provides interface CC2420Config;
   provides interface CC2420Power;
-
-  uses interface AMPacket;
-
+  provides interface Read<uint16_t> as ReadRssi;
+  
 }
 
 implementation {
   
   components CC2420ControlP;
-  Init = CC2420ControlP;
   Resource = CC2420ControlP;
   CC2420Config = CC2420ControlP;
   CC2420Power = CC2420ControlP;
-  AMPacket = CC2420ControlP;
+  ReadRssi = CC2420ControlP;
 
+  components MainC;
+  MainC.SoftwareInit -> CC2420ControlP;
+  
+  components CC2420ActiveMessageC;
+  CC2420ControlP.AMPacket -> CC2420ActiveMessageC;
+  
   components AlarmMultiplexC as Alarm;
   CC2420ControlP.StartupTimer -> Alarm;
 
@@ -81,14 +84,15 @@ implementation {
   CC2420ControlP.IOCFG1 -> Spi.IOCFG1;
   CC2420ControlP.MDMCTRL0 -> Spi.MDMCTRL0;
   CC2420ControlP.MDMCTRL1 -> Spi.MDMCTRL1;
-  CC2420ControlP.RXCTRL1 -> Spi.RXCTRL1;
   CC2420ControlP.PANID -> Spi.PANID;
+  CC2420ControlP.RXCTRL1 -> Spi.RXCTRL1;
+  CC2420ControlP.RSSI  -> Spi.RSSI;
 
   components new CC2420SpiC() as SyncSpiC;
   CC2420ControlP.SyncResource -> SyncSpiC;
 
-  components LedsC as Leds;
-  CC2420ControlP.Leds -> Leds;
+  components new CC2420SpiC() as RssiResource;
+  CC2420ControlP.RssiResource -> RssiResource;
 
 }
 
index 333d3ca7819d0f5d484ae96acfa2f7bb1a30bdb1..1dae5a2d0488307a03e80e9d8986a3cd95bcaaa8 100644 (file)
@@ -31,6 +31,7 @@
 
 /**
  * @author Jonathan Hui <jhui@archrock.com>
+ * @author Urs Hunkeler (ReadRssi implementation)
  * @version $Revision$ $Date$
  */
 
@@ -42,6 +43,7 @@ module CC2420ControlP {
   provides interface Resource;
   provides interface CC2420Config;
   provides interface CC2420Power;
+  provides interface Read<uint16_t> as ReadRssi;
 
   uses interface Alarm<T32khz,uint32_t> as StartupTimer;
   uses interface GeneralIO as CSN;
@@ -49,7 +51,6 @@ module CC2420ControlP {
   uses interface GeneralIO as VREN;
   uses interface GpioInterrupt as InterruptCCA;
 
-  uses interface Resource as SpiResource;
   uses interface CC2420Ram as PANID;
   uses interface CC2420Register as FSCTRL;
   uses interface CC2420Register as IOCFG0;
@@ -57,12 +58,15 @@ module CC2420ControlP {
   uses interface CC2420Register as MDMCTRL0;
   uses interface CC2420Register as MDMCTRL1;
   uses interface CC2420Register as RXCTRL1;
+  uses interface CC2420Register as RSSI;
   uses interface CC2420Strobe as SRXON;
   uses interface CC2420Strobe as SRFOFF;
   uses interface CC2420Strobe as SXOSCOFF;
   uses interface CC2420Strobe as SXOSCON;
   uses interface AMPacket;
-
+  
+  uses interface Resource as SpiResource;
+  uses interface Resource as RssiResource;
   uses interface Resource as SyncResource;
 
   uses interface Leds;
@@ -80,14 +84,21 @@ implementation {
   } cc2420_control_state_t;
 
   uint8_t m_channel = CC2420_DEF_CHANNEL;
+  
   uint8_t m_tx_power = CC2420_DEF_RFPOWER;
+  
   uint16_t m_pan = TOS_AM_GROUP;
+  
   uint16_t m_short_addr;
+  
   bool m_sync_busy;
-  task void syncDone_task();
-
+  
   norace cc2420_control_state_t m_state = S_VREG_STOPPED;
+  
+  /***************** Prototypes ****************/
+  task void syncDone_task();
 
+  /***************** Init Commands ****************/
   command error_t Init.init() {
     call CSN.makeOutput();
     call RSTN.makeOutput();
@@ -96,10 +107,12 @@ implementation {
     return SUCCESS;
   }
 
+  /***************** Resource Commands ****************/
   async command error_t Resource.immediateRequest() {
     error_t error = call SpiResource.immediateRequest();
-    if ( error == SUCCESS )
+    if ( error == SUCCESS ) {
       call CSN.clr();
+    }
     return error;
   }
 
@@ -118,15 +131,12 @@ implementation {
     }
   }
 
-  event void SpiResource.granted() {
-    call CSN.clr();
-    signal Resource.granted();
-  }
-
+  /***************** CC2420Power Commands ****************/
   async command error_t CC2420Power.startVReg() {
     atomic {
-      if ( m_state != S_VREG_STOPPED )
-       return FAIL;
+      if ( m_state != S_VREG_STOPPED ) {
+        return FAIL;
+      }
       m_state = S_VREG_STARTING;
     }
     call VREN.set();
@@ -134,15 +144,6 @@ implementation {
     return SUCCESS;
   }
 
-  async event void StartupTimer.fired() {
-    if ( m_state == S_VREG_STARTING ) {
-      m_state = S_VREG_STARTED;
-      call RSTN.clr();
-      call RSTN.set();
-      signal CC2420Power.startVRegDone();
-    }
-  }
-
   async command error_t CC2420Power.stopVReg() {
     m_state = S_VREG_STOPPED;
     call RSTN.clr();
@@ -153,26 +154,32 @@ implementation {
 
   async command error_t CC2420Power.startOscillator() {
     atomic {
-      if ( m_state != S_VREG_STARTED )
-       return FAIL;
-       
+      if ( m_state != S_VREG_STARTED ) {
+        return FAIL;
+      }
+        
       m_state = S_XOSC_STARTING;
       call IOCFG1.write( CC2420_SFDMUX_XOSC16M_STABLE << 
-                        CC2420_IOCFG1_CCAMUX );
+                         CC2420_IOCFG1_CCAMUX );
+                         
       call InterruptCCA.enableRisingEdge();
       call SXOSCON.strobe();
+      
       call IOCFG0.write( ( 1 << CC2420_IOCFG0_FIFOP_POLARITY ) |
-                        ( 127 << CC2420_IOCFG0_FIFOP_THR ) );
+                         ( 127 << CC2420_IOCFG0_FIFOP_THR ) );
+                         
       call FSCTRL.write( ( 1 << CC2420_FSCTRL_LOCK_THR ) |
-                        ( ( (m_channel - 11)*5+357 ) 
-                          << CC2420_FSCTRL_FREQ ) );
+                         ( ( (m_channel - 11)*5+357 ) 
+                           << CC2420_FSCTRL_FREQ ) );
+                           
       call MDMCTRL0.write( ( 1 << CC2420_MDMCTRL0_RESERVED_FRAME_MODE ) |
-                          ( 1 << CC2420_MDMCTRL0_ADR_DECODE ) |
-                          ( 2 << CC2420_MDMCTRL0_CCA_HYST ) |
-                          ( 3 << CC2420_MDMCTRL0_CCA_MOD ) |
-                          ( 1 << CC2420_MDMCTRL0_AUTOCRC ) |
-                          ( 1 << CC2420_MDMCTRL0_AUTOACK ) |
-                          ( 2 << CC2420_MDMCTRL0_PREAMBLE_LENGTH ) );
+                           ( 1 << CC2420_MDMCTRL0_ADR_DECODE ) |
+                           ( 2 << CC2420_MDMCTRL0_CCA_HYST ) |
+                           ( 3 << CC2420_MDMCTRL0_CCA_MOD ) |
+                           ( 1 << CC2420_MDMCTRL0_AUTOCRC ) |
+                           ( 0 << CC2420_MDMCTRL0_AUTOACK ) |  // we now SACK
+                           ( 2 << CC2420_MDMCTRL0_PREAMBLE_LENGTH ) );
+                           
       call RXCTRL1.write( ( 1 << CC2420_RXCTRL1_RXBPF_LOCUR ) |
                           ( 1 << CC2420_RXCTRL1_LOW_LOWGAIN ) |
                           ( 1 << CC2420_RXCTRL1_HIGH_HGM ) |
@@ -184,23 +191,12 @@ implementation {
     return SUCCESS;
   }
 
-  async event void InterruptCCA.fired() {
-    nxle_uint16_t id[ 2 ];
-    m_state = S_XOSC_STARTED;
-    id[ 0 ] = m_pan;
-    id[ 1 ] = m_short_addr;
-    call InterruptCCA.disable();
-    call IOCFG1.write( 0 );
-    call PANID.write( 0, (uint8_t*)&id, 4 );
-    call CSN.set();
-    call CSN.clr();
-    signal CC2420Power.startOscillatorDone();
-  }
 
   async command error_t CC2420Power.stopOscillator() {
     atomic {
-      if ( m_state != S_XOSC_STARTED )
-       return FAIL;
+      if ( m_state != S_XOSC_STARTED ) {
+        return FAIL;
+      }
       m_state = S_VREG_STARTED;
       call SXOSCOFF.strobe();
     }
@@ -209,8 +205,9 @@ implementation {
 
   async command error_t CC2420Power.rxOn() {
     atomic {
-      if ( m_state != S_XOSC_STARTED )
-       return FAIL;
+      if ( m_state != S_XOSC_STARTED ) {
+        return FAIL;
+      }
       call SRXON.strobe();
     }
     return SUCCESS;
@@ -218,13 +215,16 @@ implementation {
 
   async command error_t CC2420Power.rfOff() {
     atomic {  
-      if ( m_state != S_XOSC_STARTED )
-       return FAIL;
+      if ( m_state != S_XOSC_STARTED ) {
+        return FAIL;
+      }
       call SRFOFF.strobe();
     }
     return SUCCESS;
   }
 
+  
+  /***************** CC2420Config Commands ****************/
   command uint8_t CC2420Config.getChannel() {
     atomic return m_channel;
   }
@@ -251,17 +251,26 @@ implementation {
 
   command error_t CC2420Config.sync() {
     atomic {
-      if ( m_sync_busy )
+      if ( m_sync_busy ) {
         return FAIL;
+      }
+      
       m_sync_busy = TRUE;
-      if ( m_state == S_XOSC_STARTED )
+      if ( m_state == S_XOSC_STARTED ) {
         call SyncResource.request();
-      else
+      } else {
         post syncDone_task();
+      }
     }
     return SUCCESS;
   }
 
+  /***************** ReadRssi Commands ****************/
+  command error_t ReadRssi.read() { 
+    return call RssiResource.request();
+  }
+  
+  /***************** Spi Resources Events ****************/
   event void SyncResource.granted() {
 
     nxle_uint16_t id[ 2 ];
@@ -276,7 +285,7 @@ implementation {
     call CSN.clr();
     call SRFOFF.strobe();
     call FSCTRL.write( ( 1 << CC2420_FSCTRL_LOCK_THR ) |
-                      ( ( (channel - 11)*5+357 ) << CC2420_FSCTRL_FREQ ) );
+                       ( ( (channel - 11)*5+357 ) << CC2420_FSCTRL_FREQ ) );
     call PANID.write( 0, (uint8_t*)id, sizeof( id ) );
     call CSN.set();
     call CSN.clr();
@@ -288,11 +297,58 @@ implementation {
     
   }
 
+  event void SpiResource.granted() {
+    call CSN.clr();
+    signal Resource.granted();
+  }
+
+  event void RssiResource.granted() { 
+    uint16_t data;
+    call CSN.clr();
+    call RSSI.read(&data);
+    call CSN.set();
+    
+    call RssiResource.release();
+    data += 0x7f;
+    data &= 0x00ff;
+    signal ReadRssi.readDone(SUCCESS, data); 
+  }
+  
+  /***************** StartupTimer Events ****************/
+  async event void StartupTimer.fired() {
+    if ( m_state == S_VREG_STARTING ) {
+      m_state = S_VREG_STARTED;
+      call RSTN.clr();
+      call RSTN.set();
+      signal CC2420Power.startVRegDone();
+    }
+  }
+
+  /***************** InterruptCCA Events ****************/
+  async event void InterruptCCA.fired() {
+    nxle_uint16_t id[ 2 ];
+    m_state = S_XOSC_STARTED;
+    id[ 0 ] = m_pan;
+    id[ 1 ] = m_short_addr;
+    call InterruptCCA.disable();
+    call IOCFG1.write( 0 );
+    call PANID.write( 0, (uint8_t*)&id, 4 );
+    call CSN.set();
+    call CSN.clr();
+    signal CC2420Power.startOscillatorDone();
+  }
+  
+  /***************** Tasks ****************/
   task void syncDone_task() {
     atomic m_sync_busy = FALSE;
     signal CC2420Config.syncDone( SUCCESS );
   }
 
-  default event void CC2420Config.syncDone( error_t error ) {}
+  /***************** Defaults ****************/
+  default event void CC2420Config.syncDone( error_t error ) {
+  }
 
+  default event void ReadRssi.readDone(error_t error, uint16_t data) {
+  }
+  
 }
index 34620ba8a4f687bbc86c5ad7c216c23e053b961d..5f052a5c7fc7c270ba4e07891769cd884ab8aa63 100644 (file)
 configuration CC2420CsmaC {
 
   provides interface SplitControl;
-
   provides interface Send;
   provides interface Receive;
-
-  uses interface AMPacket;
+  provides interface RadioBackoff[am_id_t amId];
 
 }
 
 implementation {
 
   components CC2420CsmaP as CsmaP;
-
+  RadioBackoff = CsmaP;
   SplitControl = CsmaP;
   Send = CsmaP;
-  AMPacket = CsmaP;
 
+  components MainC;
+  MainC.SoftwareInit -> CsmaP;
+  
+  components CC2420ActiveMessageC;
+  CsmaP.AMPacket -> CC2420ActiveMessageC;
+  
   components CC2420ControlC;
-  AMPacket = CC2420ControlC;
   CsmaP.Resource -> CC2420ControlC;
   CsmaP.CC2420Power -> CC2420ControlC;
 
   components CC2420TransmitC;
-
   CsmaP.SubControl -> CC2420TransmitC;
   CsmaP.CC2420Transmit -> CC2420TransmitC;
-  CsmaP.CsmaBackoff -> CC2420TransmitC;
+  CsmaP.SubBackoff -> CC2420TransmitC;
 
   components CC2420ReceiveC;
   Receive = CC2420ReceiveC;
   CsmaP.SubControl -> CC2420ReceiveC;
 
+  components CC2420PacketC;
+  CsmaP.CC2420Packet -> CC2420PacketC;
+  
   components RandomC;
   CsmaP.Random -> RandomC;
 
   components LedsC as Leds;
   CsmaP.Leds -> Leds;
-
-  components MainC;
-  MainC.SoftwareInit -> CsmaP;
-  MainC.SoftwareInit -> CC2420ControlC;
-  MainC.SoftwareInit -> CC2420TransmitC;
-  MainC.SoftwareInit -> CC2420ReceiveC;
+  
 }
index ee9e245ddaac9db22a0d95ae0d7fea32eb19e7c9..f0382f5a3795eca06e00c1a554bb4b0776c6087f 100644 (file)
@@ -39,15 +39,17 @@ module CC2420CsmaP {
   provides interface Init;
   provides interface SplitControl;
   provides interface Send;
+  provides interface RadioBackoff[am_id_t amId];
 
   uses interface Resource;
   uses interface CC2420Power;
-  uses interface AsyncStdControl as SubControl;
+  uses interface StdControl as SubControl;
   uses interface CC2420Transmit;
-  uses interface CsmaBackoff;
+  uses interface RadioBackoff as SubBackoff;
   uses interface Random;
   uses interface AMPacket;
   uses interface Leds;
+  uses interface CC2420Packet;
 
 }
 
@@ -63,102 +65,67 @@ implementation {
   };
 
   message_t* m_msg;
+  
   uint8_t m_state = S_PREINIT;
-  uint8_t m_dsn;
+  
   error_t sendErr = SUCCESS;
   
+  /** TRUE if we are to use CCA when sending the current packet */
+  norace bool ccaOn;
+  
+  /****************** Prototypes ****************/
+  task void startDone_task();
   task void startDone_task();
   task void stopDone_task();
   task void sendDone_task();
 
-  cc2420_header_t* getHeader( message_t* msg ) {
-    return (cc2420_header_t*)( msg->data - sizeof( cc2420_header_t ) );
-  }
-
-  cc2420_metadata_t* getMetadata( message_t* msg ) {
-    return (cc2420_metadata_t*)msg->metadata;
-  }
-
+  /***************** Init Commands ****************/
   command error_t Init.init() {
-    
-    if ( m_state != S_PREINIT )
+    if ( m_state != S_PREINIT ) {
       return FAIL;
-
+    }
     m_state = S_STOPPED;
-
     return SUCCESS;
-
   }
 
+  /***************** SplitControl Commands ****************/
   command error_t SplitControl.start() {
-
-    if ( m_state != S_STOPPED ) 
+    if ( m_state != S_STOPPED ) {
       return FAIL;
+    }
 
     m_state = S_STARTING;
-
-    m_dsn = call Random.rand16();
     call CC2420Power.startVReg();
-
     return SUCCESS;
-
-  }
-
-  async event void CC2420Power.startVRegDone() {
-    call Resource.request();
-  }
-
-  event void Resource.granted() {
-    call CC2420Power.startOscillator();
-  }
-
-  async event void CC2420Power.startOscillatorDone() {
-    call SubControl.start();
-    call CC2420Power.rxOn();
-    call Resource.release();
-    post startDone_task();
-  }
-
-  task void startDone_task() {
-    m_state = S_STARTED;
-    signal SplitControl.startDone( SUCCESS );
   }
 
   command error_t SplitControl.stop() {
-
-    if ( m_state != S_STARTED )
+    if ( m_state != S_STARTED ) {
       return FAIL;
+    }
 
     m_state = S_STOPPING;
-
     call SubControl.stop();
     call CC2420Power.stopVReg();
     post stopDone_task();
-
     return SUCCESS;
-
-  }
-
-  task void stopDone_task() {
-    m_state = S_STOPPED;
-    signal SplitControl.stopDone( SUCCESS );
   }
 
+  /***************** Send Commands ****************/
   command error_t Send.cancel( message_t* p_msg ) {
-    return FAIL;
+    return call CC2420Transmit.cancel();
   }
 
   command error_t Send.send( message_t* p_msg, uint8_t len ) {
     
-    cc2420_header_t* header = getHeader( p_msg );
-    cc2420_metadata_t* metadata = getMetadata( p_msg );
+    cc2420_header_t* header = call CC2420Packet.getHeader( p_msg );
+    cc2420_metadata_t* metadata = call CC2420Packet.getMetadata( p_msg );
 
     atomic {
       if ( m_state != S_STARTED )
         return FAIL;
       m_state = S_TRANSMIT;
       m_msg = p_msg;
-      header->dsn = ++m_dsn;
     }
 
     header->length = len;
@@ -172,9 +139,11 @@ implementation {
     metadata->rssi = 0;
     metadata->lqi = 0;
     metadata->time = 0;
-
-    call CC2420Transmit.sendCCA( m_msg );
-
+    
+    ccaOn = TRUE;
+    signal RadioBackoff.requestCca[((cc2420_header_t*)(m_msg->data - 
+        sizeof(cc2420_header_t)))->type](m_msg);
+    call CC2420Transmit.send( m_msg, ccaOn );
     return SUCCESS;
 
   }
@@ -187,19 +156,89 @@ implementation {
     return TOSH_DATA_LENGTH;
   }
 
-  async event uint16_t CsmaBackoff.initial( message_t* m ) {
-    return ( call Random.rand16() & 0x1f ) + 1;
+  /**************** RadioBackoff Commands ****************/
+  /**
+   * Must be called within a requestInitialBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void RadioBackoff.setInitialBackoff[am_id_t amId](uint16_t backoffTime) {
+    call SubBackoff.setInitialBackoff(backoffTime);
   }
-
-  async event uint16_t CsmaBackoff.congestion( message_t* m ) {
-    return ( call Random.rand16() & 0x7 ) + 1;
+  
+  /**
+   * Must be called within a requestCongestionBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void RadioBackoff.setCongestionBackoff[am_id_t amId](uint16_t backoffTime) {
+    call SubBackoff.setCongestionBackoff(backoffTime);
+  }
+  
+  /**
+   * Must be called within a requestLplBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void RadioBackoff.setLplBackoff[am_id_t amId](uint16_t backoffTime) {
+    call SubBackoff.setLplBackoff(backoffTime);
+  }
+    
+  /**
+   * Enable CCA for the outbound packet.  Must be called within a requestCca
+   * event
+   * @param ccaOn TRUE to enable CCA, which is the default.
+   */
+  async command void RadioBackoff.setCca[am_id_t amId](bool useCca) {
+    ccaOn = useCca;
   }
+  
 
+  /**************** Events ****************/
   async event void CC2420Transmit.sendDone( message_t* p_msg, error_t err ) {
     atomic sendErr = err;
     post sendDone_task();
   }
 
+  async event void CC2420Power.startVRegDone() {
+    call Resource.request();
+  }
+  
+  event void Resource.granted() {
+    call CC2420Power.startOscillator();
+  }
+
+  async event void CC2420Power.startOscillatorDone() {
+    post startDone_task();
+  }
+  
+  /***************** SubBackoff Events ****************/
+  async event void SubBackoff.requestInitialBackoff(message_t *msg) {
+    call SubBackoff.setInitialBackoff ( call Random.rand16() 
+        % (0x1F * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
+        
+    signal RadioBackoff.requestInitialBackoff[((cc2420_header_t*)(msg->data - 
+        sizeof(cc2420_header_t)))->type](msg);
+  }
+
+  async event void SubBackoff.requestCongestionBackoff(message_t *msg) {
+    call SubBackoff.setCongestionBackoff( call Random.rand16() 
+        % (0x7 * CC2420_BACKOFF_PERIOD) + CC2420_MIN_BACKOFF);
+
+    signal RadioBackoff.requestCongestionBackoff[((cc2420_header_t*)(msg->data - 
+        sizeof(cc2420_header_t)))->type](msg);
+  }
+  
+  async event void SubBackoff.requestLplBackoff(message_t *msg) {
+    call SubBackoff.setLplBackoff(call Random.rand16() % 10);
+        
+    signal RadioBackoff.requestLplBackoff[((cc2420_header_t*)(msg->data - 
+        sizeof(cc2420_header_t)))->type](msg);
+  }
+  
+  async event void SubBackoff.requestCca(message_t *msg) {
+    // Lower layers than this do not configure the CCA settings
+  }
+  
+  
+  /***************** Tasks ****************/
   task void sendDone_task() {
     error_t packetErr;
     atomic packetErr = sendErr;
@@ -207,5 +246,45 @@ implementation {
     signal Send.sendDone( m_msg, packetErr );
   }
 
+  task void startDone_task() {
+    call SubControl.start();
+    call CC2420Power.rxOn();
+    call Resource.release();
+    m_state = S_STARTED;
+    signal SplitControl.startDone( SUCCESS );
+  }
+  
+  task void stopDone_task() {
+    m_state = S_STOPPED;
+    signal SplitControl.stopDone( SUCCESS );
+  }
+  
+  
+  /***************** Functions ****************/
+
+
+  /***************** Defaults ***************/
+  default event void SplitControl.startDone(error_t error) {
+  }
+  
+  default event void SplitControl.stopDone(error_t error) {
+  }
+  
+  
+  default async event void RadioBackoff.requestInitialBackoff[am_id_t amId](
+      message_t *msg) {
+  }
+
+  default async event void RadioBackoff.requestCongestionBackoff[am_id_t amId](
+      message_t *msg) {
+  }
+  
+  default async event void RadioBackoff.requestLplBackoff[am_id_t amId](
+      message_t *msg) {
+  }
+  
+  default async event void RadioBackoff.requestCca[am_id_t amId](
+      message_t *msg) {
+  }
 }
 
diff --git a/tos/chips/cc2420/CC2420DutyCycle.nc b/tos/chips/cc2420/CC2420DutyCycle.nc
new file mode 100644 (file)
index 0000000..30c75f3
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Manage the CC2420's duty cycle and power
+ * @author David Moss
+ */
+interface CC2420DutyCycle {
+  
+  /**
+   * Set the sleep interval, in binary milliseconds
+   * @param sleepIntervalMs the sleep interval in [ms]
+   */
+  command void setSleepInterval(uint16_t sleepIntervalMs);
+  
+  /**
+   * @return the sleep interval in [ms]
+   */
+  command uint16_t getSleepInterval();
+  
+  /**
+   * Sometimes the radio kicks on and an Rx interrupt causes the CCA
+   * checking for-loop to stop doing its job.  The upper layers receive
+   * a message, but the for-loop CCA check never got the detect because it
+   * got cut off.  So, LPL can override the duty cycler and leave the radio in 
+   * its current state. When the radio turns back off again, the duty cycling 
+   * continues
+   */
+  command void forceDetected();
+  
+  /**
+   * A transmitter was detected.  You must now take action to
+   * turn the radio off when the transaction is complete.
+   */
+  event void detected();
+
+}
+
diff --git a/tos/chips/cc2420/CC2420DutyCycleC.nc b/tos/chips/cc2420/CC2420DutyCycleC.nc
new file mode 100644 (file)
index 0000000..1c7ec37
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Use this component to duty cycle the radio. When a message is heard, 
+ * disable DutyCycling.
+ *
+ * @author David Moss dmm@rincon.com
+ */
+
+configuration CC2420DutyCycleC {
+  provides {
+    interface CC2420DutyCycle;
+    interface SplitControl;
+    interface State as SplitControlState;
+  }
+}
+
+implementation {
+  components MainC,
+      CC2420DutyCycleP,
+      CC2420TransmitC,
+      CC2420CsmaC,
+      LedsC,
+      new StateC() as RadioPowerStateC,
+      new StateC() as DutyCycleStateC,
+      new StateC() as CheckStateC,
+      new StateC() as SplitControlStateC,
+      new TimerMilliC() as OnTimerC,
+      new TimerMilliC() as CheckTimerC,
+      RandomC;
+
+#if defined(LOW_POWER_LISTENING) || defined(ACK_LOW_POWER_LISTENING)
+  components CC2420AckLplC as LplC;
+#elif defined(NOACK_LOW_POWER_LISTENING)
+  components CC2420NoAckLplC as LplC;
+#else
+  components CC2420LplDummyC as LplC;
+#endif
+
+  CC2420DutyCycle = CC2420DutyCycleP;
+  SplitControl = CC2420DutyCycleP;
+  SplitControlState = SplitControlStateC;
+  
+  MainC.SoftwareInit -> CC2420DutyCycleP;
+  
+  CC2420DutyCycleP.Random -> RandomC;
+  CC2420DutyCycleP.CC2420Cca -> CC2420TransmitC;
+  CC2420DutyCycleP.SubControl -> CC2420CsmaC;
+  CC2420DutyCycleP.SendState -> LplC;
+  CC2420DutyCycleP.RadioPowerState -> RadioPowerStateC;
+  CC2420DutyCycleP.DutyCycleState -> DutyCycleStateC;
+  CC2420DutyCycleP.SplitControlState -> SplitControlStateC;
+  CC2420DutyCycleP.CheckState -> CheckStateC;
+  CC2420DutyCycleP.OnTimer -> OnTimerC;
+  CC2420DutyCycleP.Leds -> LedsC;
+    
+}
+
+
diff --git a/tos/chips/cc2420/CC2420DutyCycleP.nc b/tos/chips/cc2420/CC2420DutyCycleP.nc
new file mode 100644 (file)
index 0000000..6162b60
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/** 
+ * Module to duty cycle the radio on and off, performing CCA receive checks.
+ * When a carrier is sensed, this will leave the radio on. It is then up
+ * to higher layers to turn the radio off again.  Once the radio is turned
+ * off, this module will automatically continue duty cycling and looking for
+ * a modulated signal.
+ *
+ * @author David Moss
+ */
+module CC2420DutyCycleP {
+  provides {
+    interface CC2420DutyCycle;
+    interface Init;
+    interface SplitControl;
+  }
+
+  uses {
+    interface Timer<TMilli> as OnTimer;
+    interface SplitControl as SubControl;
+    interface State as RadioPowerState;
+    interface State as DutyCycleState;
+    interface State as SplitControlState;
+    interface State as CheckState;
+    interface State as SendState;
+    interface Leds;
+    interface CC2420Cca;
+    interface Random;
+  }
+}
+
+implementation {
+  
+  /** The current period of the duty cycle, equivalent of wakeup interval */
+  uint16_t sleepInterval;
+  
+  /** The number of times the CCA has been sampled in this wakeup period */
+  uint16_t ccaChecks;
+  
+  /** TRUE if we get an Rx interrupt that stops our CCA checking loop */
+  bool detectionForced;
+  
+  /**
+   * Radio Power, Check State, and Duty Cycling State
+   */
+  enum {
+    S_OFF, // off by default
+    S_ON,
+  };
+  
+  
+  /***************** Prototypes ****************/
+  task void stopRadio();
+  task void startRadio();
+  task void getCca();
+  
+  /***************** Init Commands ****************/
+  command error_t Init.init() {
+    sleepInterval = 0;
+   return SUCCESS;
+  }
+  
+  /***************** CC2420DutyCycle Commands ****************/
+  /**
+   * Set the sleep interval, in binary milliseconds
+   * @param sleepIntervalMs the sleep interval in [ms]
+   */
+  command void CC2420DutyCycle.setSleepInterval(uint16_t sleepIntervalMs) {
+    if (!sleepInterval && sleepIntervalMs) {
+      // We were always on, now lets duty cycle
+      call DutyCycleState.forceState(S_ON);
+      call CheckState.toIdle();
+      post stopRadio();  // Might want to delay turning off the radio
+    }
+    
+    detectionForced = FALSE;
+    sleepInterval = sleepIntervalMs;
+    
+    if(sleepInterval == 0 && call DutyCycleState.getState() == S_ON) {
+      call DutyCycleState.forceState(S_OFF);
+      call CheckState.toIdle();
+      
+      /*
+       * Leave the radio on permanently if sleepInterval == 0 and the radio is 
+       * supposed to be enabled
+       */
+      if(call RadioPowerState.getState() == S_OFF) {
+        call SubControl.start();
+      }
+    }
+  }
+  
+  /**
+   * @return the sleep interval in [ms]
+   */
+  command uint16_t CC2420DutyCycle.getSleepInterval() {
+    return sleepInterval;
+  }
+  
+  command void CC2420DutyCycle.forceDetected() {
+    detectionForced = TRUE;
+  }
+  
+  /***************** SplitControl Commands ****************/
+  command error_t SplitControl.start() {
+    call SplitControlState.forceState(S_ON);
+    
+    if(sleepInterval > 0) {
+      // Begin duty cycling
+      call DutyCycleState.forceState(S_ON);
+      call CheckState.toIdle();
+      post stopRadio();
+      signal SplitControl.startDone(SUCCESS);
+      
+    } else {
+      call DutyCycleState.forceState(S_OFF);
+      call CheckState.toIdle();
+      
+      /*
+       * Leave the radio on permanently if sleepInterval == 0 and the radio is 
+       * supposed to be enabled
+       */
+      if(call RadioPowerState.getState() == S_OFF) {
+        call SubControl.start();
+        // Here, SplitControl.startDone is signaled on SubControl.startDone
+        
+      } else {
+        // Radio is already on
+        signal SplitControl.startDone(SUCCESS);
+      }
+    }
+
+    return SUCCESS;
+  }
+  
+  command error_t SplitControl.stop() {
+    call SplitControlState.forceState(S_OFF);
+    call DutyCycleState.forceState(S_OFF);
+    call CheckState.toIdle();
+    return call SubControl.stop();
+    
+    /*
+     * SubControl.stopDone signals SplitControl.stopDone when  
+     * DutyCycleState is S_OFF
+     */
+  }
+  
+  /***************** Timer Events ****************/
+  event void OnTimer.fired() {
+    if(call DutyCycleState.getState() == S_ON) {
+      if(call RadioPowerState.getState() == S_OFF) {
+        call CheckState.forceState(S_ON);
+        ccaChecks = 0;
+        
+        /*
+         * The MicaZ, running on an external oscillator I think, and
+         * returning the microcontroller out of a sleep state to immediately
+         * perform an ADC conversion, sucks.  The first ADC conversion out
+         * of a sleep state lasts about a second.  We don't want the radio
+         * on that long.  Like the CC1000 RSSI pulse check implementation
+         * done in the Rincon CC1000Radio stack, we will perform
+         * a single ADC conversion and then flip on the radio to check
+         * the channel.
+         */
+         post getCca();
+        
+      } else {
+        // Someone else turned on the radio, try again in awhile
+        call OnTimer.startOneShot(sleepInterval);
+      }
+    }
+  }
+  
+  /***************** SubControl Events ****************/
+  event void SubControl.startDone(error_t error) {
+    if(call DutyCycleState.getState() == S_ON && error) {
+      // My responsibility to try again
+      post startRadio();
+      return;
+    }
+    
+    call RadioPowerState.forceState(S_ON);
+    //call Leds.led2On();
+    
+    if(call DutyCycleState.getState() == S_ON) {
+      if(call CheckState.getState() == S_ON) {
+        post getCca();
+      }
+      
+    } else {
+      // Must have turned the radio on manually
+      signal SplitControl.startDone(SUCCESS);
+    }
+  }
+  
+  event void SubControl.stopDone(error_t error) {
+    if(error && call DutyCycleState.getState() == S_ON) {
+      // My responsibility to try again
+      post stopRadio();
+      return;
+    }
+    
+    detectionForced = FALSE;
+    call RadioPowerState.forceState(S_OFF);
+    //call Leds.led2Off();
+    
+    if(call DutyCycleState.getState() == S_ON) {
+      call OnTimer.startOneShot(sleepInterval);
+
+    } else {
+      // Must have turned off the radio manually
+      signal SplitControl.stopDone(error);
+    }
+    
+  }
+  
+  
+  /***************** Tasks ****************/
+  task void stopRadio() {
+    if(call DutyCycleState.getState() == S_ON && !detectionForced) {
+      if(call SubControl.stop() != SUCCESS) {
+        // Already stopped?
+        call OnTimer.startOneShot(sleepInterval);
+      }
+    }
+  }
+  
+  task void startRadio() {
+    if(call DutyCycleState.getState() == S_ON) {
+      if(call SubControl.start() != SUCCESS) {
+        post startRadio();
+      }
+    }
+  }
+  
+  task void getCca() {
+    uint8_t detects = 0;
+    if(call DutyCycleState.getState() == S_ON) {
+      
+      ccaChecks++;
+      if(ccaChecks == 1) {
+        // Microcontroller is ready, turn on the radio and sample a few times
+        post startRadio();
+        return;
+      }
+
+      atomic {
+        for( ; ccaChecks < MAX_LPL_CCA_CHECKS && call SendState.isIdle(); ccaChecks++) {
+          if(!call CC2420Cca.isChannelClear() || detectionForced) {
+            detects++;
+            if(detects > MIN_SAMPLES_BEFORE_DETECT) {
+              signal CC2420DutyCycle.detected(); 
+              return;
+            }
+            // Leave the radio on for upper layers to perform some transaction
+          }
+        }
+      }
+      
+      call CheckState.toIdle();
+      if(call SendState.isIdle()) {
+        post stopRadio();
+      }
+    }  
+  }
+  
+  /**************** Defaults ****************/
+  default event void CC2420DutyCycle.detected() {
+  }
+
+
+  default event void SplitControl.startDone(error_t error) {
+  }
+  
+  default event void SplitControl.stopDone(error_t error) {
+  }
+}
+
+
diff --git a/tos/chips/cc2420/CC2420LplDummyC.nc b/tos/chips/cc2420/CC2420LplDummyC.nc
new file mode 100644 (file)
index 0000000..b8ef1e6
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Dummy low power listening interface used when LowPowerListening is not
+ * compiled in with the application.
+ * Sleep interval is always 0, and duty cycle is always 100%
+ * @author David Moss
+ */
+configuration CC2420LplDummyC {
+  provides {
+    interface Send;
+    interface Receive;
+    interface LowPowerListening;
+    interface SplitControl;
+    interface State as SendState;
+  }
+  
+  uses {
+    interface Send as SubSend;
+    interface Receive as SubReceive;
+    interface SplitControl as SubControl;
+  }
+}
+
+implementation {
+  components CC2420LplDummyP;
+  components new StateC();
+  
+  Send = SubSend;
+  Receive = SubReceive;
+  SplitControl = SubControl;
+  LowPowerListening = CC2420LplDummyP;
+  SendState = StateC;
+  
+}
+
diff --git a/tos/chips/cc2420/CC2420LplDummyP.nc b/tos/chips/cc2420/CC2420LplDummyP.nc
new file mode 100644 (file)
index 0000000..97bdd0c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Dummy low power listening interface used when LowPowerListening is not
+ * compiled in with the application.
+ * Sleep interval is always 0, and duty cycle is always 100%
+ * @author David Moss
+ */
+module CC2420LplDummyP {
+  provides {
+    interface LowPowerListening;
+  }
+}
+
+implementation {
+
+  command void LowPowerListening.setLocalSleepInterval(uint16_t sleepIntervalMs) {
+  }
+  
+  command uint16_t LowPowerListening.getLocalSleepInterval() {
+    return 0;
+  }
+  
+  command void LowPowerListening.setLocalDutyCycle(uint16_t dutyCycle) {
+  }
+  
+  command uint16_t LowPowerListening.getLocalDutyCycle() {
+    return 10000;
+  }
+  
+  command void LowPowerListening.setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs) {
+  }
+  
+  command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg) {
+    return 0;
+  }
+  
+  command void LowPowerListening.setRxDutyCycle(message_t *msg, uint16_t dutyCycle) {
+  }
+  
+  command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg) {
+    return 10000;
+  }
+  
+  command uint16_t LowPowerListening.dutyCycleToSleepInterval(uint16_t dutyCycle) {
+    return 0;
+  }
+  
+  command uint16_t LowPowerListening.sleepIntervalToDutyCycle(uint16_t sleepInterval) {
+    return 10000;
+  }
+  
+}
+
diff --git a/tos/chips/cc2420/CC2420NoAckLpl.h b/tos/chips/cc2420/CC2420NoAckLpl.h
new file mode 100644 (file)
index 0000000..7d00c50
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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 David Moss
+  */
+#ifndef CC2420NOACKLPL_H
+#define CC2420NOACKLPL_H
+
+/**
+ * Low Power Listening Send States
+ */
+typedef enum {
+  S_LPL_NOT_SENDING,    // DEFAULT
+  S_LPL_FIRST_MESSAGE,  // 1. Initial backoffs, no acks, full CCA
+  S_LPL_LAST_MESSAGE,   // 3. No backoffs, acknowledgement request, no CCA
+} lpl_sendstate_t;
+
+/**
+ * Amount of time, in milliseconds, to keep the radio on after
+ * a successful receive addressed to this node
+ * You don't want this too fast, or the off timer can accidentally
+ * fire due to delays in the system.  The radio would shut off and
+ * possibly need to turn back on again immediately, which can lock up
+ * the CC2420 if it's in the middle of doing something.
+ */
+#ifndef DELAY_AFTER_RECEIVE
+#define DELAY_AFTER_RECEIVE 100
+#endif
+
+
+/**
+ * This is a measured value of the time in ms the radio is actually on
+ * We round this up to err on the side of better performance ratios
+ */
+#ifndef DUTY_ON_TIME
+#define DUTY_ON_TIME 1
+#endif
+
+/**
+ * The maximum number of CCA checks performed on each wakeup.
+ * The value is relative to the speed of transmission and speed of the
+ * microcontroller executing the receive check loop. If the transmission
+ * is ultimately back-to-back without break or the microcontroller
+ * is slow, we can do less samples. If the microcontroller is very 
+ * fast, we must do more samples.  Keep in mind the datasheet also
+ * specifies that the CCA pin is valid after 8 symbol periods of
+ * the radio being on.
+ */
+#ifndef MAX_LPL_CCA_CHECKS
+
+#if defined(PLATFORM_TELOSB)
+#define MAX_LPL_CCA_CHECKS 12
+#else
+#define MAX_LPL_CCA_CHECKS 12
+#endif
+
+#endif
+
+/**
+ * The minimum number of samples that must be taken in CC2420DutyCycleP
+ * that show the channel is not clear before a detection event is issued
+ */
+#ifndef MIN_SAMPLES_BEFORE_DETECT
+#define MIN_SAMPLES_BEFORE_DETECT 1
+#endif
+
+#endif
+
diff --git a/tos/chips/cc2420/CC2420NoAckLplC.nc b/tos/chips/cc2420/CC2420NoAckLplC.nc
new file mode 100644 (file)
index 0000000..e733b98
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Low Power Listening for the CC2420
+ * This is experimental because:
+ *  > Acknowledgements really don't work at all, even on the last message
+ *    which is supposed to return an acknowledgement from the receiver.
+ *  > The CRC is not yet manually calculated, so the entire continuous
+ *    modulation doesn't contain any useful information.
+ *    By adding in the CRC calcuation functionality to TransmitP,
+ *    we can better support mobile nodes that walk out of range and
+ *    lossy connections.  We could also put receivers back to sleep that
+ *    the "preamble" is not destined for, because the actual preamble
+ *    would have an address associated with it.
+ *
+ * @author David Moss
+ */
+#include "CC2420NoAckLpl.h"
+#warning "*** USING EXPERIMENTAL NO-ACK LOW POWER LISTENING LAYER"
+
+configuration CC2420NoAckLplC {
+  provides {
+    interface LowPowerListening;
+    interface Send;
+    interface Receive;
+    interface SplitControl;
+    interface State as SendState;
+  }
+  
+  uses { 
+    interface Send as SubSend;
+    interface Receive as SubReceive;
+    interface SplitControl as SubControl;
+  }
+}
+
+implementation {
+  components MainC,
+      CC2420NoAckLplP,
+      CC2420DutyCycleC,
+      CC2420ActiveMessageC,
+      CC2420CsmaC,
+      CC2420TransmitC,
+      CC2420PacketC,
+      RandomC,
+      LedsC,
+      new StateC() as SendStateC,
+      new StateC() as RadioStateC,
+      new TimerMilliC() as OffTimerC;
+  
+  LowPowerListening = CC2420NoAckLplP;
+  Send = CC2420NoAckLplP;
+  Receive = CC2420NoAckLplP;
+  SplitControl = CC2420DutyCycleC;
+  SendState = SendStateC;
+  
+  SubControl = CC2420NoAckLplP.SubControl;
+  SubReceive = CC2420NoAckLplP.SubReceive;
+  SubSend = CC2420NoAckLplP.SubSend;
+  
+  
+  MainC.SoftwareInit -> CC2420NoAckLplP;
+  
+  CC2420NoAckLplP.Random -> RandomC;
+  CC2420NoAckLplP.SendState -> SendStateC;
+  CC2420NoAckLplP.RadioState -> RadioStateC;
+  CC2420NoAckLplP.SplitControlState -> CC2420DutyCycleC;
+  CC2420NoAckLplP.CC2420Cca -> CC2420TransmitC;
+  CC2420NoAckLplP.OffTimer -> OffTimerC;
+  CC2420NoAckLplP.CC2420DutyCycle -> CC2420DutyCycleC;
+  CC2420NoAckLplP.Resend -> CC2420TransmitC;
+  CC2420NoAckLplP.PacketAcknowledgements -> CC2420ActiveMessageC;
+  CC2420NoAckLplP.AMPacket -> CC2420ActiveMessageC;
+  CC2420NoAckLplP.CC2420Packet -> CC2420PacketC;
+  CC2420NoAckLplP.RadioBackoff -> CC2420CsmaC;
+  CC2420NoAckLplP.Leds -> LedsC;
+  
+}
+
diff --git a/tos/chips/cc2420/CC2420NoAckLplP.nc b/tos/chips/cc2420/CC2420NoAckLplP.nc
new file mode 100644 (file)
index 0000000..8657af1
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Low Power Listening for the CC2420.  This component is responsible for
+ * delivery of an LPL packet, and for turning off the radio when the radio
+ * has run out of tasks.
+ *
+ * The CC2420DutyCycle component is responsible for duty cycling the radio
+ * and performing receive detections.
+ *
+ * @author David Moss
+ */
+
+#include "CC2420NoAckLpl.h"
+
+module CC2420NoAckLplP {
+  provides {
+    interface Init;
+    interface LowPowerListening;
+    interface Send;
+    interface Receive;
+  }
+  
+  uses {
+    interface Send as SubSend;
+    interface CC2420Transmit as Resend;
+    interface Receive as SubReceive;
+    interface AMPacket;
+    interface CC2420Cca;
+    interface SplitControl as SubControl;
+    interface CC2420DutyCycle;
+    interface CC2420Packet;
+    interface PacketAcknowledgements;
+    interface RadioBackoff[am_id_t amId];
+    interface State as SendState;
+    interface State as RadioState;
+    interface State as SplitControlState;
+    interface Random;
+    interface Timer<TMilli> as OffTimer;
+    interface Leds;
+  }
+}
+
+implementation {
+  
+  /** The message currently being sent */
+  message_t *currentSendMsg;
+  
+  /** The length of the current send message */
+  uint8_t currentSendLen;
+  
+  /** TRUE if the radio is duty cycling and not always on */
+  bool dutyCycling;
+  
+  /** TRUE if we have received a message after the last detect */
+  bool receivedMsg;
+  
+  
+  /**
+   * Radio State
+   */
+  enum {
+    S_OFF,
+    S_ON,
+  };
+  
+  /**
+   * Send States
+   */
+  enum {
+    S_IDLE,
+    S_SENDING,
+  };
+  
+  enum {
+    ONE_MESSAGE = 0,
+  };
+  
+  
+  /***************** Prototypes ***************/
+  task void send();
+  task void resend();
+  task void startRadio();
+  task void stopRadio();
+  task void detectTxDone();
+  
+  void initializeSend();
+  void startOffTimer();
+  uint16_t getActualDutyCycle(uint16_t dutyCycle);
+  
+  /***************** Init Commands ***************/
+  command error_t Init.init() {
+    dutyCycling = FALSE;
+    return SUCCESS;
+  }
+  
+  /***************** LowPowerListening Commands ***************/
+  /**
+   * Set this this node's radio sleep interval, in milliseconds.
+   * Once every interval, the node will sleep and perform an Rx check 
+   * on the radio.  Setting the sleep interval to 0 will keep the radio
+   * always on.
+   *
+   * This is the equivalent of setting the local duty cycle rate.
+   *
+   * @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
+   */
+  command void LowPowerListening.setLocalSleepInterval(
+      uint16_t sleepIntervalMs) {
+    call CC2420DutyCycle.setSleepInterval(sleepIntervalMs);
+  }
+  
+  /**
+   * @return the local node's sleep interval, in [ms]
+   */
+  command uint16_t LowPowerListening.getLocalSleepInterval() {
+    return call CC2420DutyCycle.getSleepInterval();
+  }
+  
+  /**
+   * Set this node's radio duty cycle rate, in units of [percentage*100].
+   * For example, to get a 0.05% duty cycle,
+   * <code>
+   *   call LowPowerListening.setDutyCycle(5);
+   * </code>
+   *
+   * For a 100% duty cycle (always on),
+   * <code>
+   *   call LowPowerListening.setDutyCycle(10000);
+   * </code>
+   *
+   * This is the equivalent of setting the local sleep interval explicitly.
+   * 
+   * @param dutyCycle The duty cycle percentage, in units of [percentage*100]
+   */
+  command void LowPowerListening.setLocalDutyCycle(uint16_t dutyCycle) {
+    call CC2420DutyCycle.setSleepInterval(
+        call LowPowerListening.dutyCycleToSleepInterval(dutyCycle));
+  }
+  
+  /**
+   * @return this node's radio duty cycle rate, in units of [percentage*100]
+   */
+  command uint16_t LowPowerListening.getLocalDutyCycle() {
+    return call LowPowerListening.sleepIntervalToDutyCycle(
+        call CC2420DutyCycle.getSleepInterval());
+  }
+  
+  
+  /**
+   * Configure this outgoing message so it can be transmitted to a neighbor mote
+   * with the specified Rx sleep interval.
+   * @param msg Pointer to the message that will be sent
+   * @param sleepInterval The receiving node's sleep interval, in [ms]
+   */
+  command void LowPowerListening.setRxSleepInterval(message_t *msg, 
+      uint16_t sleepIntervalMs) {
+    (call CC2420Packet.getMetadata(msg))->rxInterval = sleepIntervalMs;
+  }
+  
+  /**
+   * @return the destination node's sleep interval configured in this message
+   */
+  command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg) {
+    return (call CC2420Packet.getMetadata(msg))->rxInterval;
+  }
+  
+  /**
+   * Configure this outgoing message so it can be transmitted to a neighbor mote
+   * with the specified Rx duty cycle rate.
+   * Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25.
+   * 
+   * @param msg Pointer to the message that will be sent
+   * @param dutyCycle The duty cycle of the receiving mote, in units of 
+   *     [percentage*100]
+   */
+  command void LowPowerListening.setRxDutyCycle(message_t *msg, 
+      uint16_t dutyCycle) {
+    (call CC2420Packet.getMetadata(msg))->rxInterval =
+        call LowPowerListening.dutyCycleToSleepInterval(dutyCycle);
+  }
+  
+    
+  /**
+   * @return the destination node's duty cycle configured in this message
+   *     in units of [percentage*100]
+   */
+  command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg) {
+    return call LowPowerListening.sleepIntervalToDutyCycle(
+        (call CC2420Packet.getMetadata(msg))->rxInterval);
+  }
+  
+  /**
+   * Convert a duty cycle, in units of [percentage*100], to
+   * the sleep interval of the mote in milliseconds
+   * @param dutyCycle The duty cycle in units of [percentage*100]
+   * @return The equivalent sleep interval, in units of [ms]
+   */
+  command uint16_t LowPowerListening.dutyCycleToSleepInterval(
+      uint16_t dutyCycle) {
+    dutyCycle = getActualDutyCycle(dutyCycle);
+    
+    if(dutyCycle == 10000) {
+      return 0;
+    }
+    
+    return (DUTY_ON_TIME * (10000 - dutyCycle)) / dutyCycle;
+  }
+  
+  /**
+   * Convert a sleep interval, in units of [ms], to a duty cycle
+   * in units of [percentage*100]
+   * @param sleepInterval The sleep interval in units of [ms]
+   * @return The duty cycle in units of [percentage*100]
+   */
+  command uint16_t LowPowerListening.sleepIntervalToDutyCycle(
+      uint16_t sleepInterval) {
+    if(sleepInterval == 0) {
+      return 10000;
+    }
+    
+    return getActualDutyCycle((DUTY_ON_TIME * 10000) 
+        / (sleepInterval + DUTY_ON_TIME));
+  }
+
+  
+  /***************** Send Commands ***************/
+  /**
+   * Each call to this send command gives the message a single
+   * DSN that does not change for every copy of the message
+   * sent out.  For messages that are not acknowledged, such as
+   * a broadcast address message, the receiving end does not
+   * signal receive() more than once for that message.
+   */
+  command error_t Send.send(message_t *msg, uint8_t len) {
+    if(call SplitControlState.getState() == S_OFF) {
+      // Everything is off right now, start SplitControl and try again
+      return EOFF;
+    }
+    
+    if(call SendState.requestState(S_LPL_FIRST_MESSAGE) == SUCCESS) {
+      currentSendMsg = msg;
+      currentSendLen = len;
+      
+      // In case our off timer is running...
+      call OffTimer.stop();
+      
+      if(call RadioState.getState() == S_ON) {
+        initializeSend();
+        return SUCCESS;
+        
+      } else {
+        post startRadio();
+      }
+      
+      return SUCCESS;
+    }
+    
+    return FAIL;
+  }
+
+  command error_t Send.cancel(message_t *msg) {
+    if(currentSendMsg == msg) {
+      call SendState.toIdle();
+      startOffTimer();
+      return call SubSend.cancel(msg);
+    }
+    
+    return FAIL;
+  }
+  
+  
+  command uint8_t Send.maxPayloadLength() {
+    return call SubSend.maxPayloadLength();
+  }
+
+  command void *Send.getPayload(message_t* msg) {
+    return call SubSend.getPayload(msg);
+  }
+  
+  /***************** Receive Commands ***************/
+  command void *Receive.getPayload(message_t* msg, uint8_t* len) {
+    return call SubReceive.getPayload(msg, len);
+  }
+
+  command uint8_t Receive.payloadLength(message_t* msg) {
+    return call SubReceive.payloadLength(msg);
+  }
+
+
+  /***************** DutyCycle Events ***************/
+  /**
+   * A transmitter was detected.  You must now take action to
+   * turn the radio off when the transaction is complete.
+   */
+  event void CC2420DutyCycle.detected() {
+    // At this point, the duty cycling has been disabled temporary
+    // and it will be this component's job to turn the radio back off
+    // Wait long enough to see if we actually receive a packet
+    receivedMsg = FALSE;
+    post detectTxDone();
+  }
+  
+  
+  /***************** SubControl Events ***************/
+  event void SubControl.startDone(error_t error) {
+    if(!error) {
+      call RadioState.forceState(S_ON);
+      
+      if(call SendState.getState() == S_LPL_FIRST_MESSAGE) {
+        initializeSend();
+      }
+    }
+  }
+  
+  event void SubControl.stopDone(error_t error) {
+    if(!error) {
+      call RadioState.forceState(S_OFF);
+
+      if(call SendState.getState() == S_LPL_FIRST_MESSAGE) {
+        // We're in the middle of sending a message; start the radio back up
+        post startRadio();
+        
+      } else {
+        call OffTimer.stop();
+      }
+    }
+  }
+  
+  /***************** SubSend Events ***************/
+  event void SubSend.sendDone(message_t* msg, error_t error) {
+    switch(call SendState.getState()) {
+    case S_LPL_FIRST_MESSAGE:
+      call SendState.forceState(S_LPL_LAST_MESSAGE);
+      call PacketAcknowledgements.requestAck(msg);
+      post send();
+      return;
+    
+    case S_LPL_LAST_MESSAGE:
+      // Execute past the switch statement
+      break;
+      
+    default:
+      // Execute past the switch statement
+      break;
+    }
+    
+    call SendState.toIdle();
+    startOffTimer();
+    signal Send.sendDone(msg, error);
+  }
+  
+  /***************** SubReceive Events ***************/
+  /**
+   * If the received message is new, we signal the receive event and
+   * start the off timer.  If the last message we received had the same
+   * DSN as this message, then the chances are pretty good
+   * that this message should be ignored, especially if the destination address
+   * as the broadcast address
+   */
+  event message_t *SubReceive.receive(message_t* msg, void* payload, 
+      uint8_t len) {
+    
+    /**
+     * Now wait for the next moment the channel is free before passing the 
+     * packet up, and keep the radio on that whole time.  That's when our
+     * transmitter is done transmitting, LPL or not.
+     */
+    
+    call CC2420DutyCycle.forceDetected();
+    receivedMsg = TRUE;
+    startOffTimer();
+    return signal Receive.receive(msg, payload, len);
+  }
+  
+  /***************** Timer Events ****************/
+  event void OffTimer.fired() {
+    /*
+     * Only stop the radio if the radio is supposed to be off permanently
+     * or if the duty cycle is on and our sleep interval is not 0
+     */
+    if(call SplitControlState.getState() == S_OFF
+        || (call CC2420DutyCycle.getSleepInterval() > 0
+            && call SplitControlState.getState() == S_ON
+                && call SendState.getState() == S_LPL_NOT_SENDING)) { 
+      post stopRadio();
+    }
+  }
+  
+  /***************** RadioBackoff Events ****************/
+  /**  
+   * Request for input on the initial backoff
+   * Reply using setInitialBackoff(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void RadioBackoff.requestInitialBackoff[am_id_t amId](message_t *msg) {
+  }
+  
+  /**
+   * Request for input on the congestion backoff
+   * Reply using setCongestionBackoff(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void RadioBackoff.requestCongestionBackoff[am_id_t amId](message_t *msg) {
+  }
+  
+  /**
+   * Request for input on the low power listening backoff
+   * This should be somewhat random, but as short as possible
+   * Reply using setLplBackoff(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void RadioBackoff.requestLplBackoff[am_id_t amId](message_t *msg) {
+  }
+  
+  /**
+   * Request for input on whether or not to use CCA on the outbound packet.
+   * Replies should come in the form of setCca(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void RadioBackoff.requestCca[am_id_t amId](message_t *msg) {
+    if(call SendState.getState() == S_LPL_FIRST_MESSAGE) {
+      call RadioBackoff.setCca[amId](TRUE);
+
+    } else if(call SendState.getState() == S_LPL_LAST_MESSAGE) {
+      call RadioBackoff.setCca[amId](FALSE);
+    }
+  }
+  
+  
+  /***************** Resend Events ****************/
+  /**
+   * Signal that a message has been sent
+   *
+   * @param p_msg message to send.
+   * @param error notifaction of how the operation went.
+   */
+  async event void Resend.sendDone( message_t* p_msg, error_t error ) {
+    // This is actually caught by SubSend.sendDone
+  }
+  
+  
+  /***************** Tasks ***************/
+  task void send() {
+    if(call SubSend.send(currentSendMsg, currentSendLen) != SUCCESS) {
+      post send();
+    }
+  }
+  
+  task void resend() {
+    if(call Resend.resend(FALSE) != SUCCESS) {
+      post resend();
+    }
+  }
+  
+  task void startRadio() {
+    if(call SubControl.start() != SUCCESS) {
+      post startRadio();
+    }
+  }
+  
+  task void stopRadio() {
+    if(call SendState.getState() == S_LPL_NOT_SENDING) {
+      if(call SubControl.stop() != SUCCESS) {
+        post stopRadio();
+      }
+    }
+  }
+  
+  /**
+   * Don't start the off-timer until the end of the transmitter's transmission.
+   */
+  task void detectTxDone() {
+    uint16_t clearChannelSamples;
+    
+    if(call SendState.getState() != S_LPL_FIRST_MESSAGE
+        && call SendState.getState() != S_LPL_LAST_MESSAGE
+        && !receivedMsg) {
+      for(clearChannelSamples = 0; clearChannelSamples < MAX_LPL_CCA_CHECKS * 8; clearChannelSamples++) {
+        // In one straight shot, sample the channel repetitively and verify that
+        // the transmitter is done transmitting
+        if(!call CC2420Cca.isChannelClear()) {
+          // Nope, start over from the beginning.
+          post detectTxDone();
+          return;
+        }
+      }
+
+      // Transmitter done, turn the radio off in a few...
+      startOffTimer();
+    }
+  }
+  
+  /***************** Functions ***************/
+  void initializeSend() {
+    if(call LowPowerListening.getRxSleepInterval(currentSendMsg) 
+        > ONE_MESSAGE) {
+      call PacketAcknowledgements.noAck(currentSendMsg);
+    }
+    
+    post send();
+  }
+  
+  
+  void startOffTimer() {
+    call OffTimer.startOneShot(DELAY_AFTER_RECEIVE);
+  }
+  
+  /**
+   * Check the bounds on a given duty cycle
+   * We're never over 100%, and we're never at 0%
+   */
+  uint16_t getActualDutyCycle(uint16_t dutyCycle) {
+    if(dutyCycle > 10000) {
+      return 10000;
+    } else if(dutyCycle == 0) {
+      return 1;
+    }
+    
+    return dutyCycle;
+  }  
+}
+
index 52ce70d77be1dbb05571891b0f7d4f4484d6aa7f..2c9559783798c02a1c685cc83b88bac7332be6d1 100644 (file)
@@ -31,7 +31,8 @@
 
 /**
  * @author Jonathan Hui <jhui@archrock.com>
- * @version $Revision$ $Date$
+ * @author David Moss
+ * @author Chad Metcalf
  */
 
 #include "message.h"
@@ -70,4 +71,13 @@ interface CC2420Packet {
    */
   async command uint8_t getLqi( message_t* p_msg );
   
+  /**
+   * @return pointer to the cc2420_header_t of the given message
+   */
+  async command cc2420_header_t *getHeader(message_t *msg);
+  
+  /**
+   * @return pointer to the cc2420_metadata_t of the given message
+   */
+  async command cc2420_metadata_t *getMetadata(message_t *msg);
 }
index e06402332b9a3020aec04e8692e341c445196183..9241185fca343b6bfc2e2e767bd8647488062cf7 100644 (file)
 
 /**
  * @author Jonathan Hui <jhui@archrock.com>
- * @version $Revision$ $Date$
+ * @author David Moss
+ * @author Chad Metcalf
  */
 
 #include "IEEE802154.h"
+#include "message.h"
 
 module CC2420PacketC {
 
@@ -45,44 +47,44 @@ module CC2420PacketC {
 
 implementation {
 
-  cc2420_header_t* getHeader( message_t* msg ) {
+  async command cc2420_header_t *CC2420Packet.getHeader( message_t* msg ) {
     return (cc2420_header_t*)( msg->data - sizeof( cc2420_header_t ) );
   }
 
-  cc2420_metadata_t* getMetadata( message_t* msg ) {
+  async command cc2420_metadata_t *CC2420Packet.getMetadata( message_t* msg ) {
     return (cc2420_metadata_t*)msg->metadata;
   }
 
   async command error_t Acks.requestAck( message_t* p_msg ) {
-    getHeader( p_msg )->fcf |= 1 << IEEE154_FCF_ACK_REQ;
+    (call CC2420Packet.getHeader( p_msg ))->fcf |= 1 << IEEE154_FCF_ACK_REQ;
     return SUCCESS;
   }
 
   async command error_t Acks.noAck( message_t* p_msg ) {
-    getHeader( p_msg )->fcf &= ~(1 << IEEE154_FCF_ACK_REQ);
+    (call CC2420Packet.getHeader( p_msg ))->fcf &= ~(1 << IEEE154_FCF_ACK_REQ);
     return SUCCESS;
   }
 
   async command bool Acks.wasAcked( message_t* p_msg ) {
-    return getMetadata( p_msg )->ack;
+    return (call CC2420Packet.getMetadata( p_msg ))->ack;
   }
 
   async command void CC2420Packet.setPower( message_t* p_msg, uint8_t power ) {
     if ( power > 31 )
       power = 31;
-    getMetadata( p_msg )->tx_power = power;
+    (call CC2420Packet.getMetadata( p_msg ))->tx_power = power;
   }
 
   async command uint8_t CC2420Packet.getPower( message_t* p_msg ) {
-    return getMetadata( p_msg )->tx_power;
+    return (call CC2420Packet.getMetadata( p_msg ))->tx_power;
   }
    
   async command int8_t CC2420Packet.getRssi( message_t* p_msg ) {
-    return getMetadata( p_msg )->rssi;
+    return (call CC2420Packet.getMetadata( p_msg ))->rssi;
   }
 
   async command error_t CC2420Packet.getLqi( message_t* p_msg ) {
-    return getMetadata( p_msg )->lqi;
+    return (call CC2420Packet.getMetadata( p_msg ))->lqi;
   }
 
 }
index b1762e88159f4e8318fbc1ecd953fb943285c37e..452aad29b81fce0304306f8fc324cd4d02fb10b6 100644 (file)
 
 configuration CC2420ReceiveC {
 
-  provides interface Init;
-  provides interface AsyncStdControl;
+  provides interface StdControl;
   provides interface CC2420Receive;
   provides interface Receive;
 
 }
 
 implementation {
-
+  components MainC;
   components CC2420ReceiveP;
+  components CC2420PacketC;
+  components ActiveMessageAddressC;
   components new CC2420SpiC() as Spi;
 
   components HplCC2420PinsC as Pins;
@@ -56,18 +57,21 @@ implementation {
   components LedsC as Leds;
   CC2420ReceiveP.Leds -> Leds;
 
-  Init = CC2420ReceiveP;
-  AsyncStdControl = CC2420ReceiveP;
+  StdControl = CC2420ReceiveP;
   CC2420Receive = CC2420ReceiveP;
   Receive = CC2420ReceiveP;
 
+  MainC.SoftwareInit -> CC2420ReceiveP;
+  
   CC2420ReceiveP.CSN -> Pins.CSN;
   CC2420ReceiveP.FIFO -> Pins.FIFO;
   CC2420ReceiveP.FIFOP -> Pins.FIFOP;
   CC2420ReceiveP.InterruptFIFOP -> InterruptsC.InterruptFIFOP;
-
   CC2420ReceiveP.SpiResource -> Spi;
   CC2420ReceiveP.RXFIFO -> Spi.RXFIFO;
   CC2420ReceiveP.SFLUSHRX -> Spi.SFLUSHRX;
+  CC2420ReceiveP.SACK -> Spi.SACK;
+  CC2420ReceiveP.CC2420Packet -> CC2420PacketC;
+  CC2420ReceiveP.amAddress -> ActiveMessageAddressC;
 
 }
index c318e1d8ae69665e87a58549d34e1f12d72002a8..96df09e7d59e52de13362221a2f88e4d462e1fe2 100644 (file)
 
 /**
  * @author Jonathan Hui <jhui@archrock.com>
+ * @author David Moss
+ * @author Jung Il Choi
  * @version $Revision$ $Date$
  */
 
 module CC2420ReceiveP {
 
   provides interface Init;
-  provides interface AsyncStdControl;
+  provides interface StdControl;
   provides interface CC2420Receive;
   provides interface Receive;
 
@@ -50,9 +52,10 @@ module CC2420ReceiveP {
   uses interface CC2420Fifo as RXFIFO;
   uses interface CC2420Strobe as SACK;
   uses interface CC2420Strobe as SFLUSHRX;
-
+  uses interface CC2420Packet;
+  
   uses interface Leds;
-
+  uses async command am_addr_t amAddress();
 }
 
 implementation {
@@ -70,100 +73,129 @@ implementation {
   };
 
   uint16_t m_timestamp_queue[ TIMESTAMP_QUEUE_SIZE ];
-  uint8_t m_timestamp_head, m_timestamp_size;
+  
+  uint8_t m_timestamp_head;
+  
+  uint8_t m_timestamp_size;
+  
   uint8_t m_missed_packets;
 
+  bool fallingEdgeEnabled;
+  
   norace uint8_t m_bytes_left;
+  
   norace message_t* m_p_rx_buf;
 
   message_t m_rx_buf;
+  
   cc2420_receive_state_t m_state;
-
+  
+  /***************** Prototypes ****************/
+  void reset_state();
   void beginReceive();
   void receive();
   void waitForNextPacket();
-  task void receiveDone_task();
-
-  cc2420_header_t* getHeader( message_t* msg ) {
-    return (cc2420_header_t*)( msg->data - sizeof( cc2420_header_t ) );
-  }
+  void flush();
   
-  cc2420_metadata_t* getMetadata( message_t* msg ) {
-    return (cc2420_metadata_t*)msg->metadata;
-  }
+  task void receiveDone_task();
   
+  /***************** Init Commands ****************/
   command error_t Init.init() {
+    fallingEdgeEnabled = FALSE;
     m_p_rx_buf = &m_rx_buf;
     return SUCCESS;
   }
 
-  void reset_state() {
-    m_bytes_left = RXFIFO_SIZE;
-    m_timestamp_head = m_timestamp_size = 0;
-    m_missed_packets = 0;
-  }
-
-  async command error_t AsyncStdControl.start() {
+  /***************** StdControl ****************/
+  command error_t StdControl.start() {
     atomic {
       reset_state();
       m_state = S_STARTED;
+        
+      // Warning: MicaZ problems have been encountered with the following line
+      // after it follows a .disable command
       call InterruptFIFOP.enableFallingEdge();
     }
     return SUCCESS;
   }
 
-  async command error_t AsyncStdControl.stop() {
+
+  
+  command error_t StdControl.stop() {
     atomic {
       m_state = S_STOPPED;
+      reset_state();
+      
+      call SpiResource.release();
+      
+      // Warning: MicaZ problems have been encountered with the following line
+      // followed by a re-enable.  The re-enable doesn't occur.
       call InterruptFIFOP.disable();
     }
     return SUCCESS;
   }
 
+  /***************** Receive Commands ****************/
+  command void* Receive.getPayload(message_t* m, uint8_t* len) {
+    if (len != NULL) {
+      *len = ((uint8_t*) (call CC2420Packet.getHeader( m_p_rx_buf )))[0];
+    }
+    return m->data;
+  }
+
+  command uint8_t Receive.payloadLength(message_t* m) {
+    uint8_t* buf = (uint8_t*)(call CC2420Packet.getHeader( m_p_rx_buf ));
+    return buf[0];
+  }
+  
+  
+  /***************** CC2420Receive Commands ****************/
+  /**
+   * Start frame delimiter signifies the beginning/end of a packet
+   * See the CC2420 datasheet for details.
+   */
   async command void CC2420Receive.sfd( uint16_t time ) {
     if ( m_timestamp_size < TIMESTAMP_QUEUE_SIZE ) {
       uint8_t tail =  ( ( m_timestamp_head + m_timestamp_size ) % 
-                       TIMESTAMP_QUEUE_SIZE );
+                        TIMESTAMP_QUEUE_SIZE );
       m_timestamp_queue[ tail ] = time;
       m_timestamp_size++;
     }
   }
 
   async command void CC2420Receive.sfd_dropped() {
-    if ( m_timestamp_size )
+    if ( m_timestamp_size ) {
       m_timestamp_size--;
+    }
   }
 
+
+  /***************** InterruptFIFOP Events ****************/
   async event void InterruptFIFOP.fired() {
-    if ( m_state == S_STARTED )
+    if ( m_state == S_STARTED ) {
       beginReceive();
-    else
+      
+    } else {
       m_missed_packets++;
+    }
   }
   
-  void beginReceive() { 
-    m_state = S_RX_HEADER;
-    if ( call SpiResource.immediateRequest() == SUCCESS )
-      receive();
-    else
-      call SpiResource.request();
-  }
   
+  /***************** SpiResource Events ****************/
   event void SpiResource.granted() {
     receive();
   }
-
-  void receive() {
-    call CSN.clr();
-    call RXFIFO.beginRead( (uint8_t*)getHeader( m_p_rx_buf ), 1 );
-  }
-
+  
+  /***************** RXFIFO Events ****************/
+  /**
+   * We received some bytes from the SPI bus.  Process them in the context
+   * of the state we're in
+   */
   async event void RXFIFO.readDone( uint8_t* rx_buf, uint8_t rx_len,
-                                   error_t error ) {
-
-    cc2420_header_t* header = getHeader( m_p_rx_buf );
-    cc2420_metadata_t* metadata = getMetadata( m_p_rx_buf );
-    uint8_t* buf = (uint8_t*)header;
+                                    error_t error ) {
+    cc2420_header_t* header = call CC2420Packet.getHeader( m_p_rx_buf );
+    cc2420_metadata_t* metadata = call CC2420Packet.getMetadata( m_p_rx_buf );
+    uint8_t* buf = (uint8_t*) header;
     uint8_t length = buf[ 0 ];
 
     switch( m_state ) {
@@ -171,47 +203,67 @@ implementation {
     case S_RX_HEADER:
       m_state = S_RX_PAYLOAD;
       if ( length + 1 > m_bytes_left ) {
-       reset_state();
-       call CSN.set();
-       call CSN.clr();
-       call SFLUSHRX.strobe();
-       call SFLUSHRX.strobe();
-       call CSN.set();
-       call SpiResource.release();
-       waitForNextPacket();
-      }
-      else {
-       if ( !call FIFO.get() && !call FIFOP.get() )
-         m_bytes_left -= length + 1;
-       call RXFIFO.continueRead( (length <= MAC_PACKET_SIZE) ? buf + 1 : NULL,
-                                 length );
+        flush();
+        
+      } else {
+        if ( !call FIFO.get() && !call FIFOP.get() ) {
+          m_bytes_left -= length + 1;
+        }
+        
+        if(length <= MAC_PACKET_SIZE) {
+          if(length > 0) {
+            // Length is in bounds; read in this packet
+            call RXFIFO.continueRead((uint8_t*)(call CC2420Packet.getHeader(
+                m_p_rx_buf )) + 1, length);
+                
+          } else {
+            // Length == 0; start reading the next packet
+            call CSN.set();
+            call SpiResource.release();
+            waitForNextPacket();
+          }
+          
+        } else {
+          // Length is too large; we have to flush the entire Rx FIFO
+          flush();
+        }
       }
       break;
       
     case S_RX_PAYLOAD:
-      
       call CSN.set();
+      
+#ifndef CC2420_NO_ACKNOWLEDGEMENTS
+      // Sorry about the preprocessing stuff. BaseStation depends on it.
+      if (((( header->fcf >> IEEE154_FCF_ACK_REQ ) & 0x01) == 1) 
+          && (header->dest == call amAddress())
+          && ((( header->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7) == IEEE154_TYPE_DATA)) {
+        call CSN.clr();
+        call SACK.strobe();
+        call CSN.set();
+      }
+#endif
+      
       call SpiResource.release();
       
       if ( m_timestamp_size ) {
-       if ( length > 10 ) {
-         metadata->time = m_timestamp_queue[ m_timestamp_head ];
-         m_timestamp_head = ( m_timestamp_head + 1 ) % TIMESTAMP_QUEUE_SIZE;
-         m_timestamp_size--;
-       }
-      }
-      else {
-       metadata->time = 0xffff;
+        if ( length > 10 ) {
+          metadata->time = m_timestamp_queue[ m_timestamp_head ];
+          m_timestamp_head = ( m_timestamp_head + 1 ) % TIMESTAMP_QUEUE_SIZE;
+          m_timestamp_size--;
+        }
+      } else {
+        metadata->time = 0xffff;
       }
       
-      // pass packet up if crc is good
+      // We may have received an ack that should be processed by Transmit
       if ( ( buf[ length ] >> 7 ) && rx_buf ) {
-       uint8_t type = ( header->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7;
-       signal CC2420Receive.receive( type, m_p_rx_buf );
-       if ( type == IEEE154_TYPE_DATA ) {
-         post receiveDone_task();
-         return;
-       }
+        uint8_t type = ( header->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7;
+        signal CC2420Receive.receive( type, m_p_rx_buf );
+        if ( type == IEEE154_TYPE_DATA ) {
+          post receiveDone_task();
+          return;
+        }
       }
       
       waitForNextPacket();
@@ -226,10 +278,17 @@ implementation {
     
   }
 
+  async event void RXFIFO.writeDone( uint8_t* tx_buf, uint8_t tx_len, error_t error ) {
+  }  
+  
+  /***************** Tasks *****************/
+  /**
+   * Fill in metadata details, pass the packet up the stack, and
+   * get the next packet.
+   */
   task void receiveDone_task() {
-    
-    cc2420_header_t* header = getHeader( m_p_rx_buf );
-    cc2420_metadata_t* metadata = getMetadata( m_p_rx_buf );
+    cc2420_header_t* header = call CC2420Packet.getHeader( m_p_rx_buf );
+    cc2420_metadata_t* metadata = call CC2420Packet.getMetadata( m_p_rx_buf );
     uint8_t* buf = (uint8_t*)header;
     uint8_t length = buf[ 0 ];
     
@@ -237,42 +296,86 @@ implementation {
     metadata->rssi = buf[ length - 1 ];
     metadata->lqi = buf[ length ] & 0x7f;
     m_p_rx_buf = signal Receive.receive( m_p_rx_buf, m_p_rx_buf->data, 
-                                        length );
+                                         length );
 
     waitForNextPacket();
+  }
 
+  
+  /****************** Functions ****************/
+  /**
+   * Attempt to acquire the SPI bus to receive a packet.
+   */
+  void beginReceive() { 
+    m_state = S_RX_HEADER;
+    
+    if ( call SpiResource.immediateRequest() == SUCCESS ) {
+      receive();
+    } else {
+      call SpiResource.request();
+    }
+  }
+  
+  /**
+   * Flush out the Rx FIFO
+   */
+  void flush() {
+    reset_state();
+    call CSN.set();
+    call CSN.clr();
+    call SFLUSHRX.strobe();
+    call SFLUSHRX.strobe();
+    call CSN.set();
+    call SpiResource.release();
+    waitForNextPacket();
+  }
+  
+  /**
+   * The first byte of each packet is the length byte.  Read in that single
+   * byte, and then read in the rest of the packet.  The CC2420 could contain
+   * multiple packets that have been buffered up, so if something goes wrong, 
+   * we necessarily want to flush out the FIFO unless we have to.
+   */
+  void receive() {
+    call CSN.clr();
+    call RXFIFO.beginRead( (uint8_t*)(call CC2420Packet.getHeader( m_p_rx_buf )), 1 );
   }
 
-  void waitForNextPacket() {
 
+  /**
+   * Determine if there's a packet ready to go, or if we should do nothing
+   * until the next packet arrives
+   */
+  void waitForNextPacket() {
     atomic {
-      if ( m_state == S_STOPPED )
-       return;
+      if ( m_state == S_STOPPED ) {
+        return;
+      }
 
       if ( ( m_missed_packets && call FIFO.get() ) || !call FIFOP.get() ) {
-       if ( m_missed_packets )
-         m_missed_packets--;
-       beginReceive();
-      }
-      else {
-       m_state = S_STARTED;
-       m_missed_packets = 0;
+        // A new packet is buffered up and ready to go
+        if ( m_missed_packets ) {
+          m_missed_packets--;
+        }
+        
+        beginReceive();
+        
+      } else {
+        // Wait for the next packet to arrive
+        m_state = S_STARTED;
+        m_missed_packets = 0;
       }
-    }      
-    
-  }
-
-  command void* Receive.getPayload(message_t* m, uint8_t* len) {
-    if (len != NULL) {
-      *len = TOSH_DATA_LENGTH;
     }
-    return m->data;
   }
-
-  command uint8_t Receive.payloadLength(message_t* m) {
-    uint8_t* buf = (uint8_t*)getHeader( m_p_rx_buf );
-    return buf[0];
+  
+  /**
+   * Reset this component
+   */
+  void reset_state() {
+    m_bytes_left = RXFIFO_SIZE;
+    m_timestamp_head = 0;
+    m_timestamp_size = 0;
+    m_missed_packets = 0;
   }
 
-  async event void RXFIFO.writeDone( uint8_t* tx_buf, uint8_t tx_len, error_t error ) {}  
 }
index 8d54674b13dbf93fb6fb7d60ceb435a41b14955d..97885031ea37818c6367fde9611aef06e0172145 100644 (file)
@@ -50,6 +50,8 @@ generic configuration CC2420SpiC() {
   provides interface CC2420Strobe as STXONCCA;
   provides interface CC2420Strobe as SXOSCON;
   provides interface CC2420Strobe as SXOSCOFF;
+  
+  provides interface CC2420Strobe as SACK;
 
   // registers
   provides interface CC2420Register as FSCTRL;
@@ -57,8 +59,9 @@ generic configuration CC2420SpiC() {
   provides interface CC2420Register as IOCFG1;
   provides interface CC2420Register as MDMCTRL0;
   provides interface CC2420Register as MDMCTRL1;
-  provides interface CC2420Register as RXCTRL1;
   provides interface CC2420Register as TXCTRL;
+  provides interface CC2420Register as RXCTRL1;
+  provides interface CC2420Register as RSSI;
 
   // ram
   provides interface CC2420Ram as IEEEADR;
@@ -93,6 +96,8 @@ implementation {
   STXONCCA = Spi.Strobe[ CC2420_STXONCCA ];
   SXOSCON = Spi.Strobe[ CC2420_SXOSCON ];
   SXOSCOFF = Spi.Strobe[ CC2420_SXOSCOFF ];
+  
+  SACK = Spi.Strobe[ CC2420_SACK ];
 
   // registers
   FSCTRL = Spi.Reg[ CC2420_FSCTRL ];
@@ -100,8 +105,9 @@ implementation {
   IOCFG1 = Spi.Reg[ CC2420_IOCFG1 ];
   MDMCTRL0 = Spi.Reg[ CC2420_MDMCTRL0 ];
   MDMCTRL1 = Spi.Reg[ CC2420_MDMCTRL1 ];
-  RXCTRL1 = Spi.Reg[ CC2420_RXCTRL1 ];
   TXCTRL = Spi.Reg[ CC2420_TXCTRL ];
+  RXCTRL1 = Spi.Reg[ CC2420_RXCTRL1 ];
+  RSSI = Spi.Reg[ CC2420_RSSI ];
 
   // ram
   IEEEADR = Spi.Ram[ CC2420_RAM_IEEEADR ];
index 14a760062850b90a3776c97294edebace0b173fd..4bc4540dd54ed8c57e5aa90fe37510facb59b14a 100644 (file)
@@ -67,11 +67,11 @@ implementation {
   async command error_t Resource.request[ uint8_t id ]() {
     atomic {
       if ( m_resource_busy )
-       m_requests |= 1 << id;
+        m_requests |= 1 << id;
       else {
-       m_holder = id;
-       m_resource_busy = TRUE;
-       call SpiResource.request();
+        m_holder = id;
+        m_resource_busy = TRUE;
+        call SpiResource.request();
       }
     }
     return SUCCESS;
@@ -81,11 +81,11 @@ implementation {
     error_t error;
     atomic {
       if ( m_resource_busy )
-       return EBUSY;
+        return EBUSY;
       error = call SpiResource.immediateRequest();
       if ( error == SUCCESS ) {
-       m_holder = id;
-       m_resource_busy = TRUE;
+        m_holder = id;
+        m_resource_busy = TRUE;
       }
     }
     return error;
@@ -94,24 +94,27 @@ implementation {
   async command error_t Resource.release[ uint8_t id ]() {
     uint8_t i;
     atomic {
-      if ( m_holder != id )
-       return FAIL;
+      if ( m_holder != id ) {
+        return FAIL;
+      }
+      
       m_holder = NO_HOLDER;
       call SpiResource.release();
       if ( !m_requests ) {
-       m_resource_busy = FALSE;
-      }
-      else {
-       for ( i = m_holder + 1; ; i++ ) {
-         if ( i >= RESOURCE_COUNT )
-           i = 0;
-         if ( m_requests & ( 1 << i ) ) {
-           m_holder = i;
-           m_requests &= ~( 1 << i );
-           call SpiResource.request();
-           return SUCCESS;
-         }
-       }
+        m_resource_busy = FALSE;
+      } else {
+        for ( i = m_holder + 1; ; i++ ) {
+          if ( i >= RESOURCE_COUNT ) {
+            i = 0;
+          }
+          
+          if ( m_requests & ( 1 << i ) ) {
+            m_holder = i;
+            m_requests &= ~( 1 << i );
+            call SpiResource.request();
+            return SUCCESS;
+          }
+        }
       }
       return SUCCESS;
     }
@@ -128,12 +131,18 @@ implementation {
   }
 
   async command cc2420_status_t Fifo.beginRead[ uint8_t addr ]( uint8_t* data, 
-                                                               uint8_t len ) {
+                                                                uint8_t len ) {
     
-    cc2420_status_t status;
+    cc2420_status_t status = 0;
+
+    atomic {
+      if(!m_resource_busy) {
+        return status;
+      }
+    }
     
     m_addr = addr | 0x40;
-    
+        
     status = call SpiByte.write( m_addr );
     call Fifo.continueRead[ addr ]( data, len );
     
@@ -142,16 +151,22 @@ implementation {
   }
 
   async command error_t Fifo.continueRead[ uint8_t addr ]( uint8_t* data,
-                                                          uint8_t len ) {
+                                                           uint8_t len ) {
     call SpiPacket.send( NULL, data, len );
     return SUCCESS;
   }
 
   async command cc2420_status_t Fifo.write[ uint8_t addr ]( uint8_t* data, 
-                                                           uint8_t len ) {
-
-    uint8_t status;
+                                                            uint8_t len ) {
 
+    uint8_t status = 0;
+    atomic {
+      if(!m_resource_busy) {
+        return status;
+      }
+    }
+    
     m_addr = addr;
 
     status = call SpiByte.write( m_addr );
@@ -162,11 +177,17 @@ implementation {
   }
 
   async command cc2420_status_t Ram.read[ uint16_t addr ]( uint8_t offset,
-                                                          uint8_t* data, 
-                                                          uint8_t len ) {
+                                                           uint8_t* data, 
+                                                           uint8_t len ) {
 
-    cc2420_status_t status;
+    cc2420_status_t status = 0;
 
+    atomic {
+      if(!m_resource_busy) {
+        return status;
+      }
+    }
+    
     addr += offset;
 
     call SpiByte.write( addr | 0x80 );
@@ -179,7 +200,7 @@ implementation {
   }
 
   async event void SpiPacket.sendDone( uint8_t* tx_buf, uint8_t* rx_buf, 
-                                      uint16_t len, error_t error ) {
+                                       uint16_t len, error_t error ) {
     if ( m_addr & 0x40 )
       signal Fifo.readDone[ m_addr & ~0x40 ]( rx_buf, len, error );
     else
@@ -187,11 +208,17 @@ implementation {
   }
 
   async command cc2420_status_t Ram.write[ uint16_t addr ]( uint8_t offset,
-                                                           uint8_t* data, 
-                                                           uint8_t len ) {
+                                                            uint8_t* data, 
+                                                            uint8_t len ) {
 
     cc2420_status_t status = 0;
 
+    atomic {
+      if(!m_resource_busy) {
+        return status;
+      }
+    }
+    
     addr += offset;
 
     call SpiByte.write( addr | 0x80 );
@@ -205,7 +232,13 @@ implementation {
 
   async command cc2420_status_t Reg.read[ uint8_t addr ]( uint16_t* data ) {
 
-    cc2420_status_t status;
+    cc2420_status_t status = 0;
+    
+    atomic {
+      if(!m_resource_busy) {
+        return status;
+      }
+    }
     
     status = call SpiByte.write( addr | 0x40 );
     *data = (uint16_t)call SpiByte.write( 0 ) << 8;
@@ -216,6 +249,11 @@ implementation {
   }
 
   async command cc2420_status_t Reg.write[ uint8_t addr ]( uint16_t data ) {
+    atomic {
+      if(!m_resource_busy) {
+        return 0;
+      }
+    }
 
     call SpiByte.write( addr );
     call SpiByte.write( data >> 8 );
@@ -224,6 +262,12 @@ implementation {
   }
 
   async command cc2420_status_t Strobe.strobe[ uint8_t addr ]() {
+    atomic {
+      if(!m_resource_busy) {
+        return 0;
+      }
+    }
+    
     return call SpiByte.write( addr );
   }
 
diff --git a/tos/chips/cc2420/CC2420TinyosNetworkC.nc b/tos/chips/cc2420/CC2420TinyosNetworkC.nc
new file mode 100644 (file)
index 0000000..6abf1ea
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Original TinyOS T-Frames use a packet header that is not compatible with
+ * other 6LowPAN networks.  They do not include the network byte 
+ * responsible for identifying the packing as being sourced from a TinyOS
+ * network.
+ *
+ * TinyOS I-Frames are interoperability packets that do include a network
+ * byte as defined by 6LowPAN specifications.  The I-Frame header type is
+ * the default packet header used in TinyOS networks.
+ *
+ * Since either packet header is acceptable, this layer must do some 
+ * preprocessing (sorry) to figure out whether or not it needs to include 
+ * the functionality to process I-frames.  If I-Frames are used, then
+ * the network byte is added on the way out and checked on the way in.
+ * If the packet came from a network different from a TinyOS network, the
+ * user may access it through the DispatchP's NonTinyosReceive[] Receive 
+ * interface and process it in a different radio stack.
+ *
+ * If T-Frames are used instead, this layer is simply pass-through wiring to the
+ * layer beneath.  
+ *
+ * Define "CC2420_IFRAME_TYPE" to use the interoperability frame and 
+ * this layer
+ * 
+ * @author David Moss
+ */
+#include "CC2420.h"
+
+configuration CC2420TinyosNetworkC {
+  provides {
+    interface Send;
+    interface Receive;
+  }
+  
+  uses {
+    interface Receive as SubReceive;
+    interface Send as SubSend;
+  }
+}
+
+implementation {
+
+#ifdef CC2420_IFRAME_TYPE
+  components CC2420TinyosNetworkP;
+  components CC2420PacketC;
+  
+  CC2420TinyosNetworkP.Send = Send;
+  CC2420TinyosNetworkP.Receive = Receive;
+  CC2420TinyosNetworkP.SubSend = SubSend;
+  CC2420TinyosNetworkP.SubReceive = SubReceive;
+  
+  CC2420TinyosNetworkP.CC2420Packet -> CC2420PacketC;
+
+#else
+  Send = SubSend;
+  Receive = SubReceive;
+#endif
+
+}
+
diff --git a/tos/chips/cc2420/CC2420TinyosNetworkP.nc b/tos/chips/cc2420/CC2420TinyosNetworkP.nc
new file mode 100644 (file)
index 0000000..18b3bc9
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Fills in the network ID byte for outgoing packets for compatibility with
+ * other 6LowPAN networks.  Filters incoming packets that are not
+ * TinyOS network compatible.  Provides the 6LowpanSnoop interface to
+ * sniff for packets that were not originated from TinyOS.
+ *
+ * @author David Moss
+ */
+#include "CC2420.h"
+
+module CC2420TinyosNetworkP {
+  provides {
+    interface Send;
+    interface Receive;
+    
+    interface Receive as NonTinyosReceive[uint8_t networkId];
+  }
+  
+  uses {
+    interface Send as SubSend;
+    interface Receive as SubReceive;
+    interface CC2420Packet;
+  }
+}
+
+implementation {
+
+  /***************** Send Commands ****************/
+  command error_t Send.send(message_t* msg, uint8_t len) {
+    (call CC2420Packet.getHeader(msg))->network = TINYOS_6LOWPAN_NETWORK_ID;
+    return call SubSend.send(msg, len);
+  }
+
+  command error_t Send.cancel(message_t* msg) {
+    return call SubSend.cancel(msg);
+  }
+
+  command uint8_t Send.maxPayloadLength() {
+    return call SubSend.maxPayloadLength();
+  }
+
+  command void* Send.getPayload(message_t* msg) {
+    return call SubSend.getPayload(msg);
+  }
+  
+  /***************** Receive Commands ****************/
+  command void* Receive.getPayload(message_t* msg, uint8_t* len) {
+    return call SubReceive.getPayload(msg, len);
+  }
+
+  command uint8_t Receive.payloadLength(message_t* msg) {
+    return call SubReceive.payloadLength(msg);
+  }
+  
+  /***************** NonTinyosReceive Commands ****************/
+  command void* NonTinyosReceive.getPayload[uint8_t networkId](message_t* msg, uint8_t* len) {
+    return call SubReceive.getPayload(msg, len);
+  }
+
+  command uint8_t NonTinyosReceive.payloadLength[uint8_t networkId](message_t* msg) {
+    return call SubReceive.payloadLength(msg);
+  }
+  
+  /***************** SubSend Events *****************/
+  event void SubSend.sendDone(message_t* msg, error_t error) {
+    signal Send.sendDone(msg, error);
+  }
+  
+  /***************** SubReceive Events ***************/
+  event message_t *SubReceive.receive(message_t *msg, void *payload, uint8_t len) {
+    if((call CC2420Packet.getHeader(msg))->network == TINYOS_6LOWPAN_NETWORK_ID) {
+      return signal Receive.receive(msg, payload, len);
+      
+    } else {
+      return signal NonTinyosReceive.receive[(call CC2420Packet.getHeader(msg))->network](msg, payload, len);
+    }
+  }
+  
+  /***************** Defaults ****************/
+  default event message_t *NonTinyosReceive.receive[uint8_t networkId](message_t *msg, void *payload, uint8_t len) {
+    return msg;
+  }
+  
+}
index e556f77a09082be572830c57531ec27ad6a7530e..d30a84b644444640bc94f983b0fb9bfdd13ed000 100644 (file)
 interface CC2420Transmit {
 
   /**
-   * Send a message with CCA enabled.
+   * Send a message
    *
    * @param p_msg message to send.
+   * @param useCca TRUE if this Tx should use clear channel assessments
    * @return SUCCESS if the request was accepted, FAIL otherwise.
    */
-  async command error_t sendCCA( message_t* p_msg );
+  async command error_t send( message_t* p_msg, bool useCca );
 
   /**
-   * Send a message with CCA disabled.
-   *
-   * @param p_msg message to send.
-   * @return SUCCESS if the request was accepted, FAIL otherwise.
-   */
-  async command error_t send( message_t* p_msg );
-
-  /**
-   * Send the previous message again with CCA enabled.
-   *
-   * @return SUCCESS if the request was accepted, FAIL otherwise.
-   */
-  async command error_t resendCCA();
-
-  /**
-   * Send the previous message again with CCA disabled.
-   *
+   * Send the previous message again
+   * @param useCca TRUE if this re-Tx should use clear channel assessments
    * @return SUCCESS if the request was accepted, FAIL otherwise.
    */
-  async command error_t resend();
+  async command error_t resend(bool useCca);
 
   /**
    * Cancel sending of the message.
index 5e0766084aa35c63726b882b9307fb5b486c68b7..12405d427ef2558bd42694ebe3b5e8a21fae84a9 100644 (file)
  * @version $Revision$ $Date$
  */
 
-configuration CC2420TransmitC {
+#include "IEEE802154.h"
 
-  provides interface Init;
-  provides interface AsyncStdControl;
-  provides interface CC2420Transmit;
-  provides interface CsmaBackoff;
-  provides interface RadioTimeStamping;
+configuration CC2420TransmitC {
 
+  provides {
+    interface StdControl;
+    interface CC2420Transmit;
+    interface RadioBackoff;
+    interface RadioTimeStamping;
+    interface CC2420Cca;
+  }
 }
 
 implementation {
 
   components CC2420TransmitP;
-  Init = Alarm;
-  Init = CC2420TransmitP;
-  AsyncStdControl = CC2420TransmitP;
+  StdControl = CC2420TransmitP;
   CC2420Transmit = CC2420TransmitP;
-  CsmaBackoff = CC2420TransmitP;
+  RadioBackoff = CC2420TransmitP;
   RadioTimeStamping = CC2420TransmitP;
+  CC2420Cca = CC2420TransmitP;
 
+  components MainC;
+  MainC.SoftwareInit -> CC2420TransmitP;
+  MainC.SoftwareInit -> Alarm;
+  
   components AlarmMultiplexC as Alarm;
   CC2420TransmitP.BackoffTimer -> Alarm;
 
@@ -76,11 +82,17 @@ implementation {
   CC2420TransmitP.TXCTRL      -> Spi.TXCTRL;
   CC2420TransmitP.TXFIFO      -> Spi.TXFIFO;
   CC2420TransmitP.TXFIFO_RAM  -> Spi.TXFIFO_RAM;
-
+  CC2420TransmitP.MDMCTRL1    -> Spi.MDMCTRL1;
+  
   components CC2420ReceiveC;
   CC2420TransmitP.CC2420Receive -> CC2420ReceiveC;
-
-  components LedsC as Leds;
-  CC2420TransmitP.Leds -> Leds;
-
+  
+  components new TimerMilliC() as LplDisableTimerC;
+  CC2420TransmitP.LplDisableTimer -> LplDisableTimerC;
+  
+  components CC2420PacketC;
+  CC2420TransmitP.CC2420Packet -> CC2420PacketC;
+  
+  components LedsC;
+  CC2420TransmitP.Leds -> LedsC;
 }
index 9793949b57782028da323f7cf16166c95f503b0a..b1a43f60b0acb6bba5e0e8c4e54df3178d262c36 100644 (file)
 
 /**
  * @author Jonathan Hui <jhui@archrock.com>
+ * @author David Moss
+ * @author Jung Il Choi
  * @version $Revision$ $Date$
  */
 
+#include "CC2420.h"
+#include "crc.h"
+
 module CC2420TransmitP {
 
   provides interface Init;
-  provides interface AsyncStdControl;
+  provides interface StdControl;
   provides interface CC2420Transmit as Send;
-  provides interface CsmaBackoff;
+  provides interface RadioBackoff;
   provides interface RadioTimeStamping as TimeStamp;
-
+  provides interface CC2420Cca;
+  
   uses interface Alarm<T32khz,uint32_t> as BackoffTimer;
+  uses interface CC2420Packet;
   uses interface GpioCapture as CaptureSFD;
   uses interface GeneralIO as CCA;
   uses interface GeneralIO as CSN;
@@ -56,10 +63,11 @@ module CC2420TransmitP {
   uses interface CC2420Strobe as STXON;
   uses interface CC2420Strobe as STXONCCA;
   uses interface CC2420Strobe as SFLUSHTX;
+  uses interface CC2420Register as MDMCTRL1;
 
+  uses interface Timer<TMilli> as LplDisableTimer;
   uses interface CC2420Receive;
   uses interface Leds;
-
 }
 
 implementation {
@@ -73,7 +81,9 @@ implementation {
     S_SFD,
     S_EFD,
     S_ACK_WAIT,
-    S_CANCEL,
+    S_LOAD_CANCEL,
+    S_TX_CANCEL,
+    S_CCA_CANCEL,
   } cc2420_transmit_state_t;
 
   // This specifies how many jiffies the stack should wait after a
@@ -84,48 +94,49 @@ implementation {
     CC2420_ABORT_PERIOD = 320
   };
   
-  norace message_t* m_msg;
+  norace message_t *m_msg;
+  
   norace bool m_cca;
+  
   norace uint8_t m_tx_power;
+  
   cc2420_transmit_state_t m_state = S_STOPPED;
+  
   bool m_receiving = FALSE;
+  
   uint16_t m_prev_time;
+  
+  bool signalSendDone;
+  
+  /** TRUE if the current lpl tx is taking place with continuous modulation */
+  norace bool continuousModulation;
+  
+  /** Total CCA checks that showed no activity before the NoAck LPL send */
+  norace int8_t totalCcaChecks;
+  
+  /** The initial backoff period */
+  norace uint16_t myInitialBackoff;
+  
+  /** The congestion backoff period */
+  norace uint16_t myCongestionBackoff;
+  
+  /** The low power listening backoff period */
+  norace uint16_t myLplBackoff;
+  
 
+  /***************** Prototypes ****************/
+  error_t send( message_t *p_msg, bool cca );
+  error_t resend( bool cca );
   void loadTXFIFO();
   void attemptSend();
-
-  cc2420_header_t* getHeader( message_t* msg ) {
-    return (cc2420_header_t*)( msg->data - sizeof( cc2420_header_t ) );
-  }
-
-  cc2420_metadata_t* getMetadata( message_t* msg ) {
-    return (cc2420_metadata_t*)msg->metadata;
-  }
-
-  void startBackoffTimer(uint16_t time) {
-    call BackoffTimer.start(time);
-  }
-
-  void stopBackoffTimer() {
-    call BackoffTimer.stop();
-  }
-
-  error_t acquireSpiResource() {
-    error_t error = call SpiResource.immediateRequest();
-    if ( error != SUCCESS )
-      call SpiResource.request();
-    return error;
-  }
-
-  error_t releaseSpiResource() {
-    return call SpiResource.release();
-  }
-
-  void signalDone( error_t err ) {
-    atomic m_state = S_STARTED;
-    signal Send.sendDone( m_msg, err );
-  }
-
+  void congestionBackoff();
+  error_t acquireSpiResource();
+  error_t releaseSpiResource();
+  void signalDone( error_t err );
+  
+  task void startLplTimer();
+  
+  /***************** Init Commands *****************/
   command error_t Init.init() {
     call CCA.makeInput();
     call CSN.makeOutput();
@@ -133,7 +144,8 @@ implementation {
     return SUCCESS;
   }
 
-  async command error_t AsyncStdControl.start() {
+  /***************** StdControl Commands ****************/
+  command error_t StdControl.start() {
     atomic {
       call CaptureSFD.captureRisingEdge();
       m_state = S_STARTED;
@@ -143,308 +155,620 @@ implementation {
     return SUCCESS;
   }
 
-  async command error_t AsyncStdControl.stop() {
+  command error_t StdControl.stop() {
     atomic {
       m_state = S_STOPPED;
-      stopBackoffTimer();
+      call BackoffTimer.stop();
       call CaptureSFD.disable();
+      call SpiResource.release();
     }
     return SUCCESS;
   }
 
-  error_t send( message_t* p_msg, bool cca ) {
 
+  /**************** Send Commands ****************/
+  async command error_t Send.send( message_t* p_msg, bool useCca ) {
+    return send( p_msg, useCca );
+  }
+
+  async command error_t Send.resend(bool useCca) {
+    return resend( useCca );
+  }
+
+  async command error_t Send.cancel() {
     atomic {
-      if ( m_state != S_STARTED )
-       return FAIL;
-      m_state = S_LOAD;
-      m_cca = cca;
-      m_msg = p_msg;
+      signalSendDone = FALSE;
+      switch( m_state ) {
+      case S_LOAD:
+        m_state = S_LOAD_CANCEL;
+        break;
+        
+      case S_SAMPLE_CCA:
+        m_state = S_CCA_CANCEL;
+        break;
+        
+      case S_BEGIN_TRANSMIT:
+        m_state = S_TX_CANCEL;
+        break;
+        
+      default:
+        // cancel not allowed while radio is busy transmitting
+        return FAIL;
+      }
     }
 
-    if ( acquireSpiResource() == SUCCESS )
-      loadTXFIFO();
-
     return SUCCESS;
-
   }
 
-  async command error_t Send.sendCCA( message_t* p_msg ) {
-    return send( p_msg, TRUE );
+  async command error_t Send.modify( uint8_t offset, uint8_t* buf, 
+                                     uint8_t len ) {
+    call CSN.clr();
+    call TXFIFO_RAM.write( offset, buf, len );
+    call CSN.set();
+    return SUCCESS;
   }
 
-  async command error_t Send.send( message_t* p_msg ) {
-    return send( p_msg, FALSE );
+  /***************** RadioBackoff Commands ****************/
+  /**
+   * Must be called within a requestInitialBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void RadioBackoff.setInitialBackoff(uint16_t backoffTime) {
+    myInitialBackoff = backoffTime + 1;
   }
-
-  error_t resend( bool cca ) {
-
-    atomic {
-      if ( m_state != S_STARTED )
-       return FAIL;
-      m_cca = cca;
-      m_state = cca ? S_SAMPLE_CCA : S_BEGIN_TRANSMIT;
-    }
-
-    if ( m_cca ) {
-      startBackoffTimer( signal CsmaBackoff.initial( m_msg ) * 
-                              CC2420_BACKOFF_PERIOD );
-    }
-    else if ( acquireSpiResource() == SUCCESS ) {
-      attemptSend();
-    }
-    
-    return SUCCESS;
   
+  /**
+   * Must be called within a requestCongestionBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void RadioBackoff.setCongestionBackoff(uint16_t backoffTime) {
+    myCongestionBackoff = backoffTime + 1;
   }
   
-  async command error_t Send.resendCCA() {
-    return resend( TRUE );
+  /**
+   * Must be called within a requestLplBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void RadioBackoff.setLplBackoff(uint16_t backoffTime) {
+    myLplBackoff = backoffTime + 1;
   }
-
-  async command error_t Send.resend() {
-    return resend( FALSE );
+  
+  async command void RadioBackoff.setCca(bool useCca) {
   }
+  
+  
+  
+  /***************** CC2420Cca Commands ****************/
+  /**
+   * @return TRUE if the CCA pin shows a clear channel
+   */
+  command bool CC2420Cca.isChannelClear() {
+    return call CCA.get();
+  }
+  
 
-  async command error_t Send.cancel() {
-
-    stopBackoffTimer();
-
+  /**
+   * The CaptureSFD event is actually an interrupt from the capture pin
+   * which is connected to timing circuitry and timer modules.  This
+   * type of interrupt allows us to see what time (being some relative value)
+   * the event occurred, and lets us accurately timestamp our packets.  This
+   * allows higher levels in our system to synchronize with other nodes.
+   *
+   * Because the SFD events can occur so quickly, and the interrupts go
+   * in both directions, we set up the interrupt but check the SFD pin to
+   * determine if that interrupt condition has already been met - meaning,
+   * we should fall through and continue executing code where that interrupt
+   * would have picked up and executed had our microcontroller been fast enough.
+   */
+  async event void CaptureSFD.captured( uint16_t time ) {
     atomic {
       switch( m_state ) {
-      case S_LOAD:
-       m_state = S_CANCEL;
-       break;
-      case S_SAMPLE_CCA: case S_BEGIN_TRANSMIT:
-       m_state = S_STARTED;
-       break;
+        
+      case S_SFD:
+        call CaptureSFD.captureFallingEdge();
+        signal TimeStamp.transmittedSFD( time, m_msg );
+        releaseSpiResource();
+        call BackoffTimer.stop();
+        m_state = S_EFD;
+        if ( ( ( (call CC2420Packet.getHeader( m_msg ))->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == IEEE154_TYPE_DATA ) {
+          (call CC2420Packet.getMetadata( m_msg ))->time = time;
+        }
+        
+        if ( call SFD.get() ) {
+          break;
+        }
+        /** Fall Through because the next interrupt was already received */
+        
+      case S_EFD:
+        call CaptureSFD.captureRisingEdge();
+        if ( (call CC2420Packet.getHeader( m_msg ))->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
+          m_state = S_ACK_WAIT;
+          call BackoffTimer.start( CC2420_ACK_WAIT_DELAY );
+        } else {
+        
+#ifdef NOACK_LOW_POWER_LISTENING
+          if(continuousModulation) {
+            // Wait for the LplDisableTimer to fire before running signalDone()
+            return;
+          }
+#endif
+          signalDone(SUCCESS);
+        }
+        
+        if ( !call SFD.get() ) {
+          break;
+        }
+        /** Fall Through because the next interrupt was already received */
+        
       default:
-       // cancel not allowed while radio is busy transmitting
-       return FAIL;
+        if ( !m_receiving ) {
+          call CaptureSFD.captureFallingEdge();
+          signal TimeStamp.receivedSFD( time );
+          call CC2420Receive.sfd( time );
+          m_receiving = TRUE;
+          m_prev_time = time;
+          if ( call SFD.get() ) {
+            // wait for the next interrupt before moving on
+            return;
+          }
+        }
+        
+        call CaptureSFD.captureRisingEdge();
+        m_receiving = FALSE;
+        if ( time - m_prev_time < 10 ) {
+          call CC2420Receive.sfd_dropped();
+        }
+        break;
+      
       }
     }
+  }
 
-    return SUCCESS;
+  /***************** CC2420Receive Events ****************/
+  /**
+   * If the packet we just received was an ack that we were expecting,
+   * our send is complete.
+   */
+  async event void CC2420Receive.receive( uint8_t type, message_t* ack_msg ) {
+    cc2420_header_t* ack_header;
+    cc2420_header_t* msg_header;
+    cc2420_metadata_t* msg_metadata;
+    uint8_t* ack_buf;
+    uint8_t length;
 
+    if ( type == IEEE154_TYPE_ACK ) {
+      ack_header = call CC2420Packet.getHeader( ack_msg );
+      msg_header = call CC2420Packet.getHeader( m_msg );
+      msg_metadata = call CC2420Packet.getMetadata( m_msg );
+      ack_buf = (uint8_t *) ack_header;
+      length = ack_header->length;
+      
+      if ( m_state == S_ACK_WAIT &&
+           msg_header->dsn == ack_header->dsn ) {
+        call BackoffTimer.stop();
+        msg_metadata->ack = TRUE;
+        msg_metadata->rssi = ack_buf[ length - 1 ];
+        msg_metadata->lqi = ack_buf[ length ] & 0x7f;
+        signalDone(SUCCESS);
+      }
+    }
   }
 
-  void loadTXFIFO() {
-    cc2420_header_t* header = getHeader( m_msg );
-    uint8_t tx_power = getMetadata( m_msg )->tx_power;
-    if ( !tx_power )
-      tx_power = CC2420_DEF_RFPOWER;
-    call CSN.clr();
-    if ( m_tx_power != tx_power )
-      call TXCTRL.write( ( 2 << CC2420_TXCTRL_TXMIXBUF_CUR ) |
-                        ( 3 << CC2420_TXCTRL_PA_CURRENT ) |
-                        ( 1 << CC2420_TXCTRL_RESERVED ) |
-                        ( tx_power << CC2420_TXCTRL_PA_LEVEL ) );
-    m_tx_power = tx_power;
-    call TXFIFO.write( (uint8_t*)header, header->length - 1 );
+  /***************** SpiResource Events ****************/
+  event void SpiResource.granted() {
+    uint8_t cur_state;
+
+    atomic {
+      cur_state = m_state;
+    }
+
+    switch( cur_state ) {
+    case S_LOAD:
+      loadTXFIFO();
+      break;
+      
+    case S_BEGIN_TRANSMIT:
+      attemptSend();
+      break;
+      
+    case S_LOAD_CANCEL:
+    case S_CCA_CANCEL:
+    case S_TX_CANCEL:
+      call CSN.clr();
+      call SFLUSHTX.strobe();
+      call CSN.set();
+      releaseSpiResource();
+      atomic {
+        if (signalSendDone) {
+          signalDone(ECANCEL);
+        } else {
+          m_state = S_STARTED;
+        }
+      }
+      break;
+      
+    default:
+      releaseSpiResource();
+      break;
+    }
   }
   
+  /***************** TXFIFO Events ****************/
+  /**
+   * The TXFIFO is used to load packets into the transmit buffer on the
+   * chip
+   */
   async event void TXFIFO.writeDone( uint8_t* tx_buf, uint8_t tx_len,
-                                    error_t error ) {
+                                     error_t error ) {
 
     call CSN.set();
-
-    if ( m_state == S_CANCEL ) {
-      m_state = S_STARTED;
-    }
-    else if ( !m_cca ) {
-      m_state = S_BEGIN_TRANSMIT;
+    if ( m_state == S_LOAD_CANCEL ) {
+      atomic {
+        call CSN.clr();
+        call SFLUSHTX.strobe();
+        call CSN.set();
+      }
+      releaseSpiResource();
+      if (signalSendDone) {
+        signalDone(ECANCEL);
+      } else {
+        m_state = S_STARTED;
+      }
+      
+    } else if ( !m_cca ) {
+      atomic {
+        if (m_state == S_LOAD_CANCEL) {
+          m_state = S_TX_CANCEL;
+        } else {
+          m_state = S_BEGIN_TRANSMIT;
+        }
+      }
       attemptSend();
-    }
-    else {
+      
+    else {
       releaseSpiResource();
-      m_state = S_SAMPLE_CCA;
-      startBackoffTimer( signal CsmaBackoff.initial( m_msg ) * 
-                        CC2420_BACKOFF_PERIOD );
+      atomic {
+        if (m_state == S_LOAD_CANCEL) {
+          m_state = S_CCA_CANCEL;
+        } else {
+          m_state = S_SAMPLE_CCA;
+        }
+      }
+      
+      signal RadioBackoff.requestInitialBackoff(m_msg);
+      call BackoffTimer.start(myInitialBackoff);
     }
-
   }
 
-  void congestionBackoff() {
-    atomic {
-      uint16_t time = signal CsmaBackoff.congestion( m_msg );
-      if ( time )
-       startBackoffTimer( time * CC2420_BACKOFF_PERIOD );
-      else
-       m_state = S_STARTED;
-    }
+  
+  async event void TXFIFO.readDone( uint8_t* tx_buf, uint8_t tx_len, 
+      error_t error ) {
   }
-
+  
+  
+  /***************** Timer Events ****************/
+  /**
+   * The backoff timer is mainly used to wait for a moment before trying
+   * to send a packet again. But we also use it to timeout the wait for
+   * an acknowledgement, and timeout the wait for an SFD interrupt when
+   * we should have gotten one.
+   */
   async event void BackoffTimer.fired() {
-
     atomic {
       switch( m_state ) {
-       
-      case S_SAMPLE_CCA :
-       // sample CCA and wait a little longer if free, just in case we
-       // sampled during the ack turn-around window
-       if ( call CCA.get() ) {
-         m_state = S_BEGIN_TRANSMIT;
-         startBackoffTimer( CC2420_TIME_ACK_TURNAROUND );
-       }
-       else {
-         congestionBackoff();
-       }
-       break;
-       
-      case S_BEGIN_TRANSMIT :
-       if ( acquireSpiResource() == SUCCESS )
-         attemptSend();
-       break;
-       
-      case S_ACK_WAIT :
-       signalDone( SUCCESS );
-       break;
-       
-#ifdef PLATFORM_MICAZ
+        
+      case S_SAMPLE_CCA : 
+        // sample CCA and wait a little longer if free, just in case we
+        // sampled during the ack turn-around window
+        if ( call CCA.get() ) {
+          m_state = S_BEGIN_TRANSMIT;
+          call BackoffTimer.start( CC2420_TIME_ACK_TURNAROUND );
+          
+        } else {
+          congestionBackoff();
+        }
+        break;
+        
+      case S_CCA_CANCEL:
+        m_state = S_TX_CANCEL;
+        /** Fall Through */
+        
+      case S_BEGIN_TRANSMIT:
+      case S_TX_CANCEL:
+        if ( acquireSpiResource() == SUCCESS ) {
+          attemptSend();
+        }
+        break;
+        
+      case S_ACK_WAIT:
+        signalDone( SUCCESS );
+        break;
+
       case S_SFD:
-       // We didn't receive an SFD interrupt within CC2420_ABORT_PERIOD
-       // jiffies. Assume something is wrong.
-       call SFLUSHTX.strobe();
-       call CaptureSFD.disable();
-       call CaptureSFD.captureRisingEdge();
-       signalDone( ERETRY );
-       break;
-#endif
+        // We didn't receive an SFD interrupt within CC2420_ABORT_PERIOD
+        // jiffies. Assume something is wrong.
+        call SFLUSHTX.strobe();
+        call CaptureSFD.captureRisingEdge();
+        releaseSpiResource();
+        signalDone( ERETRY );
+        break;
+
       default:
-       break;
+        break;
+      }
+    }
+  }
+  
+  event void LplDisableTimer.fired() {
+    call MDMCTRL1.write(0 << CC2420_MDMCTRL1_TX_MODE);
+    signalDone( SUCCESS );
+  }
+    
+  /***************** Functions ****************/
+  /**
+   * Set up a message to be sent. First load it into the outbound tx buffer
+   * on the chip, then attempt to send it.
+   * @param *p_msg Pointer to the message that needs to be sent
+   * @param cca TRUE if this transmit should use clear channel assessment
+   */
+  error_t send( message_t* p_msg, bool cca ) {
+    atomic {
+      if (m_state == S_LOAD_CANCEL
+          || m_state == S_CCA_CANCEL
+          || m_state == S_TX_CANCEL) {
+        return ECANCEL;
+      }
+      
+      if ( m_state != S_STARTED ) {
+        return FAIL;
       }
+      
+      m_state = S_LOAD;
+      m_cca = cca;
+      m_msg = p_msg;
+      totalCcaChecks = 0;
+    }
+    
+    if ( acquireSpiResource() == SUCCESS ) {
+      loadTXFIFO();
     }
 
+    return SUCCESS;
   }
   
-  void attemptSend() {
+  /**
+   * Resend a packet that already exists in the outbound tx buffer on the
+   * chip
+   * @param cca TRUE if this transmit should use clear channel assessment
+   */
+  error_t resend( bool cca ) {
 
+    atomic {
+      if (m_state == S_LOAD_CANCEL
+          || m_state == S_CCA_CANCEL
+          || m_state == S_TX_CANCEL) {
+        return ECANCEL;
+      }
+      
+      if ( m_state != S_STARTED ) {
+        return FAIL;
+      }
+      
+      m_cca = cca;
+      m_state = cca ? S_SAMPLE_CCA : S_BEGIN_TRANSMIT;
+      totalCcaChecks = 0;
+    }
+    
+    if(m_cca) {
+      if((call CC2420Packet.getMetadata( m_msg ))->rxInterval > 0) {
+        signal RadioBackoff.requestLplBackoff(m_msg);
+        call BackoffTimer.start( myLplBackoff );
+        
+      } else {
+        signal RadioBackoff.requestInitialBackoff(m_msg);
+        call BackoffTimer.start( myInitialBackoff );
+      }
+      
+    } else if ( acquireSpiResource() == SUCCESS ) {
+      attemptSend();
+    }
+    
+    return SUCCESS;
+  }
+  
+  /**
+   * Attempt to send the packet we have loaded into the tx buffer on 
+   * the radio chip.  The STXONCCA will send the packet immediately if
+   * the channel is clear.  If we're not concerned about whether or not
+   * the channel is clear (i.e. m_cca == FALSE), then STXON will send the
+   * packet without checking for a clear channel.
+   *
+   * If the packet didn't get sent, then congestion == TRUE.  In that case,
+   * we reset the backoff timer and try again in a moment.
+   *
+   * If the packet got sent, we should expect an SFD interrupt to take
+   * over, signifying the packet is getting sent.
+   */
+  void attemptSend() {
     uint8_t status;
     bool congestion = TRUE;
+    
+    continuousModulation = FALSE;
+    
+#ifdef NOACK_LOW_POWER_LISTENING
+      // When the message is being sent with LPL, CCA implies this is the first
+      // message.  Send it using the continuous modulation delivery
+      continuousModulation = m_cca 
+          && (call CC2420Packet.getMetadata( m_msg ))->rxInterval > 0;
+#endif
 
-    call CSN.clr();
+    atomic {
+      if (m_state == S_TX_CANCEL) {
+        call SFLUSHTX.strobe();
+        releaseSpiResource();
+        call CSN.set();
+        if (signalSendDone) {
+          signalDone(ECANCEL);
+        } else {
+          m_state = S_STARTED;
+        }
+        return;
+      }
+      
+      
+      call CSN.clr();
+      
+      if(continuousModulation) {
+        /*
+         * We do a complex backoff like this because the last message of a
+         * continuous modulation delivery is currently reloaded into the 
+         * SPI bus and sent off without CCA.  This leaves a small quiet gap
+         * between the continuous modulation and its last message that other
+         * transmitters are guaranteed to hit.
+         *
+         * In the future, when the CRC is built into the continuous delivery
+         * message, this complex backoff may not be needed.  Alternatively,
+         * directly accessing the TXFIFO RAM and adjusting the FCF to 
+         * request an acknowledgement, and then resend without CCA will 
+         * decrease the quiet gap.
+         */
+        if(totalCcaChecks < 20) {
+          if(call CCA.get()) {
+            // Extended backoff
+            totalCcaChecks++;
+          } else {
+            // Saw another transmitter, start over
+            totalCcaChecks = 0;
+          }
+          
+          call CSN.set();
+          releaseSpiResource();
+          signal RadioBackoff.requestInitialBackoff(m_msg);       
+          call BackoffTimer.start( myInitialBackoff );
+          return;
+        }
+        
+        call MDMCTRL1.write(2 << CC2420_MDMCTRL1_TX_MODE);
+      } else {
+        call MDMCTRL1.write(0 << CC2420_MDMCTRL1_TX_MODE);
+      }
 
-    status = m_cca ? call STXONCCA.strobe() : call STXON.strobe();
-    if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {
-      status = call SNOP.strobe();
-      if ( status & CC2420_STATUS_TX_ACTIVE )
-       congestion = FALSE;
+      status = m_cca ? call STXONCCA.strobe() : call STXON.strobe();
+      if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {
+        status = call SNOP.strobe();
+        if ( status & CC2420_STATUS_TX_ACTIVE ) {
+          congestion = FALSE;
+          
+          if(continuousModulation) {
+            post startLplTimer();
+          }
+        }
+      }
+      
+      m_state = congestion ? S_SAMPLE_CCA : S_SFD;
+      call CSN.set();
     }
-    atomic m_state = congestion ? S_SAMPLE_CCA : S_SFD;
     
-    call CSN.set();
-
     if ( congestion ) {
+      totalCcaChecks = 0;
       releaseSpiResource();
       congestionBackoff();
+    } else {
+      call BackoffTimer.start(CC2420_ABORT_PERIOD);
     }
-#ifdef PLATFORM_MICAZ
-    else {
-      startBackoffTimer(CC2420_ABORT_PERIOD);
-    }
-#endif
-
   }
-
-  async command error_t Send.modify( uint8_t offset, uint8_t* buf, 
-                                    uint8_t len ) {
-    call CSN.clr();
-    call TXFIFO_RAM.write( offset, buf, len );
-    call CSN.set();
-    return SUCCESS;
-  }
-
-  async event void CaptureSFD.captured( uint16_t time ) {
-
+  
+  
+  /**  
+   * Congestion Backoff
+   */
+  void congestionBackoff() {
     atomic {
-      switch( m_state ) {
-       
-      case S_SFD:
-       call CaptureSFD.captureFallingEdge();
-       signal TimeStamp.transmittedSFD( time, m_msg );
-       releaseSpiResource();
-       stopBackoffTimer();
-       m_state = S_EFD;
-       if ( ( ( getHeader( m_msg )->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == 
-            IEEE154_TYPE_DATA )
-         getMetadata( m_msg )->time = time;
-       if ( call SFD.get() )
-         break;
-       
-      case S_EFD:
-       call CaptureSFD.captureRisingEdge();
-       if ( getHeader( m_msg )->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
-         m_state = S_ACK_WAIT;
-         startBackoffTimer( CC2420_ACK_WAIT_DELAY );
-       }
-       else {
-         signalDone(SUCCESS);
-       }
-       if ( !call SFD.get() )
-         break;
-       
-      default:
-       if ( !m_receiving ) {
-         call CaptureSFD.captureFallingEdge();
-         signal TimeStamp.receivedSFD( time );
-         call CC2420Receive.sfd( time );
-         m_receiving = TRUE;
-         m_prev_time = time;
-         if ( call SFD.get() )
-           return;
-       }
-       if ( m_receiving ) {
-         call CaptureSFD.captureRisingEdge();
-         m_receiving = FALSE;
-         if ( time - m_prev_time < 10 )
-           call CC2420Receive.sfd_dropped();
-       }
-       break;
-      
+      if((call CC2420Packet.getMetadata(m_msg))->rxInterval > 0) {
+        signal RadioBackoff.requestLplBackoff(m_msg);
+        call BackoffTimer.start(myLplBackoff);
+        
+      } else {
+        signal RadioBackoff.requestCongestionBackoff(m_msg);
+        call BackoffTimer.start(myCongestionBackoff);
       }
     }
   }
-
-  async event void CC2420Receive.receive( uint8_t type, message_t* ack_msg ) {
-
-    if ( type == IEEE154_TYPE_ACK ) {
-      cc2420_header_t* ack_header = getHeader( ack_msg );
-      cc2420_header_t* msg_header = getHeader( m_msg );
-      cc2420_metadata_t* msg_metadata = getMetadata( m_msg );
-      uint8_t* ack_buf = (uint8_t*)ack_header;
-      uint8_t length = ack_header->length;
-      
-      if ( m_state == S_ACK_WAIT &&
-          msg_header->dsn == ack_header->dsn ) {
-       stopBackoffTimer();
-       msg_metadata->ack = TRUE;
-       msg_metadata->rssi = ack_buf[ length - 1 ];
-       msg_metadata->lqi = ack_buf[ length ] & 0x7f;
-       signalDone(SUCCESS);
-      }
+  
+  error_t acquireSpiResource() {
+    error_t error = call SpiResource.immediateRequest();
+    if ( error != SUCCESS ) {
+      call SpiResource.request();
     }
-
+    return error;
   }
 
-  event void SpiResource.granted() {
+  error_t releaseSpiResource() {
+    call SpiResource.release();
+    return SUCCESS;
+  }
 
-    uint8_t cur_state;
 
-    atomic {
-      cur_state = m_state;
+  /** 
+   * Setup the packet transmission power and load the tx fifo buffer on
+   * the chip with our outbound packet.  
+   *
+   * Warning: the tx_power metadata might not be initialized and
+   * could be a value other than 0 on boot.  Verification is needed here
+   * to make sure the value won't overstep its bounds in the TXCTRL register
+   * and is transmitting at max power by default.
+   *
+   * It should be possible to manually calculate the packet's CRC here and
+   * tack it onto the end of the header + payload when loading into the TXFIFO,
+   * so the continuous modulation low power listening strategy will continually
+   * deliver valid packets.  This would increase receive reliability for
+   * mobile nodes and lossy connections.  The crcByte() function should use
+   * the same CRC polynomial as the CC2420's AUTOCRC functionality.
+   */
+  void loadTXFIFO() {
+    cc2420_header_t* header = call CC2420Packet.getHeader( m_msg );
+    uint8_t tx_power = (call CC2420Packet.getMetadata( m_msg ))->tx_power;
+    
+    if ( !tx_power ) {
+      // If our packet's tx_power wasn't configured to anything but 0,
+      // send it using the default RF power.  This assumes the
+      // packet's metadata is all set to 0's on boot.
+      
+      tx_power = CC2420_DEF_RFPOWER;
     }
-
-    switch( cur_state ) {
-    case S_LOAD: loadTXFIFO(); break;
-    case S_BEGIN_TRANSMIT: attemptSend(); break;
-    default: releaseSpiResource(); break;
+    
+    call CSN.clr();
+    
+    if ( m_tx_power != tx_power ) {
+      call TXCTRL.write( ( 2 << CC2420_TXCTRL_TXMIXBUF_CUR ) |
+                         ( 3 << CC2420_TXCTRL_PA_CURRENT ) |
+                         ( 1 << CC2420_TXCTRL_RESERVED ) |
+                         ( (tx_power & 0x1F) << CC2420_TXCTRL_PA_LEVEL ) );
     }
-
+    
+    m_tx_power = tx_power;
+    
+    call TXFIFO.write( (uint8_t*)header, header->length - 1 );
+  }
+  
+  void signalDone( error_t err ) {
+    atomic m_state = S_STARTED;
+    signal Send.sendDone( m_msg, err );
+  }
+  
+  
+  
+  /***************** Tasks ****************/
+  task void startLplTimer() {
+    call LplDisableTimer.startOneShot((call CC2420Packet.getMetadata( m_msg ))->rxInterval + 10);
   }
 
-  async event void TXFIFO.readDone( uint8_t* tx_buf, uint8_t tx_len, error_t error ) {}
-
-  default async event void TimeStamp.transmittedSFD( uint16_t time, message_t* p_msg ) {}
-  default async event void TimeStamp.receivedSFD( uint16_t time ) {}
+  /***************** Defaults ****************/
+  default async event void TimeStamp.transmittedSFD( uint16_t time, message_t* p_msg ) {
+  }
+  
+  default async event void TimeStamp.receivedSFD( uint16_t time ) {
+  }
 
 }
+
diff --git a/tos/chips/cc2420/PacketLink.nc b/tos/chips/cc2420/PacketLink.nc
new file mode 100644 (file)
index 0000000..0b8e54a
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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 David Moss
+ * @author Jon Wyant
+ */
+
+interface PacketLink {
+
+  /**
+   * Set the maximum number of times attempt message delivery
+   * Default is 0
+   * @param msg
+   * @param maxRetries the maximum number of attempts to deliver
+   *     the message
+   */
+  command void setRetries(message_t *msg, uint16_t maxRetries);
+
+  /**
+   * Set a delay between each retry attempt
+   * @param msg
+   * @param retryDelay the delay betweeen retry attempts, in milliseconds
+   */
+  command void setRetryDelay(message_t *msg, uint16_t retryDelay);
+
+  /** 
+   * @return the maximum number of retry attempts for this message
+   */
+  command uint16_t getRetries(message_t *msg);
+
+  /**
+   * @return the delay between retry attempts in ms for this message
+   */
+  command uint16_t getRetryDelay(message_t *msg);
+
+  /**
+   * @return TRUE if the message was delivered.
+   */
+  command bool wasDelivered(message_t *msg);
+
+}
+
+
diff --git a/tos/chips/cc2420/PacketLinkC.nc b/tos/chips/cc2420/PacketLinkC.nc
new file mode 100644 (file)
index 0000000..2b5280c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Reliable Packet Link Functionality
+ * @author David Moss
+ * @author Jon Wyant
+ */
+
+#warning "*** USING PACKET LINK LAYER"
+
+configuration PacketLinkC {
+  provides {
+    interface Send;
+    interface PacketLink;
+  }
+  
+  uses {
+    interface Send as SubSend;
+  }
+}
+
+implementation {
+
+  components PacketLinkP,
+      ActiveMessageC,
+      CC2420PacketC,
+      RandomC,
+      new StateC() as SendStateC,
+      new TimerMilliC() as DelayTimerC;
+  
+  PacketLink = PacketLinkP;
+  Send = PacketLinkP.Send;
+  SubSend = PacketLinkP.SubSend;
+  
+  PacketLinkP.SendState -> SendStateC;
+  PacketLinkP.DelayTimer -> DelayTimerC;
+  PacketLinkP.PacketAcknowledgements -> ActiveMessageC;
+  PacketLinkP.AMPacket -> ActiveMessageC;
+  PacketLinkP.CC2420Packet -> CC2420PacketC;
+
+}
diff --git a/tos/chips/cc2420/PacketLinkDummyC.nc b/tos/chips/cc2420/PacketLinkDummyC.nc
new file mode 100644 (file)
index 0000000..2ea159c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Dummy configuration for PacketLink Layer
+ * @author David Moss
+ * @author Jon Wyant
+ */
+configuration PacketLinkDummyC {
+  provides {
+    interface Send;
+    interface PacketLink;
+  }
+  
+  uses {
+    interface Send as SubSend;
+  }
+}
+
+implementation {
+  components PacketLinkDummyP,
+      ActiveMessageC;
+  
+  PacketLink = PacketLinkDummyP;
+  Send = SubSend;
+  
+  PacketLinkDummyP.PacketAcknowledgements -> ActiveMessageC;
+  
+}
+
diff --git a/tos/chips/cc2420/PacketLinkDummyP.nc b/tos/chips/cc2420/PacketLinkDummyP.nc
new file mode 100644 (file)
index 0000000..1688da6
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Dummy module for Packet Link layer
+ * @author David Moss
+ * @author Jon Wyant
+ */
+
+module PacketLinkDummyP {
+  provides {
+    interface PacketLink;
+  }
+  
+  uses {
+    interface PacketAcknowledgements;
+  }
+}
+
+implementation {
+  
+  /***************** PacketLink Commands ***************/
+  /**
+   * Set the maximum number of times attempt message delivery
+   * Default is 0
+   * @param msg
+   * @param maxRetries the maximum number of attempts to deliver
+   *     the message
+   */
+  command void PacketLink.setRetries(message_t *msg, uint16_t maxRetries) {
+  }
+
+  /**
+   * Set a delay between each retry attempt
+   * @param msg
+   * @param retryDelay the delay betweeen retry attempts, in milliseconds
+   */
+  command void PacketLink.setRetryDelay(message_t *msg, uint16_t retryDelay) {
+  }
+
+  /** 
+   * @return the maximum number of retry attempts for this message
+   */
+  command uint16_t PacketLink.getRetries(message_t *msg) {
+    return 0;
+  }
+
+  /**
+   * @return the delay between retry attempts in ms for this message
+   */
+  command uint16_t PacketLink.getRetryDelay(message_t *msg) {
+    return 0;
+  }
+
+  /**
+   * @return TRUE if the message was delivered.
+   *     This should always be TRUE if the message was sent to the
+   *     AM_BROADCAST_ADDR
+   */
+  command bool PacketLink.wasDelivered(message_t *msg) {
+    return call PacketAcknowledgements.wasAcked(msg);
+  }
+}
+
diff --git a/tos/chips/cc2420/PacketLinkP.nc b/tos/chips/cc2420/PacketLinkP.nc
new file mode 100644 (file)
index 0000000..cccd212
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+
+/**
+ * Reliable Packet Link Functionality
+ * @author David Moss
+ * @author Jon Wyant
+ */
+#include "CC2420.h"
+
+module PacketLinkP {
+  provides {
+    interface Send;
+    interface PacketLink;
+  }
+  
+  uses {
+    interface Send as SubSend;
+    interface State as SendState;
+    interface PacketAcknowledgements;
+    interface Timer<TMilli> as DelayTimer;
+    interface AMPacket;
+    interface CC2420Packet;
+  }
+}
+
+implementation {
+  
+  /** The message currently being sent */
+  message_t *currentSendMsg;
+  
+  /** Length of the current send message */
+  uint8_t currentSendLen;
+  
+  /** The length of the current send message */
+  uint16_t totalRetries;
+  
+  
+  /**
+   * Send States
+   */
+  enum {
+    S_IDLE,
+    S_SENDING,
+  };
+  
+  
+  /***************** Prototypes ***************/
+  task void send();
+  void signalDone(error_t error);
+    
+  /***************** PacketLink Commands ***************/
+  /**
+   * Set the maximum number of times attempt message delivery
+   * Default is 0
+   * @param msg
+   * @param maxRetries the maximum number of attempts to deliver
+   *     the message
+   */
+  command void PacketLink.setRetries(message_t *msg, uint16_t maxRetries) {
+    (call CC2420Packet.getMetadata(msg))->maxRetries = maxRetries;
+  }
+
+  /**
+   * Set a delay between each retry attempt
+   * @param msg
+   * @param retryDelay the delay betweeen retry attempts, in milliseconds
+   */
+  command void PacketLink.setRetryDelay(message_t *msg, uint16_t retryDelay) {
+    (call CC2420Packet.getMetadata(msg))->retryDelay = retryDelay;
+  }
+
+  /** 
+   * @return the maximum number of retry attempts for this message
+   */
+  command uint16_t PacketLink.getRetries(message_t *msg) {
+    return (call CC2420Packet.getMetadata(msg))->maxRetries;
+  }
+
+  /**
+   * @return the delay between retry attempts in ms for this message
+   */
+  command uint16_t PacketLink.getRetryDelay(message_t *msg) {
+    return (call CC2420Packet.getMetadata(msg))->retryDelay;
+  }
+
+  /**
+   * @return TRUE if the message was delivered.
+   */
+  command bool PacketLink.wasDelivered(message_t *msg) {
+    return call PacketAcknowledgements.wasAcked(msg);
+  }
+  
+  /***************** Send Commands ***************/
+  /**
+   * Each call to this send command gives the message a single
+   * DSN that does not change for every copy of the message
+   * sent out.  For messages that are not acknowledged, such as
+   * a broadcast address message, the receiving end does not
+   * signal receive() more than once for that message.
+   */
+  command error_t Send.send(message_t *msg, uint8_t len) {
+    error_t error;
+    if(call SendState.requestState(S_SENDING) == SUCCESS) {
+    
+      currentSendMsg = msg;
+      currentSendLen = len;
+      totalRetries = 0;
+
+      if(call PacketLink.getRetries(msg) > 0) {
+        call PacketAcknowledgements.requestAck(msg);
+      }
+      
+      if((error = call SubSend.send(msg, len)) != SUCCESS) {    
+        call SendState.toIdle();
+      }
+      
+      return error;
+    }
+    
+    return EBUSY;
+  }
+
+  command error_t Send.cancel(message_t *msg) {
+    if(currentSendMsg == msg) {
+      call SendState.toIdle();
+      return call SubSend.cancel(msg);
+    }
+    
+    return FAIL;
+  }
+  
+  
+  command uint8_t Send.maxPayloadLength() {
+    return call SubSend.maxPayloadLength();
+  }
+
+  command void *Send.getPayload(message_t* msg) {
+    return call SubSend.getPayload(msg);
+  }
+  
+  
+  /***************** SubSend Events ***************/
+  event void SubSend.sendDone(message_t* msg, error_t error) {
+    if(call SendState.getState() == S_SENDING) {
+      totalRetries++;
+      if(call PacketAcknowledgements.wasAcked(msg)) {
+        signalDone(SUCCESS);
+        return;
+        
+      } else if(totalRetries < call PacketLink.getRetries(currentSendMsg)) {
+        
+        if(call PacketLink.getRetryDelay(currentSendMsg) > 0) {
+          // Resend after some delay
+          call DelayTimer.startOneShot(call PacketLink.getRetryDelay(currentSendMsg));
+          
+        } else {
+          // Resend immediately
+          post send();
+        }
+        
+        return;
+      }
+    }
+    
+    signalDone(error);
+  }
+  
+  
+  /***************** Timer Events ****************/  
+  /**
+   * When this timer is running, that means we're sending repeating messages
+   * to a node that is receive check duty cycling.
+   */
+  event void DelayTimer.fired() {
+    if(call SendState.getState() == S_SENDING) {
+      post send();
+    }
+  }
+  
+  /***************** Tasks ***************/
+  task void send() {
+    if(call PacketLink.getRetries(currentSendMsg) > 0) {
+      call PacketAcknowledgements.requestAck(currentSendMsg);
+    }
+    
+    if(call SubSend.send(currentSendMsg, currentSendLen) != SUCCESS) {
+      post send();
+    }
+  }
+  
+  /***************** Functions ***************/  
+  void signalDone(error_t error) {
+    call DelayTimer.stop();
+    call SendState.toIdle();
+    signal Send.sendDone(currentSendMsg, error);
+  }
+}
+
diff --git a/tos/chips/cc2420/README.txt b/tos/chips/cc2420/README.txt
new file mode 100644 (file)
index 0000000..518940d
--- /dev/null
@@ -0,0 +1,45 @@
+
+CC2420 Release Notes 4/11/07
+
+Known Issues
+__________________________________________
+ > LPL Lockups when the node is also accessing the USART
+ > NoAck LPL doesn't ack at the end properly, and also isn't
+   finished being implemented. The CRC of the packet needs to 
+   manually be loaded into TXFIFO before continuous modulation.
+
+Low Power Listening Schemes and Preprocessor Variables
+__________________________________________
+There are two low power listening schemes.  
+The default is called "AckLpl", because it inserts acknowledgement gaps and
+short backoffs during the packet retransmission process.  
+This allows the transmitter to stop transmitting early, but increases the 
+power consumption per receive check.  
+
+The second is called "NoAckLpl", because it does not insert acknowledgement
+gaps or backoffs in the retransmission process, so the receive checks are 
+shorter but the transmissions are longer.  This is more experimental than
+the Ack LPL version.
+
+To compile in the default Ack LPL version, #define the preprocessor variable:
+
+  LOW_POWER_LISTENING
+ -or-  
+  ACK_LOW_POWER_LISTENING
+  
+  
+To compile in the NoAck LPL version, #define:
+
+  NOACK_LOW_POWER_LISTENING
+
+  
+To compile in the PacketLink layer, #define:
+
+  PACKET_LINK
+  
+  
+To remove SACK auto-acknowledgements, #define:
+
+  CC2420_NO_ACKNOWLEDGEMENTS
+  
diff --git a/tos/chips/cc2420/RadioBackoff.nc b/tos/chips/cc2420/RadioBackoff.nc
new file mode 100644 (file)
index 0000000..98d6382
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Interface to request and specify backoff periods for messages
+ * @author David Moss
+ */
+interface RadioBackoff {
+
+  /**
+   * Must be called within a requestInitialBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void setInitialBackoff(uint16_t backoffTime);
+  
+  /**
+   * Must be called within a requestCongestionBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void setCongestionBackoff(uint16_t backoffTime);
+  
+  
+  /**
+   * Must be called within a requestLplBackoff event
+   * @param backoffTime the amount of time in some unspecified units to backoff
+   */
+  async command void setLplBackoff(uint16_t backoffTime);
+
+
+  /**
+   * Enable CCA for the outbound packet.  Must be called within a requestCca
+   * event
+   * @param ccaOn TRUE to enable CCA, which is the default.
+   */
+  async command void setCca(bool ccaOn);
+
+
+  /**  
+   * Request for input on the initial backoff
+   * Reply using setInitialBackoff(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void requestInitialBackoff(message_t *msg);
+  
+  /**
+   * Request for input on the congestion backoff
+   * Reply using setCongestionBackoff(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void requestCongestionBackoff(message_t *msg);
+  
+  /**
+   * Request for input on the low power listening backoff
+   * This should be somewhat random, but as short as possible
+   * Reply using setLplBackoff(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void requestLplBackoff(message_t *msg);
+  
+  /**
+   * Request for input on whether or not to use CCA on the outbound packet.
+   * Replies should come in the form of setCca(..)
+   * @param msg pointer to the message being sent
+   */
+  async event void requestCca(message_t *msg);
+}
+
diff --git a/tos/chips/cc2420/UniqueReceiveC.nc b/tos/chips/cc2420/UniqueReceiveC.nc
new file mode 100644 (file)
index 0000000..2a8dd9a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * This layer keeps a history of the past RECEIVE_HISTORY_SIZE received messages
+ * If the source address and dsn number of a newly received message matches
+ * our recent history, we drop the message because we've already seen it.
+ * This should sit at the bottom of the stack
+ * @author David Moss
+ */
+configuration UniqueReceiveC {
+  provides {
+    interface Receive;
+    interface Receive as DuplicateReceive;
+  }
+  
+  uses {
+    interface Receive as SubReceive;
+  }
+}
+
+implementation {
+  components UniqueReceiveP,
+      CC2420PacketC,
+      MainC;
+  
+  Receive = UniqueReceiveP.Receive;
+  DuplicateReceive = UniqueReceiveP.DuplicateReceive;
+  SubReceive = UniqueReceiveP.SubReceive;
+      
+  MainC.SoftwareInit -> UniqueReceiveP;
+  
+  UniqueReceiveP.CC2420Packet -> CC2420PacketC;
+  
+}
+
diff --git a/tos/chips/cc2420/UniqueReceiveP.nc b/tos/chips/cc2420/UniqueReceiveP.nc
new file mode 100644 (file)
index 0000000..fb63ec6
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/** 
+ * This layer keeps a history of the past RECEIVE_HISTORY_SIZE received messages
+ * If the source address and dsn number of a newly received message matches
+ * our recent history, we drop the message because we've already seen it.
+ * @author David Moss
+ */
+#include "CC2420.h"
+
+module UniqueReceiveP {
+  provides {
+    interface Receive;
+    interface Receive as DuplicateReceive;
+    interface Init;
+  }
+  
+  uses {
+    interface Receive as SubReceive;
+    interface CC2420Packet;
+  }
+}
+
+implementation {
+  
+  struct {
+    am_addr_t source;
+    uint8_t dsn;
+  } receivedMessages[RECEIVE_HISTORY_SIZE];
+  
+  uint8_t writeIndex = 0;
+  
+  /** History element containing info on a source previously received from */
+  uint8_t recycleSourceElement;
+  
+  enum {
+    INVALID_ELEMENT = 0xFF,
+  };
+  
+  /***************** Init Commands *****************/
+  command error_t Init.init() {
+    int i;
+    for(i = 0; i < RECEIVE_HISTORY_SIZE; i++) {
+      receivedMessages[i].source = (am_addr_t) 0xFFFF;
+      receivedMessages[i].dsn = 0;
+    }
+    return SUCCESS;
+  }
+  
+  /***************** Prototypes Commands ***************/
+  bool hasSeen(uint16_t msgSource, uint8_t msgDsn);
+  void insert(uint16_t msgSource, uint8_t msgDsn);
+  
+  /***************** Receive Commands ***************/
+  command void *Receive.getPayload(message_t* msg, uint8_t* len) {
+    return call SubReceive.getPayload(msg, len);
+  }
+
+  command uint8_t Receive.payloadLength(message_t* msg) {
+    return call SubReceive.payloadLength(msg);
+  }
+  
+  
+  /***************** DuplicateReceive Commands ****************/
+  command void *DuplicateReceive.getPayload(message_t* msg, uint8_t* len) {
+    return call SubReceive.getPayload(msg, len);
+  }
+
+  command uint8_t DuplicateReceive.payloadLength(message_t* msg) {
+    return call SubReceive.payloadLength(msg);
+  }
+  
+  /***************** SubReceive Events *****************/
+  event message_t *SubReceive.receive(message_t* msg, void* payload, 
+      uint8_t len) {
+    uint16_t msgSource = (call CC2420Packet.getHeader(msg))->src;
+    uint8_t msgDsn = (call CC2420Packet.getHeader(msg))->dsn;
+    
+    if(hasSeen(msgSource, msgDsn)) {
+      return signal DuplicateReceive.receive(msg, payload, len);
+      
+    } else {
+      insert(msgSource, msgDsn);
+      return signal Receive.receive(msg, payload, len);
+    }
+  }
+  
+  /****************** Functions ****************/  
+  /**
+   * This function does two things:
+   *  1. It loops through our entire receive history and detects if we've 
+   *     seen this DSN before from the given source (duplicate packet)
+   *  2. It detects if we've seen messages from this source before, so we know
+   *     where to update our history if it turns out this is a new message.
+   *
+   * The global recycleSourceElement variable stores the location of the next insert
+   * if we've received a packet from that source before.  Otherwise, it's up 
+   * to the insert() function to decide who to kick out of our history.
+   */
+  bool hasSeen(uint16_t msgSource, uint8_t msgDsn) {
+    int i;
+    recycleSourceElement = INVALID_ELEMENT;
+    
+    atomic {
+      for(i = 0; i < RECEIVE_HISTORY_SIZE; i++) {
+        if(receivedMessages[i].source == msgSource) {
+          if(receivedMessages[i].dsn == msgDsn) {
+            // Only exit this loop if we found a duplicate packet
+            return TRUE;
+          }
+          
+          recycleSourceElement = i;
+        }
+      }
+    }
+      
+    return FALSE;
+  }
+  
+  /**
+   * Insert the message into the history.  If we received a message from this
+   * source before, insert it into the same location as last time and verify
+   * that the "writeIndex" is not pointing to that location. Otherwise,
+   * insert it into the "writeIndex" location.
+   */
+  void insert(uint16_t msgSource, uint8_t msgDsn) {
+    uint8_t element = recycleSourceElement;
+    bool increment = FALSE;
+   
+    atomic {
+      if(element == INVALID_ELEMENT || writeIndex == element) {
+        // Use the writeIndex element to insert this new message into
+        element = writeIndex;
+        increment = TRUE;
+      }
+
+      receivedMessages[element].source = msgSource;
+      receivedMessages[element].dsn = msgDsn;
+      if(increment) {
+        writeIndex++;
+        writeIndex %= RECEIVE_HISTORY_SIZE;
+      }
+    }
+  }
+  
+  /***************** Defaults ****************/
+  default event message_t *DuplicateReceive.receive(message_t *msg, void *payload, uint8_t len) {
+    return msg;
+  }
+}
+
diff --git a/tos/chips/cc2420/UniqueSendC.nc b/tos/chips/cc2420/UniqueSendC.nc
new file mode 100644 (file)
index 0000000..a2cbcef
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Generate a unique dsn byte for this outgoing packet
+ * This should sit at the top of the stack
+ * @author David Moss
+ */
+configuration UniqueSendC {
+  provides {
+    interface Send;
+  }
+  
+  uses {
+    interface Send as SubSend;
+  }
+}
+
+implementation {
+  components UniqueSendP,
+      new StateC(),
+      RandomC,
+      CC2420PacketC,
+      MainC;
+      
+  Send = UniqueSendP.Send;
+  SubSend = UniqueSendP.SubSend;
+  
+  MainC.SoftwareInit -> UniqueSendP;
+  
+  UniqueSendP.State -> StateC;
+  UniqueSendP.Random -> RandomC;
+  UniqueSendP.CC2420Packet -> CC2420PacketC;
+  
+}
+
diff --git a/tos/chips/cc2420/UniqueSendP.nc b/tos/chips/cc2420/UniqueSendP.nc
new file mode 100644 (file)
index 0000000..74df958
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * This layer is responsible for supplying a unique data sequence number (dsn)
+ * to each outgoing message.
+ * @author David Moss
+ */
+module UniqueSendP {
+  provides {
+    interface Send;
+    interface Init;
+  }
+  
+  uses {
+    interface Send as SubSend;
+    interface State;
+    interface Random;
+    interface CC2420Packet;
+  }
+}
+
+implementation {
+
+  uint8_t localSendId;
+  
+  enum {
+    S_IDLE,
+    S_SENDING,
+  };
+  
+  /***************** Init Commands ****************/
+  command error_t Init.init() {
+    localSendId = call Random.rand16();
+    return SUCCESS;
+  }
+
+  /***************** Send Commands ****************/
+  /**
+   * Each call to this send command gives the message a single
+   * DSN that does not change for every copy of the message
+   * sent out.  For messages that are not acknowledged, such as
+   * a broadcast address message, the receiving end does not
+   * signal receive() more than once for that message.
+   */
+  command error_t Send.send(message_t *msg, uint8_t len) {
+    error_t error;
+    if(call State.requestState(S_SENDING) == SUCCESS) {
+      (call CC2420Packet.getHeader(msg))->dsn = localSendId++;
+      
+      if((error = call SubSend.send(msg, len)) != SUCCESS) {
+        call State.toIdle();
+      }
+      
+      return error;
+    }
+    
+    return EBUSY;
+  }
+
+  command error_t Send.cancel(message_t *msg) {
+    return call SubSend.cancel(msg);
+  }
+  
+  
+  command uint8_t Send.maxPayloadLength() {
+    return call SubSend.maxPayloadLength();
+  }
+
+  command void *Send.getPayload(message_t* msg) {
+    return call SubSend.getPayload(msg);
+  }
+  
+  /***************** SubSend Events ****************/
+  event void SubSend.sendDone(message_t *msg, error_t error) {
+    call State.toIdle();
+    signal Send.sendDone(msg, error);
+  }
+  
+}
+
diff --git a/tos/interfaces/LowPowerListening.nc b/tos/interfaces/LowPowerListening.nc
new file mode 100644 (file)
index 0000000..0326907
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2005-2006 Rincon Research 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 Rincon Research 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
+ * RINCON RESEARCH 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
+ */
+/**
+ * Low Power Listening interface
+ *
+ * @author Jonathan Hui
+ * @author David Moss
+ */
+#include "message.h"
+interface LowPowerListening {
+
+  /**
+   * Set this this node's radio sleep interval, in milliseconds.
+   * Once every interval, the node will sleep and perform an Rx check 
+   * on the radio.  Setting the sleep interval to 0 will keep the radio
+   * always on.
+   *
+   * This is the equivalent of setting the local duty cycle rate.
+   *
+   * @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
+   */
+  command void setLocalSleepInterval(uint16_t sleepIntervalMs);
+  
+  /**
+   * @return the local node's sleep interval, in [ms]
+   */
+  command uint16_t getLocalSleepInterval();
+  
+  /**
+   * Set this node's radio duty cycle rate, in units of [percentage*100].
+   * For example, to get a 0.05% duty cycle,
+   * <code>
+   *   call LowPowerListening.setDutyCycle(5);
+   * </code>
+   *
+   * For a 100% duty cycle (always on),
+   * <code>
+   *   call LowPowerListening.setDutyCycle(10000);
+   * </code>
+   *
+   * This is the equivalent of setting the local sleep interval explicitly.
+   * 
+   * @param dutyCycle The duty cycle percentage, in units of [percentage*100]
+   */
+  command void setLocalDutyCycle(uint16_t dutyCycle);
+  
+  /**
+   * @return this node's radio duty cycle rate, in units of [percentage*100]
+   */
+  command uint16_t getLocalDutyCycle();
+  
+  
+  /**
+   * Configure this outgoing message so it can be transmitted to a neighbor mote
+   * with the specified Rx sleep interval.
+   * @param msg Pointer to the message that will be sent
+   * @param sleepInterval The receiving node's sleep interval, in [ms]
+   */
+  command void setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs);
+  
+  /**
+   * @return the destination node's sleep interval configured in this message
+   */
+  command uint16_t getRxSleepInterval(message_t *msg);
+  
+  /**
+   * Configure this outgoing message so it can be transmitted to a neighbor mote
+   * with the specified Rx duty cycle rate.
+   * Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25.
+   * 
+   * @param msg Pointer to the message that will be sent
+   * @param dutyCycle The duty cycle of the receiving mote, in units of 
+   *     [percentage*100]
+   */
+  command void setRxDutyCycle(message_t *msg, uint16_t dutyCycle);
+  
+  /**
+   * @return the destination node's duty cycle configured in this message
+   *     in units of [percentage*100]
+   */
+  command uint16_t getRxDutyCycle(message_t *msg);
+  
+  /**
+   * Convert a duty cycle, in units of [percentage*100], to
+   * the sleep interval of the mote in milliseconds
+   * @param dutyCycle The duty cycle in units of [percentage*100]
+   * @return The equivalent sleep interval, in units of [ms]
+   */
+  command uint16_t dutyCycleToSleepInterval(uint16_t dutyCycle);
+  
+  /**
+   * Convert a sleep interval, in units of [ms], to a duty cycle
+   * in units of [percentage*100]
+   * @param sleepInterval The sleep interval in units of [ms]
+   * @return The duty cycle in units of [percentage*100]
+   */
+  command uint16_t sleepIntervalToDutyCycle(uint16_t sleepInterval);
+  
+}