]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
added ack, received packet strength, LPL (compile with PFLAGS +=-DLOW_POWER_LISTENING)
authormaxmul <maxmul>
Fri, 13 Jul 2007 15:54:08 +0000 (15:54 +0000)
committermaxmul <maxmul>
Fri, 13 Jul 2007 15:54:08 +0000 (15:54 +0000)
26 files changed:
tos/chips/xe1205/AckSendReceive.nc [new file with mode: 0644]
tos/chips/xe1205/CsmaControl.nc [new file with mode: 0644]
tos/chips/xe1205/LPLControl.nc [new file with mode: 0644]
tos/chips/xe1205/LowPowerListening.nc [new file with mode: 0644]
tos/chips/xe1205/XE1205.h
tos/chips/xe1205/XE1205ActiveMessageC.nc
tos/chips/xe1205/XE1205CsmaP.nc [new file with mode: 0644]
tos/chips/xe1205/XE1205CsmaRadioC.nc [new file with mode: 0644]
tos/chips/xe1205/XE1205LowPowerListening.h [new file with mode: 0644]
tos/chips/xe1205/XE1205LowPowerListeningC.nc [new file with mode: 0644]
tos/chips/xe1205/XE1205LowPowerListeningP.nc [new file with mode: 0644]
tos/chips/xe1205/XE1205SendReceiveC.nc
tos/chips/xe1205/XE1205SendReceiveP.nc
tos/chips/xe1205/XE1205SpiImplP.nc
tos/chips/xe1205/conf/XE1205PatternConf.nc
tos/chips/xe1205/conf/XE1205PatternConfP.nc
tos/chips/xe1205/conf/XE1205PhyRssiConfP.nc
tos/chips/xe1205/conf/XE1205RssiConf.nc
tos/chips/xe1205/phy/XE1205PhyC.nc
tos/chips/xe1205/phy/XE1205PhyP.nc
tos/chips/xe1205/phy/XE1205PhyRssi.nc [new file with mode: 0644]
tos/chips/xe1205/phy/XE1205PhyRxTx.nc
tos/chips/xe1205/xe1205debug.h
tos/platforms/tinynode/chips/xe1205/Xe1205Spi0C.nc [new file with mode: 0644]
tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDma0P.nc [new file with mode: 0644]
tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDmaP.nc [new file with mode: 0644]

diff --git a/tos/chips/xe1205/AckSendReceive.nc b/tos/chips/xe1205/AckSendReceive.nc
new file mode 100644 (file)
index 0000000..34c3b4b
--- /dev/null
@@ -0,0 +1,4 @@
+interface AckSendReceive {
+    command void setAckPayload(uint16_t _pl);
+    command uint16_t getAckPayload();
+}
diff --git a/tos/chips/xe1205/CsmaControl.nc b/tos/chips/xe1205/CsmaControl.nc
new file mode 100644 (file)
index 0000000..a789827
--- /dev/null
@@ -0,0 +1,5 @@
+interface CsmaControl {
+    
+    async command void enableCca();
+    async command void disableCca();
+}
diff --git a/tos/chips/xe1205/LPLControl.nc b/tos/chips/xe1205/LPLControl.nc
new file mode 100644 (file)
index 0000000..9e8a6fd
--- /dev/null
@@ -0,0 +1,5 @@
+
+interface LPLControl {
+    
+    async command void setMode(uint8_t mode);
+}
diff --git a/tos/chips/xe1205/LowPowerListening.nc b/tos/chips/xe1205/LowPowerListening.nc
new file mode 100644 (file)
index 0000000..8bd970f
--- /dev/null
@@ -0,0 +1,129 @@
+/*\r
+ * Copyright (c) 2005-2006 Rincon Research Corporation\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * - Redistributions of source code must retain the above copyright\r
+ *   notice, this list of conditions and the following disclaimer.\r
+ * - Redistributions in binary form must reproduce the above copyright\r
+ *   notice, this list of conditions and the following disclaimer in the\r
+ *   documentation and/or other materials provided with the\r
+ *   distribution.\r
+ * - Neither the name of the Arch Rock Corporation nor the names of\r
+ *   its contributors may be used to endorse or promote products derived\r
+ *   from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE\r
+ * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\r
+ * OF THE POSSIBILITY OF SUCH DAMAGE\r
+ */\r
\r
+/**\r
+ * Low Power Listening interface\r
+ *\r
+ * @author David Moss\r
+ * @author Jonathan Hui\r
+ */\r
\r
+interface LowPowerListening {\r
+\r
+  /**\r
+   * Set this this node's radio sleep interval, in milliseconds.\r
+   * Once every interval, the node will sleep and perform an Rx check \r
+   * on the radio.  Setting the sleep interval to 0 will keep the radio\r
+   * always on.\r
+   *\r
+   * This is the equivalent of setting the local duty cycle rate.\r
+   *\r
+   * @param sleepIntervalMs the length of this node's Rx check interval, in [ms]\r
+   */\r
+  command void setLocalSleepInterval(uint16_t sleepIntervalMs);\r
+  \r
+  /**\r
+   * @return the local node's sleep interval, in [ms]\r
+   */\r
+  command uint16_t getLocalSleepInterval();\r
+  \r
+  /**\r
+   * Set this node's radio duty cycle rate, in units of [percentage*100].\r
+   * For example, to get a 0.05% duty cycle,\r
+   * <code>\r
+   *   call LowPowerListening.setDutyCycle(5);  // or equivalently...\r
+   *   call LowPowerListening.setDutyCycle(00005);  // for better readability?\r
+   * </code>\r
+   *\r
+   * For a 100% duty cycle (always on),\r
+   * <code>\r
+   *   call LowPowerListening.setDutyCycle(10000);\r
+   * </code>\r
+   *\r
+   * This is the equivalent of setting the local sleep interval explicitly.\r
+   * \r
+   * @param dutyCycle The duty cycle percentage, in units of [percentage*100]\r
+   */\r
+  command void setLocalDutyCycle(uint16_t dutyCycle);\r
+  \r
+  /**\r
+   * @return this node's radio duty cycle rate, in units of [percentage*100]\r
+   */\r
+  command uint16_t getLocalDutyCycle();\r
+  \r
+  \r
+  /**\r
+   * Configure this outgoing message so it can be transmitted to a neighbor mote\r
+   * with the specified Rx sleep interval.\r
+   * @param msg Pointer to the message that will be sent\r
+   * @param sleepInterval The receiving node's sleep interval, in [ms]\r
+   */\r
+  command void setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs);\r
+  \r
+  /**\r
+   * @return the destination node's sleep interval configured in this message\r
+   */\r
+  command uint16_t getRxSleepInterval(message_t *msg);\r
+  \r
+  /**\r
+   * Configure this outgoing message so it can be transmitted to a neighbor mote\r
+   * with the specified Rx duty cycle rate.\r
+   * Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25.\r
+   * \r
+   * @param msg Pointer to the message that will be sent\r
+   * @param dutyCycle The duty cycle of the receiving mote, in units of \r
+   *     [percentage*100]\r
+   */\r
+  command void setRxDutyCycle(message_t *msg, uint16_t dutyCycle);\r
+  \r
+  /**\r
+   * @return the destination node's duty cycle configured in this message\r
+   *     in units of [percentage*100]\r
+   */\r
+  command uint16_t getRxDutyCycle(message_t *msg);\r
+  \r
+  /**\r
+   * Convert a duty cycle, in units of [percentage*100], to\r
+   * the sleep interval of the mote in milliseconds\r
+   * @param dutyCycle The duty cycle in units of [percentage*100]\r
+   * @return The equivalent sleep interval, in units of [ms]\r
+   */\r
+  command uint16_t dutyCycleToSleepInterval(uint16_t dutyCycle);\r
+  \r
+  /**\r
+   * Convert a sleep interval, in units of [ms], to a duty cycle\r
+   * in units of [percentage*100]\r
+   * @param sleepInterval The sleep interval in units of [ms]\r
+   * @return The duty cycle in units of [percentage*100]\r
+   */\r
+  command uint16_t sleepIntervalToDutyCycle(uint16_t sleepInterval);\r
+  \r
+}\r
index 226abeee9ee584a0da4dee411924e04799432b43..bcd8b86e0e4957c14c0fd01679b54ef5ccba8ea4 100644 (file)
@@ -52,15 +52,19 @@ typedef nx_struct xe1205_header_t {
   nx_am_addr_t source;
   nx_am_id_t type;
   nx_am_group_t group;
+  nx_uint8_t ack;
 } xe1205_header_t;
 
 typedef nx_struct xe1205_footer_t {
-  nxle_uint16_t crc;  
+#ifdef LOW_POWER_LISTENING
+    nx_uint16_t rxInterval;
+#endif
+  nxle_uint16_t crc;
 } xe1205_footer_t;
 
 typedef nx_struct xe1205_metadata_t {
   nx_uint8_t length;
-  nx_uint8_t ack;// xxx this should move to header or footer, leaving it here for now for 1.x compat
+  nx_uint8_t strength;
 } xe1205_metadata_t;
 
 
@@ -108,7 +112,8 @@ enum {
 };
 
 enum {
-  data_pattern = 0x893456,
+    data_pattern = 0x893456,
+    ack_pattern = 0x123fed
 };
 
 
@@ -133,9 +138,12 @@ typedef enum {
 
 
 typedef enum {
-  xe1205_channelpreset_867mhz=0,
-  xe1205_channelpreset_868mhz=1,
-  xe1205_channelpreset_869mhz=2,
+  xe1205_channelpreset_868mhz=0,
+  xe1205_channelpreset_869mhz=1,
+  xe1205_channelpreset_870mhz=2,
+  xe1205_channelpreset_433mhz=3,
+  xe1205_channelpreset_434mhz=4,
+  xe1205_channelpreset_435mhz=5,
 } xe1205_channelpreset_t;
 
 typedef enum {
@@ -188,5 +196,36 @@ enum {
 };
 
 
+
+enum {
+  RSSI_BELOW_110 = 0,
+  RSSI_110_TO_105 = 1,
+  RSSI_105_TO_100 = 2,
+  RSSI_100_TO_95 = 3,
+  RSSI_95_TO_90 = 4,
+  RSSI_90_TO_85 = 5,
+  RSSI_ABOVE_85 = 6
+};
+
+uint8_t const rssiTab[] = {
+  RSSI_BELOW_110,  // 0b0000
+  RSSI_110_TO_105, // 0b0001
+  RSSI_105_TO_100, // 0b0010
+  RSSI_100_TO_95,  // 0b0011
+  RSSI_95_TO_90,   // 0b0100 *
+  RSSI_95_TO_90,   // 0b0101 *
+  RSSI_95_TO_90,   // 0b0110 *
+  RSSI_95_TO_90,   // 0b0111
+  RSSI_90_TO_85,   // 0b1000 *
+  RSSI_90_TO_85,   // 0b1001 *
+  RSSI_90_TO_85,   // 0b1010 *
+  RSSI_90_TO_85,   // 0b1011 
+  RSSI_ABOVE_85,   // 0b1100 *
+  RSSI_ABOVE_85,   // 0b1101 *
+  RSSI_ABOVE_85,   // 0b1110 *
+  RSSI_ABOVE_85    // 0b1111 
+  // (*) : 'inconsistent' pairs
+};
+
 #endif /* _XE1205CONST_H */
 
index 3f2c76862336168ea3c5cdc1c3543d51a89e30f6..49c68c86a5eba258f8205b8d1800c6a7a8400915 100644 (file)
@@ -44,20 +44,30 @@ configuration XE1205ActiveMessageC {
     interface AMPacket;
     interface Packet;
     interface PacketAcknowledgements;
+    #ifdef LOW_POWER_LISTENING
+    interface LowPowerListening;
+    #endif
   }
 }
 implementation {
   components XE1205SendReceiveC;
-  SplitControl           = XE1205SendReceiveC;
   Packet                 = XE1205SendReceiveC;
   PacketAcknowledgements = XE1205SendReceiveC;
+ components XE1205ActiveMessageP;
 
-
-  components XE1205ActiveMessageP;
+#ifdef LOW_POWER_LISTENING
+  components  XE1205LowPowerListeningC as Lpl;
+  LowPowerListening = Lpl;
+  XE1205ActiveMessageP.SubSend -> Lpl.Send;
+  XE1205ActiveMessageP.SubReceive -> Lpl.Receive;
+  SplitControl = Lpl;
+#else
   XE1205ActiveMessageP.Packet     -> XE1205SendReceiveC;
   XE1205ActiveMessageP.SubSend    -> XE1205SendReceiveC.Send;
   XE1205ActiveMessageP.SubReceive -> XE1205SendReceiveC.Receive;
-
+  SplitControl = XE1205SendReceiveC;
+#endif
   AMPacket = XE1205ActiveMessageP;
   AMSend   = XE1205ActiveMessageP;
   Receive  = XE1205ActiveMessageP.Receive;
diff --git a/tos/chips/xe1205/XE1205CsmaP.nc b/tos/chips/xe1205/XE1205CsmaP.nc
new file mode 100644 (file)
index 0000000..2ed3942
--- /dev/null
@@ -0,0 +1,318 @@
+/* Copyright (c) 2007 Shockfish SA
+*  All rights reserved.
+*
+*  Permission to use, copy, modify, and distribute this software and its
+*  documentation for any purpose, without fee, and without written
+*  agreement is hereby granted, provided that the above copyright
+*  notice, the (updated) modification history and the author appear in
+*  all copies of this source code.
+*
+*  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 COPYRIGHT HOLDERS OR CONTRIBUTORS
+*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+*  OR PROFITS) 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 Maxime Muller
+ *
+ */
+
+#include "XE1205.h"
+#include "XE1205LowPowerListening.h"
+
+#define MAX(X,Y) X>Y ? X:Y
+
+module XE1205CsmaP {
+
+    provides {
+       interface Init @atleastonce();
+       interface SplitControl @atleastonce();
+       interface Send;
+       interface Receive;
+       interface CsmaControl;
+       interface LPLControl;
+       interface CsmaBackoff[am_id_t amId];
+    }
+    uses {
+       interface SplitControl as SubControl;
+       interface Receive as SubReceive;
+       interface Send as SubSend;
+       interface XE1205PhyRssi as Rssi;
+       interface XE1205PhyConf as RadioConf;
+       interface Timer<TMilli> as BackoffTimer;
+       interface Random;
+    }
+}
+implementation {
+
+    enum {
+       RADIO_DISABLED,
+       RADIO_IDLE,
+       RADIO_RX,
+       RADIO_TX,
+    };
+
+    uint8_t rState;
+    uint8_t rxRssi;
+    uint8_t clrRssi;
+    norace uint8_t rssiSampleCnt;
+    bool enableCCA;
+
+    message_t * txMsg;
+    uint8_t txLen;
+    enum {
+       RSSI_RX = 0,
+       RSSI_CLR = 1,
+    };
+    uint16_t MA_LENGTH = 8;
+    uint8_t MAX_RSSI_SAMPLE = 4;
+    norace float RSSI_RX_MA;
+    norace float RSSI_CLR_MA;
+    
+    /*
+     * function prototypes
+     */
+
+    task void readRssi();
+    task void send();
+    
+    command error_t Init.init() {
+       rssiSampleCnt=0;
+       rState = RADIO_DISABLED;
+       RSSI_RX_MA = RSSI_ABOVE_85;
+       RSSI_CLR_MA = RSSI_90_TO_85;
+       return SUCCESS;
+    }
+    
+    command error_t SplitControl.start() {
+       return call SubControl.start();
+    }
+
+    event void SubControl.startDone(error_t err) {
+       if (err!=SUCCESS) {
+           atomic {
+           if (rState == RADIO_TX)
+               signal Send.sendDone(txMsg,FAIL);
+           else
+               signal SplitControl.startDone(FAIL);
+           }
+       } else {
+           atomic {
+               if (rState == RADIO_TX) {
+                   if(enableCCA==TRUE) {
+                       if(SUCCESS != post readRssi()) {
+                           signal Send.sendDone(txMsg,FAIL);
+                           return;
+                       }
+                   } 
+                   else {
+                       post send();
+                       return;
+                       if (SUCCESS != post send()) {
+                           signal Send.sendDone(txMsg,FAIL);
+                           return;
+                       }
+                   }
+               }
+               if(SUCCESS != post readRssi())
+                   signal SplitControl.startDone(FAIL);
+           }
+       }
+    }
+
+    command error_t SplitControl.stop() { 
+
+       return call SubControl.stop();
+    }
+
+    event void SubControl.stopDone(error_t err) {
+       atomic {
+       if (rState == RADIO_RX) // LPL: shutdown if no activity
+           if (err==SUCCESS)
+                rState = RADIO_IDLE;
+       }
+       signal SplitControl.stopDone(err);
+    }
+
+
+
+    void updateRssiMA(uint8_t maType, uint8_t value) {
+
+       switch (maType) {
+       case RSSI_CLR:
+           if((float)value < MAX(RSSI_RX_MA,RSSI_RX_MA))
+               RSSI_CLR_MA = (RSSI_CLR_MA*(MA_LENGTH - 1)+ value )/(MA_LENGTH);
+           break;
+           
+       case RSSI_RX:
+           RSSI_RX_MA  = (RSSI_RX_MA*(MA_LENGTH - 1)+ value )/(MA_LENGTH);
+           break;
+
+       default:
+           break;
+       }
+    }
+
+    event message_t *SubReceive.receive(message_t* msg, void* payload, uint8_t len){
+       
+       uint8_t strgth = ((xe1205_metadata_t*)((uint8_t*)msg->footer + sizeof(xe1205_footer_t)))->strength;
+       updateRssiMA(RSSI_RX, strgth);
+       return signal Receive.receive(msg, payload, len);
+    }
+
+    command error_t Send.send(message_t* msg, uint8_t len) {
+       error_t err;
+       atomic {
+           switch (rState) {
+
+           case RADIO_DISABLED:
+               return EOFF;
+
+           default:
+       
+               rState = RADIO_TX;
+               atomic txMsg = msg;
+               atomic txLen = len;
+               err = call SubControl.start();
+               return err;
+           }
+       }
+    }
+    
+    task void send() {
+       if (SUCCESS != call SubSend.send(txMsg, txLen)) {
+           atomic rState = RADIO_IDLE;
+           signal Send.sendDone(txMsg, FAIL);   
+       }
+    }
+
+    event void SubSend.sendDone(message_t *msg, error_t err) {
+       atomic rState = RADIO_IDLE;
+       signal Send.sendDone(msg, err);
+    }
+
+    command void* Send.getPayload(message_t* m) {
+       return m->data;
+    }
+
+    command uint8_t Send.maxPayloadLength() {
+       return TOSH_DATA_LENGTH;
+    }
+
+    command error_t Send.cancel( message_t* p_msg ) {
+       return FAIL;
+    }
+
+    command uint8_t Receive.payloadLength(message_t* msg) {
+       return call SubReceive.payloadLength(msg);
+    }
+
+    command void *Receive.getPayload(message_t* msg, uint8_t* len) {
+       return call SubReceive.getPayload(msg, len);
+    }
+    
+    task void readRssi() {
+       if(SUCCESS!=call Rssi.getRssi()) {
+        
+           atomic {
+           if (rState == RADIO_TX) {    
+               signal Send.sendDone(txMsg, FAIL);
+           } else {
+               signal SplitControl.startDone(FAIL);
+           }
+           }
+       }
+    }
+
+
+    event void BackoffTimer.fired() {
+       rssiSampleCnt = 0;
+       if(SUCCESS != post send()) {
+           atomic rState = RADIO_IDLE;
+           signal Send.sendDone(txMsg,FAIL);
+       }
+    }
+    async event void Rssi.rssiDone(uint8_t val) {
+       
+       updateRssiMA(RSSI_CLR, val);
+       atomic {
+           if (rState == RADIO_DISABLED) {
+               rState = RADIO_IDLE;
+               signal SplitControl.startDone(SUCCESS);
+               return;
+           }
+       }
+
+       // RX for LPL only
+       atomic {
+       if (rState == RADIO_RX) {
+           if (RSSI_CLR_MA >= (float)val) { // go back to sleep
+               call SubControl.stop();
+               return;
+           } else
+               // tell lpl layer we have some activity
+               signal SplitControl.startDone(SUCCESS);
+       }
+       
+       // TX
+       if (rState == RADIO_TX) {
+           rssiSampleCnt++;
+           if ( RSSI_RX_MA >= (float)val || RSSI_CLR_MA >= (float)val || !enableCCA) { // it's a go
+               if (enableCCA) {
+                   call BackoffTimer.startOneShot(signal CsmaBackoff.initial[((xe1205_header_t*)(txMsg->data -  sizeof(xe1205_header_t)))->type](txMsg));
+               } else
+                   post send();
+               return;
+           }
+           else 
+               if (enableCCA && rssiSampleCnt < MAX_RSSI_SAMPLE) {
+                   post readRssi();
+               } else {
+                   call BackoffTimer.startOneShot(signal CsmaBackoff.congestion[((xe1205_header_t*)(txMsg->data -  sizeof(xe1205_header_t)))->type](txMsg));
+               }
+           }
+       }
+    }
+    
+    async command void LPLControl.setMode(uint8_t mode) {
+       switch (mode) {
+
+       case RX:
+           atomic {
+               if(rState!=RADIO_TX)
+                   rState = RADIO_RX;
+           }
+           break;
+
+       case IDLE:
+           atomic rState = RADIO_IDLE;
+
+       default:
+           return;
+       }
+    }
+    
+    async command void CsmaControl.enableCca() {
+       atomic enableCCA = TRUE;
+    }
+    
+    async command void CsmaControl.disableCca() {
+       atomic enableCCA = FALSE;
+    }
+
+ default async event uint16_t CsmaBackoff.initial[am_id_t amId](message_t *m) { 
+     return (call Random.rand16() & 0x07) + 1;
+ }
+ default async event uint16_t CsmaBackoff.congestion[am_id_t amId](message_t *m) { 
+     return (call Random.rand16() & 0xF) + 1;
+ }
+
+}
diff --git a/tos/chips/xe1205/XE1205CsmaRadioC.nc b/tos/chips/xe1205/XE1205CsmaRadioC.nc
new file mode 100644 (file)
index 0000000..5dbc6d5
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright (c) 2007 Shockfish SA
+*  All rights reserved.
+*
+*  Permission to use, copy, modify, and distribute this software and its
+*  documentation for any purpose, without fee, and without written
+*  agreement is hereby granted, provided that the above copyright
+*  notice, the (updated) modification history and the author appear in
+*  all copies of this source code.
+*
+*  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 COPYRIGHT HOLDERS OR CONTRIBUTORS
+*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+*  OR PROFITS) 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 Maxime Muller
+ *
+ */
+
+#include "message.h"
+#include "XE1205.h"
+
+configuration XE1205CsmaRadioC {
+    provides {
+       interface SplitControl;
+       interface Send;
+       interface Receive;
+       interface Packet;
+       interface CsmaControl;
+       interface CsmaBackoff[am_id_t amId];
+       interface PacketAcknowledgements;
+       interface LPLControl;
+    }
+}
+implementation {
+    components XE1205CsmaP as CsmaP;
+    components XE1205SendReceiveP as SendReceive;
+    components XE1205PhyP;
+    components new TimerMilliC() as BackoffTimerC;
+    components MainC, RandomC,ActiveMessageC, ActiveMessageAddressC;
+    
+    MainC.SoftwareInit -> CsmaP;
+    
+    Send =  CsmaP;
+    Receive = CsmaP;
+    Packet =  SendReceive;
+    PacketAcknowledgements = SendReceive;
+    
+    SplitControl = CsmaP;
+    CsmaControl = CsmaP;
+    CsmaBackoff = CsmaP;
+    LPLControl = CsmaP;
+  
+
+    CsmaP.SubControl -> SendReceive.SplitControl;
+    CsmaP.SubReceive -> SendReceive.Receive;
+    CsmaP.SubSend ->  SendReceive.Send;
+    CsmaP.Rssi -> XE1205PhyP.XE1205PhyRssi;
+    CsmaP.BackoffTimer -> BackoffTimerC;
+    CsmaP.Random -> RandomC;
+
+}
diff --git a/tos/chips/xe1205/XE1205LowPowerListening.h b/tos/chips/xe1205/XE1205LowPowerListening.h
new file mode 100644 (file)
index 0000000..e34086e
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright (c) 2007 Shockfish SA
+*  All rights reserved.
+*
+*  Permission to use, copy, modify, and distribute this software and its
+*  documentation for any purpose, without fee, and without written
+*  agreement is hereby granted, provided that the above copyright
+*  notice, the (updated) modification history and the author appear in
+*  all copies of this source code.
+*
+*  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 COPYRIGHT HOLDERS OR CONTRIBUTORS
+*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+*  OR PROFITS) 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 Maxime Muller
+ *
+ */
+
+#ifndef XE1205LOWPOWERLISTENING_H
+#define XE1205LOWPOWERLISTENING_H
+
+/**
+ * Amount of time, in milliseconds, to keep the radio on after
+ * a successful receive addressed to this node
+ */
+
+#ifndef DELAY_AFTER_RECEIVE
+#define DELAY_AFTER_RECEIVE 20
+#endif
+
+/**
+ * Value used to indicate the message being sent should be transmitted
+ * one time
+ */
+
+#ifndef ONE_MESSAGE
+#define ONE_MESSAGE 0
+#endif
+
+#ifndef DEFAULT_DUTY_PERIOD
+#define DEFAULT_DUTY_PERIOD 1000
+#endif
+
+
+enum { 
+    IDLE = 0,
+    RX = 1,
+};
+
+#endif
diff --git a/tos/chips/xe1205/XE1205LowPowerListeningC.nc b/tos/chips/xe1205/XE1205LowPowerListeningC.nc
new file mode 100644 (file)
index 0000000..e7e60df
--- /dev/null
@@ -0,0 +1,44 @@
+
+
+configuration XE1205LowPowerListeningC {
+    provides {
+       interface SplitControl;
+       interface Send;
+       interface Receive;
+       interface LowPowerListening;
+       //      interface CsmaBackoff[am_id_t amId];
+    }
+}
+implementation {
+    components MainC,
+       XE1205ActiveMessageC,
+       XE1205LowPowerListeningP,
+       /*XE1205CsmaP as*/ XE1205CsmaRadioC,
+       RandomC;
+    components new TimerMilliC() as SendTimeoutC;
+    components new TimerMilliC() as OnTimerC;
+    components new TimerMilliC() as OffTimerC;
+    
+    Send = XE1205LowPowerListeningP;
+    Receive = XE1205LowPowerListeningP;
+    SplitControl = XE1205LowPowerListeningP;
+    LowPowerListening = XE1205LowPowerListeningP;
+    //    CsmaBackoff = XE1205LowPowerListeningP;
+
+    MainC.SoftwareInit -> XE1205LowPowerListeningP;
+    
+    //XE1205LowPowerListeningP.LowPowerListening -> XE1205CsmaRadioC;    
+    XE1205LowPowerListeningP.SubControl -> XE1205CsmaRadioC;
+    XE1205LowPowerListeningP.CsmaControl -> XE1205CsmaRadioC;
+    //  XE1205LowPowerListeningP.SubBackoff -> XE1205CsmaRadioC;
+    XE1205LowPowerListeningP.SubSend -> XE1205CsmaRadioC.Send;
+    XE1205LowPowerListeningP.SubReceive -> XE1205CsmaRadioC.Receive;
+    XE1205LowPowerListeningP.AMPacket -> XE1205ActiveMessageC;
+    XE1205LowPowerListeningP.PacketAcknowledgements -> XE1205ActiveMessageC;// XE1205CsmaRadioC;
+    XE1205LowPowerListeningP.SendTimeout -> SendTimeoutC;
+    XE1205LowPowerListeningP.OnTimer -> OnTimerC;
+    XE1205LowPowerListeningP.OffTimer -> OffTimerC;
+    XE1205LowPowerListeningP.Random -> RandomC;
+    XE1205LowPowerListeningP.LPLControl -> XE1205CsmaRadioC.LPLControl;
+
+}
diff --git a/tos/chips/xe1205/XE1205LowPowerListeningP.nc b/tos/chips/xe1205/XE1205LowPowerListeningP.nc
new file mode 100644 (file)
index 0000000..df2487a
--- /dev/null
@@ -0,0 +1,360 @@
+/* Copyright (c) 2007 Shockfish SA
+*  All rights reserved.
+*
+*  Permission to use, copy, modify, and distribute this software and its
+*  documentation for any purpose, without fee, and without written
+*  agreement is hereby granted, provided that the above copyright
+*  notice, the (updated) modification history and the author appear in
+*  all copies of this source code.
+*
+*  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 COPYRIGHT HOLDERS OR CONTRIBUTORS
+*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+*  OR PROFITS) 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 Maxime Muller
+ *
+ */
+
+#include "XE1205LowPowerListening.h"
+
+module XE1205LowPowerListeningP {
+    provides {
+       interface Init;
+       interface SplitControl;
+       interface Send;
+       interface Receive;
+       interface LowPowerListening;
+
+    }
+    uses {
+       interface LPLControl;
+       interface SplitControl as SubControl;   
+       interface CsmaControl;
+       interface Send as SubSend;
+       interface Receive as SubReceive;
+       interface AMPacket;
+       interface PacketAcknowledgements;
+       interface Timer<TMilli> as SendTimeout;
+       interface Timer<TMilli> as OnTimer;
+       interface Timer<TMilli> as OffTimer;
+       interface Random;
+    }
+}
+
+implementation {
+
+    message_t * curTxMsg;
+    uint8_t curTxMsgLength;
+    uint8_t seqNo;
+    uint8_t lastSeqNo;
+    uint8_t txSeqNo;
+    uint16_t sleepInterval;
+    uint16_t sleepTime;
+    bool fromSplitStart = FALSE;
+    bool fromSplitStop = FALSE;
+
+    typedef enum {
+       RADIO_INIT,
+       RADIO_ON,
+       RADIO_OFF,
+       RADIO_TX,
+    } lpl_state_t;
+    
+    lpl_state_t rState;
+    
+    
+    void sendDone(error_t err);
+
+    xe1205_header_t* getHeader( message_t* msg ) {
+       return (xe1205_header_t*)( msg->data - sizeof(xe1205_header_t) );
+    }
+    
+    xe1205_footer_t* getFooter(message_t* msg) {
+       return (xe1205_footer_t*)(msg->footer);
+    }
+    command error_t Init.init() {
+       sleepTime = DEFAULT_DUTY_PERIOD;
+       atomic rState = RADIO_INIT;
+       txSeqNo = call Random.rand16()&0xFE;
+       return SUCCESS;
+    }
+
+    command error_t SplitControl.start() {
+       // start dutyCycling
+       if (rState == RADIO_OFF || rState == RADIO_INIT) {
+           if (SUCCESS==call SubControl.start()) {
+               fromSplitStart = TRUE;
+               return SUCCESS;
+           }
+       } 
+       return FAIL; 
+    }
+    
+    event void SubControl.startDone(error_t err) {
+       if(!err) {
+           if(sleepTime > 0) {// keep radio on for a while
+               call OffTimer.stop();
+               call OnTimer.startOneShot(DELAY_AFTER_RECEIVE);
+           }
+           if (sleepTime == 0) // radio always on
+               call LPLControl.setMode(IDLE); 
+           atomic rState = RADIO_ON;
+
+           if (fromSplitStart) {
+               fromSplitStart=FALSE;
+               signal SplitControl.startDone(err);
+           }
+       }
+       else {
+           call SubControl.start();
+       }
+    }
+
+    command error_t SplitControl.stop() {
+       fromSplitStop = TRUE;
+       
+       return call SubControl.stop();
+    }
+
+    event void SubControl.stopDone(error_t err) {
+       if(!err) {
+           if (rState == RADIO_ON) { 
+               if (call OnTimer.isRunning()) {
+                   call OnTimer.stop();
+               }
+           }
+           atomic rState = RADIO_OFF;
+           if (fromSplitStop==FALSE) {
+               call OffTimer.startOneShot(sleepTime);
+           } else {
+               fromSplitStop = FALSE;
+               signal SplitControl.startDone(err);
+           }
+       } else
+           call OffTimer.startOneShot(sleepTime);
+    }
+
+    event void OffTimer.fired() { 
+       if (SUCCESS==call SubControl.start()) {
+               if (sleepTime > 0)
+                   call LPLControl.setMode(RX);
+               if (sleepTime == 0) // radio always on
+                   call LPLControl.setMode(IDLE); 
+           } else call OffTimer.startOneShot(sleepTime);
+           //}
+    }
+
+    event void OnTimer.fired() {
+       // switch off the radio
+       if(sleepTime > 0)
+           if (SUCCESS != call SubControl.stop()) {
+               // retry
+               call OnTimer.startOneShot(DELAY_AFTER_RECEIVE);
+           }
+    }
+
+    task void sendPkt() {
+       if(SUCCESS != call SubSend.send(curTxMsg,curTxMsgLength)) {
+           call LPLControl.setMode(IDLE); 
+           call OffTimer.startOneShot(sleepTime);
+           
+           sendDone(FAIL);
+       } 
+    }
+
+    /*
+     * send commands
+     */
+    command error_t Send.send(message_t *msg, uint8_t len) {   
+       if (rState == RADIO_INIT) return EOFF;
+       
+       else {
+           call OffTimer.stop();
+           call OnTimer.stop();
+           atomic rState = RADIO_TX;
+           curTxMsg = msg;
+           curTxMsgLength = len;
+           if(call LowPowerListening.getRxSleepInterval(curTxMsg) 
+              > ONE_MESSAGE) {
+               txSeqNo+=0x02;
+               if (AM_BROADCAST_ADDR != call AMPacket.destination(curTxMsg))
+                   getHeader(curTxMsg)->ack = txSeqNo|0x01;
+               else
+                   getHeader(curTxMsg)->ack = txSeqNo&0xFE;
+               call CsmaControl.enableCca();
+               
+               if(SUCCESS==post sendPkt()) {
+                   call SendTimeout.startOneShot(call LowPowerListening.getRxSleepInterval(curTxMsg) * 2);
+                   return SUCCESS;
+               }
+               else {
+                   call SendTimeout.stop();
+                   call LPLControl.setMode(IDLE);
+                   call OffTimer.startOneShot(sleepTime);
+                   return FAIL;
+               }
+           } else {
+               call LPLControl.setMode(IDLE);
+               call OffTimer.startOneShot(sleepTime);
+               return FAIL;
+           }
+       }
+    }
+
+    event void SendTimeout.fired() {
+       atomic {
+       if (rState == RADIO_TX) // let sendDone occur
+           rState = RADIO_ON;
+       }
+       call OffTimer.startOneShot(DELAY_AFTER_RECEIVE);
+    }
+       
+    void sendDone(error_t err) {
+       atomic {
+           if (rState == RADIO_TX)
+               rState = RADIO_ON;
+       }
+       if(err!=FAIL) 
+           call SubControl.stop();
+       signal Send.sendDone(curTxMsg, err);
+    }
+
+    event void SubSend.sendDone(message_t *msg, error_t err) {
+       if(rState == RADIO_TX 
+          && call SendTimeout.isRunning()) 
+           if ( AM_BROADCAST_ADDR != call AMPacket.destination(msg) 
+                && call PacketAcknowledgements.wasAcked(msg)) {
+               sendDone(err);
+               return;
+           }
+           else { // ack timeout or bcast msg
+               call CsmaControl.disableCca();
+               if(SUCCESS!=post sendPkt())
+                   sendDone(FAIL);
+               return;
+           }
+       sendDone(err);
+    }
+
+    command error_t Send.cancel(message_t *msg) {
+       if(curTxMsg == msg) {
+           atomic rState = RADIO_ON;
+           return SUCCESS;
+       }       
+       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
+     */
+    event message_t *SubReceive.receive(message_t *msg,void *payload, uint8_t len) {
+       
+    if ((getHeader(msg)->ack & 0xFE ) == lastSeqNo
+       && call AMPacket.destination(msg) == AM_BROADCAST_ADDR) {
+       return msg;
+    } else {
+       lastSeqNo = getHeader(msg)->ack & 0xFE;
+       if(!call SendTimeout.isRunning()) {
+           // catched a packet between pktSend
+           call OffTimer.startOneShot(DELAY_AFTER_RECEIVE);
+       }
+
+       return signal Receive.receive(msg,payload,len);
+       }
+    }
+    
+    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);
+    }
+
+    uint16_t getActualDutyCycle(uint16_t dutyCycle) {
+       if(dutyCycle > 10000) {
+           return 10000;
+       } else if(dutyCycle == 0) {
+           return 1;
+       }
+       return dutyCycle;
+    }
+
+    command void LowPowerListening.setLocalSleepInterval(uint16_t sTime) {
+       if(sleepTime == 0 && sTime >0) {
+           call LPLControl.setMode(RX);
+           call OnTimer.startOneShot(DELAY_AFTER_RECEIVE);
+       }
+       sleepTime = sTime;
+    }
+    
+    command uint16_t LowPowerListening.getLocalSleepInterval() {
+       return sleepTime;
+    }
+
+    command void LowPowerListening.setLocalDutyCycle(uint16_t d) {
+       return call LowPowerListening.setLocalSleepInterval(call LowPowerListening.dutyCycleToSleepInterval(d));
+    }
+
+    command uint16_t LowPowerListening.getLocalDutyCycle() {
+       return call LowPowerListening.sleepIntervalToDutyCycle(sleepTime);
+    }
+
+    command void LowPowerListening.setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs) {
+       xe1205_footer_t *footer = getFooter(msg);
+
+       footer->rxInterval =  sleepIntervalMs;
+    }
+
+    command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg) {
+       xe1205_footer_t *footer = getFooter(msg);
+
+       if (footer->rxInterval >= 0)
+           return sleepTime;
+       else
+           return -(footer->rxInterval + 1);
+    }
+
+    command void LowPowerListening.setRxDutyCycle(message_t *msg, uint16_t dCycle) {
+       getFooter(msg)->rxInterval =  call LowPowerListening.dutyCycleToSleepInterval(dCycle);
+    }
+
+    command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg) {
+       return call LowPowerListening.sleepIntervalToDutyCycle(getFooter(msg)->rxInterval);
+    }
+
+    command uint16_t LowPowerListening.dutyCycleToSleepInterval(uint16_t dCycle) {
+       dCycle = getActualDutyCycle(dCycle);
+
+       if(dCycle == 10000) {
+           return 0;
+       }
+       return (DELAY_AFTER_RECEIVE * (10000 - dCycle)) / dCycle;
+    }
+
+    command uint16_t LowPowerListening.sleepIntervalToDutyCycle(uint16_t sInterval) {
+       if(sInterval == 0) {
+           return 10000;
+       }
+       
+       return getActualDutyCycle((DELAY_AFTER_RECEIVE * 10000) 
+                                 / (sInterval + DELAY_AFTER_RECEIVE));
+    }
+}
index f84a147cfadd54a16480fc50ed31b943dfabafb0..7ba4dd359cb13dc73aad45175b7a09a2f6534f93 100644 (file)
@@ -39,6 +39,7 @@ configuration XE1205SendReceiveC {
     provides interface Send;
     provides interface Packet;
     provides interface PacketAcknowledgements;
+    provides interface AckSendReceive;
     provides interface SplitControl @atleastonce();
     provides interface Receive;
 }
@@ -49,10 +50,12 @@ implementation {
   Receive = XE1205SendReceiveP;
   Packet = XE1205SendReceiveP;
   PacketAcknowledgements = XE1205SendReceiveP;
+  AckSendReceive =  XE1205SendReceiveP;
   SplitControl = XE1205SendReceiveP;
 
   components XE1205PhyC;
   XE1205SendReceiveP.XE1205PhyRxTx -> XE1205PhyC;
+  XE1205SendReceiveP.XE1205PhyRssi -> XE1205PhyC;
   XE1205SendReceiveP.PhySplitControl -> XE1205PhyC;
 }
 
index b86ce5cac672ccbc1a76dc204147129c4a7af32a..77bfff4aa7113c69c4f832f098c458c2e540cb42 100644 (file)
  * @author Henri Dubois-Ferriere
  *
  */
+
+
 module XE1205SendReceiveP {
     provides interface Send;
     provides interface Packet;
     provides interface PacketAcknowledgements;
     provides interface Receive;
-    provides interface SplitControl @atleastonce();;
+    provides interface AckSendReceive;
+    provides interface SplitControl @atleastonce();
 
     uses interface XE1205PhyRxTx;
+    uses interface XE1205PhyRssi;
     uses interface SplitControl as PhySplitControl;
 }
 implementation {
 
-  #include "crc.h"
-  #include "xe1205debug.h"
+#include "crc.h"
+#include "xe1205debug.h"
 
 #define min(X, Y)  ((X) < (Y) ? (X) : (Y))
-
-  // Phy header definition. This is not seen by anything above us.
-  typedef nx_struct xe1205_phy_header_t {
-    nx_uint8_t whitening;
-    nx_uint8_t length;
-  } xe1205_phy_header_t;
+    enum {
+       PKT_CODE = 0,
+       ACK_CODE = 1
+    };
+
+    // Phy header definition. This is not seen by anything above us.
+    typedef nx_struct xe1205_phy_header_t {
+       nx_uint8_t whitening;
+       nx_uint8_t length;
+    } xe1205_phy_header_t;
+
+    typedef struct ackMsg_t {
+       uint16_t pl;
+    } ackMsg_t;
   
-  xe1205_phy_header_t txPhyHdr;
-  norace xe1205_phy_header_t rxPhyHdr; // we don't accept an incoming packet until previous one has been copied into local buf
+    xe1205_phy_header_t txPhyHdr;
+    norace xe1205_phy_header_t rxPhyHdr; // we don't accept an incoming packet until previous one has been copied into local buf
 
-  norace message_t *txMsgPtr=NULL;   // message under transmission (non-null until after sendDone).
-  norace char txBuf[16];             // buffer used to pass outgoing bytes to Phy
+    norace message_t ackMsg;
+    norace message_t *ackMsgPtr = &ackMsg;
 
-  norace uint8_t *rxBufPtr=NULL;     // pointer to raw frame received from Phy
-  message_t rxMsg;                   // for rx path buffer swapping with upper modules
-  message_t *rxMsgPtr=&rxMsg; 
+    norace message_t *txMsgSendDonePtr=NULL;
+    norace message_t *txMsgPtr=NULL;   // message under transmission (non-null until after sendDone).
+    norace uint8_t _len;
+    norace char txBuf[16];             // buffer used to pass outgoing bytes to Phy
 
-  norace uint8_t txIndex, txLen;     // State for packet transmissions
-  norace uint16_t txRunningCRC;      // Crc for outgoing pkts is computed incrementally
+    norace uint8_t *rxBufPtr=NULL;     // pointer to raw frame received from Phy
+    message_t rxMsg;                   // for rx path buffer swapping with upper modules
+    message_t *rxMsgPtr=&rxMsg; 
 
-  norace uint8_t txWhiteByte;
+    norace uint8_t txIndex, txLen;     // State for packet transmissions
+    norace uint16_t txRunningCRC;      // Crc for outgoing pkts is computed incrementally
 
-  uint8_t const pktPreamble[] = {
-    0x55, 0x55, 0x55,
-    (data_pattern >> 16) & 0xff, (data_pattern >> 8) & 0xff, data_pattern & 0xff
-  };
+    norace uint8_t txWhiteByte;
+    norace bool sendingAck=FALSE;
 
+    uint16_t ackPayload;
 
-  xe1205_header_t* getHeader( message_t* msg ) {
-    return (xe1205_header_t*)( msg->data - sizeof(xe1205_header_t) );
-  }
+    bool warmUp=FALSE;
 
-  xe1205_footer_t* getFooter(message_t* msg) {
-    return (xe1205_footer_t*)(msg->footer);
-  }
-  
-  xe1205_metadata_t* getMetadata(message_t* msg) {
-    return (xe1205_metadata_t*)((uint8_t*)msg->footer + sizeof(xe1205_footer_t));
-  }
-  
+    uint8_t const pktPreamble[] = {
+       0x55, 0x55, 0x55,
+       (data_pattern >> 16) & 0xff, (data_pattern >> 8) & 0xff, data_pattern & 0xff
+    };
+
+    uint8_t const ackPreamble[] = {
+       0x55, 0x55, 0x55,
+       (ack_pattern >> 16) & 0xff, (ack_pattern >> 8) & 0xff, ack_pattern & 0xff
+    };
 
-  command uint8_t Send.maxPayloadLength() {
-    return call Packet.maxPayloadLength();
-  }
+    task void signalPacketReceived();
 
-  command void* Send.getPayload(message_t* m) {
-    return call Packet.getPayload(m, NULL);
-  }
+    error_t sendRadioOn(uint8_t preamble);
 
-  command void* Receive.getPayload(message_t* m, uint8_t* len) {
-    return call Packet.getPayload(m, len);
-  }
+    xe1205_header_t* getHeader( message_t* msg ) {
+       return (xe1205_header_t*)( msg->data - sizeof(xe1205_header_t) );
+    }
 
-  command uint8_t Receive.payloadLength(message_t* m) {
-    return call Packet.payloadLength(m);
-  }
+    xe1205_footer_t* getFooter(message_t* msg) {
+       return (xe1205_footer_t*)(msg->footer);
+    }
+  
+    xe1205_metadata_t* getMetadata(message_t* msg) {
+       return (xe1205_metadata_t*)((uint8_t*)msg->footer + sizeof(xe1205_footer_t));
+    }
+
+    command void AckSendReceive.setAckPayload(uint16_t _pl) {
+       ackPayload = _pl;
+    }
+    
+    command uint16_t AckSendReceive.getAckPayload() {
+       return ackPayload;
+    }
 
+    command uint8_t Send.maxPayloadLength() {
+       return call Packet.maxPayloadLength();
+    }
 
-  command error_t SplitControl.start() {
-    error_t err;
-    err = call PhySplitControl.start();
+    command void* Send.getPayload(message_t* m) {
+       return call Packet.getPayload(m, NULL);
+    }
 
-    return err;
-  }
+    command void* Receive.getPayload(message_t* m, uint8_t* len) {
+       return call Packet.getPayload(m, len);
+    }
 
-  command error_t SplitControl.stop() {
-    error_t err;
+    command uint8_t Receive.payloadLength(message_t* m) {
+       return call Packet.payloadLength(m);
+    }
 
-    // One could also argue that this is split phase so should cope and do the right thing.
-    // Or one could argue that whatever the phy is doing underneath just gets interrupted.
-    if (call XE1205PhyRxTx.busy()) return EBUSY;
+   task void sendDoneTask() {
+       txMsgSendDonePtr = txMsgPtr;
+       txMsgPtr=NULL;
+       signal Send.sendDone(txMsgSendDonePtr, SUCCESS);
 
-    err = call PhySplitControl.stop();
+    }
 
-    return err;
+    task void sendDoneFailTask() {
+       txMsgSendDonePtr = txMsgPtr;
+       txMsgPtr=NULL;
+       signal Send.sendDone(txMsgSendDonePtr, FAIL);
 
-  }
+    }
 
-  event void PhySplitControl.startDone(error_t error) {
-    signal SplitControl.startDone(error);
-  }
+    command error_t SplitControl.start() {
+       error_t err;
+       err = call PhySplitControl.start();
 
-  event void PhySplitControl.stopDone(error_t error) { 
-    signal SplitControl.stopDone(error);
-  }
+       return err;
+    }
 
+    command error_t SplitControl.stop() {
+       error_t err;
 
+       // One could also argue that this is split phase so should cope and do the right thing.
+       // Or one could argue that whatever the phy is doing underneath just gets interrupted.
+       if (call XE1205PhyRxTx.busy()) return EBUSY;
 
-  command error_t Send.cancel(message_t* msg) {
-    /* Cancel is unsupported for now. */
-    return FAIL;
-  }
+       err = call PhySplitControl.stop();
+       txMsgPtr=NULL;
+       rxBufPtr = NULL;
+       return err;
 
-  void checkCrcAndUnwhiten(uint8_t* msg, uint8_t white, uint8_t len) {
-    uint16_t crc = 0;
-    uint8_t i, b;
-    uint8_t* uwPtr = (uint8_t*) getHeader(rxMsgPtr);
-    for(i = 0; i < sizeof(xe1205_header_t) + len; i++) {
-      b = msg[i] ^ white;
-      uwPtr[i] = b;
-      crc = crcByte(crc, b);
-    }
-    getFooter(rxMsgPtr)->crc = (crc == (msg[i] | (msg[i+1] << 8)));
-  }
-
-  void updateCRCAndWhiten(char* src, char* dst, uint8_t len)
-  {
-    uint8_t i;
-    for(i=0; i < len; i++) {
-      txRunningCRC = crcByte(txRunningCRC, src[i]); 
-      dst[i] = src[i] ^ txWhiteByte;
     }
-  }
 
+    event void PhySplitControl.startDone(error_t error) {
+       if (txMsgPtr!=NULL) {
 
-  command error_t Send.send(message_t* msg, uint8_t len) {
-    error_t err;
+           sendRadioOn(PKT_CODE);
+       } else {
+           if (warmUp==TRUE) {
 
-    if (txMsgPtr) return EBUSY;
+               post sendDoneFailTask();
+           }
+       }
+       warmUp=FALSE;
+       signal SplitControl.startDone(error);
+    }
 
-    if (call XE1205PhyRxTx.busy()) return EBUSY;
-    if (call XE1205PhyRxTx.off()) return EOFF;
+    event void PhySplitControl.stopDone(error_t error) { 
+       
+       signal SplitControl.stopDone(error);
+    }
 
 
-    txWhiteByte++;
-    txPhyHdr.whitening = txWhiteByte;
-    txPhyHdr.length = len;
-    txRunningCRC=0;
-    getMetadata(msg)->length = len; 
 
-    txIndex = min(sizeof(xe1205_header_t) + len + sizeof(xe1205_footer_t), 
-           sizeof(txBuf) - sizeof(pktPreamble) - sizeof(xe1205_phy_header_t));
-    txLen = len + sizeof(xe1205_header_t) + sizeof(xe1205_footer_t);
-    if (txIndex == txLen - 1) txIndex--; // don't send a single last byte
+ task void sendAck() {
+     atomic {
+        ((xe1205_metadata_t*)((uint8_t*)ackMsgPtr->footer + sizeof(xe1205_footer_t)))->length = sizeof(ackMsg_t);
+        ((xe1205_header_t*)(&ackMsg.data - sizeof(xe1205_header_t)))->group = \
+            (getHeader((message_t*)rxMsgPtr))->group;
+        ((xe1205_header_t*)(ackMsgPtr->data - sizeof(xe1205_header_t)))->type = \
+            ((xe1205_header_t*)(rxMsgPtr->data - sizeof(xe1205_header_t)))->type;
+        ((xe1205_header_t*)(ackMsgPtr->data - sizeof(xe1205_header_t)))->dest = \
+            ((xe1205_header_t*)(rxMsgPtr->data - sizeof(xe1205_header_t)))->source;
+        ((xe1205_header_t*)(ackMsgPtr->data - sizeof(xe1205_header_t)))->source = TOS_NODE_ID; 
+        ((ackMsg_t*)(ackMsgPtr->data))->pl = ackPayload;
+
+        txMsgPtr = ackMsgPtr;
+     }
+        _len = sizeof(ackMsg_t);
+     sendRadioOn(ACK_CODE);
+ }
+
+    command error_t Send.cancel(message_t* msg) {
+       /* Cancel is unsupported for now. */
+       return FAIL;
+    }
 
-    memcpy(txBuf, pktPreamble, sizeof(pktPreamble));
-    memcpy(txBuf + sizeof(pktPreamble), &txPhyHdr, sizeof(txPhyHdr));
-    
-    if (txIndex == txLen) {    // slap on CRC if we're already at end of packet
-      updateCRCAndWhiten((char*) getHeader(msg), 
-                        txBuf + sizeof(pktPreamble) + sizeof(xe1205_phy_header_t),
-                        sizeof(xe1205_header_t) + len); 
-      txBuf[sizeof(pktPreamble) + sizeof(xe1205_phy_header_t) + txLen - 2] = txRunningCRC & 0xff; 
-      txBuf[sizeof(pktPreamble) + sizeof(xe1205_phy_header_t) + txLen - 1] = txRunningCRC >> 8; 
-    } else {
-      updateCRCAndWhiten((char*) getHeader(msg), 
-                        txBuf + sizeof(pktPreamble) + sizeof(xe1205_phy_header_t),
-                        txIndex);
+    void checkCrcAndUnwhiten(uint8_t* msg, uint8_t white, uint8_t len) {
+       uint16_t crc = 0;
+       uint8_t i, b;
+       uint8_t* uwPtr ;
+       atomic uwPtr= (uint8_t*) getHeader(rxMsgPtr);
+       for(i = 0; i < sizeof(xe1205_header_t) + len + offsetof(xe1205_footer_t,crc) ; i++) {
+           b = msg[i] ^ white;
+           uwPtr[i] = b;
+           crc = crcByte(crc, b);
+       }
+       atomic {
+           getFooter(rxMsgPtr)->crc = (crc == (msg[i] | (msg[i+1] << 8)));
+       }
     }
-    
-    
-    txMsgPtr = msg;
 
-    // note that the continue send can come in before this instruction returns .
-    err = call XE1205PhyRxTx.sendFrame(txBuf, txIndex + sizeof(pktPreamble) + sizeof(xe1205_phy_header_t));
-    if (err != SUCCESS) txMsgPtr = NULL; 
-    
-    return err;
-  }
+    inline void updateCRCAndWhiten(char* src, char* dst, uint8_t len)
+       {
+           uint8_t i;
+           for(i=0; i < len; i++) {
+               txRunningCRC = crcByte(txRunningCRC, src[i]); 
+               dst[i] = src[i] ^ txWhiteByte;
+           }
+       }
+
+    error_t sendRadioOn(uint8_t preamble) {
+       error_t err;
+       txWhiteByte++;
+       txPhyHdr.whitening = txWhiteByte;
+       txPhyHdr.length = _len;
+       txRunningCRC=0;
+       getMetadata(txMsgPtr)->length = _len; 
+       if (((xe1205_header_t*)( (uint8_t*)txMsgPtr->data - sizeof(xe1205_header_t)))->ack==1) {
+           call XE1205PhyRxTx.enableAck(TRUE);
+       }
+       txIndex = min(sizeof(xe1205_header_t) + _len + sizeof(xe1205_footer_t), 
+                     sizeof(txBuf) - sizeof(pktPreamble) - sizeof(xe1205_phy_header_t));
+       txLen = _len + sizeof(xe1205_header_t) + sizeof(xe1205_footer_t);
+       if (txIndex == txLen - 1) txIndex--; // don't send a single last byte
+
+       switch (preamble) {
+       case PKT_CODE:
+           memcpy(txBuf, pktPreamble, sizeof(pktPreamble));
+           memcpy(txBuf + sizeof(pktPreamble), &txPhyHdr, sizeof(txPhyHdr));
+           break;
+       case ACK_CODE:
+           sendingAck=TRUE;
+           memcpy(txBuf, ackPreamble, sizeof(ackPreamble));
+           memcpy(txBuf + sizeof(pktPreamble), &txPhyHdr, sizeof(txPhyHdr));
+
+           post signalPacketReceived();
+           break;
+       }
+       
+       
+       if (txIndex == txLen) {    // slap on CRC if we're already at end of packet
+           updateCRCAndWhiten((char*) getHeader(txMsgPtr), 
+                              txBuf + sizeof(pktPreamble) + sizeof(xe1205_phy_header_t),
+                              sizeof(xe1205_header_t) + _len); 
+           txBuf[sizeof(pktPreamble) + sizeof(xe1205_phy_header_t) + txLen - 2] = txRunningCRC & 0xff; 
+           txBuf[sizeof(pktPreamble) + sizeof(xe1205_phy_header_t) + txLen - 1] = txRunningCRC >> 8; 
+       } else {
+           updateCRCAndWhiten((char*) getHeader(txMsgPtr), 
+                              txBuf + sizeof(pktPreamble) + sizeof(xe1205_phy_header_t),
+                              txIndex);
+       }
+       // note that the continue send can come in before this instruction returns .
+       err = call XE1205PhyRxTx.sendFrame(txBuf, txIndex + sizeof(pktPreamble) + sizeof(xe1205_phy_header_t));
+       if (err != SUCCESS) { 
+           if (preamble==PKT_CODE)
+               post sendDoneFailTask();
+           txMsgPtr = NULL;
+       }
+       return err;
+    }
 
+    command error_t Send.send(message_t* msg, uint8_t len) {
+
+       atomic {
+           if (txMsgPtr){ return EBUSY;}
+           if (msg==NULL) { return FAIL;}
+           if (call XE1205PhyRxTx.busy()==TRUE){ return EBUSY;}
+
+           if (call XE1205PhyRxTx.off()) {
+               txMsgPtr = msg;
+               _len = len;
+               if(call PhySplitControl.start()==SUCCESS) {
+                   warmUp=TRUE;
+                   return SUCCESS;
+               } else {txMsgPtr=NULL;return EOFF;}
+           }
+           txMsgPtr = msg;
+           _len = len;
+       }
+       
+       return  sendRadioOn(PKT_CODE);
+    }
 
-  task void sendDoneTask() {
-    signal Send.sendDone(txMsgPtr, SUCCESS);
-    txMsgPtr = NULL;
-  }
 
  
 
-  async event char* XE1205PhyRxTx.continueSend(uint8_t* len) __attribute__ ((noinline))
-  {
-    uint8_t curIndex = txIndex;
-    uint8_t l = min(txLen - txIndex, sizeof(txBuf));
-    if (txIndex + l == txLen - 1) l--; // don't send a single last byte
+    async event char* XE1205PhyRxTx.continueSend(uint8_t* len) __attribute__ ((noinline))
+    {
+       
+       uint8_t curIndex = txIndex;
+       uint8_t l = min(txLen - txIndex, sizeof(txBuf));
+       if (txIndex + l == txLen - 1) l--; // don't send a single last byte
 
-    *len = l;
-    if (!l) return NULL;
+       *len = l;
+       if (!l) return NULL;
 
-    txIndex += l;
+       txIndex += l;
 
-    // if we're at end of packet, slap on CRC
-    if (txIndex == txLen) {
-      updateCRCAndWhiten(&((char*) (getHeader(txMsgPtr)))[curIndex], txBuf, l - 2);
-      txBuf[l - 2] = txRunningCRC & 0xff; 
-      txBuf[l - 1] = txRunningCRC >> 8; 
-    } else {
-      updateCRCAndWhiten(((char*) getHeader(txMsgPtr)) + curIndex, txBuf, l);
-    }
-    
 
-    return txBuf;
-  }
+       // if we're at end of packet, slap on CRC
+       if (txIndex == txLen) {
+           updateCRCAndWhiten(&((char*) (getHeader(txMsgPtr)))[curIndex], txBuf, l - 2);
+           txBuf[l - 2] = txRunningCRC & 0xff; 
+           txBuf[l - 1] = txRunningCRC >> 8;
 
+       } else {
+           updateCRCAndWhiten(((char*) getHeader(txMsgPtr)) + curIndex, txBuf, l);
+       }
 
-  uint8_t sendDones = 0;
-  async event void XE1205PhyRxTx.sendFrameDone() __attribute__ ((noinline)) {
-    sendDones++;
-    if (post sendDoneTask() != SUCCESS)
-      xe1205check(2, FAIL);
-  }
 
-  command void Packet.clear(message_t* msg) {
-    memset(msg, 0, sizeof(message_t));
-  }
-
-  command uint8_t Packet.payloadLength(message_t* msg) {
-    return getMetadata(msg)->length;
-  }
-  command void Packet.setPayloadLength(message_t* msg, uint8_t len) {
-    getMetadata(msg)->length  = len;
-  }
-  
-  command uint8_t Packet.maxPayloadLength() {
-    return TOSH_DATA_LENGTH;
-  }
-
-  command void* Packet.getPayload(message_t* msg, uint8_t* len) {
-    if (len != NULL) {
-      *len = getMetadata(msg)->length;
+       return txBuf;
     }
-    return (void*)msg->data;
-  }
-
-  async command error_t PacketAcknowledgements.requestAck(message_t* msg) {
-    xe1205_metadata_t* md = getMetadata(msg); // xxx this should move to header or footer, leaving it here for now for 1.x compat
-    md->ack = 1;                              
-    return SUCCESS;
-  }
 
-  async command error_t PacketAcknowledgements.noAck(message_t* msg) {
-    xe1205_metadata_t* md = getMetadata(msg);
-    md->ack = 1;
-    return SUCCESS;
-  }
 
-  async command bool PacketAcknowledgements.wasAcked(message_t* msg) {
-    xe1205_metadata_t* md = getMetadata(msg);
-    return md->ack;
-  }
+    uint8_t sendDones = 0;
+    async event void XE1205PhyRxTx.sendFrameDone(error_t err) __attribute__ ((noinline)) {
+       sendDones++;
+       if(sendingAck==FALSE)
+           if(err==SUCCESS) {
+               if (post sendDoneTask() != SUCCESS)
+                   xe1205check(2, FAIL);
+           } else {
+               if (post sendDoneFailTask() != SUCCESS)
+                   xe1205check(2, FAIL);
+           }
+       else {
+
+           txMsgPtr = NULL;
+           sendingAck=FALSE;
+       }
+    }
 
-  default event void Send.sendDone(message_t* msg, error_t error) { }
+    command void Packet.clear(message_t* msg) {
+       memset(msg, 0, sizeof(message_t));
+    }
 
-  async event uint8_t XE1205PhyRxTx.rxFrameBegin(char* data, uint8_t len)  __attribute__ ((noinline)) {
+    command uint8_t Packet.payloadLength(message_t* msg) {
+       return getMetadata(msg)->length;
+    }
+    command void Packet.setPayloadLength(message_t* msg, uint8_t len) {
+       getMetadata(msg)->length  = len;
+    }
+  
+    command uint8_t Packet.maxPayloadLength() {
+       return TOSH_DATA_LENGTH;
+    }
 
-    uint8_t datalen;
+    command void* Packet.getPayload(message_t* msg, uint8_t* len) {
+       if (len != NULL) {
+           *len = getMetadata(msg)->length;
+       }
+       return (void*)msg->data;
+    }
 
-    memcpy(&rxPhyHdr, data, sizeof(xe1205_phy_header_t));
-    datalen = rxPhyHdr.length;
-    if (datalen > TOSH_DATA_LENGTH || rxBufPtr) return len;
-    
-    return datalen + sizeof(xe1205_header_t) + sizeof(xe1205_footer_t) + sizeof(xe1205_phy_header_t);
-  }
+    async command error_t PacketAcknowledgements.requestAck(message_t* msg) {
+       (getHeader(msg))-> ack |= 0x01;
+       return SUCCESS;
+    }
 
-  task void signalPacketReceived()   __attribute__ ((noinline)) {
+    async command error_t PacketAcknowledgements.noAck(message_t* msg) {
+       (getHeader(msg))-> ack &= 0xFE;
+       return SUCCESS;
+    }
 
-    checkCrcAndUnwhiten(rxBufPtr, rxPhyHdr.whitening, rxPhyHdr.length);
-    if (!getFooter(rxMsgPtr)->crc) {
-      atomic rxBufPtr = NULL;
-      return;
+    async command bool PacketAcknowledgements.wasAcked(message_t* msg) {
+       return  (getHeader(msg))-> ack & 0x01;
     }
-    getMetadata((message_t*) rxMsgPtr)->length = rxPhyHdr.length;
 
-    atomic rxBufPtr = NULL;
-    rxMsgPtr =  signal Receive.receive(rxMsgPtr, rxMsgPtr->data, getMetadata(rxMsgPtr)->length);
-  }
+ default event void Send.sendDone(message_t* msg, error_t error) { }
+
+ async event uint8_t XE1205PhyRxTx.rxFrameBegin(char* data, uint8_t len)  __attribute__ ((noinline)) {
 
+     uint8_t datalen;
 
-  uint32_t nrxmsgs;
-  async event void XE1205PhyRxTx.rxFrameEnd(char* data, uint8_t len, error_t status)   __attribute__ ((noinline)) {
-    if (status != SUCCESS) return;
-    //    nrxmsgs++;
-    if (rxBufPtr) return; // this could happen whenever rxFrameBegin was called with rxBufPtr still active
-    rxBufPtr = (data + sizeof(xe1205_phy_header_t));
-    xe1205check(1, post signalPacketReceived());
-  }
+     memcpy(&rxPhyHdr, data, sizeof(xe1205_phy_header_t));
+     datalen = rxPhyHdr.length;
+     if (datalen > TOSH_DATA_LENGTH || rxBufPtr) return len;
+    
+     return datalen + sizeof(xe1205_header_t) + sizeof(xe1205_footer_t) + sizeof(xe1205_phy_header_t);
+ }
+
+ task void signalPacketReceived()   __attribute__ ((noinline)) {
+     
+     atomic { 
+        getMetadata((message_t*) rxMsgPtr)->length = rxPhyHdr.length; 
+        
+        rxBufPtr = NULL;
+        rxMsgPtr =  signal Receive.receive(rxMsgPtr, rxMsgPtr->data, getMetadata(rxMsgPtr)->length);
+     }
+ }
+
+
+ uint32_t nrxmsgs;
+ async event void XE1205PhyRxTx.rxFrameEnd(char* data, uint8_t len, error_t status)   __attribute__ ((noinline)) {
+     if (status != SUCCESS){ return;}
+
+     if (rxBufPtr) return; // this could happen whenever rxFrameBegin was called with rxBufPtr still active
+     rxBufPtr = (data + sizeof(xe1205_phy_header_t));
+
+     checkCrcAndUnwhiten(rxBufPtr, rxPhyHdr.whitening, rxPhyHdr.length);
+
+     if (!getFooter(rxMsgPtr)->crc) {
+        atomic rxBufPtr = NULL;
+        return;
+     }
+     
+     getMetadata((message_t*) rxMsgPtr)->strength =  call XE1205PhyRssi.readRxRssi();
+     getMetadata((message_t*) rxMsgPtr)->length = rxPhyHdr.length;
+
+     if ((getHeader((message_t*)rxMsgPtr))->dest == TOS_NODE_ID &&
+        (((getHeader((message_t*)rxMsgPtr))->ack)& 0x01)==1) {
+        post sendAck();
+     } else {
+        atomic rxBufPtr = NULL;
+        rxMsgPtr =  signal Receive.receive(rxMsgPtr, rxMsgPtr->data, getMetadata(rxMsgPtr)->length);
+     }
+
+ }
+ async event void XE1205PhyRssi.rssiDone(uint8_t _rssi) { }
 
 }
 
index fdf4f81a72f0d2e1297cc6ef36e4869601afe534..6cafcc351a48020150cfe0ee1da7d1c9e3f208f6 100644 (file)
 
 module XE1205SpiImplP {
 
-  provides interface XE1205Fifo as Fifo @atmostonce();
-  provides interface XE1205Register as Reg[uint8_t id];
+    provides interface XE1205Fifo as Fifo @atmostonce();
+    provides interface XE1205Register as Reg[uint8_t id];
 
-  provides interface Init @atleastonce();
+    provides interface Init @atleastonce();
 
-  provides interface Resource[ uint8_t id ];
+    provides interface Resource[ uint8_t id ];
 
-  uses interface Resource as SpiResource;
-  uses interface GeneralIO as NssDataPin;
-  uses interface GeneralIO as NssConfigPin;
-  uses interface SpiByte;
-  uses interface SpiPacket;
+    uses interface Resource as SpiResource;
+    uses interface GeneralIO as NssDataPin;
+    uses interface GeneralIO as NssConfigPin;
+    uses interface SpiByte;
+    uses interface SpiPacket;
 }
 
 implementation {
 
 #include "xe1205debug.h"
 
-  enum {
-    RESOURCE_COUNT = uniqueCount( "XE1205Spi.Resource" ),
-    NO_HOLDER = 0xff,
-  };
-
-
-  bool m_resource_busy = FALSE;
-  uint8_t m_requests = 0;
-  uint8_t m_holder = NO_HOLDER;
-
-  command error_t Init.init() {
-    call NssDataPin.makeOutput();
-    call NssConfigPin.makeOutput();
-    call NssDataPin.set();
-    call NssConfigPin.set();
-    return SUCCESS;
-  }
-
-  async command error_t Resource.request[ uint8_t id ]() {
-    atomic {
-      if ( m_resource_busy )
-       m_requests |= 1 << id;
-      else {
-       m_holder = id;
-       m_resource_busy = TRUE;
-       call SpiResource.request();
-      }
+    enum {
+       RESOURCE_COUNT = uniqueCount( "XE1205Spi.Resource" ),
+       NO_HOLDER = 0xff,
+    };
+
+
+    bool m_resource_busy = FALSE;
+    uint8_t m_requests = 0;
+    uint8_t m_holder = NO_HOLDER;
+
+    command error_t Init.init() {
+       call NssDataPin.makeOutput();
+       call NssConfigPin.makeOutput();
+       call NssDataPin.set();
+       call NssConfigPin.set();
+       return SUCCESS;
+    }
+
+    async command error_t Resource.request[ uint8_t id ]() {
+       atomic {
+           if ( m_resource_busy )
+               m_requests |= 1 << id;
+           else {
+               m_holder = id;
+               m_resource_busy = TRUE;
+               
+               call SpiResource.request();
+           }
+       }
+       return SUCCESS;
     }
-    return SUCCESS;
-  }
   
-  async command error_t Resource.immediateRequest[ uint8_t id ]() {
-    error_t error;
-    atomic {
-      if ( m_resource_busy )
-       return EBUSY;
-      error = call SpiResource.immediateRequest();
-      if ( error == SUCCESS ) {
-       m_holder = id;
-       m_resource_busy = TRUE;
-      }
-      xe1205check(9, error);
+    async command error_t Resource.immediateRequest[ uint8_t id ]() {
+       error_t error;
+       atomic {
+           if ( m_resource_busy )
+               return EBUSY;
+           error = call SpiResource.immediateRequest();
+           if ( error == SUCCESS ) {
+               m_holder = id;
+               m_resource_busy = TRUE;
+
+           }
+           xe1205check(9, error);
+       }
+       return error;
     }
-    return error;
-  }
-
-  async command error_t Resource.release[ uint8_t id ]() {
-    uint8_t i;
-    atomic {
-      if ( m_holder != id ) {
-       xe1205check(11, 1);
-       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();
+
+    async command error_t Resource.release[ uint8_t id ]() {
+       uint8_t i;
+       atomic {
+           if ( m_holder != id ) {
+               xe1205check(11, 1);
+               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;
+                   }
+               }
+           }
            return SUCCESS;
-         }
        }
-      }
-      return SUCCESS;
     }
-  }
   
-  async command uint8_t Resource.isOwner[ uint8_t id ]() {
-    atomic return (m_holder == id);
-  }
+    async command uint8_t Resource.isOwner[ uint8_t id ]() {
+       atomic return (m_holder == id);
+    }
 
-  event void SpiResource.granted() {
-    uint8_t holder;
-    atomic holder = m_holder;
-    signal Resource.granted[ holder ]();
-  }
+    event void SpiResource.granted() {
+       uint8_t holder;
+       atomic holder = m_holder;
+       signal Resource.granted[ holder ]();
+    }
 
 
 default event void Resource.granted[ uint8_t id ]() {
 }
+ default event void Resource.granted[ uint8_t id ]() {
+ }
 
-  async command error_t Fifo.write(uint8_t* data, uint8_t length) {
-    error_t status;
+ async command error_t Fifo.write(uint8_t* data, uint8_t length) __attribute__ ((noinline)){
 
-#if 1
-    if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
-      xe1205check(8, 1);
+#if 0
+     if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
+        xe1205check(8, 1);
 #endif
 
-    call NssDataPin.clr();
-    call NssConfigPin.set();
-    status = call SpiPacket.send(data, NULL, length);
 
-    if (status != SUCCESS) {
-      xe1205check(1, status);
-      call NssDataPin.set();
-      return status;
-    }
-    return SUCCESS;
-  }
-
-  async event void SpiPacket.sendDone(uint8_t* tx_buf, uint8_t* rx_buf, 
-                                     uint16_t len, error_t error) 
-  {
-    
-    xe1205check(2, error);
-#if 1
-    if (call NssConfigPin.get() != TRUE) xe1205check(4, 1);
-    if (call NssDataPin.get() != FALSE) xe1205check(12, 1);
-#endif
-    call NssDataPin.set();
-    if (tx_buf)
-      signal Fifo.writeDone(error);
-    else
-      signal Fifo.readDone(error);
-  }
+     call SpiPacket.send(data, NULL, length);
 
-  async command error_t Fifo.read(uint8_t* data, uint8_t length) {
-    error_t status;
+     return SUCCESS;
+ }
 
-#if 1
-    if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
-      xe1205check(5, 1);
+ async event void SpiPacket.sendDone(uint8_t* tx_buf, uint8_t* rx_buf, 
+                                    uint16_t len, error_t error) 
+ {
+
+#if 0
+     if (call NssConfigPin.get() != TRUE) xe1205check(4, 1);
+     if (call NssDataPin.get() != FALSE) xe1205check(12, 1);
 #endif
+     TOSH_SET_NSS_DATA_PIN();
+     if (tx_buf) {
 
-    call NssDataPin.clr();
+        signal Fifo.writeDone(error);
+     } else
+        signal Fifo.readDone(error);
+ }
 
-    status = call SpiPacket.send(NULL, data, length);
-    if (status != SUCCESS) {
-      xe1205check(3, status);
-      call NssDataPin.set();
-      return status;
-    }
-    return SUCCESS;
-  }
+ async command error_t Fifo.read(uint8_t* data, uint8_t length) {
+     error_t status;
+
+#if 0
+     if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
+        xe1205check(5, 1);
+#endif
 
-  async command void Reg.read[uint8_t addr](uint8_t* data) 
-  {
+     TOSH_CLR_NSS_DATA_PIN();
+     status = call SpiPacket.send(NULL, data, length);
+     if (status != SUCCESS) {
+        xe1205check(3, status);
+        call NssDataPin.set();
+        return status;
+     }
+     return SUCCESS;
+ }
+
+ async command void Reg.read[uint8_t addr](uint8_t* data) 
+ {
 #if 1
-    if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
-      xe1205check(6, 1);
+     if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
+        xe1205check(6, 1);
 #endif
 
-    call NssDataPin.set();
-    call NssConfigPin.clr();
-    call SpiByte.write(XE1205_READ(addr));
-    *data = call SpiByte.write(0);
-    call NssConfigPin.set();
 }
+     call NssDataPin.set();
+     call NssConfigPin.clr();
+     call SpiByte.write(XE1205_READ(addr));
+     *data = call SpiByte.write(0);
+     call NssConfigPin.set();
+ }
 
 async command void Reg.write[uint8_t addr](uint8_t data) 
 {
+ async command void Reg.write[uint8_t addr](uint8_t data) 
+ {
 #if 1
-    if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
-      xe1205check(7, 1);
+     if (call NssDataPin.get() != TRUE || call NssConfigPin.get() != TRUE)
+        xe1205check(7, 1);
 #endif
 
-    call NssDataPin.set();
-    call NssConfigPin.clr();
-    call SpiByte.write(XE1205_WRITE(addr));
-    call SpiByte.write(data);
-    call NssConfigPin.set();
 }
+     call NssDataPin.set();
+     call NssConfigPin.clr();
+     call SpiByte.write(XE1205_WRITE(addr));
+     call SpiByte.write(data);
+     call NssConfigPin.set();
+ }
 
 default async event void Fifo.readDone(error_t error) {}
 default async event void Fifo.writeDone(error_t error) {}
+ default async event void Fifo.readDone(error_t error) {}
+ default async event void Fifo.writeDone(error_t error) {}
 }
index 01345136a74a361954bc226bbe553a537234f742..3e3be5c88e999691f59c9ce069148dc916d2a41a 100644 (file)
@@ -61,6 +61,8 @@ interface XE1205PatternConf {
    * @return SUCCESS if operation done ok, error status otherwise 
    */
   async command error_t loadPattern(uint8_t* pattern, uint8_t len);
+  async command error_t loadDataPatternHasBus();
+  async command error_t loadAckPatternHasBus();
 
   /**
    * Set the number of bit errors accepted by the XE1205 
index 5ba8c76ced8e30c235ec3ce6457e08f2b9911e43..c4ca0e45e00ad4e1a7c3a8dc1d264ec82a094ee9 100644 (file)
@@ -96,7 +96,26 @@ implementation {
     call SpiResource.release();
     return SUCCESS;
   }
-    
+  async command error_t XE1205PatternConf.loadDataPatternHasBus() {
+      
+      call Pattern13.write((data_pattern >> 16) & 0xff);
+      call Pattern14.write((data_pattern >> 8) & 0xff);
+      call Pattern15.write(data_pattern & 0xff);
+     
+    return SUCCESS;
+
+  }
+
+  async command error_t XE1205PatternConf.loadAckPatternHasBus() {
+
+      call Pattern13.write((ack_pattern >> 16) & 0xff);
+      call Pattern14.write((ack_pattern >> 8) & 0xff);
+      call Pattern15.write(ack_pattern & 0xff);
+
+    return SUCCESS;
+
+  }
+
   async command error_t XE1205PatternConf.loadPattern(uint8_t* pattern, uint8_t len) 
   {
     error_t status;
index 6b48e65df93e130617db79f555907f6e90b33364..88b5eee96b2314bd76e4f0bb40feb77d15fea4fe 100644 (file)
 
 module XE1205PhyRssiConfP {
 
-  provides interface XE1205PhyConf;
-  provides interface XE1205RssiConf;
-  provides interface Init @atleastonce();
-
-  uses interface Resource as SpiResource;
-  uses interface XE1205Register as MCParam0;
-  uses interface XE1205Register as MCParam1;
-  uses interface XE1205Register as MCParam2;
-  uses interface XE1205Register as MCParam3;
-  uses interface XE1205Register as MCParam4;
-  uses interface XE1205Register as TXParam7;
-  uses interface XE1205Register as RXParam8;
-  uses interface XE1205Register as RXParam9;
+    provides interface XE1205PhyConf;
+    provides interface XE1205RssiConf;
+    provides interface Init @atleastonce();
+
+    uses interface Resource as SpiResource;
+    uses interface XE1205Register as MCParam0;
+    uses interface XE1205Register as MCParam1;
+    uses interface XE1205Register as MCParam2;
+    uses interface XE1205Register as MCParam3;
+    uses interface XE1205Register as MCParam4;
+    uses interface XE1205Register as TXParam7;
+    uses interface XE1205Register as RXParam8;
+    uses interface XE1205Register as RXParam9;
 }
 implementation {
 #include "xe1205debug.h"
 
-/* 
- * Default settings for initial parameters. 
- */ 
+    /* 
    * Default settings for initial parameters. 
    */ 
 #ifndef XE1205_BITRATE_DEFAULT
 #define XE1205_BITRATE_DEFAULT  76170
 #endif
-  //xxx/make this computed as a fun of XE1205_BITRATE_DEFAULT
+    //xxx/make this computed as a fun of XE1205_BITRATE_DEFAULT
 #ifndef XE1205_FREQDEV_DEFAULT
 #define XE1205_FREQDEV_DEFAULT  100000
 #endif
 
 
-/*
- * Register calculation helper macros.
- */
+    /*
    * Register calculation helper macros.
    */
 #define XE1205_FREQ(value_)                     (((value_) * 100) / 50113L)
 #define XE1205_EFFECTIVE_FREQ(value_)           (((int32_t)((int16_t)(value_)) * 50113L) / 100)
 #define XE1205_FREQ_DEV_HI(value_)              ((XE1205_FREQ(value_) >> 8) & 0x01)
@@ -84,301 +84,293 @@ implementation {
 #define XE1205_EFFECTIVE_BIT_RATE(value_)       (152340L / ((value_) + 1))
 
 
-  /**
-   * Frequency bands.
-   */
-  enum xe1205_freq_bands {
-    XE1205_Band_434 = 434000000,
-    XE1205_Band_869 = 869000000,
-    XE1205_Band_915 = 915000000
-  };
+    /**
+     * Frequency bands.
+     */
+    enum xe1205_freq_bands {
+       XE1205_Band_434 = 434000000,
+       XE1205_Band_869 = 869000000,
+       XE1205_Band_915 = 915000000
+    };
   
 
-  // this value is the time between rssi measurement updates, plus a buffer time.
-  // we keep it cached for fast access during packet reception
-  uint16_t rssi_period_us; 
-
-  // time to xmit/receive a byte at current bitrate 
-  uint16_t byte_time_us;
-
-  // norace is ok because protected by the isOwner() calls
-  norace uint8_t rxparam9 = 0xff; 
-  norace uint8_t txparam7 = 0xff;
-
-  // returns appropriate baseband filter in khz bw for given bitrate in bits/sec.
-  uint16_t baseband_bw_from_bitrate(uint32_t bitrate) {
-    return (bitrate * 400) /152340;
-  }
-
-
-  // returns appropriate freq. deviation for given bitrate in bits/sec.
-  uint32_t freq_dev_from_bitrate(uint32_t bitrate) {
-    return (bitrate * 6) / 5;
-  }
-
-  // returns xe1205 encoding of baseband bandwidth in appropriate bit positions
-  // for writing into rxparam7 register
-  uint8_t baseband_bw_rxparam7_bits(uint16_t bbw_khz) 
-  {
-    if(bbw_khz <= 10) {
-      return 0x00;
-    } else if(bbw_khz <= 20) {
-      return 0x20;
-    } else if(bbw_khz <= 40) {
-      return 0x40;
-    } else if(bbw_khz <= 200) {
-      return 0x60;
-    } else if(bbw_khz <= 400) {
-      return 0x10;
-    } else return 0x10; 
-  }
-
-  // returns the period (in us) between two successive rssi measurements
-  // (see xemics data sheet 4.2.3.4), as a function of frequency deviation
-  uint16_t rssi_meas_time(uint32_t freqdev_hz) 
-  {
-    if (freqdev_hz > 20000)      // at 152kbps, equiv to 2 byte times, at 76kbps, equiv to 1 byte time, at 38kbps equiv to 4 bits, etc
-      return 100;
-    else if (freqdev_hz > 10000) // at 9.6kbps, equiv to 4 byte times.
-      return 200;           
-    else if (freqdev_hz > 7000)
-      return 300;
-    else if (freqdev_hz > 5000)  // at 4.8kbps, equiv to 4 byte times.
-      return 400;
-    else 
-      return 500;                // at 1200, equiv to 13 byte times.
-  }
-
-  task void initTask() 
-  {
-    atomic {
-      byte_time_us = 8000000 / XE1205_BITRATE_DEFAULT;
-      rssi_period_us = rssi_meas_time(XE1205_FREQDEV_DEFAULT) + 10;
-
-      xe1205check(1, call SpiResource.immediateRequest()); // should always succeed: task happens after softwareInit, before interrupts are enabled
-
-      call TXParam7.write(0x00); // tx power 0dbm, normal modulation & bitsync, no flitering
-      txparam7=0;
-
-      call MCParam0.write(0x3c | XE1205_FREQ_DEV_HI(XE1205_FREQDEV_DEFAULT)); // buffered mode, transceiver select using SW(0:1), Data output, 868mhz band, 
-      call MCParam1.write(XE1205_FREQ_DEV_LO(XE1205_FREQDEV_DEFAULT));
-      call MCParam2.write(XE1205_BIT_RATE(XE1205_BITRATE_DEFAULT));
-
-      call MCParam3.write(XE1205_FREQ_HI(-2000000)); // 869mhz - 2mhz = 867mhz (preset 0)
-      call MCParam4.write(XE1205_FREQ_LO(-2000000));
-
-
-      call RXParam8.write(baseband_bw_rxparam7_bits(baseband_bw_from_bitrate(XE1205_BITRATE_DEFAULT))
-                         | 0x0a); // calibrate & init baseband filter each time bbw changes
-
-      call RXParam9.write(0x00); // rssi off by default, fei off
-      rxparam9=0;
-
-      call SpiResource.release();
+    // this value is the time between rssi measurement updates, plus a buffer time.
+    // we keep it cached for fast access during packet reception
+    uint16_t rssi_period_us; 
+
+    // time to xmit/receive a byte at current bitrate 
+    uint16_t byte_time_us;
+
+    // norace is ok because protected by the isOwner() calls
+    norace uint8_t rxparam9 = 0xff; 
+    norace uint8_t txparam7 = 0xff;
+
+    // returns appropriate baseband filter in khz bw for given bitrate in bits/sec.
+    uint16_t baseband_bw_from_bitrate(uint32_t bitrate) {
+       return (bitrate * 400) /152340;
+    }
+
+
+    // returns appropriate freq. deviation for given bitrate in bits/sec.
+    uint32_t freq_dev_from_bitrate(uint32_t bitrate) {
+       return (bitrate * 6) / 5;
+    }
+
+    // returns xe1205 encoding of baseband bandwidth in appropriate bit positions
+    // for writing into rxparam7 register
+    uint8_t baseband_bw_rxparam7_bits(uint16_t bbw_khz) 
+    {
+       if(bbw_khz <= 10) {
+           return 0x00;
+       } else if(bbw_khz <= 20) {
+           return 0x20;
+       } else if(bbw_khz <= 40) {
+           return 0x40;
+       } else if(bbw_khz <= 200) {
+           return 0x60;
+       } else if(bbw_khz <= 400) {
+           return 0x10;
+       } else return 0x10; 
     }
-  }
 
-  command error_t Init.init() 
-  {
-    post initTask();
-    return SUCCESS;
-  }
+    // returns the period (in us) between two successive rssi measurements
+    // (see xemics data sheet 4.2.3.4), as a function of frequency deviation
+    uint16_t rssi_meas_time(uint32_t freqdev_hz) 
+    {
+       if (freqdev_hz > 20000)      // at 152kbps, equiv to 2 byte times, at 76kbps, equiv to 1 byte time, at 38kbps equiv to 4 bits, etc
+           return 100;
+       else if (freqdev_hz > 10000) // at 9.6kbps, equiv to 4 byte times.
+           return 200;           
+       else if (freqdev_hz > 7000)
+           return 300;
+       else if (freqdev_hz > 5000)  // at 4.8kbps, equiv to 4 byte times.
+           return 400;
+       else 
+           return 500;                // at 1200, equiv to 13 byte times.
+    }
+
+    task void initTask() 
+    {
+       atomic {
+           byte_time_us = 8000000 / XE1205_BITRATE_DEFAULT;
+           rssi_period_us = rssi_meas_time(XE1205_FREQDEV_DEFAULT) + 10;
+
+           xe1205check(1, call SpiResource.immediateRequest()); // should always succeed: task happens after softwareInit, before interrupts are enabled
+
+           call TXParam7.write(0x00); // tx power 0dbm, normal modulation & bitsync, no flitering
+           txparam7=0;
+
+           call MCParam0.write(0x3c | XE1205_FREQ_DEV_HI(XE1205_FREQDEV_DEFAULT)); // buffered mode, transceiver select using SW(0:1), Data output, 868mhz band, 
+           call MCParam1.write(XE1205_FREQ_DEV_LO(XE1205_FREQDEV_DEFAULT));
+           call MCParam2.write(XE1205_BIT_RATE(XE1205_BITRATE_DEFAULT));
+
+           call MCParam3.write(XE1205_FREQ_HI(-1000000)); // 869mhz - 1mhz = 868mhz (preset 0)
+           call MCParam4.write(XE1205_FREQ_LO(-1000000));
+
+
+           call RXParam8.write(baseband_bw_rxparam7_bits(baseband_bw_from_bitrate(XE1205_BITRATE_DEFAULT))
+                               | 0x0a); // calibrate & init baseband filter each time bbw changes
+
+           call RXParam9.write(0x00); // rssi off by default, fei off
+           rxparam9=0;
+           call SpiResource.release();
+       }
+    }
+
+    command error_t Init.init() 
+    {
+       post initTask();
+       return SUCCESS;
+    }
   
-  event void SpiResource.granted() {
-  }
+    event void SpiResource.granted() {
+    }
 
-  error_t tuneManual(uint32_t freq) 
-  {
-    uint32_t bandCenter;
-    uint8_t mcp0reg;
-    uint16_t mcp34reg;
-    error_t status;
+    error_t tuneManual(uint32_t freq) 
+    {
+       uint32_t bandCenter;
+       uint8_t mcp0reg;
+       uint16_t mcp34reg;
+       error_t status;
 
-    if (call SpiResource.isOwner()) return EBUSY;
-    status = call SpiResource.immediateRequest();
-    xe1205check(2, status);
-    if (status != SUCCESS) return status;
+       if (call SpiResource.isOwner()) return EBUSY;
+       status = call SpiResource.immediateRequest();
+       xe1205check(2, status);
+       if (status != SUCCESS) return status;
 
 
-    call MCParam0.read(&mcp0reg);
+       call MCParam0.read(&mcp0reg);
 
-    mcp0reg &= ~0x6;
+       mcp0reg &= ~0x6;
 
-    if ((freq >= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x8000)))
-       && (freq <= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x7fff)))) {
+       if ((freq >= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x8000)))
+           && (freq <= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x7fff)))) {
 
-      mcp0reg |= (1 << 1);
-      bandCenter = XE1205_Band_434;
+           mcp0reg |= (1 << 1);
+           bandCenter = XE1205_Band_434;
 
-    } else if ((freq >= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x8000)))
-              && (freq <= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x7fff)))) {
+       } else if ((freq >= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x8000)))
+                  && (freq <= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x7fff)))) {
 
-      mcp0reg |= (2 << 1);
-      bandCenter = XE1205_Band_869;
+           mcp0reg |= (2 << 1);
+           bandCenter = XE1205_Band_869;
 
-    } else if ((freq >= (XE1205_Band_915+ XE1205_EFFECTIVE_FREQ(0x8000)))
-              && (freq <= (XE1205_Band_915 + XE1205_EFFECTIVE_FREQ(0x7fff)))) {
+       } else if ((freq >= (XE1205_Band_915+ XE1205_EFFECTIVE_FREQ(0x8000)))
+                  && (freq <= (XE1205_Band_915 + XE1205_EFFECTIVE_FREQ(0x7fff)))) {
 
-      mcp0reg |= (3 << 1);
-      bandCenter = XE1205_Band_915;
+           mcp0reg |= (3 << 1);
+           bandCenter = XE1205_Band_915;
 
-    } else {
-      call SpiResource.release();
-      return EINVAL;
-    }                       
+       } else {
+           call SpiResource.release();
+           return EINVAL;
+       }                       
 
 
-    mcp34reg = XE1205_FREQ(freq - bandCenter);
+       mcp34reg = XE1205_FREQ(freq - bandCenter);
 
-    call MCParam0.write(mcp0reg);
-    call MCParam3.write(mcp34reg >> 8);
-    call MCParam4.write(mcp34reg & 0xff);
+       call MCParam0.write(mcp0reg);
+       call MCParam3.write(mcp34reg >> 8);
+       call MCParam4.write(mcp34reg & 0xff);
+
+       call SpiResource.release();
+
+       return SUCCESS;
+    }
 
-    call SpiResource.release();
 
-    return SUCCESS;
-  }
+    command error_t XE1205PhyConf.tunePreset(xe1205_channelpreset_t preset) 
+    {
+       switch(preset) {
 
+       case xe1205_channelpreset_868mhz:
+           return tuneManual(868000000);
 
-  command error_t XE1205PhyConf.tunePreset(xe1205_channelpreset_t preset) 
-  {
-    switch(preset) {
-    case xe1205_channelpreset_867mhz:
-      return tuneManual(867000000);
+       case xe1205_channelpreset_869mhz:
+           return tuneManual(869000000);
 
-    case xe1205_channelpreset_868mhz:
-      return tuneManual(868000000);
+       case xe1205_channelpreset_870mhz:
+           return tuneManual(870000000);
 
-    case xe1205_channelpreset_869mhz:
-      return tuneManual(869000000);
+       case xe1205_channelpreset_433mhz:
+           return tuneManual(433000000);
 
-    default:
-      return FAIL;
+       case xe1205_channelpreset_434mhz:
+           return tuneManual(434000000);
+
+       case xe1205_channelpreset_435mhz:
+           return tuneManual(435000000);
+
+       default:
+           return FAIL;
+       }
     }
-  }
 
-  async command error_t XE1205PhyConf.setRFPower(xe1205_txpower_t txpow)
-  {
-    error_t status;
+    async command error_t XE1205PhyConf.setRFPower(xe1205_txpower_t txpow)
+    {
+       error_t status;
 
-    if (txpow > xe1205_txpower_15dbm)
-      return EINVAL;
+       if (txpow > xe1205_txpower_15dbm)
+           return EINVAL;
 
-    if (call SpiResource.isOwner()) return EBUSY;
-    status = call SpiResource.immediateRequest();
-    xe1205check(3, status);
-    if (status != SUCCESS) return status;
+       if (call SpiResource.isOwner()) return EBUSY;
+       status = call SpiResource.immediateRequest();
+       xe1205check(3, status);
+       if (status != SUCCESS) return status;
 
-    txparam7 &= ~(3 << 6);
-    txparam7 |= (txpow << 6);
-    call TXParam7.write(txparam7);
-    call SpiResource.release();
-    return SUCCESS;
-  }
+       txparam7 &= ~(3 << 6);
+       txparam7 |= (txpow << 6);
+       call TXParam7.write(txparam7);
+       call SpiResource.release();
+       return SUCCESS;
+    }
 
 
   
 
-  command error_t XE1205PhyConf.setBitrate(xe1205_bitrate_t bitrate) 
-  {
-    uint16_t bbw;
-    uint32_t freqdev;
-    uint8_t rxp8reg, mcp0reg, mcp1reg, mcp2reg;
-    error_t status;
-
-    if (bitrate < xe1205_bitrate_38085 || bitrate > xe1205_bitrate_152340) return EINVAL;
-
-    if (call SpiResource.isOwner()) return EBUSY;
-    status = call SpiResource.immediateRequest();
-    xe1205check(4, status);
-    if (status != SUCCESS) return status;
-
-    // receiver bandwidth
-    call RXParam8.read(&rxp8reg);
-    bbw = baseband_bw_from_bitrate(bitrate);
-    rxp8reg &= ~0x70;
-    rxp8reg |= baseband_bw_rxparam7_bits(bbw);
-
-
-    // frequency deviation
-    freqdev = freq_dev_from_bitrate(bitrate);
-    rssi_period_us = rssi_meas_time(freqdev) + 10;
-
-    call MCParam0.read(&mcp0reg);
-    mcp0reg &= ~0x01;
-    mcp0reg |= XE1205_FREQ_DEV_HI(freqdev);
-
-    mcp1reg = XE1205_FREQ_DEV_LO(freqdev);
-
-    mcp2reg = XE1205_BIT_RATE(bitrate);
-
-    call RXParam8.write(rxp8reg);
-    call MCParam0.write(mcp0reg);
-    call MCParam1.write(mcp1reg);
-    call MCParam2.write(mcp2reg);;
-
-    atomic byte_time_us =   8000000 / bitrate;
-    call SpiResource.release(); 
-    return SUCCESS;
-  }
-
-  async command uint16_t XE1205PhyConf.getByteTime_us() { 
-    return byte_time_us;
-  }
-
-  async command error_t XE1205RssiConf.setRssiMode(bool on) 
-  {
-    error_t status;
-
-    if (call SpiResource.isOwner()) return EBUSY;
-    status = call SpiResource.immediateRequest();
-    xe1205check(5, status);
-    if (status != SUCCESS) return status;
-
-    if (on) 
-      rxparam9 |= 0x80;
-    else 
-      rxparam9 &= ~0x80;
-    call RXParam9.write(rxparam9);
-    call SpiResource.release();
-    return SUCCESS;
-  }
-
-  async command uint16_t XE1205RssiConf.getRssiMeasurePeriod_us() {
-    return rssi_period_us;
-  }
-
-  async command error_t XE1205RssiConf.setRssiRange(bool high) 
-  {
-    error_t status;
-
-    if (call SpiResource.isOwner()) return EBUSY;
-    status = call SpiResource.immediateRequest();
-    xe1205check(6, status);
-    if (status != SUCCESS) return status;
-
-    if (high) 
-      rxparam9 |= 0x40;
-    else 
-      rxparam9 &= ~0x40;
-    call RXParam9.write(rxparam9);
-    call SpiResource.release();
-    return SUCCESS;
-  }
-
-  async command error_t XE1205RssiConf.getRssi(uint8_t* rssi) 
-  {
-    error_t status;
-
-    if (call SpiResource.isOwner()) return EBUSY;
-    status = call SpiResource.immediateRequest();
-    xe1205check(7, status);
-    if (status != SUCCESS) return status;
-
-    call RXParam9.read(rssi);
-    *rssi = (*rssi >> 4) & 0x03;
-    call SpiResource.release();
-    return SUCCESS;
-  }
+    command error_t XE1205PhyConf.setBitrate(xe1205_bitrate_t bitrate) 
+    {
+       uint16_t bbw;
+       uint32_t freqdev;
+       uint8_t rxp8reg, mcp0reg, mcp1reg, mcp2reg;
+       error_t status;
+
+       if (bitrate < xe1205_bitrate_38085 || bitrate > xe1205_bitrate_152340) return EINVAL;
+
+       if (call SpiResource.isOwner()) return EBUSY;
+       status = call SpiResource.immediateRequest();
+       xe1205check(4, status);
+       if (status != SUCCESS) return status;
+
+       // receiver bandwidth
+       call RXParam8.read(&rxp8reg);
+       bbw = baseband_bw_from_bitrate(bitrate);
+       rxp8reg &= ~0x70;
+       rxp8reg |= baseband_bw_rxparam7_bits(bbw);
+
+
+       // frequency deviation
+       freqdev = freq_dev_from_bitrate(bitrate);
+       rssi_period_us = rssi_meas_time(freqdev) + 10;
+
+       call MCParam0.read(&mcp0reg);
+       mcp0reg &= ~0x01;
+       mcp0reg |= XE1205_FREQ_DEV_HI(freqdev);
+
+       mcp1reg = XE1205_FREQ_DEV_LO(freqdev);
+
+       mcp2reg = XE1205_BIT_RATE(bitrate);
+
+       call RXParam8.write(rxp8reg);
+       call MCParam0.write(mcp0reg);
+       call MCParam1.write(mcp1reg);
+       call MCParam2.write(mcp2reg);;
+
+       atomic byte_time_us =   8000000 / bitrate;
+       call SpiResource.release(); 
+       return SUCCESS;
+    }
+
+    async command uint16_t XE1205PhyConf.getByteTime_us() { 
+       return byte_time_us;
+    }
+
+    async command error_t XE1205RssiConf.setRssiMode(bool on) 
+    {
+       // must have bus
+       if (on) 
+           rxparam9 |= 0x80;
+       else 
+           rxparam9 &= ~0x80;
+       call RXParam9.write(rxparam9);
+
+       return SUCCESS;
+    }
+
+    async command uint16_t XE1205RssiConf.getRssiMeasurePeriod_us() {
+       return rssi_period_us;
+    }
+
+    async command error_t XE1205RssiConf.setRssiRange(bool high) 
+    {
+       // must have bus
+       if (high) {
+           rxparam9 |= 0x40;
+       } else {
+           rxparam9 &= ~0x40;
+       }
+       call RXParam9.write(rxparam9);
+       return SUCCESS;
+    }
+
+    async command error_t XE1205RssiConf.getRssi(uint8_t* rssi) 
+    {
+       // must have bus
+       call RXParam9.read(rssi);
+    
+       *rssi = (*rssi >> 4) & 0x03;
+
+       return SUCCESS;
+    }
 
 }
index 5c60d9ed0bb56e8e482ecbea084d72f0961c8ed7..e3dc4fe7a79d0bb283258902d9a9ca9294dbdb99 100644 (file)
@@ -48,7 +48,7 @@ interface XE1205RssiConf {
    * @param on: 1 to enable, 0 to disable
    * @return SUCCESS if operation done ok, error status otherwise 
    */
-  async command error_t setRssiMode(bool on);
+    async command error_t setRssiMode(bool on);
 
   /** 
    * Return the returns the period (in us) between two successive rssi measurements, 
index 49c673ba196c24bdae03b746a833b4a56c415ffa..06bc684f6b51c0ffca11599a9360690a16ae2dda 100644 (file)
@@ -38,6 +38,7 @@
 
 configuration XE1205PhyC {
   provides interface XE1205PhyRxTx;
+  provides interface XE1205PhyRssi;
   provides interface SplitControl;
 }
 implementation {
@@ -57,6 +58,9 @@ implementation {
   components new XE1205SpiC() as SpiConfig;
   XE1205PhyP.SpiResourceConfig -> SpiConfig;
 
+  components new XE1205SpiC() as SpiRSSI;
+  XE1205PhyP.SpiResourceRssi -> SpiRSSI;
+
   components HplXE1205InterruptsC;
   XE1205PhyP.Interrupt0 -> HplXE1205InterruptsC.Interrupt0;
   XE1205PhyP.Interrupt1 -> HplXE1205InterruptsC.Interrupt1;
@@ -64,13 +68,20 @@ implementation {
 
   XE1205PhyRxTx = XE1205PhyP;
   SplitControl = XE1205PhyP;
+  XE1205PhyRssi = XE1205PhyP;
 
   components MainC;
   MainC.SoftwareInit -> XE1205PhyP.Init;
 
+  components XE1205PatternConfC;
+  XE1205PhyP.XE1205PatternConf -> XE1205PatternConfC;
+
   components XE1205IrqConfC;
   XE1205PhyP.XE1205IrqConf -> XE1205IrqConfC;
 
+  components XE1205PhyRssiConfC;
+  XE1205PhyP.XE1205RssiConf -> XE1205PhyRssiConfC;
+
   components new Alarm32khz16C();
   XE1205PhyP.Alarm32khz16 -> Alarm32khz16C.Alarm;
 #if 0
index 92bbbfd46bb6c383748a26bf952e9344404ba32b..377ad953ea75bcbd57de65b10428968b6143a9a5 100644 (file)
 #include "Timer.h"
 
 module XE1205PhyP {
-  provides interface XE1205PhyRxTx;
+    provides interface XE1205PhyRxTx;
+    provides interface XE1205PhyRssi;
 
-  provides interface Init @atleastonce();
-  provides interface SplitControl @atleastonce();
+    provides interface Init @atleastonce();
+    provides interface SplitControl @atleastonce();
 
-  uses interface Resource as SpiResourceTX;
-  uses interface Resource as SpiResourceRX;
-  uses interface Resource as SpiResourceConfig;
+    uses interface Resource as SpiResourceTX;
+    uses interface Resource as SpiResourceRX;
+    uses interface Resource as SpiResourceConfig;
+    uses interface Resource as SpiResourceRssi;
 
-  uses interface XE1205PhySwitch;
-  uses interface XE1205IrqConf;
-  uses interface XE1205Fifo;
+    uses interface XE1205PhySwitch;
+    uses interface XE1205IrqConf;
+    uses interface XE1205Fifo;
+    uses interface XE1205RssiConf;
+    uses interface XE1205PatternConf;
 
-  uses interface GpioInterrupt as Interrupt0;
-  uses interface GpioInterrupt as Interrupt1;
+    uses interface GpioInterrupt as Interrupt0;
+    uses interface GpioInterrupt as Interrupt1;
 
-  uses interface Alarm<T32khz,uint16_t> as Alarm32khz16;
+    uses interface Alarm<T32khz,uint16_t> as Alarm32khz16;
 #if 0
-  uses interface GeneralIO as Dpin;
+    uses interface GeneralIO as Dpin;
 #endif
 }
 implementation {
 
 #include "xe1205debug.h"
 
-  char* txBuf = NULL;
-  uint8_t rxFrameIndex = 0;
-  uint8_t rxFrameLen = 0;
-  uint8_t nextTxLen=0;
-  uint8_t nextRxLen;
-  char rxFrame[xe1205_mtu];
-  uint8_t headerLen = 4;
-
-  uint16_t stats_rxOverruns;
-
-  typedef enum { // remember to update busy() and off(), start(), stop() if states are added
-    RADIO_LISTEN=0, 
-    RADIO_RX_HEADER=1, 
-    RADIO_RX_PACKET=2, 
-    RADIO_RX_PACKET_LAST=3, 
-    RADIO_TX=4,
-    RADIO_SLEEP=5, 
-    RADIO_STARTING=6 
-  } phy_state_t;
-
-  phy_state_t state = RADIO_SLEEP;
-
-  void armPatternDetect();
-
-  ////////////////////////////////////////////////////////////////////////////////////
-  //
-  // jiffy/microseconds/bytetime conversion functions.
-  //
-  ////////////////////////////////////////////////////////////////////////////////////
-
-  // 1 jiffie = 1/32768 = 30.52us; 
-  // we approximate to 32us for quicker computation and also to account for interrupt/processing overhead.
-  inline uint32_t usecs_to_jiffies(uint32_t usecs) {
-    return usecs >> 5;
-  }
-
-  command error_t Init.init() 
-  { 
+    char* txBuf = NULL;
+    uint8_t rxFrameIndex = 0;
+    uint8_t rxFrameLen = 0;
+    uint8_t nextTxLen=0;
+    uint8_t nextRxLen;
+    char rxFrame[xe1205_mtu];
+    uint8_t headerLen = 4;
+
+    uint16_t stats_rxOverruns;
+
+    enum {
+       RSSI_RANGE_LOW=1,
+       RSSI_RANGE_HIGH=2,
+       RSSI_OFF=0,
+    };
+    uint8_t rssiRange = RSSI_OFF;
+    norace uint8_t rssiL,rssiH;
+    uint8_t * rLow = &rssiL;
+    uint8_t * rHigh = &rssiH;
+
+
+    bool enableAck = FALSE;
+
+    typedef enum { // remember to update busy() and off(), start(), stop() if states are added
+       RADIO_LISTEN=0, 
+       RADIO_RX_HEADER=1, 
+       RADIO_RX_PACKET=2, 
+       RADIO_RX_PACKET_LAST=3, 
+       RADIO_TX=4,
+       RADIO_SLEEP=5, 
+       RADIO_STARTING=6,
+       RADIO_RSSI=7,
+       RADIO_RX_ACK=8,
+       RADIO_TX_ACK=9
+    } phy_state_t;
+
+    phy_state_t state = RADIO_SLEEP;
+
+
+    void armPatternDetect();
+
+    ////////////////////////////////////////////////////////////////////////////////////
+    //
+    // jiffy/microseconds/bytetime conversion functions.
+    //
+    ////////////////////////////////////////////////////////////////////////////////////
+
+    // 1 jiffie = 1/32768 = 30.52us; 
+    // we approximate to 32us for quicker computation and also to account for interrupt/processing overhead.
+    inline uint32_t usecs_to_jiffies(uint32_t usecs) {
+       return usecs >> 5;
+    }
+
+    command error_t Init.init() 
+    { 
 #if 0
-    call Dpin.makeOutput();
+       call Dpin.makeOutput();
 #endif
-    call XE1205PhySwitch.sleepMode();
-    call XE1205PhySwitch.antennaOff();
-    return SUCCESS;
-  }
-
-  task void startDone() {
-    signal SplitControl.startDone(SUCCESS);
-  }
-
-  event void SpiResourceTX.granted() {  }
-  event void SpiResourceRX.granted() {  }
-  event void SpiResourceConfig.granted() { 
-    armPatternDetect();
-    call SpiResourceConfig.release();
-
-    atomic {
-      if (state == RADIO_STARTING) post startDone();
-      call Interrupt0.enableRisingEdge();
-      state = RADIO_LISTEN;
+       call XE1205PhySwitch.sleepMode();
+       call XE1205PhySwitch.antennaOff();
+       return SUCCESS;
     }
-  }
-
 
-  task void stopDone() {
-    signal SplitControl.stopDone(SUCCESS);
-  }
+    task void startDone() {    
+       signal SplitControl.startDone(SUCCESS);
+    }
 
-  command error_t SplitControl.start() 
-  {
-    atomic {
-      if (state != RADIO_SLEEP) return EBUSY;
-      state = RADIO_STARTING;
+    event void SpiResourceTX.granted() {  }
+    event void SpiResourceRX.granted() {  }
+    event void SpiResourceConfig.granted() { 
+       armPatternDetect();
+       call SpiResourceConfig.release();
+       atomic {
+           if (state == RADIO_STARTING){
+               post startDone();}
+           if (state == RADIO_RX_ACK) { 
+               enableAck=FALSE; 
+               signal XE1205PhyRxTx.sendFrameDone(FAIL);
+           }
+           state = RADIO_LISTEN;
+
+           call Interrupt0.enableRisingEdge();
+       }
     }
+    event void SpiResourceRssi.granted() {  }
 
-    call XE1205PhySwitch.rxMode();
-    call XE1205PhySwitch.antennaRx();
-
-    call Alarm32khz16.start(usecs_to_jiffies(XE1205_Sleep_to_RX_Time));
-    return SUCCESS;
-  }
-
-  command error_t SplitControl.stop() 
-  {
-    atomic {
-      call XE1205PhySwitch.sleepMode();
-      call XE1205PhySwitch.antennaOff();
-      state = RADIO_SLEEP;
-      call Interrupt0.disable();
-      call Interrupt1.disable();
+    task void stopDone() {
+       signal SplitControl.stopDone(SUCCESS);
     }
-    post stopDone();
-    return SUCCESS;
-  }
-
-  default event void SplitControl.startDone(error_t error) { }
-  default event void SplitControl.stopDone(error_t error) { }
-
-  async command bool XE1205PhyRxTx.busy() {
-    atomic return (state != RADIO_LISTEN &&
-                  state != RADIO_SLEEP &&
-                  state != RADIO_STARTING);
-  }
-
-  async command bool XE1205PhyRxTx.off() {
-    atomic return (state == RADIO_SLEEP ||
-                  state == RADIO_STARTING);
-  }
-
-  void armPatternDetect() 
-  {
-    // small chance of a pattern arriving right after we arm, 
-    // and IRQ0 hasn't been enabled yet, so we would miss the interrupt
-    // xxx maybe this can also be addressed with periodic timer?
-    xe1205check(2, call XE1205IrqConf.armPatternDetector(TRUE));
-    xe1205check(1, call XE1205IrqConf.clearFifoOverrun(TRUE));  
-  }
-
-  async command void XE1205PhyRxTx.setRxHeaderLen(uint8_t l) 
-  {
-    if (l > 8) l = 8;
-    if (!l) return;
-    headerLen = l;
-  }
-
-  async command uint8_t XE1205PhyRxTx.getRxHeaderLen() {
-    return headerLen;
-  }
-
-  void computeNextRxLength() 
-  {
-    uint8_t n = rxFrameLen - rxFrameIndex; 
-    
-    // for timesync and such, we want the end of the packet to coincide with a fifofull event, 
-    // so that we know precisely when last byte was received 
-
-    if (n > 16) {
-      if (n < 32) nextRxLen = n - 16; else nextRxLen = 15;
-    } 
-    else {
-      nextRxLen = n;
+
+    command error_t SplitControl.start() 
+    {
+
+           atomic {
+               if (state == RADIO_LISTEN){ post startDone(); return SUCCESS;}
+               if (state != RADIO_SLEEP) return EBUSY;
+               state = RADIO_STARTING;
+           }
+           call XE1205PhySwitch.rxMode();
+           call XE1205PhySwitch.antennaRx();
+           
+           
+           call Alarm32khz16.start(usecs_to_jiffies(XE1205_Sleep_to_RX_Time));
+           return SUCCESS;
     }
-  }
 
+    command error_t SplitControl.stop() 
+    {
+       atomic {
+           if (!call XE1205PhyRxTx.busy()) {
+               
+               call XE1205PhySwitch.sleepMode();
+               call XE1205PhySwitch.antennaOff();
+               state = RADIO_SLEEP;
+               call Interrupt0.disable();
+               call Interrupt1.disable();
+               post stopDone();
+               return SUCCESS;
+           } else return FAIL;
+       }
 
-  async command error_t XE1205PhyRxTx.sendFrame(char* data, uint8_t frameLen)  __attribute__ ((noinline)) 
-  {
-    error_t status;
+    }
+
+ default event void SplitControl.startDone(error_t error) { }
+ default event void SplitControl.stopDone(error_t error) { }
+ default async event void XE1205PhyRssi.rssiDone(uint8_t _rssi) { }
+
+ async command bool XE1205PhyRxTx.busy() {
+     atomic return (state != RADIO_LISTEN &&
+                   state != RADIO_SLEEP);
+ }
+
+ async command bool XE1205PhyRxTx.off() {
+     atomic return (state == RADIO_SLEEP ||
+                   state == RADIO_STARTING);
+ }
+
+
+ async command void XE1205PhyRxTx.enableAck(bool onOff) {
+     atomic enableAck = onOff;
+ }
+
+
+ void armPatternDetect() 
+ {
+     // small chance of a pattern arriving right after we arm, 
+     // and IRQ0 hasn't been enabled yet, so we would miss the interrupt
+     // xxx maybe this can also be addressed with periodic timer?
+     call XE1205IrqConf.armPatternDetector(TRUE);
+     call XE1205IrqConf.clearFifoOverrun(TRUE);  
+ }
+
+ async command void XE1205PhyRxTx.setRxHeaderLen(uint8_t l) 
+ {
+     if (l > 8) l = 8;
+     if (!l) return;
+     headerLen = l;
+ }
+
+ async command uint8_t XE1205PhyRxTx.getRxHeaderLen() {
+     return headerLen;
+ }
+
+ void computeNextRxLength() 
+ {
+     uint8_t n = rxFrameLen - rxFrameIndex; 
+    
+     // for timesync and such, we want the end of the packet to coincide with a fifofull event, 
+     // so that we know precisely when last byte was received 
+
+     if (n > 16) {
+        if (n < 32) nextRxLen = n - 16; else nextRxLen = 15;
+     } 
+     else {
+        nextRxLen = n;
+     }
+ }
+
+ command uint8_t  XE1205PhyRssi.readRxRssi() {
+     return rssiTab[(rssiH<<2) |rssiL];
+ }
+
+ task void rssiDone() {
+
+     signal XE1205PhyRssi.rssiDone( rssiTab[(rssiH<<2) |rssiL]);
+ }
+
+ void readRssi() {
+     if(rssiRange ==RSSI_RANGE_LOW ) {
+        rssiRange = RSSI_RANGE_HIGH;
+        call XE1205RssiConf.getRssi(rLow);
+        call XE1205RssiConf.setRssiRange(TRUE);
+        call Alarm32khz16.start(usecs_to_jiffies(call XE1205RssiConf.getRssiMeasurePeriod_us()));
+     } else {
+        call XE1205RssiConf.getRssi(rHigh);
+        call XE1205RssiConf.setRssiMode(FALSE);
+
+        if(state == RADIO_RSSI) {
+            armPatternDetect();
+            call SpiResourceRssi.release();
+            call Interrupt0.enableRisingEdge();
+            atomic state = RADIO_LISTEN;
+            signal XE1205PhyRssi.rssiDone( rssiTab[(rssiH<<2) |rssiL]);
+        } else { // go on with rx of packet
+            call Alarm32khz16.start(3000);
+        }
+        rssiRange = RSSI_OFF;
+     }
+ }
+
+
+ error_t getRssi() {
+     error_t err;
+
+     if(call SpiResourceRssi.immediateRequest() != SUCCESS) {
+        return FAIL;
+     }
+     err = call XE1205RssiConf.setRssiMode(TRUE);
+     err = ecombine(err,call XE1205RssiConf.setRssiRange(FALSE));
+     rssiRange=RSSI_RANGE_LOW;
+     call Alarm32khz16.start(usecs_to_jiffies(call XE1205RssiConf.getRssiMeasurePeriod_us()));
+     return err;
+ }
+
+
+ async command error_t XE1205PhyRssi.getRssi() {
+     error_t err;
+     atomic {
+        if (state != RADIO_LISTEN&&rssiRange==RSSI_OFF) return EBUSY;
+        if (call XE1205PhyRxTx.off()) {
+            return EOFF;
+        }
+        err=getRssi();
+        if (SUCCESS ==err) {
+            state = RADIO_RSSI;
+        }
+        return err;
+     }
+ }
+
+ async command error_t XE1205PhyRxTx.sendFrame(char* data, uint8_t frameLen)  __attribute__ ((noinline)) 
+ {
+     error_t status;
    
-    if (frameLen < 6) return EINVAL;
+     if (frameLen < 6) return EINVAL;
 
-    atomic {
-      if (state == RADIO_SLEEP) return EOFF;
-      if (state != RADIO_LISTEN) return EBUSY;
-      if (frameLen == 0 || frameLen > xe1205_mtu + 7) return EINVAL; // 7 = 4 preamble + 3 sync
-      
-      call XE1205PhySwitch.txMode(); // it takes 100us to switch from rx to tx, ie less than one byte at 76kbps
-      call Interrupt0.disable();
-
-      status = call SpiResourceTX.immediateRequest();
-      xe1205check(3, status);
-      if (status != SUCCESS) {
-       call XE1205PhySwitch.rxMode(); 
-       call SpiResourceConfig.request();
-       return status;
-      }
-      call XE1205PhySwitch.antennaTx();
-      state = RADIO_TX;
-    }
+     atomic {
+        if (state == RADIO_SLEEP) return EOFF;
 
-    status = call XE1205Fifo.write(data, frameLen);
-    // cannot happen with current SPI implementation (at least with NoDma)
+        if (call XE1205PhyRxTx.busy()) return EBUSY;
+        if (frameLen == 0 || frameLen > xe1205_mtu + 7) return EINVAL; // 7 = 4 preamble + 3 sync
+      
+        call XE1205PhySwitch.txMode(); // it takes 100us to switch from rx to tx, ie less than one byte at 76kbps
+        call Interrupt0.disable();
+
+        status = call SpiResourceTX.immediateRequest();
+        xe1205check(3, status);
+        if (status != SUCCESS) {
+            call XE1205PhySwitch.rxMode(); 
+            call SpiResourceConfig.request();
+            return status;
+        }
+        call XE1205PhySwitch.antennaTx();
+        state = RADIO_TX;
+        
+     }
+
+
+     call XE1205Fifo.write(data, frameLen);
+     atomic {
+       
+        txBuf = signal XE1205PhyRxTx.continueSend(&nextTxLen);
+     }
+     if (nextTxLen) {
+        call Interrupt0.enableFallingEdge();
+     } else {
+        call Interrupt0.disable();
+        call Interrupt1.enableRisingEdge();
+     }
+     // cannot happen with current SPI implementation (at least with NoDma)
 #if 0
-    if (status != SUCCESS) {
-      xe1205error(8, status);
-      call XE1205PhySwitch.rxMode(); 
-      call XE1205PhySwitch.antennaRx();
-      armPatternDetect();
-      call SpiResourceTX.release();
-      atomic {
-       call Interrupt0.enableRisingEdge();
-       state = RADIO_LISTEN;
-      }
-      return status;
-    }
+     if (status != SUCCESS) {
+        xe1205error(8, status);
+        call XE1205PhySwitch.rxMode(); 
+        call XE1205PhySwitch.antennaRx();
+        call XE1205PatternConf.loadDataPatternHasBus();
+        armPatternDetect();
+        call SpiResourceTX.release();
+        atomic {
+            call Interrupt0.enableRisingEdge();
+            state = RADIO_LISTEN;
+        }
+        return status;
+     }
 #endif
 
-    return SUCCESS;
-  }
-
-
-
-  uint16_t rxByte=0;
-
-  /**
-   * In transmit: nTxFifoEmpty. (ie after the last byte has been *read out of the fifo*)
-   * In receive: write_byte. 
-   */
-  async event void Interrupt0.fired()  __attribute__ ((noinline)) 
-  { 
-    error_t status;
-
-    switch (state) {
-
-    case RADIO_LISTEN:
-      rxByte=1;
-      state = RADIO_RX_HEADER;
-      status = call SpiResourceRX.immediateRequest();
-      xe1205check(4, status);
-      if (status != SUCCESS) {
-       state = RADIO_LISTEN;
-       call Interrupt0.disable(); // because pattern detector won't be rearmed right away
-       call SpiResourceConfig.request();
-       return;
-      }
-      return;
-
-    case RADIO_RX_HEADER:
-      rxByte++;
-      if (rxByte == 2) {
-       call Alarm32khz16.start(3000);
-      }
-
-      if (rxByte == headerLen + 1) {
-       call Interrupt0.disable();
-       xe1205check(8, call XE1205Fifo.read(rxFrame, headerLen));
-       call Interrupt1.enableRisingEdge();
-      }
-      return;
-
-    case RADIO_TX:
-
-      call Interrupt0.disable(); // avoid spurious IRQ0s from nTxFifoEmpty rebounding briefly after first byte is written.
-                                 // note that we should really wait till writedone() to re-enable either interrupt.
-      xe1205check(5, call XE1205Fifo.write(txBuf, nextTxLen));
-      return;
-
-    default:
-      return;
-    }
-  }
+     return SUCCESS;
+ }
 
 
 
-  /**
-   * In transmit: TxStopped. (ie after the last byte has been *sent*)
-   * In receive: Fifofull.
-   */
-  async event void Interrupt1.fired()  __attribute__ ((noinline)) 
-  { 
-    switch (state) {
+ uint16_t rxByte=0;
 
-    case RADIO_RX_PACKET:
-      xe1205check(9, call XE1205Fifo.read(&rxFrame[rxFrameIndex], nextRxLen));
-      call Interrupt1.disable(); // in case it briefly goes back to full just after we read first byte
-      rxFrameIndex += nextRxLen;
-      computeNextRxLength();
-      
-      if (nextRxLen==0) {
-       state = RADIO_RX_PACKET_LAST;
-      }
-
-      return;
-
-    case RADIO_RX_HEADER: // somehow the FIFO has filled before we finished reading the header bytes
-      call Interrupt1.disable();
-      call Alarm32khz16.stop();
-      signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL);
-      armPatternDetect();
-      call SpiResourceRX.release();
-      atomic {
-       call Interrupt0.enableRisingEdge();
-       state = RADIO_LISTEN;
-      }
-      return;
-
-    case RADIO_TX:
-
-      call Interrupt1.disable();
-      call XE1205PhySwitch.rxMode(); 
-      call XE1205PhySwitch.antennaRx();
-      signal XE1205PhyRxTx.sendFrameDone();
-      armPatternDetect();
-      call SpiResourceTX.release();
-      atomic {
-       call Interrupt0.enableRisingEdge();
-       state = RADIO_LISTEN;
-      }
-      return;
-
-    default:
-      return;
-    }
-  }
-
-  async event void XE1205Fifo.readDone(error_t error) {
-    xe1205check(6, error);
-    switch(state) {
-    case RADIO_RX_HEADER:
-      rxFrameLen = signal XE1205PhyRxTx.rxFrameBegin(rxFrame, headerLen);
-      if (rxFrameLen <= headerLen) {
-       call Interrupt1.disable();
-       call Alarm32khz16.stop();
-       signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL);
-       armPatternDetect();
-       call SpiResourceRX.release();
-       atomic {
-         call Interrupt0.enableRisingEdge();
-         state = RADIO_LISTEN;
-       }
-       return;
-      }
-
-      rxFrameIndex = headerLen;
-      computeNextRxLength();
-      state = RADIO_RX_PACKET;
-      return;
-
-    case RADIO_RX_PACKET_LAST:
-      call Alarm32khz16.stop();
-      signal XE1205PhyRxTx.rxFrameEnd(rxFrame, rxFrameLen + headerLen, SUCCESS);
-      armPatternDetect(); 
-      call SpiResourceRX.release();
-      atomic {
-       call Interrupt0.enableRisingEdge();
-       state = RADIO_LISTEN;
-      }
-      return;
-
-    case RADIO_RX_PACKET:
-      call Interrupt1.enableRisingEdge();
-      return;
-
-    default:
-      xe1205check(10, FAIL);
-      return;
-    }
-  }
-
-  async event void XE1205Fifo.writeDone(error_t error)  __attribute__ ((noinline)) { 
-    xe1205check(7, error);
-    switch(state) {
-    case RADIO_TX:
-      txBuf = signal XE1205PhyRxTx.continueSend(&nextTxLen);
-      if (nextTxLen) {
-       call Interrupt0.enableFallingEdge();
-      } else {
-       call Interrupt0.disable();
-       call Interrupt1.enableRisingEdge();
-      }
-      return;
-    default:
-      xe1205check(11, FAIL);
-    }
-  }
-
-  async event void Alarm32khz16.fired() {
-
-    switch(state) {
-
-    case RADIO_STARTING:
-      call SpiResourceConfig.request();
-      return;
-
-    case RADIO_RX_HEADER:
-    case RADIO_RX_PACKET:
-      stats_rxOverruns++;
-      signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL);
-      armPatternDetect(); 
-      call SpiResourceRX.release();
-      atomic {
-       call Interrupt0.enableRisingEdge();
-       state = RADIO_LISTEN;
-      }
-      return;
-    default:
-    }
+ /**
+  * In transmit: nTxFifoEmpty. (ie after the last byte has been *read out of the fifo*)
+  * In receive: write_byte. 
+  */
+ async event void Interrupt0.fired() __attribute__ ((noinline)) 
+ { 
+     error_t status;
+    
+     switch (state) {
+
+     case RADIO_RX_ACK:
+        
+        call Alarm32khz16.stop();
+     case RADIO_LISTEN:
+        rxByte=1;
+        atomic state = RADIO_RX_HEADER;
+        status = call SpiResourceRX.immediateRequest();
+        atomic {
+        if (status != SUCCESS) {
+            state = RADIO_LISTEN;
+            call Interrupt0.disable(); // because pattern detector won't be rearmed right away
+            call SpiResourceConfig.request();
+            return;
+        }
+        }
+        call Alarm32khz16.start(3000);
+        return;
+
+     case RADIO_RX_HEADER:
+        rxByte++;
+        if (rxByte == 2) {
+            call Alarm32khz16.start(3000);
+        }
+        if (rxByte == headerLen + 1) {
+            call Interrupt0.disable();
+            call XE1205Fifo.read(rxFrame, headerLen);
+            call Interrupt1.enableRisingEdge();
+        }
+
+        return;
+
+     case RADIO_TX:
+        call Interrupt0.disable(); // avoid spurious IRQ0s from nTxFifoEmpty rebounding briefly after first byte is written.
+        // note that we should really wait till writedone() to re-enable either interrupt.
+        call XE1205Fifo.write(txBuf, nextTxLen);
+        txBuf = signal XE1205PhyRxTx.continueSend(&nextTxLen);
+        if (nextTxLen) {
+            call Interrupt0.enableFallingEdge();
+        } else {
+            call Interrupt0.disable();
+            call Interrupt1.enableRisingEdge();
+        }
+        return;
+
+     case RADIO_RSSI: // trigged while getting rssi
+        call Interrupt0.disable(); // because pattern detector won't be rearmed right away
+        return;
+
+     default:
+        
+        return;
+     }
+ }
+
+
+
+ /**
+  * In transmit: TxStopped. (ie after the last byte has been *sent*)
+  * In receive: Fifofull.
+  */
+ async event void Interrupt1.fired()  __attribute__ ((noinline)) 
+ { 
+
+     switch (state) {
+
+     case RADIO_RX_PACKET:
+        call Interrupt1.disable(); // in case it briefly goes back to full just after we read first byte
+        call XE1205Fifo.read(&rxFrame[rxFrameIndex], nextRxLen);
+
+        rxFrameIndex += nextRxLen;
+        computeNextRxLength();
+        if (nextRxLen==0) {
+            state = RADIO_RX_PACKET_LAST;
+        }
+        return;
+
+     case RADIO_RX_HEADER: // somehow the FIFO has filled before we finished reading the header bytes
+
+        call Interrupt1.disable();
+        call Alarm32khz16.stop();
+
+        signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL);
+        call XE1205PatternConf.loadDataPatternHasBus();
+        armPatternDetect();
+        call SpiResourceRX.release();
+        atomic {            
+            call Interrupt0.enableRisingEdge();
+            state = RADIO_LISTEN;
+        }
+        return;
+
+     case RADIO_TX:
+
+        call Interrupt1.disable();
+        call XE1205PhySwitch.rxMode(); 
+        call XE1205PhySwitch.antennaRx();
+        if (enableAck==FALSE) {
+            call XE1205PatternConf.loadDataPatternHasBus();
+            armPatternDetect();
+            signal XE1205PhyRxTx.sendFrameDone(SUCCESS);
+            call SpiResourceTX.release();
+            atomic {
+                call Interrupt0.enableRisingEdge();
+                state = RADIO_LISTEN;
+            }
+        } else {
+
+            call XE1205PatternConf.loadAckPatternHasBus();
+            armPatternDetect();
+            call SpiResourceTX.release();
+            
+            call Alarm32khz16.start(usecs_to_jiffies(8000));
+            atomic {
+                call Interrupt0.enableRisingEdge();
+                state = RADIO_RX_ACK;
+            }
+        }
+
+        return;
+
+     default:
+        return;
+     }
+ }
+
+
+
+ async event void XE1205Fifo.readDone(error_t error) {
+
+     switch(state) {
+     case RADIO_RX_HEADER:
+        rxFrameLen = signal XE1205PhyRxTx.rxFrameBegin(rxFrame, headerLen);
+        if (rxFrameLen <= headerLen) {
+            call Interrupt1.disable();
+            call Alarm32khz16.stop();
+
+            signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL);
+            call XE1205PatternConf.loadDataPatternHasBus();
+            armPatternDetect();
+            call SpiResourceRX.release();
+            atomic {
+                state = RADIO_LISTEN;
+                call Interrupt0.enableRisingEdge();
+            }
+            return;
+        }
+        atomic {
+            if(rssiRange==RSSI_OFF) {
+                getRssi();
+            }
+        }
+        rxFrameIndex = headerLen;
+        computeNextRxLength();
+        state = RADIO_RX_PACKET;
+
+        return;
+
+     case RADIO_RX_PACKET_LAST:
+        call Alarm32khz16.stop();
+
+        atomic {
+            call XE1205PatternConf.loadDataPatternHasBus();
+            armPatternDetect(); 
+            state = RADIO_LISTEN;
+            call Interrupt0.enableRisingEdge();
+            call SpiResourceRX.release();
+        }
+        if( enableAck == FALSE) {
+            signal XE1205PhyRxTx.rxFrameEnd(rxFrame, rxFrameLen + headerLen, SUCCESS); 
+
+        } else {
+            enableAck = FALSE;
+            signal XE1205PhyRxTx.sendFrameDone(SUCCESS);
+        }
+
+        
+
+
+
+        return;
+
+     case RADIO_RX_PACKET:
+
+        call Interrupt1.enableRisingEdge();
+        return;
+
+     default:
+        xe1205check(10, FAIL);
+        return;
+     }
+ }
+
+ async event void XE1205Fifo.writeDone(error_t error)  __attribute__ ((noinline)) { 
+
+ }
+   
+
+ async event void Alarm32khz16.fired() {
+
+     switch(state) {
+
+     case RADIO_STARTING:
+        call SpiResourceConfig.request();      
+        return;
+
+     case RADIO_LISTEN:
+     case RADIO_RX_HEADER:
+     case RADIO_RX_PACKET:
+        if (rssiRange!=RSSI_OFF) {
+                readRssi();
+                return;
+            }
+        stats_rxOverruns++;
+
+        signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL);
+        call XE1205PatternConf.loadDataPatternHasBus();
+        armPatternDetect(); 
+        call SpiResourceRX.release();
+
+        atomic {
+            state = RADIO_LISTEN;
+            call Interrupt0.enableRisingEdge();
+        }
+
+        return;
+
+     case RADIO_RSSI:
+            readRssi();
+        return;
+
+     case RADIO_RX_ACK: // ack timeout
+
+        enableAck = FALSE;
+        call SpiResourceRX.immediateRequest();
+            
+        signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL);
+       
+        call XE1205PatternConf.loadDataPatternHasBus();
+
+        armPatternDetect();
+
+        call SpiResourceRX.release();
+        
+        atomic {
+            state = RADIO_LISTEN;
+            call Interrupt0.enableRisingEdge();
+
+        }
+
+        signal XE1205PhyRxTx.sendFrameDone(FAIL);
+        return;
+     default:
+   
+
+        return;
+     }
 
 }
+ }
 
 
 }
diff --git a/tos/chips/xe1205/phy/XE1205PhyRssi.nc b/tos/chips/xe1205/phy/XE1205PhyRssi.nc
new file mode 100644 (file)
index 0000000..6e0fc60
--- /dev/null
@@ -0,0 +1,6 @@
+interface XE1205PhyRssi {
+
+    async command error_t getRssi();
+    command uint8_t readRxRssi();
+    async event void rssiDone(uint8_t _rssi);
+}
index 19ac314c160d6c40b93ff61e51cabf55a0cda070..c3d464d1c4ada92f95199abad0333cbaa86e1a1e 100644 (file)
@@ -64,7 +64,7 @@ interface XE1205PhyRxTx {
    * the client module returned NULL to continueSendBuf().
    *
    */
-  async event void sendFrameDone();
+  async event void sendFrameDone(error_t err);
 
 
   /**
@@ -129,4 +129,5 @@ interface XE1205PhyRxTx {
 
 
 
+  async command void enableAck(bool onOff);
 }
index a649d021a9358f6c4770cb5ca323ef254234c959..c2a3a014af981ddf21e757aee3535467ee9fc6ad 100644 (file)
@@ -4,7 +4,7 @@ uint16_t lasterr;
 void xe1205error(uint8_t loc, uint8_t value_)  __attribute__ ((noinline)) {
   // this is just to make sure the compiler doesn't optimize 
   // out calls to this function, since we use it as a gdb breakpoint
-  atomic var += value_ + loc; 
+  atomic var += value_ + loc;
 }
 
 
diff --git a/tos/platforms/tinynode/chips/xe1205/Xe1205Spi0C.nc b/tos/platforms/tinynode/chips/xe1205/Xe1205Spi0C.nc
new file mode 100644 (file)
index 0000000..c528654
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2005-2006 Arched Rock 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 Arched Rock 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
+ * ARCHED ROCK 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
+ */
+
+/**
+ * An implementation of the SPI on USART0 for the MSP430. The current
+ * implementation defaults not using the DMA and performing the SPI
+ * transfers in software. To utilize the DMA, use Msp430SpiDma0P in
+ * place of Msp430SpiNoDma0P.
+ *
+ * @author Jonathan Hui <jhui@archedrock.com>
+ * @version $Revision$ $Date$
+ */
+
+#include "msp430usart.h"
+
+generic configuration Xe1205Spi0C() {
+
+  provides interface Resource;
+  provides interface SpiByte;
+  provides interface SpiPacket;
+
+  uses interface Msp430SpiConfigure;
+}
+
+implementation {
+
+  enum {
+    CLIENT_ID = unique( MSP430_SPIO_BUS ),
+  };
+
+  components Xe1205SpiNoDma0P as SpiP;
+  Resource = SpiP.Resource[ CLIENT_ID ];
+  SpiByte = SpiP.SpiByte;
+  SpiPacket = SpiP.SpiPacket[ CLIENT_ID ];
+  Msp430SpiConfigure = SpiP.Msp430SpiConfigure[ CLIENT_ID ];
+
+  components new Msp430Usart0C() as UsartC;
+  SpiP.ResourceConfigure[ CLIENT_ID ] <- UsartC.ResourceConfigure;
+  SpiP.UsartResource[ CLIENT_ID ] -> UsartC.Resource;
+  SpiP.UsartInterrupts -> UsartC.HplMsp430UsartInterrupts;
+
+}
diff --git a/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDma0P.nc b/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDma0P.nc
new file mode 100644 (file)
index 0000000..60ca5af
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2005-2006 Arched Rock 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 Arched Rock 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
+ * ARCHED ROCK 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 Jonathan Hui <jhui@archedrock.com>
+ * @version $Revision$ $Date$
+ */
+
+configuration Xe1205SpiNoDma0P {
+
+  provides interface Resource[ uint8_t id ];
+  provides interface ResourceConfigure[uint8_t id ];
+  provides interface SpiByte;
+  provides interface SpiPacket[ uint8_t id ];
+
+  uses interface Resource as UsartResource[ uint8_t id ];
+  uses interface Msp430SpiConfigure[ uint8_t id ];
+  uses interface HplMsp430UsartInterrupts as UsartInterrupts;
+
+}
+
+implementation {
+
+  components new Xe1205SpiNoDmaP() as SpiP;
+  Resource = SpiP.Resource;
+  ResourceConfigure = SpiP.ResourceConfigure;
+  Msp430SpiConfigure = SpiP.Msp430SpiConfigure;
+  SpiByte = SpiP.SpiByte;
+  SpiPacket = SpiP.SpiPacket;
+  UsartResource = SpiP.UsartResource;
+  UsartInterrupts = SpiP.UsartInterrupts;
+
+  components HplMsp430Usart0C as UsartC;
+  SpiP.Usart -> UsartC;
+
+  components LedsC as Leds;
+  SpiP.Leds -> Leds;
+
+}
diff --git a/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDmaP.nc b/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDmaP.nc
new file mode 100644 (file)
index 0000000..dd40806
--- /dev/null
@@ -0,0 +1,245 @@
+/**
+ * Copyright (c) 2005-2006 Arched Rock 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 Arched Rock 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
+ * ARCHED ROCK 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 Jonathan Hui <jhui@archedrock.com>
+ * @author Maxime Muller
+ * @version $Revision$ $Date$
+ *
+ * nss_data toggling for each rx byte
+ */
+
+
+generic module Xe1205SpiNoDmaP() {
+
+  provides interface Resource[ uint8_t id ];
+  provides interface ResourceConfigure[ uint8_t id ];
+  provides interface SpiByte;
+  provides interface SpiPacket[ uint8_t id ];
+
+  uses interface Resource as UsartResource[ uint8_t id ];
+  uses interface Msp430SpiConfigure[ uint8_t id ];
+  uses interface HplMsp430Usart as Usart;
+  uses interface HplMsp430UsartInterrupts as UsartInterrupts;
+  uses interface Leds;
+
+}
+
+implementation {
+
+  enum {
+    SPI_ATOMIC_SIZE = 2,
+  };
+
+  norace uint8_t* m_tx_buf;
+  norace uint8_t* m_rx_buf;
+  norace uint16_t m_len;
+  norace uint16_t m_pos;
+  norace uint8_t m_client;
+
+  void signalDone();
+  task void signalDone_task();
+
+  async command error_t Resource.immediateRequest[ uint8_t id ]() {
+    return call UsartResource.immediateRequest[ id ]();
+  }
+
+  async command error_t Resource.request[ uint8_t id ]() {
+    return call UsartResource.request[ id ]();
+  }
+
+  async command uint8_t Resource.isOwner[ uint8_t id ]() {
+    return call UsartResource.isOwner[ id ]();
+  }
+
+  async command error_t Resource.release[ uint8_t id ]() {
+    return call UsartResource.release[ id ]();
+  }
+
+  async command void ResourceConfigure.configure[ uint8_t id ]() {
+    call Usart.setModeSpi(call Msp430SpiConfigure.getConfig[id]());
+  }
+
+  async command void ResourceConfigure.unconfigure[ uint8_t id ]() {
+    call Usart.resetUsart(TRUE);
+    call Usart.disableSpi();
+    call Usart.resetUsart(FALSE);
+  }
+
+  event void UsartResource.granted[ uint8_t id ]() {
+    signal Resource.granted[ id ]();
+  }
+
+  async command uint8_t SpiByte.write( uint8_t tx ) {
+    uint8_t byte;
+    // we are in spi mode which is configured to have turned off interrupts
+    // call Usart.disableRxIntr();
+    call Usart.tx( tx );
+    while( !call Usart.isRxIntrPending() );
+    call Usart.clrRxIntr();
+    byte = call Usart.rx();
+    //    call Usart.enableRxIntr();
+    return byte;
+  }
+
+  default async command error_t UsartResource.isOwner[ uint8_t id ]() { return FAIL; }
+  default async command error_t UsartResource.request[ uint8_t id ]() { return FAIL; }
+  default async command error_t UsartResource.immediateRequest[ uint8_t id ]() { return FAIL; }
+  default async command error_t UsartResource.release[ uint8_t id ]() { return FAIL; }
+ default async command msp430_spi_union_config_t* Msp430SpiConfigure.getConfig[uint8_t id]() {
+    return &msp430_spi_default_config;
+  }
+
+  default event void Resource.granted[ uint8_t id ]() {}
+
+  void continueOp() {
+      uint8_t end;
+      uint8_t tmp;
+      
+      atomic {
+         
+         TOSH_CLR_NSS_DATA_PIN();
+         call Usart.tx( 0 );
+         while( !call Usart.isRxIntrPending() );
+         TOSH_SET_NSS_DATA_PIN();
+         
+         end = m_pos + SPI_ATOMIC_SIZE;
+         if ( end > m_len )
+             end = m_len;
+         
+         while ( ++m_pos < end ) {
+             TOSH_CLR_NSS_DATA_PIN();
+             call Usart.tx( 0 );
+             while( !call Usart.isRxIntrPending() );       
+             tmp = call Usart.rx();
+             m_rx_buf[ m_pos - 1 ] = tmp;
+         }
+      }
+  }
+  
+
+
+  inline  void sendBuffer(uint8_t const* buffer_, int size_) {
+
+      TOSH_CLR_NSS_DATA_PIN();
+
+      call Usart.isTxIntrPending();
+      call Usart.rx();
+      while(size_ > 0) {
+         call Usart.tx(*buffer_);
+         ++buffer_;
+         --size_;            
+         while( !call Usart.isRxIntrPending() );
+         call Usart.rx();
+      }
+      call Usart.disableRxIntr();
+      TOSH_SET_NSS_DATA_PIN();
+  }
+
+
+
+     inline void readData() {
+      uint8_t end;
+      uint8_t tmp;
+      
+      atomic {
+       TOSH_TOGGLE_YELLOW_LED_PIN();
+         call Usart.tx( 0 );
+         call Usart.isTxIntrPending();
+         call Usart.rx();
+         end = m_pos + SPI_ATOMIC_SIZE;
+         if ( end > m_len )
+             end = m_len;
+       
+         while ( ++m_pos < end ) {
+             TOSH_CLR_NSS_DATA_PIN();
+             call Usart.tx( 0 );
+             while( !call Usart.isRxIntrPending() );
+             tmp = call Usart.rx();
+             TOSH_SET_NSS_DATA_PIN();
+             m_rx_buf[ m_pos - 1 ] = tmp;
+         }
+      }
+      
+  }
+
+  async command error_t SpiPacket.send[ uint8_t id ]( uint8_t* tx_buf,
+                                                      uint8_t* rx_buf,
+                                                      uint16_t len ) {
+
+      m_client = id;
+      m_tx_buf = tx_buf;
+      m_rx_buf = rx_buf;
+      m_len = len;
+      m_pos = 0;
+
+      if (m_tx_buf)
+         sendBuffer(m_tx_buf,m_len);
+      else {
+         call Usart.enableRxIntr();
+
+         continueOp();
+      }
+
+      return SUCCESS;
+
+  }
+
+  task void signalDone_task() {
+      atomic signalDone();
+  }
+
+  async event void UsartInterrupts.rxDone( uint8_t data ) {
+   
+      if ( m_rx_buf ) {
+         m_rx_buf[ m_pos-1 ] = data;
+      } else 
+         return;
+     TOSH_SET_NSS_DATA_PIN();
+    if ( m_pos < m_len ) {
+       continueOp();
+
+    } else {
+       call Usart.disableRxIntr();
+       signalDone();
+    }
+  }
+
+  void signalDone() {
+    signal SpiPacket.sendDone[ m_client ]( m_tx_buf, m_rx_buf, m_len,
+                                          SUCCESS );
+  }
+
+  async event void UsartInterrupts.txDone() {}
+
+  default async event void SpiPacket.sendDone[ uint8_t id ]( uint8_t* tx_buf, uint8_t* rx_buf, uint16_t len, error_t error ) {}
+
+}