--- /dev/null
+interface AckSendReceive {
+ command void setAckPayload(uint16_t _pl);
+ command uint16_t getAckPayload();
+}
--- /dev/null
+interface CsmaControl {
+
+ async command void enableCca();
+ async command void disableCca();
+}
--- /dev/null
+
+interface LPLControl {
+
+ async command void setMode(uint8_t mode);
+}
--- /dev/null
+/*\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
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;
};
enum {
- data_pattern = 0x893456,
+ data_pattern = 0x893456,
+ ack_pattern = 0x123fed
};
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 {
};
+
+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 */
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;
--- /dev/null
+/* 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;
+ }
+
+}
--- /dev/null
+/* 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;
+
+}
--- /dev/null
+/* 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
--- /dev/null
+
+
+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;
+
+}
--- /dev/null
+/* 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));
+ }
+}
provides interface Send;
provides interface Packet;
provides interface PacketAcknowledgements;
+ provides interface AckSendReceive;
provides interface SplitControl @atleastonce();
provides interface Receive;
}
Receive = XE1205SendReceiveP;
Packet = XE1205SendReceiveP;
PacketAcknowledgements = XE1205SendReceiveP;
+ AckSendReceive = XE1205SendReceiveP;
SplitControl = XE1205SendReceiveP;
components XE1205PhyC;
XE1205SendReceiveP.XE1205PhyRxTx -> XE1205PhyC;
+ XE1205SendReceiveP.XE1205PhyRssi -> XE1205PhyC;
XE1205SendReceiveP.PhySplitControl -> XE1205PhyC;
}
* @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) { }
}
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) {}
}
* @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
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;
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)
#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;
+ }
}
* @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,
configuration XE1205PhyC {
provides interface XE1205PhyRxTx;
+ provides interface XE1205PhyRssi;
provides interface SplitControl;
}
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;
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
#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;
+ }
- }
+ }
}
--- /dev/null
+interface XE1205PhyRssi {
+
+ async command error_t getRssi();
+ command uint8_t readRxRssi();
+ async event void rssiDone(uint8_t _rssi);
+}
* the client module returned NULL to continueSendBuf().
*
*/
- async event void sendFrameDone();
+ async event void sendFrameDone(error_t err);
/**
+ async command void enableAck(bool onOff);
}
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;
}
--- /dev/null
+/**
+ * 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;
+
+}
--- /dev/null
+/**
+ * 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;
+
+}
--- /dev/null
+/**
+ * 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 ) {}
+
+}