From: maxmul Date: Fri, 13 Jul 2007 15:54:08 +0000 (+0000) Subject: added ack, received packet strength, LPL (compile with PFLAGS +=-DLOW_POWER_LISTENING) X-Git-Tag: release_tools_1_2_4_1~34 X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=commitdiff_plain;h=f05e333221d21758aa1d1ab77929e5d0238f5370 added ack, received packet strength, LPL (compile with PFLAGS +=-DLOW_POWER_LISTENING) --- diff --git a/tos/chips/xe1205/AckSendReceive.nc b/tos/chips/xe1205/AckSendReceive.nc new file mode 100644 index 00000000..34c3b4bd --- /dev/null +++ b/tos/chips/xe1205/AckSendReceive.nc @@ -0,0 +1,4 @@ +interface AckSendReceive { + command void setAckPayload(uint16_t _pl); + command uint16_t getAckPayload(); +} diff --git a/tos/chips/xe1205/CsmaControl.nc b/tos/chips/xe1205/CsmaControl.nc new file mode 100644 index 00000000..a7898278 --- /dev/null +++ b/tos/chips/xe1205/CsmaControl.nc @@ -0,0 +1,5 @@ +interface CsmaControl { + + async command void enableCca(); + async command void disableCca(); +} diff --git a/tos/chips/xe1205/LPLControl.nc b/tos/chips/xe1205/LPLControl.nc new file mode 100644 index 00000000..9e8a6fd4 --- /dev/null +++ b/tos/chips/xe1205/LPLControl.nc @@ -0,0 +1,5 @@ + +interface LPLControl { + + async command void setMode(uint8_t mode); +} diff --git a/tos/chips/xe1205/LowPowerListening.nc b/tos/chips/xe1205/LowPowerListening.nc new file mode 100644 index 00000000..8bd970fe --- /dev/null +++ b/tos/chips/xe1205/LowPowerListening.nc @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2005-2006 Rincon Research Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * - Neither the name of the Arch 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 + */ + +/** + * Low Power Listening interface + * + * @author David Moss + * @author Jonathan Hui + */ + +interface LowPowerListening { + + /** + * Set this this node's radio sleep interval, in milliseconds. + * Once every interval, the node will sleep and perform an Rx check + * on the radio. Setting the sleep interval to 0 will keep the radio + * always on. + * + * This is the equivalent of setting the local duty cycle rate. + * + * @param sleepIntervalMs the length of this node's Rx check interval, in [ms] + */ + command void setLocalSleepInterval(uint16_t sleepIntervalMs); + + /** + * @return the local node's sleep interval, in [ms] + */ + command uint16_t getLocalSleepInterval(); + + /** + * Set this node's radio duty cycle rate, in units of [percentage*100]. + * For example, to get a 0.05% duty cycle, + * + * call LowPowerListening.setDutyCycle(5); // or equivalently... + * call LowPowerListening.setDutyCycle(00005); // for better readability? + * + * + * For a 100% duty cycle (always on), + * + * call LowPowerListening.setDutyCycle(10000); + * + * + * This is the equivalent of setting the local sleep interval explicitly. + * + * @param dutyCycle The duty cycle percentage, in units of [percentage*100] + */ + command void setLocalDutyCycle(uint16_t dutyCycle); + + /** + * @return this node's radio duty cycle rate, in units of [percentage*100] + */ + command uint16_t getLocalDutyCycle(); + + + /** + * Configure this outgoing message so it can be transmitted to a neighbor mote + * with the specified Rx sleep interval. + * @param msg Pointer to the message that will be sent + * @param sleepInterval The receiving node's sleep interval, in [ms] + */ + command void setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs); + + /** + * @return the destination node's sleep interval configured in this message + */ + command uint16_t getRxSleepInterval(message_t *msg); + + /** + * Configure this outgoing message so it can be transmitted to a neighbor mote + * with the specified Rx duty cycle rate. + * Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25. + * + * @param msg Pointer to the message that will be sent + * @param dutyCycle The duty cycle of the receiving mote, in units of + * [percentage*100] + */ + command void setRxDutyCycle(message_t *msg, uint16_t dutyCycle); + + /** + * @return the destination node's duty cycle configured in this message + * in units of [percentage*100] + */ + command uint16_t getRxDutyCycle(message_t *msg); + + /** + * Convert a duty cycle, in units of [percentage*100], to + * the sleep interval of the mote in milliseconds + * @param dutyCycle The duty cycle in units of [percentage*100] + * @return The equivalent sleep interval, in units of [ms] + */ + command uint16_t dutyCycleToSleepInterval(uint16_t dutyCycle); + + /** + * Convert a sleep interval, in units of [ms], to a duty cycle + * in units of [percentage*100] + * @param sleepInterval The sleep interval in units of [ms] + * @return The duty cycle in units of [percentage*100] + */ + command uint16_t sleepIntervalToDutyCycle(uint16_t sleepInterval); + +} diff --git a/tos/chips/xe1205/XE1205.h b/tos/chips/xe1205/XE1205.h index 226abeee..bcd8b86e 100644 --- a/tos/chips/xe1205/XE1205.h +++ b/tos/chips/xe1205/XE1205.h @@ -52,15 +52,19 @@ typedef nx_struct xe1205_header_t { nx_am_addr_t source; nx_am_id_t type; nx_am_group_t group; + nx_uint8_t ack; } xe1205_header_t; typedef nx_struct xe1205_footer_t { - nxle_uint16_t crc; +#ifdef LOW_POWER_LISTENING + nx_uint16_t rxInterval; +#endif + nxle_uint16_t crc; } xe1205_footer_t; typedef nx_struct xe1205_metadata_t { nx_uint8_t length; - nx_uint8_t ack;// xxx this should move to header or footer, leaving it here for now for 1.x compat + nx_uint8_t strength; } xe1205_metadata_t; @@ -108,7 +112,8 @@ enum { }; enum { - data_pattern = 0x893456, + data_pattern = 0x893456, + ack_pattern = 0x123fed }; @@ -133,9 +138,12 @@ typedef enum { typedef enum { - xe1205_channelpreset_867mhz=0, - xe1205_channelpreset_868mhz=1, - xe1205_channelpreset_869mhz=2, + xe1205_channelpreset_868mhz=0, + xe1205_channelpreset_869mhz=1, + xe1205_channelpreset_870mhz=2, + xe1205_channelpreset_433mhz=3, + xe1205_channelpreset_434mhz=4, + xe1205_channelpreset_435mhz=5, } xe1205_channelpreset_t; typedef enum { @@ -188,5 +196,36 @@ enum { }; + +enum { + RSSI_BELOW_110 = 0, + RSSI_110_TO_105 = 1, + RSSI_105_TO_100 = 2, + RSSI_100_TO_95 = 3, + RSSI_95_TO_90 = 4, + RSSI_90_TO_85 = 5, + RSSI_ABOVE_85 = 6 +}; + +uint8_t const rssiTab[] = { + RSSI_BELOW_110, // 0b0000 + RSSI_110_TO_105, // 0b0001 + RSSI_105_TO_100, // 0b0010 + RSSI_100_TO_95, // 0b0011 + RSSI_95_TO_90, // 0b0100 * + RSSI_95_TO_90, // 0b0101 * + RSSI_95_TO_90, // 0b0110 * + RSSI_95_TO_90, // 0b0111 + RSSI_90_TO_85, // 0b1000 * + RSSI_90_TO_85, // 0b1001 * + RSSI_90_TO_85, // 0b1010 * + RSSI_90_TO_85, // 0b1011 + RSSI_ABOVE_85, // 0b1100 * + RSSI_ABOVE_85, // 0b1101 * + RSSI_ABOVE_85, // 0b1110 * + RSSI_ABOVE_85 // 0b1111 + // (*) : 'inconsistent' pairs +}; + #endif /* _XE1205CONST_H */ diff --git a/tos/chips/xe1205/XE1205ActiveMessageC.nc b/tos/chips/xe1205/XE1205ActiveMessageC.nc index 3f2c7686..49c68c86 100644 --- a/tos/chips/xe1205/XE1205ActiveMessageC.nc +++ b/tos/chips/xe1205/XE1205ActiveMessageC.nc @@ -44,20 +44,30 @@ configuration XE1205ActiveMessageC { interface AMPacket; interface Packet; interface PacketAcknowledgements; + #ifdef LOW_POWER_LISTENING + interface LowPowerListening; + #endif } } implementation { components XE1205SendReceiveC; - SplitControl = XE1205SendReceiveC; Packet = XE1205SendReceiveC; PacketAcknowledgements = XE1205SendReceiveC; + components XE1205ActiveMessageP; - - components XE1205ActiveMessageP; +#ifdef LOW_POWER_LISTENING + components XE1205LowPowerListeningC as Lpl; + LowPowerListening = Lpl; + XE1205ActiveMessageP.SubSend -> Lpl.Send; + XE1205ActiveMessageP.SubReceive -> Lpl.Receive; + SplitControl = Lpl; +#else + XE1205ActiveMessageP.Packet -> XE1205SendReceiveC; XE1205ActiveMessageP.SubSend -> XE1205SendReceiveC.Send; XE1205ActiveMessageP.SubReceive -> XE1205SendReceiveC.Receive; - + SplitControl = XE1205SendReceiveC; +#endif AMPacket = XE1205ActiveMessageP; AMSend = XE1205ActiveMessageP; Receive = XE1205ActiveMessageP.Receive; diff --git a/tos/chips/xe1205/XE1205CsmaP.nc b/tos/chips/xe1205/XE1205CsmaP.nc new file mode 100644 index 00000000..2ed39422 --- /dev/null +++ b/tos/chips/xe1205/XE1205CsmaP.nc @@ -0,0 +1,318 @@ +/* Copyright (c) 2007 Shockfish SA +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software and its +* documentation for any purpose, without fee, and without written +* agreement is hereby granted, provided that the above copyright +* notice, the (updated) modification history and the author appear in +* all copies of this source code. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, +* OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @author Maxime Muller + * + */ + +#include "XE1205.h" +#include "XE1205LowPowerListening.h" + +#define MAX(X,Y) X>Y ? X:Y + +module XE1205CsmaP { + + provides { + interface Init @atleastonce(); + interface SplitControl @atleastonce(); + interface Send; + interface Receive; + interface CsmaControl; + interface LPLControl; + interface CsmaBackoff[am_id_t amId]; + } + uses { + interface SplitControl as SubControl; + interface Receive as SubReceive; + interface Send as SubSend; + interface XE1205PhyRssi as Rssi; + interface XE1205PhyConf as RadioConf; + interface Timer as BackoffTimer; + interface Random; + } +} +implementation { + + enum { + RADIO_DISABLED, + RADIO_IDLE, + RADIO_RX, + RADIO_TX, + }; + + uint8_t rState; + uint8_t rxRssi; + uint8_t clrRssi; + norace uint8_t rssiSampleCnt; + bool enableCCA; + + message_t * txMsg; + uint8_t txLen; + enum { + RSSI_RX = 0, + RSSI_CLR = 1, + }; + uint16_t MA_LENGTH = 8; + uint8_t MAX_RSSI_SAMPLE = 4; + norace float RSSI_RX_MA; + norace float RSSI_CLR_MA; + + /* + * function prototypes + */ + + task void readRssi(); + task void send(); + + command error_t Init.init() { + rssiSampleCnt=0; + rState = RADIO_DISABLED; + RSSI_RX_MA = RSSI_ABOVE_85; + RSSI_CLR_MA = RSSI_90_TO_85; + return SUCCESS; + } + + command error_t SplitControl.start() { + return call SubControl.start(); + } + + event void SubControl.startDone(error_t err) { + if (err!=SUCCESS) { + atomic { + if (rState == RADIO_TX) + signal Send.sendDone(txMsg,FAIL); + else + signal SplitControl.startDone(FAIL); + } + } else { + atomic { + if (rState == RADIO_TX) { + if(enableCCA==TRUE) { + if(SUCCESS != post readRssi()) { + signal Send.sendDone(txMsg,FAIL); + return; + } + } + else { + post send(); + return; + if (SUCCESS != post send()) { + signal Send.sendDone(txMsg,FAIL); + return; + } + } + } + if(SUCCESS != post readRssi()) + signal SplitControl.startDone(FAIL); + } + } + } + + command error_t SplitControl.stop() { + + return call SubControl.stop(); + } + + event void SubControl.stopDone(error_t err) { + atomic { + if (rState == RADIO_RX) // LPL: shutdown if no activity + if (err==SUCCESS) + rState = RADIO_IDLE; + } + signal SplitControl.stopDone(err); + } + + + + void updateRssiMA(uint8_t maType, uint8_t value) { + + switch (maType) { + case RSSI_CLR: + if((float)value < MAX(RSSI_RX_MA,RSSI_RX_MA)) + RSSI_CLR_MA = (RSSI_CLR_MA*(MA_LENGTH - 1)+ value )/(MA_LENGTH); + break; + + case RSSI_RX: + RSSI_RX_MA = (RSSI_RX_MA*(MA_LENGTH - 1)+ value )/(MA_LENGTH); + break; + + default: + break; + } + } + + event message_t *SubReceive.receive(message_t* msg, void* payload, uint8_t len){ + + uint8_t strgth = ((xe1205_metadata_t*)((uint8_t*)msg->footer + sizeof(xe1205_footer_t)))->strength; + updateRssiMA(RSSI_RX, strgth); + return signal Receive.receive(msg, payload, len); + } + + command error_t Send.send(message_t* msg, uint8_t len) { + error_t err; + atomic { + switch (rState) { + + case RADIO_DISABLED: + return EOFF; + + default: + + rState = RADIO_TX; + atomic txMsg = msg; + atomic txLen = len; + err = call SubControl.start(); + return err; + } + } + } + + task void send() { + if (SUCCESS != call SubSend.send(txMsg, txLen)) { + atomic rState = RADIO_IDLE; + signal Send.sendDone(txMsg, FAIL); + } + } + + event void SubSend.sendDone(message_t *msg, error_t err) { + atomic rState = RADIO_IDLE; + signal Send.sendDone(msg, err); + } + + command void* Send.getPayload(message_t* m) { + return m->data; + } + + command uint8_t Send.maxPayloadLength() { + return TOSH_DATA_LENGTH; + } + + command error_t Send.cancel( message_t* p_msg ) { + return FAIL; + } + + command uint8_t Receive.payloadLength(message_t* msg) { + return call SubReceive.payloadLength(msg); + } + + command void *Receive.getPayload(message_t* msg, uint8_t* len) { + return call SubReceive.getPayload(msg, len); + } + + task void readRssi() { + if(SUCCESS!=call Rssi.getRssi()) { + + atomic { + if (rState == RADIO_TX) { + signal Send.sendDone(txMsg, FAIL); + } else { + signal SplitControl.startDone(FAIL); + } + } + } + } + + + event void BackoffTimer.fired() { + rssiSampleCnt = 0; + if(SUCCESS != post send()) { + atomic rState = RADIO_IDLE; + signal Send.sendDone(txMsg,FAIL); + } + } + async event void Rssi.rssiDone(uint8_t val) { + + updateRssiMA(RSSI_CLR, val); + atomic { + if (rState == RADIO_DISABLED) { + rState = RADIO_IDLE; + signal SplitControl.startDone(SUCCESS); + return; + } + } + + // RX for LPL only + atomic { + if (rState == RADIO_RX) { + if (RSSI_CLR_MA >= (float)val) { // go back to sleep + call SubControl.stop(); + return; + } else + // tell lpl layer we have some activity + signal SplitControl.startDone(SUCCESS); + } + + // TX + if (rState == RADIO_TX) { + rssiSampleCnt++; + if ( RSSI_RX_MA >= (float)val || RSSI_CLR_MA >= (float)val || !enableCCA) { // it's a go + if (enableCCA) { + call BackoffTimer.startOneShot(signal CsmaBackoff.initial[((xe1205_header_t*)(txMsg->data - sizeof(xe1205_header_t)))->type](txMsg)); + } else + post send(); + return; + } + else + if (enableCCA && rssiSampleCnt < MAX_RSSI_SAMPLE) { + post readRssi(); + } else { + call BackoffTimer.startOneShot(signal CsmaBackoff.congestion[((xe1205_header_t*)(txMsg->data - sizeof(xe1205_header_t)))->type](txMsg)); + } + } + } + } + + async command void LPLControl.setMode(uint8_t mode) { + switch (mode) { + + case RX: + atomic { + if(rState!=RADIO_TX) + rState = RADIO_RX; + } + break; + + case IDLE: + atomic rState = RADIO_IDLE; + + default: + return; + } + } + + async command void CsmaControl.enableCca() { + atomic enableCCA = TRUE; + } + + async command void CsmaControl.disableCca() { + atomic enableCCA = FALSE; + } + + default async event uint16_t CsmaBackoff.initial[am_id_t amId](message_t *m) { + return (call Random.rand16() & 0x07) + 1; + } + + default async event uint16_t CsmaBackoff.congestion[am_id_t amId](message_t *m) { + return (call Random.rand16() & 0xF) + 1; + } + +} diff --git a/tos/chips/xe1205/XE1205CsmaRadioC.nc b/tos/chips/xe1205/XE1205CsmaRadioC.nc new file mode 100644 index 00000000..5dbc6d56 --- /dev/null +++ b/tos/chips/xe1205/XE1205CsmaRadioC.nc @@ -0,0 +1,69 @@ +/* Copyright (c) 2007 Shockfish SA +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software and its +* documentation for any purpose, without fee, and without written +* agreement is hereby granted, provided that the above copyright +* notice, the (updated) modification history and the author appear in +* all copies of this source code. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, +* OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @author Maxime Muller + * + */ + +#include "message.h" +#include "XE1205.h" + +configuration XE1205CsmaRadioC { + provides { + interface SplitControl; + interface Send; + interface Receive; + interface Packet; + interface CsmaControl; + interface CsmaBackoff[am_id_t amId]; + interface PacketAcknowledgements; + interface LPLControl; + } +} +implementation { + components XE1205CsmaP as CsmaP; + components XE1205SendReceiveP as SendReceive; + components XE1205PhyP; + components new TimerMilliC() as BackoffTimerC; + components MainC, RandomC,ActiveMessageC, ActiveMessageAddressC; + + MainC.SoftwareInit -> CsmaP; + + Send = CsmaP; + Receive = CsmaP; + Packet = SendReceive; + PacketAcknowledgements = SendReceive; + + SplitControl = CsmaP; + CsmaControl = CsmaP; + CsmaBackoff = CsmaP; + LPLControl = CsmaP; + + + CsmaP.SubControl -> SendReceive.SplitControl; + CsmaP.SubReceive -> SendReceive.Receive; + CsmaP.SubSend -> SendReceive.Send; + CsmaP.Rssi -> XE1205PhyP.XE1205PhyRssi; + CsmaP.BackoffTimer -> BackoffTimerC; + CsmaP.Random -> RandomC; + +} diff --git a/tos/chips/xe1205/XE1205LowPowerListening.h b/tos/chips/xe1205/XE1205LowPowerListening.h new file mode 100644 index 00000000..e34086e8 --- /dev/null +++ b/tos/chips/xe1205/XE1205LowPowerListening.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2007 Shockfish SA +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software and its +* documentation for any purpose, without fee, and without written +* agreement is hereby granted, provided that the above copyright +* notice, the (updated) modification history and the author appear in +* all copies of this source code. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, +* OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @author Maxime Muller + * + */ + +#ifndef XE1205LOWPOWERLISTENING_H +#define XE1205LOWPOWERLISTENING_H + +/** + * Amount of time, in milliseconds, to keep the radio on after + * a successful receive addressed to this node + */ + +#ifndef DELAY_AFTER_RECEIVE +#define DELAY_AFTER_RECEIVE 20 +#endif + +/** + * Value used to indicate the message being sent should be transmitted + * one time + */ + +#ifndef ONE_MESSAGE +#define ONE_MESSAGE 0 +#endif + +#ifndef DEFAULT_DUTY_PERIOD +#define DEFAULT_DUTY_PERIOD 1000 +#endif + + +enum { + IDLE = 0, + RX = 1, +}; + +#endif diff --git a/tos/chips/xe1205/XE1205LowPowerListeningC.nc b/tos/chips/xe1205/XE1205LowPowerListeningC.nc new file mode 100644 index 00000000..e7e60df9 --- /dev/null +++ b/tos/chips/xe1205/XE1205LowPowerListeningC.nc @@ -0,0 +1,44 @@ + + +configuration XE1205LowPowerListeningC { + provides { + interface SplitControl; + interface Send; + interface Receive; + interface LowPowerListening; + // interface CsmaBackoff[am_id_t amId]; + } +} +implementation { + components MainC, + XE1205ActiveMessageC, + XE1205LowPowerListeningP, + /*XE1205CsmaP as*/ XE1205CsmaRadioC, + RandomC; + components new TimerMilliC() as SendTimeoutC; + components new TimerMilliC() as OnTimerC; + components new TimerMilliC() as OffTimerC; + + Send = XE1205LowPowerListeningP; + Receive = XE1205LowPowerListeningP; + SplitControl = XE1205LowPowerListeningP; + LowPowerListening = XE1205LowPowerListeningP; + // CsmaBackoff = XE1205LowPowerListeningP; + + MainC.SoftwareInit -> XE1205LowPowerListeningP; + + //XE1205LowPowerListeningP.LowPowerListening -> XE1205CsmaRadioC; + XE1205LowPowerListeningP.SubControl -> XE1205CsmaRadioC; + XE1205LowPowerListeningP.CsmaControl -> XE1205CsmaRadioC; + // XE1205LowPowerListeningP.SubBackoff -> XE1205CsmaRadioC; + XE1205LowPowerListeningP.SubSend -> XE1205CsmaRadioC.Send; + XE1205LowPowerListeningP.SubReceive -> XE1205CsmaRadioC.Receive; + XE1205LowPowerListeningP.AMPacket -> XE1205ActiveMessageC; + XE1205LowPowerListeningP.PacketAcknowledgements -> XE1205ActiveMessageC;// XE1205CsmaRadioC; + XE1205LowPowerListeningP.SendTimeout -> SendTimeoutC; + XE1205LowPowerListeningP.OnTimer -> OnTimerC; + XE1205LowPowerListeningP.OffTimer -> OffTimerC; + XE1205LowPowerListeningP.Random -> RandomC; + XE1205LowPowerListeningP.LPLControl -> XE1205CsmaRadioC.LPLControl; + +} diff --git a/tos/chips/xe1205/XE1205LowPowerListeningP.nc b/tos/chips/xe1205/XE1205LowPowerListeningP.nc new file mode 100644 index 00000000..df2487ad --- /dev/null +++ b/tos/chips/xe1205/XE1205LowPowerListeningP.nc @@ -0,0 +1,360 @@ +/* Copyright (c) 2007 Shockfish SA +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software and its +* documentation for any purpose, without fee, and without written +* agreement is hereby granted, provided that the above copyright +* notice, the (updated) modification history and the author appear in +* all copies of this source code. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS +* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, +* OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @author Maxime Muller + * + */ + +#include "XE1205LowPowerListening.h" + +module XE1205LowPowerListeningP { + provides { + interface Init; + interface SplitControl; + interface Send; + interface Receive; + interface LowPowerListening; + + } + uses { + interface LPLControl; + interface SplitControl as SubControl; + interface CsmaControl; + interface Send as SubSend; + interface Receive as SubReceive; + interface AMPacket; + interface PacketAcknowledgements; + interface Timer as SendTimeout; + interface Timer as OnTimer; + interface Timer 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)); + } +} diff --git a/tos/chips/xe1205/XE1205SendReceiveC.nc b/tos/chips/xe1205/XE1205SendReceiveC.nc index f84a147c..7ba4dd35 100644 --- a/tos/chips/xe1205/XE1205SendReceiveC.nc +++ b/tos/chips/xe1205/XE1205SendReceiveC.nc @@ -39,6 +39,7 @@ configuration XE1205SendReceiveC { provides interface Send; provides interface Packet; provides interface PacketAcknowledgements; + provides interface AckSendReceive; provides interface SplitControl @atleastonce(); provides interface Receive; } @@ -49,10 +50,12 @@ implementation { Receive = XE1205SendReceiveP; Packet = XE1205SendReceiveP; PacketAcknowledgements = XE1205SendReceiveP; + AckSendReceive = XE1205SendReceiveP; SplitControl = XE1205SendReceiveP; components XE1205PhyC; XE1205SendReceiveP.XE1205PhyRxTx -> XE1205PhyC; + XE1205SendReceiveP.XE1205PhyRssi -> XE1205PhyC; XE1205SendReceiveP.PhySplitControl -> XE1205PhyC; } diff --git a/tos/chips/xe1205/XE1205SendReceiveP.nc b/tos/chips/xe1205/XE1205SendReceiveP.nc index b86ce5ca..77bfff4a 100644 --- a/tos/chips/xe1205/XE1205SendReceiveP.nc +++ b/tos/chips/xe1205/XE1205SendReceiveP.nc @@ -35,297 +35,429 @@ * @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) { } } diff --git a/tos/chips/xe1205/XE1205SpiImplP.nc b/tos/chips/xe1205/XE1205SpiImplP.nc index fdf4f81a..6cafcc35 100644 --- a/tos/chips/xe1205/XE1205SpiImplP.nc +++ b/tos/chips/xe1205/XE1205SpiImplP.nc @@ -69,196 +69,191 @@ 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) {} } diff --git a/tos/chips/xe1205/conf/XE1205PatternConf.nc b/tos/chips/xe1205/conf/XE1205PatternConf.nc index 01345136..3e3be5c8 100644 --- a/tos/chips/xe1205/conf/XE1205PatternConf.nc +++ b/tos/chips/xe1205/conf/XE1205PatternConf.nc @@ -61,6 +61,8 @@ interface XE1205PatternConf { * @return SUCCESS if operation done ok, error status otherwise */ async command error_t loadPattern(uint8_t* pattern, uint8_t len); + async command error_t loadDataPatternHasBus(); + async command error_t loadAckPatternHasBus(); /** * Set the number of bit errors accepted by the XE1205 diff --git a/tos/chips/xe1205/conf/XE1205PatternConfP.nc b/tos/chips/xe1205/conf/XE1205PatternConfP.nc index 5ba8c76c..c4ca0e45 100644 --- a/tos/chips/xe1205/conf/XE1205PatternConfP.nc +++ b/tos/chips/xe1205/conf/XE1205PatternConfP.nc @@ -96,7 +96,26 @@ implementation { call SpiResource.release(); return SUCCESS; } - + async command error_t XE1205PatternConf.loadDataPatternHasBus() { + + call Pattern13.write((data_pattern >> 16) & 0xff); + call Pattern14.write((data_pattern >> 8) & 0xff); + call Pattern15.write(data_pattern & 0xff); + + return SUCCESS; + + } + + async command error_t XE1205PatternConf.loadAckPatternHasBus() { + + call Pattern13.write((ack_pattern >> 16) & 0xff); + call Pattern14.write((ack_pattern >> 8) & 0xff); + call Pattern15.write(ack_pattern & 0xff); + + return SUCCESS; + + } + async command error_t XE1205PatternConf.loadPattern(uint8_t* pattern, uint8_t len) { error_t status; diff --git a/tos/chips/xe1205/conf/XE1205PhyRssiConfP.nc b/tos/chips/xe1205/conf/XE1205PhyRssiConfP.nc index 6b48e65d..88b5eee9 100644 --- a/tos/chips/xe1205/conf/XE1205PhyRssiConfP.nc +++ b/tos/chips/xe1205/conf/XE1205PhyRssiConfP.nc @@ -42,38 +42,38 @@ module XE1205PhyRssiConfP { - provides interface XE1205PhyConf; - provides interface XE1205RssiConf; - provides interface Init @atleastonce(); - - uses interface Resource as SpiResource; - uses interface XE1205Register as MCParam0; - uses interface XE1205Register as MCParam1; - uses interface XE1205Register as MCParam2; - uses interface XE1205Register as MCParam3; - uses interface XE1205Register as MCParam4; - uses interface XE1205Register as TXParam7; - uses interface XE1205Register as RXParam8; - uses interface XE1205Register as RXParam9; + provides interface XE1205PhyConf; + provides interface XE1205RssiConf; + provides interface Init @atleastonce(); + + uses interface Resource as SpiResource; + uses interface XE1205Register as MCParam0; + uses interface XE1205Register as MCParam1; + uses interface XE1205Register as MCParam2; + uses interface XE1205Register as MCParam3; + uses interface XE1205Register as MCParam4; + uses interface XE1205Register as TXParam7; + uses interface XE1205Register as RXParam8; + uses interface XE1205Register as RXParam9; } implementation { #include "xe1205debug.h" -/* - * Default settings for initial parameters. - */ + /* + * Default settings for initial parameters. + */ #ifndef XE1205_BITRATE_DEFAULT #define XE1205_BITRATE_DEFAULT 76170 #endif - //xxx/make this computed as a fun of XE1205_BITRATE_DEFAULT + //xxx/make this computed as a fun of XE1205_BITRATE_DEFAULT #ifndef XE1205_FREQDEV_DEFAULT #define XE1205_FREQDEV_DEFAULT 100000 #endif -/* - * Register calculation helper macros. - */ + /* + * Register calculation helper macros. + */ #define XE1205_FREQ(value_) (((value_) * 100) / 50113L) #define XE1205_EFFECTIVE_FREQ(value_) (((int32_t)((int16_t)(value_)) * 50113L) / 100) #define XE1205_FREQ_DEV_HI(value_) ((XE1205_FREQ(value_) >> 8) & 0x01) @@ -84,301 +84,293 @@ implementation { #define XE1205_EFFECTIVE_BIT_RATE(value_) (152340L / ((value_) + 1)) - /** - * Frequency bands. - */ - enum xe1205_freq_bands { - XE1205_Band_434 = 434000000, - XE1205_Band_869 = 869000000, - XE1205_Band_915 = 915000000 - }; + /** + * Frequency bands. + */ + enum xe1205_freq_bands { + XE1205_Band_434 = 434000000, + XE1205_Band_869 = 869000000, + XE1205_Band_915 = 915000000 + }; - // this value is the time between rssi measurement updates, plus a buffer time. - // we keep it cached for fast access during packet reception - uint16_t rssi_period_us; - - // time to xmit/receive a byte at current bitrate - uint16_t byte_time_us; - - // norace is ok because protected by the isOwner() calls - norace uint8_t rxparam9 = 0xff; - norace uint8_t txparam7 = 0xff; - - // returns appropriate baseband filter in khz bw for given bitrate in bits/sec. - uint16_t baseband_bw_from_bitrate(uint32_t bitrate) { - return (bitrate * 400) /152340; - } - - - // returns appropriate freq. deviation for given bitrate in bits/sec. - uint32_t freq_dev_from_bitrate(uint32_t bitrate) { - return (bitrate * 6) / 5; - } - - // returns xe1205 encoding of baseband bandwidth in appropriate bit positions - // for writing into rxparam7 register - uint8_t baseband_bw_rxparam7_bits(uint16_t bbw_khz) - { - if(bbw_khz <= 10) { - return 0x00; - } else if(bbw_khz <= 20) { - return 0x20; - } else if(bbw_khz <= 40) { - return 0x40; - } else if(bbw_khz <= 200) { - return 0x60; - } else if(bbw_khz <= 400) { - return 0x10; - } else return 0x10; - } - - // returns the period (in us) between two successive rssi measurements - // (see xemics data sheet 4.2.3.4), as a function of frequency deviation - uint16_t rssi_meas_time(uint32_t freqdev_hz) - { - if (freqdev_hz > 20000) // at 152kbps, equiv to 2 byte times, at 76kbps, equiv to 1 byte time, at 38kbps equiv to 4 bits, etc - return 100; - else if (freqdev_hz > 10000) // at 9.6kbps, equiv to 4 byte times. - return 200; - else if (freqdev_hz > 7000) - return 300; - else if (freqdev_hz > 5000) // at 4.8kbps, equiv to 4 byte times. - return 400; - else - return 500; // at 1200, equiv to 13 byte times. - } - - task void initTask() - { - atomic { - byte_time_us = 8000000 / XE1205_BITRATE_DEFAULT; - rssi_period_us = rssi_meas_time(XE1205_FREQDEV_DEFAULT) + 10; - - xe1205check(1, call SpiResource.immediateRequest()); // should always succeed: task happens after softwareInit, before interrupts are enabled - - call TXParam7.write(0x00); // tx power 0dbm, normal modulation & bitsync, no flitering - txparam7=0; - - call MCParam0.write(0x3c | XE1205_FREQ_DEV_HI(XE1205_FREQDEV_DEFAULT)); // buffered mode, transceiver select using SW(0:1), Data output, 868mhz band, - call MCParam1.write(XE1205_FREQ_DEV_LO(XE1205_FREQDEV_DEFAULT)); - call MCParam2.write(XE1205_BIT_RATE(XE1205_BITRATE_DEFAULT)); - - call MCParam3.write(XE1205_FREQ_HI(-2000000)); // 869mhz - 2mhz = 867mhz (preset 0) - call MCParam4.write(XE1205_FREQ_LO(-2000000)); - - - call RXParam8.write(baseband_bw_rxparam7_bits(baseband_bw_from_bitrate(XE1205_BITRATE_DEFAULT)) - | 0x0a); // calibrate & init baseband filter each time bbw changes - - call RXParam9.write(0x00); // rssi off by default, fei off - rxparam9=0; - - call SpiResource.release(); + // this value is the time between rssi measurement updates, plus a buffer time. + // we keep it cached for fast access during packet reception + uint16_t rssi_period_us; + + // time to xmit/receive a byte at current bitrate + uint16_t byte_time_us; + + // norace is ok because protected by the isOwner() calls + norace uint8_t rxparam9 = 0xff; + norace uint8_t txparam7 = 0xff; + + // returns appropriate baseband filter in khz bw for given bitrate in bits/sec. + uint16_t baseband_bw_from_bitrate(uint32_t bitrate) { + return (bitrate * 400) /152340; + } + + + // returns appropriate freq. deviation for given bitrate in bits/sec. + uint32_t freq_dev_from_bitrate(uint32_t bitrate) { + return (bitrate * 6) / 5; + } + + // returns xe1205 encoding of baseband bandwidth in appropriate bit positions + // for writing into rxparam7 register + uint8_t baseband_bw_rxparam7_bits(uint16_t bbw_khz) + { + if(bbw_khz <= 10) { + return 0x00; + } else if(bbw_khz <= 20) { + return 0x20; + } else if(bbw_khz <= 40) { + return 0x40; + } else if(bbw_khz <= 200) { + return 0x60; + } else if(bbw_khz <= 400) { + return 0x10; + } else return 0x10; } - } - command error_t Init.init() - { - post initTask(); - return SUCCESS; - } + // returns the period (in us) between two successive rssi measurements + // (see xemics data sheet 4.2.3.4), as a function of frequency deviation + uint16_t rssi_meas_time(uint32_t freqdev_hz) + { + if (freqdev_hz > 20000) // at 152kbps, equiv to 2 byte times, at 76kbps, equiv to 1 byte time, at 38kbps equiv to 4 bits, etc + return 100; + else if (freqdev_hz > 10000) // at 9.6kbps, equiv to 4 byte times. + return 200; + else if (freqdev_hz > 7000) + return 300; + else if (freqdev_hz > 5000) // at 4.8kbps, equiv to 4 byte times. + return 400; + else + return 500; // at 1200, equiv to 13 byte times. + } + + task void initTask() + { + atomic { + byte_time_us = 8000000 / XE1205_BITRATE_DEFAULT; + rssi_period_us = rssi_meas_time(XE1205_FREQDEV_DEFAULT) + 10; + + xe1205check(1, call SpiResource.immediateRequest()); // should always succeed: task happens after softwareInit, before interrupts are enabled + + call TXParam7.write(0x00); // tx power 0dbm, normal modulation & bitsync, no flitering + txparam7=0; + + call MCParam0.write(0x3c | XE1205_FREQ_DEV_HI(XE1205_FREQDEV_DEFAULT)); // buffered mode, transceiver select using SW(0:1), Data output, 868mhz band, + call MCParam1.write(XE1205_FREQ_DEV_LO(XE1205_FREQDEV_DEFAULT)); + call MCParam2.write(XE1205_BIT_RATE(XE1205_BITRATE_DEFAULT)); + + call MCParam3.write(XE1205_FREQ_HI(-1000000)); // 869mhz - 1mhz = 868mhz (preset 0) + call MCParam4.write(XE1205_FREQ_LO(-1000000)); + + + call RXParam8.write(baseband_bw_rxparam7_bits(baseband_bw_from_bitrate(XE1205_BITRATE_DEFAULT)) + | 0x0a); // calibrate & init baseband filter each time bbw changes + + call RXParam9.write(0x00); // rssi off by default, fei off + rxparam9=0; + call SpiResource.release(); + } + } + + command error_t Init.init() + { + post initTask(); + return SUCCESS; + } - event void SpiResource.granted() { - } + event void SpiResource.granted() { + } - error_t tuneManual(uint32_t freq) - { - uint32_t bandCenter; - uint8_t mcp0reg; - uint16_t mcp34reg; - error_t status; + error_t tuneManual(uint32_t freq) + { + uint32_t bandCenter; + uint8_t mcp0reg; + uint16_t mcp34reg; + error_t status; - if (call SpiResource.isOwner()) return EBUSY; - status = call SpiResource.immediateRequest(); - xe1205check(2, status); - if (status != SUCCESS) return status; + if (call SpiResource.isOwner()) return EBUSY; + status = call SpiResource.immediateRequest(); + xe1205check(2, status); + if (status != SUCCESS) return status; - call MCParam0.read(&mcp0reg); + call MCParam0.read(&mcp0reg); - mcp0reg &= ~0x6; + mcp0reg &= ~0x6; - if ((freq >= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x8000))) - && (freq <= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x7fff)))) { + if ((freq >= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x8000))) + && (freq <= (XE1205_Band_434 + XE1205_EFFECTIVE_FREQ(0x7fff)))) { - mcp0reg |= (1 << 1); - bandCenter = XE1205_Band_434; + mcp0reg |= (1 << 1); + bandCenter = XE1205_Band_434; - } else if ((freq >= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x8000))) - && (freq <= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x7fff)))) { + } else if ((freq >= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x8000))) + && (freq <= (XE1205_Band_869 + XE1205_EFFECTIVE_FREQ(0x7fff)))) { - mcp0reg |= (2 << 1); - bandCenter = XE1205_Band_869; + mcp0reg |= (2 << 1); + bandCenter = XE1205_Band_869; - } else if ((freq >= (XE1205_Band_915+ XE1205_EFFECTIVE_FREQ(0x8000))) - && (freq <= (XE1205_Band_915 + XE1205_EFFECTIVE_FREQ(0x7fff)))) { + } else if ((freq >= (XE1205_Band_915+ XE1205_EFFECTIVE_FREQ(0x8000))) + && (freq <= (XE1205_Band_915 + XE1205_EFFECTIVE_FREQ(0x7fff)))) { - mcp0reg |= (3 << 1); - bandCenter = XE1205_Band_915; + mcp0reg |= (3 << 1); + bandCenter = XE1205_Band_915; - } else { - call SpiResource.release(); - return EINVAL; - } + } else { + call SpiResource.release(); + return EINVAL; + } - mcp34reg = XE1205_FREQ(freq - bandCenter); + mcp34reg = XE1205_FREQ(freq - bandCenter); - call MCParam0.write(mcp0reg); - call MCParam3.write(mcp34reg >> 8); - call MCParam4.write(mcp34reg & 0xff); + call MCParam0.write(mcp0reg); + call MCParam3.write(mcp34reg >> 8); + call MCParam4.write(mcp34reg & 0xff); + + call SpiResource.release(); + + return SUCCESS; + } - call SpiResource.release(); - return SUCCESS; - } + command error_t XE1205PhyConf.tunePreset(xe1205_channelpreset_t preset) + { + switch(preset) { + case xe1205_channelpreset_868mhz: + return tuneManual(868000000); - command error_t XE1205PhyConf.tunePreset(xe1205_channelpreset_t preset) - { - switch(preset) { - case xe1205_channelpreset_867mhz: - return tuneManual(867000000); + case xe1205_channelpreset_869mhz: + return tuneManual(869000000); - case xe1205_channelpreset_868mhz: - return tuneManual(868000000); + case xe1205_channelpreset_870mhz: + return tuneManual(870000000); - case xe1205_channelpreset_869mhz: - return tuneManual(869000000); + case xe1205_channelpreset_433mhz: + return tuneManual(433000000); - default: - return FAIL; + case xe1205_channelpreset_434mhz: + return tuneManual(434000000); + + case xe1205_channelpreset_435mhz: + return tuneManual(435000000); + + default: + return FAIL; + } } - } - async command error_t XE1205PhyConf.setRFPower(xe1205_txpower_t txpow) - { - error_t status; + async command error_t XE1205PhyConf.setRFPower(xe1205_txpower_t txpow) + { + error_t status; - if (txpow > xe1205_txpower_15dbm) - return EINVAL; + if (txpow > xe1205_txpower_15dbm) + return EINVAL; - if (call SpiResource.isOwner()) return EBUSY; - status = call SpiResource.immediateRequest(); - xe1205check(3, status); - if (status != SUCCESS) return status; + if (call SpiResource.isOwner()) return EBUSY; + status = call SpiResource.immediateRequest(); + xe1205check(3, status); + if (status != SUCCESS) return status; - txparam7 &= ~(3 << 6); - txparam7 |= (txpow << 6); - call TXParam7.write(txparam7); - call SpiResource.release(); - return SUCCESS; - } + txparam7 &= ~(3 << 6); + txparam7 |= (txpow << 6); + call TXParam7.write(txparam7); + call SpiResource.release(); + return SUCCESS; + } - command error_t XE1205PhyConf.setBitrate(xe1205_bitrate_t bitrate) - { - uint16_t bbw; - uint32_t freqdev; - uint8_t rxp8reg, mcp0reg, mcp1reg, mcp2reg; - error_t status; - - if (bitrate < xe1205_bitrate_38085 || bitrate > xe1205_bitrate_152340) return EINVAL; - - if (call SpiResource.isOwner()) return EBUSY; - status = call SpiResource.immediateRequest(); - xe1205check(4, status); - if (status != SUCCESS) return status; - - // receiver bandwidth - call RXParam8.read(&rxp8reg); - bbw = baseband_bw_from_bitrate(bitrate); - rxp8reg &= ~0x70; - rxp8reg |= baseband_bw_rxparam7_bits(bbw); - - - // frequency deviation - freqdev = freq_dev_from_bitrate(bitrate); - rssi_period_us = rssi_meas_time(freqdev) + 10; - - call MCParam0.read(&mcp0reg); - mcp0reg &= ~0x01; - mcp0reg |= XE1205_FREQ_DEV_HI(freqdev); - - mcp1reg = XE1205_FREQ_DEV_LO(freqdev); - - mcp2reg = XE1205_BIT_RATE(bitrate); - - call RXParam8.write(rxp8reg); - call MCParam0.write(mcp0reg); - call MCParam1.write(mcp1reg); - call MCParam2.write(mcp2reg);; - - atomic byte_time_us = 8000000 / bitrate; - call SpiResource.release(); - return SUCCESS; - } - - async command uint16_t XE1205PhyConf.getByteTime_us() { - return byte_time_us; - } - - async command error_t XE1205RssiConf.setRssiMode(bool on) - { - error_t status; - - if (call SpiResource.isOwner()) return EBUSY; - status = call SpiResource.immediateRequest(); - xe1205check(5, status); - if (status != SUCCESS) return status; - - if (on) - rxparam9 |= 0x80; - else - rxparam9 &= ~0x80; - call RXParam9.write(rxparam9); - call SpiResource.release(); - return SUCCESS; - } - - async command uint16_t XE1205RssiConf.getRssiMeasurePeriod_us() { - return rssi_period_us; - } - - async command error_t XE1205RssiConf.setRssiRange(bool high) - { - error_t status; - - if (call SpiResource.isOwner()) return EBUSY; - status = call SpiResource.immediateRequest(); - xe1205check(6, status); - if (status != SUCCESS) return status; - - if (high) - rxparam9 |= 0x40; - else - rxparam9 &= ~0x40; - call RXParam9.write(rxparam9); - call SpiResource.release(); - return SUCCESS; - } - - async command error_t XE1205RssiConf.getRssi(uint8_t* rssi) - { - error_t status; - - if (call SpiResource.isOwner()) return EBUSY; - status = call SpiResource.immediateRequest(); - xe1205check(7, status); - if (status != SUCCESS) return status; - - call RXParam9.read(rssi); - *rssi = (*rssi >> 4) & 0x03; - call SpiResource.release(); - return SUCCESS; - } + command error_t XE1205PhyConf.setBitrate(xe1205_bitrate_t bitrate) + { + uint16_t bbw; + uint32_t freqdev; + uint8_t rxp8reg, mcp0reg, mcp1reg, mcp2reg; + error_t status; + + if (bitrate < xe1205_bitrate_38085 || bitrate > xe1205_bitrate_152340) return EINVAL; + + if (call SpiResource.isOwner()) return EBUSY; + status = call SpiResource.immediateRequest(); + xe1205check(4, status); + if (status != SUCCESS) return status; + + // receiver bandwidth + call RXParam8.read(&rxp8reg); + bbw = baseband_bw_from_bitrate(bitrate); + rxp8reg &= ~0x70; + rxp8reg |= baseband_bw_rxparam7_bits(bbw); + + + // frequency deviation + freqdev = freq_dev_from_bitrate(bitrate); + rssi_period_us = rssi_meas_time(freqdev) + 10; + + call MCParam0.read(&mcp0reg); + mcp0reg &= ~0x01; + mcp0reg |= XE1205_FREQ_DEV_HI(freqdev); + + mcp1reg = XE1205_FREQ_DEV_LO(freqdev); + + mcp2reg = XE1205_BIT_RATE(bitrate); + + call RXParam8.write(rxp8reg); + call MCParam0.write(mcp0reg); + call MCParam1.write(mcp1reg); + call MCParam2.write(mcp2reg);; + + atomic byte_time_us = 8000000 / bitrate; + call SpiResource.release(); + return SUCCESS; + } + + async command uint16_t XE1205PhyConf.getByteTime_us() { + return byte_time_us; + } + + async command error_t XE1205RssiConf.setRssiMode(bool on) + { + // must have bus + if (on) + rxparam9 |= 0x80; + else + rxparam9 &= ~0x80; + call RXParam9.write(rxparam9); + + return SUCCESS; + } + + async command uint16_t XE1205RssiConf.getRssiMeasurePeriod_us() { + return rssi_period_us; + } + + async command error_t XE1205RssiConf.setRssiRange(bool high) + { + // must have bus + if (high) { + rxparam9 |= 0x40; + } else { + rxparam9 &= ~0x40; + } + call RXParam9.write(rxparam9); + return SUCCESS; + } + + async command error_t XE1205RssiConf.getRssi(uint8_t* rssi) + { + // must have bus + call RXParam9.read(rssi); + + *rssi = (*rssi >> 4) & 0x03; + + return SUCCESS; + } } diff --git a/tos/chips/xe1205/conf/XE1205RssiConf.nc b/tos/chips/xe1205/conf/XE1205RssiConf.nc index 5c60d9ed..e3dc4fe7 100644 --- a/tos/chips/xe1205/conf/XE1205RssiConf.nc +++ b/tos/chips/xe1205/conf/XE1205RssiConf.nc @@ -48,7 +48,7 @@ interface XE1205RssiConf { * @param on: 1 to enable, 0 to disable * @return SUCCESS if operation done ok, error status otherwise */ - async command error_t setRssiMode(bool on); + async command error_t setRssiMode(bool on); /** * Return the returns the period (in us) between two successive rssi measurements, diff --git a/tos/chips/xe1205/phy/XE1205PhyC.nc b/tos/chips/xe1205/phy/XE1205PhyC.nc index 49c673ba..06bc684f 100644 --- a/tos/chips/xe1205/phy/XE1205PhyC.nc +++ b/tos/chips/xe1205/phy/XE1205PhyC.nc @@ -38,6 +38,7 @@ configuration XE1205PhyC { provides interface XE1205PhyRxTx; + provides interface XE1205PhyRssi; provides interface SplitControl; } implementation { @@ -57,6 +58,9 @@ implementation { components new XE1205SpiC() as SpiConfig; XE1205PhyP.SpiResourceConfig -> SpiConfig; + components new XE1205SpiC() as SpiRSSI; + XE1205PhyP.SpiResourceRssi -> SpiRSSI; + components HplXE1205InterruptsC; XE1205PhyP.Interrupt0 -> HplXE1205InterruptsC.Interrupt0; XE1205PhyP.Interrupt1 -> HplXE1205InterruptsC.Interrupt1; @@ -64,13 +68,20 @@ implementation { XE1205PhyRxTx = XE1205PhyP; SplitControl = XE1205PhyP; + XE1205PhyRssi = XE1205PhyP; components MainC; MainC.SoftwareInit -> XE1205PhyP.Init; + components XE1205PatternConfC; + XE1205PhyP.XE1205PatternConf -> XE1205PatternConfC; + components XE1205IrqConfC; XE1205PhyP.XE1205IrqConf -> XE1205IrqConfC; + components XE1205PhyRssiConfC; + XE1205PhyP.XE1205RssiConf -> XE1205PhyRssiConfC; + components new Alarm32khz16C(); XE1205PhyP.Alarm32khz16 -> Alarm32khz16C.Alarm; #if 0 diff --git a/tos/chips/xe1205/phy/XE1205PhyP.nc b/tos/chips/xe1205/phy/XE1205PhyP.nc index 92bbbfd4..377ad953 100644 --- a/tos/chips/xe1205/phy/XE1205PhyP.nc +++ b/tos/chips/xe1205/phy/XE1205PhyP.nc @@ -39,410 +39,607 @@ #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 as Alarm32khz16; + uses interface Alarm as Alarm32khz16; #if 0 - uses interface GeneralIO as Dpin; + uses interface GeneralIO as Dpin; #endif } implementation { #include "xe1205debug.h" - char* txBuf = NULL; - uint8_t rxFrameIndex = 0; - uint8_t rxFrameLen = 0; - uint8_t nextTxLen=0; - uint8_t nextRxLen; - char rxFrame[xe1205_mtu]; - uint8_t headerLen = 4; - - uint16_t stats_rxOverruns; - - typedef enum { // remember to update busy() and off(), start(), stop() if states are added - RADIO_LISTEN=0, - RADIO_RX_HEADER=1, - RADIO_RX_PACKET=2, - RADIO_RX_PACKET_LAST=3, - RADIO_TX=4, - RADIO_SLEEP=5, - RADIO_STARTING=6 - } phy_state_t; - - phy_state_t state = RADIO_SLEEP; - - void armPatternDetect(); - - //////////////////////////////////////////////////////////////////////////////////// - // - // jiffy/microseconds/bytetime conversion functions. - // - //////////////////////////////////////////////////////////////////////////////////// - - // 1 jiffie = 1/32768 = 30.52us; - // we approximate to 32us for quicker computation and also to account for interrupt/processing overhead. - inline uint32_t usecs_to_jiffies(uint32_t usecs) { - return usecs >> 5; - } - - command error_t Init.init() - { + char* txBuf = NULL; + uint8_t rxFrameIndex = 0; + uint8_t rxFrameLen = 0; + uint8_t nextTxLen=0; + uint8_t nextRxLen; + char rxFrame[xe1205_mtu]; + uint8_t headerLen = 4; + + uint16_t stats_rxOverruns; + + enum { + RSSI_RANGE_LOW=1, + RSSI_RANGE_HIGH=2, + RSSI_OFF=0, + }; + uint8_t rssiRange = RSSI_OFF; + norace uint8_t rssiL,rssiH; + uint8_t * rLow = &rssiL; + uint8_t * rHigh = &rssiH; + + + bool enableAck = FALSE; + + typedef enum { // remember to update busy() and off(), start(), stop() if states are added + RADIO_LISTEN=0, + RADIO_RX_HEADER=1, + RADIO_RX_PACKET=2, + RADIO_RX_PACKET_LAST=3, + RADIO_TX=4, + RADIO_SLEEP=5, + RADIO_STARTING=6, + RADIO_RSSI=7, + RADIO_RX_ACK=8, + RADIO_TX_ACK=9 + } phy_state_t; + + phy_state_t state = RADIO_SLEEP; + + + void armPatternDetect(); + + //////////////////////////////////////////////////////////////////////////////////// + // + // jiffy/microseconds/bytetime conversion functions. + // + //////////////////////////////////////////////////////////////////////////////////// + + // 1 jiffie = 1/32768 = 30.52us; + // we approximate to 32us for quicker computation and also to account for interrupt/processing overhead. + inline uint32_t usecs_to_jiffies(uint32_t usecs) { + return usecs >> 5; + } + + command error_t Init.init() + { #if 0 - call Dpin.makeOutput(); + call Dpin.makeOutput(); #endif - call XE1205PhySwitch.sleepMode(); - call XE1205PhySwitch.antennaOff(); - return SUCCESS; - } - - task void startDone() { - signal SplitControl.startDone(SUCCESS); - } - - event void SpiResourceTX.granted() { } - event void SpiResourceRX.granted() { } - event void SpiResourceConfig.granted() { - armPatternDetect(); - call SpiResourceConfig.release(); - - atomic { - if (state == RADIO_STARTING) post startDone(); - call Interrupt0.enableRisingEdge(); - state = RADIO_LISTEN; + call XE1205PhySwitch.sleepMode(); + call XE1205PhySwitch.antennaOff(); + return SUCCESS; } - } - - task void stopDone() { - signal SplitControl.stopDone(SUCCESS); - } + task void startDone() { + signal SplitControl.startDone(SUCCESS); + } - command error_t SplitControl.start() - { - atomic { - if (state != RADIO_SLEEP) return EBUSY; - state = RADIO_STARTING; + event void SpiResourceTX.granted() { } + event void SpiResourceRX.granted() { } + event void SpiResourceConfig.granted() { + armPatternDetect(); + call SpiResourceConfig.release(); + atomic { + if (state == RADIO_STARTING){ + post startDone();} + if (state == RADIO_RX_ACK) { + enableAck=FALSE; + signal XE1205PhyRxTx.sendFrameDone(FAIL); + } + state = RADIO_LISTEN; + + call Interrupt0.enableRisingEdge(); + } } + event void SpiResourceRssi.granted() { } - call XE1205PhySwitch.rxMode(); - call XE1205PhySwitch.antennaRx(); - - call Alarm32khz16.start(usecs_to_jiffies(XE1205_Sleep_to_RX_Time)); - return SUCCESS; - } - - command error_t SplitControl.stop() - { - atomic { - call XE1205PhySwitch.sleepMode(); - call XE1205PhySwitch.antennaOff(); - state = RADIO_SLEEP; - call Interrupt0.disable(); - call Interrupt1.disable(); + task void stopDone() { + signal SplitControl.stopDone(SUCCESS); } - post stopDone(); - return SUCCESS; - } - - default event void SplitControl.startDone(error_t error) { } - default event void SplitControl.stopDone(error_t error) { } - - async command bool XE1205PhyRxTx.busy() { - atomic return (state != RADIO_LISTEN && - state != RADIO_SLEEP && - state != RADIO_STARTING); - } - - async command bool XE1205PhyRxTx.off() { - atomic return (state == RADIO_SLEEP || - state == RADIO_STARTING); - } - - void armPatternDetect() - { - // small chance of a pattern arriving right after we arm, - // and IRQ0 hasn't been enabled yet, so we would miss the interrupt - // xxx maybe this can also be addressed with periodic timer? - xe1205check(2, call XE1205IrqConf.armPatternDetector(TRUE)); - xe1205check(1, call XE1205IrqConf.clearFifoOverrun(TRUE)); - } - - async command void XE1205PhyRxTx.setRxHeaderLen(uint8_t l) - { - if (l > 8) l = 8; - if (!l) return; - headerLen = l; - } - - async command uint8_t XE1205PhyRxTx.getRxHeaderLen() { - return headerLen; - } - - void computeNextRxLength() - { - uint8_t n = rxFrameLen - rxFrameIndex; - - // for timesync and such, we want the end of the packet to coincide with a fifofull event, - // so that we know precisely when last byte was received - - if (n > 16) { - if (n < 32) nextRxLen = n - 16; else nextRxLen = 15; - } - else { - nextRxLen = n; + + command error_t SplitControl.start() + { + + atomic { + if (state == RADIO_LISTEN){ post startDone(); return SUCCESS;} + if (state != RADIO_SLEEP) return EBUSY; + state = RADIO_STARTING; + } + call XE1205PhySwitch.rxMode(); + call XE1205PhySwitch.antennaRx(); + + + call Alarm32khz16.start(usecs_to_jiffies(XE1205_Sleep_to_RX_Time)); + return SUCCESS; } - } + command error_t SplitControl.stop() + { + atomic { + if (!call XE1205PhyRxTx.busy()) { + + call XE1205PhySwitch.sleepMode(); + call XE1205PhySwitch.antennaOff(); + state = RADIO_SLEEP; + call Interrupt0.disable(); + call Interrupt1.disable(); + post stopDone(); + return SUCCESS; + } else return FAIL; + } - async command error_t XE1205PhyRxTx.sendFrame(char* data, uint8_t frameLen) __attribute__ ((noinline)) - { - error_t status; + } + + default event void SplitControl.startDone(error_t error) { } + default event void SplitControl.stopDone(error_t error) { } + default async event void XE1205PhyRssi.rssiDone(uint8_t _rssi) { } + + async command bool XE1205PhyRxTx.busy() { + atomic return (state != RADIO_LISTEN && + state != RADIO_SLEEP); + } + + async command bool XE1205PhyRxTx.off() { + atomic return (state == RADIO_SLEEP || + state == RADIO_STARTING); + } + + + async command void XE1205PhyRxTx.enableAck(bool onOff) { + atomic enableAck = onOff; + } + + + void armPatternDetect() + { + // small chance of a pattern arriving right after we arm, + // and IRQ0 hasn't been enabled yet, so we would miss the interrupt + // xxx maybe this can also be addressed with periodic timer? + call XE1205IrqConf.armPatternDetector(TRUE); + call XE1205IrqConf.clearFifoOverrun(TRUE); + } + + async command void XE1205PhyRxTx.setRxHeaderLen(uint8_t l) + { + if (l > 8) l = 8; + if (!l) return; + headerLen = l; + } + + async command uint8_t XE1205PhyRxTx.getRxHeaderLen() { + return headerLen; + } + + void computeNextRxLength() + { + uint8_t n = rxFrameLen - rxFrameIndex; + + // for timesync and such, we want the end of the packet to coincide with a fifofull event, + // so that we know precisely when last byte was received + + if (n > 16) { + if (n < 32) nextRxLen = n - 16; else nextRxLen = 15; + } + else { + nextRxLen = n; + } + } + + command uint8_t XE1205PhyRssi.readRxRssi() { + return rssiTab[(rssiH<<2) |rssiL]; + } + + task void rssiDone() { + + signal XE1205PhyRssi.rssiDone( rssiTab[(rssiH<<2) |rssiL]); + } + + void readRssi() { + if(rssiRange ==RSSI_RANGE_LOW ) { + rssiRange = RSSI_RANGE_HIGH; + call XE1205RssiConf.getRssi(rLow); + call XE1205RssiConf.setRssiRange(TRUE); + call Alarm32khz16.start(usecs_to_jiffies(call XE1205RssiConf.getRssiMeasurePeriod_us())); + } else { + call XE1205RssiConf.getRssi(rHigh); + call XE1205RssiConf.setRssiMode(FALSE); + + if(state == RADIO_RSSI) { + armPatternDetect(); + call SpiResourceRssi.release(); + call Interrupt0.enableRisingEdge(); + atomic state = RADIO_LISTEN; + signal XE1205PhyRssi.rssiDone( rssiTab[(rssiH<<2) |rssiL]); + } else { // go on with rx of packet + call Alarm32khz16.start(3000); + } + rssiRange = RSSI_OFF; + } + } + + + error_t getRssi() { + error_t err; + + if(call SpiResourceRssi.immediateRequest() != SUCCESS) { + return FAIL; + } + err = call XE1205RssiConf.setRssiMode(TRUE); + err = ecombine(err,call XE1205RssiConf.setRssiRange(FALSE)); + rssiRange=RSSI_RANGE_LOW; + call Alarm32khz16.start(usecs_to_jiffies(call XE1205RssiConf.getRssiMeasurePeriod_us())); + return err; + } + + + async command error_t XE1205PhyRssi.getRssi() { + + error_t err; + atomic { + if (state != RADIO_LISTEN&&rssiRange==RSSI_OFF) return EBUSY; + if (call XE1205PhyRxTx.off()) { + return EOFF; + } + err=getRssi(); + if (SUCCESS ==err) { + state = RADIO_RSSI; + } + return err; + } + } + + async command error_t XE1205PhyRxTx.sendFrame(char* data, uint8_t frameLen) __attribute__ ((noinline)) + { + error_t status; - if (frameLen < 6) return EINVAL; + if (frameLen < 6) return EINVAL; - atomic { - if (state == RADIO_SLEEP) return EOFF; - if (state != RADIO_LISTEN) return EBUSY; - if (frameLen == 0 || frameLen > xe1205_mtu + 7) return EINVAL; // 7 = 4 preamble + 3 sync - - call XE1205PhySwitch.txMode(); // it takes 100us to switch from rx to tx, ie less than one byte at 76kbps - call Interrupt0.disable(); - - status = call SpiResourceTX.immediateRequest(); - xe1205check(3, status); - if (status != SUCCESS) { - call XE1205PhySwitch.rxMode(); - call SpiResourceConfig.request(); - return status; - } - call XE1205PhySwitch.antennaTx(); - state = RADIO_TX; - } + atomic { + if (state == RADIO_SLEEP) return EOFF; - status = call XE1205Fifo.write(data, frameLen); - // cannot happen with current SPI implementation (at least with NoDma) + if (call XE1205PhyRxTx.busy()) return EBUSY; + if (frameLen == 0 || frameLen > xe1205_mtu + 7) return EINVAL; // 7 = 4 preamble + 3 sync + + call XE1205PhySwitch.txMode(); // it takes 100us to switch from rx to tx, ie less than one byte at 76kbps + call Interrupt0.disable(); + + status = call SpiResourceTX.immediateRequest(); + xe1205check(3, status); + if (status != SUCCESS) { + call XE1205PhySwitch.rxMode(); + call SpiResourceConfig.request(); + return status; + } + call XE1205PhySwitch.antennaTx(); + state = RADIO_TX; + + } + + + call XE1205Fifo.write(data, frameLen); + atomic { + + txBuf = signal XE1205PhyRxTx.continueSend(&nextTxLen); + } + if (nextTxLen) { + call Interrupt0.enableFallingEdge(); + } else { + call Interrupt0.disable(); + call Interrupt1.enableRisingEdge(); + } + // cannot happen with current SPI implementation (at least with NoDma) #if 0 - if (status != SUCCESS) { - xe1205error(8, status); - call XE1205PhySwitch.rxMode(); - call XE1205PhySwitch.antennaRx(); - armPatternDetect(); - call SpiResourceTX.release(); - atomic { - call Interrupt0.enableRisingEdge(); - state = RADIO_LISTEN; - } - return status; - } + if (status != SUCCESS) { + xe1205error(8, status); + call XE1205PhySwitch.rxMode(); + call XE1205PhySwitch.antennaRx(); + call XE1205PatternConf.loadDataPatternHasBus(); + armPatternDetect(); + call SpiResourceTX.release(); + atomic { + call Interrupt0.enableRisingEdge(); + state = RADIO_LISTEN; + } + return status; + } #endif - return SUCCESS; - } - - - - uint16_t rxByte=0; - - /** - * In transmit: nTxFifoEmpty. (ie after the last byte has been *read out of the fifo*) - * In receive: write_byte. - */ - async event void Interrupt0.fired() __attribute__ ((noinline)) - { - error_t status; - - switch (state) { - - case RADIO_LISTEN: - rxByte=1; - state = RADIO_RX_HEADER; - status = call SpiResourceRX.immediateRequest(); - xe1205check(4, status); - if (status != SUCCESS) { - state = RADIO_LISTEN; - call Interrupt0.disable(); // because pattern detector won't be rearmed right away - call SpiResourceConfig.request(); - return; - } - return; - - case RADIO_RX_HEADER: - rxByte++; - if (rxByte == 2) { - call Alarm32khz16.start(3000); - } - - if (rxByte == headerLen + 1) { - call Interrupt0.disable(); - xe1205check(8, call XE1205Fifo.read(rxFrame, headerLen)); - call Interrupt1.enableRisingEdge(); - } - return; - - case RADIO_TX: - - call Interrupt0.disable(); // avoid spurious IRQ0s from nTxFifoEmpty rebounding briefly after first byte is written. - // note that we should really wait till writedone() to re-enable either interrupt. - xe1205check(5, call XE1205Fifo.write(txBuf, nextTxLen)); - return; - - default: - return; - } - } + return SUCCESS; + } - /** - * In transmit: TxStopped. (ie after the last byte has been *sent*) - * In receive: Fifofull. - */ - async event void Interrupt1.fired() __attribute__ ((noinline)) - { - switch (state) { + uint16_t rxByte=0; - case RADIO_RX_PACKET: - xe1205check(9, call XE1205Fifo.read(&rxFrame[rxFrameIndex], nextRxLen)); - call Interrupt1.disable(); // in case it briefly goes back to full just after we read first byte - rxFrameIndex += nextRxLen; - computeNextRxLength(); - - if (nextRxLen==0) { - state = RADIO_RX_PACKET_LAST; - } - - return; - - case RADIO_RX_HEADER: // somehow the FIFO has filled before we finished reading the header bytes - call Interrupt1.disable(); - call Alarm32khz16.stop(); - signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL); - armPatternDetect(); - call SpiResourceRX.release(); - atomic { - call Interrupt0.enableRisingEdge(); - state = RADIO_LISTEN; - } - return; - - case RADIO_TX: - - call Interrupt1.disable(); - call XE1205PhySwitch.rxMode(); - call XE1205PhySwitch.antennaRx(); - signal XE1205PhyRxTx.sendFrameDone(); - armPatternDetect(); - call SpiResourceTX.release(); - atomic { - call Interrupt0.enableRisingEdge(); - state = RADIO_LISTEN; - } - return; - - default: - return; - } - } - - async event void XE1205Fifo.readDone(error_t error) { - xe1205check(6, error); - switch(state) { - case RADIO_RX_HEADER: - rxFrameLen = signal XE1205PhyRxTx.rxFrameBegin(rxFrame, headerLen); - if (rxFrameLen <= headerLen) { - call Interrupt1.disable(); - call Alarm32khz16.stop(); - signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL); - armPatternDetect(); - call SpiResourceRX.release(); - atomic { - call Interrupt0.enableRisingEdge(); - state = RADIO_LISTEN; - } - return; - } - - rxFrameIndex = headerLen; - computeNextRxLength(); - state = RADIO_RX_PACKET; - return; - - case RADIO_RX_PACKET_LAST: - call Alarm32khz16.stop(); - signal XE1205PhyRxTx.rxFrameEnd(rxFrame, rxFrameLen + headerLen, SUCCESS); - armPatternDetect(); - call SpiResourceRX.release(); - atomic { - call Interrupt0.enableRisingEdge(); - state = RADIO_LISTEN; - } - return; - - case RADIO_RX_PACKET: - call Interrupt1.enableRisingEdge(); - return; - - default: - xe1205check(10, FAIL); - return; - } - } - - async event void XE1205Fifo.writeDone(error_t error) __attribute__ ((noinline)) { - xe1205check(7, error); - switch(state) { - case RADIO_TX: - txBuf = signal XE1205PhyRxTx.continueSend(&nextTxLen); - if (nextTxLen) { - call Interrupt0.enableFallingEdge(); - } else { - call Interrupt0.disable(); - call Interrupt1.enableRisingEdge(); - } - return; - default: - xe1205check(11, FAIL); - } - } - - async event void Alarm32khz16.fired() { - - switch(state) { - - case RADIO_STARTING: - call SpiResourceConfig.request(); - return; - - case RADIO_RX_HEADER: - case RADIO_RX_PACKET: - stats_rxOverruns++; - signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL); - armPatternDetect(); - call SpiResourceRX.release(); - atomic { - call Interrupt0.enableRisingEdge(); - state = RADIO_LISTEN; - } - return; - default: - } + /** + * In transmit: nTxFifoEmpty. (ie after the last byte has been *read out of the fifo*) + * In receive: write_byte. + */ + async event void Interrupt0.fired() __attribute__ ((noinline)) + { + error_t status; + + switch (state) { + + case RADIO_RX_ACK: + + call Alarm32khz16.stop(); + case RADIO_LISTEN: + rxByte=1; + atomic state = RADIO_RX_HEADER; + status = call SpiResourceRX.immediateRequest(); + atomic { + if (status != SUCCESS) { + state = RADIO_LISTEN; + call Interrupt0.disable(); // because pattern detector won't be rearmed right away + call SpiResourceConfig.request(); + return; + } + } + call Alarm32khz16.start(3000); + return; + + case RADIO_RX_HEADER: + rxByte++; + if (rxByte == 2) { + call Alarm32khz16.start(3000); + } + if (rxByte == headerLen + 1) { + call Interrupt0.disable(); + call XE1205Fifo.read(rxFrame, headerLen); + call Interrupt1.enableRisingEdge(); + } + + return; + + case RADIO_TX: + call Interrupt0.disable(); // avoid spurious IRQ0s from nTxFifoEmpty rebounding briefly after first byte is written. + // note that we should really wait till writedone() to re-enable either interrupt. + call XE1205Fifo.write(txBuf, nextTxLen); + txBuf = signal XE1205PhyRxTx.continueSend(&nextTxLen); + if (nextTxLen) { + call Interrupt0.enableFallingEdge(); + } else { + call Interrupt0.disable(); + call Interrupt1.enableRisingEdge(); + } + return; + + case RADIO_RSSI: // trigged while getting rssi + call Interrupt0.disable(); // because pattern detector won't be rearmed right away + return; + + default: + + return; + } + } + + + + /** + * In transmit: TxStopped. (ie after the last byte has been *sent*) + * In receive: Fifofull. + */ + async event void Interrupt1.fired() __attribute__ ((noinline)) + { + + switch (state) { + + case RADIO_RX_PACKET: + call Interrupt1.disable(); // in case it briefly goes back to full just after we read first byte + call XE1205Fifo.read(&rxFrame[rxFrameIndex], nextRxLen); + + rxFrameIndex += nextRxLen; + computeNextRxLength(); + if (nextRxLen==0) { + state = RADIO_RX_PACKET_LAST; + } + return; + + case RADIO_RX_HEADER: // somehow the FIFO has filled before we finished reading the header bytes + + call Interrupt1.disable(); + call Alarm32khz16.stop(); + + signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL); + call XE1205PatternConf.loadDataPatternHasBus(); + armPatternDetect(); + call SpiResourceRX.release(); + atomic { + call Interrupt0.enableRisingEdge(); + state = RADIO_LISTEN; + } + return; + + case RADIO_TX: + + call Interrupt1.disable(); + call XE1205PhySwitch.rxMode(); + call XE1205PhySwitch.antennaRx(); + if (enableAck==FALSE) { + call XE1205PatternConf.loadDataPatternHasBus(); + armPatternDetect(); + signal XE1205PhyRxTx.sendFrameDone(SUCCESS); + call SpiResourceTX.release(); + atomic { + call Interrupt0.enableRisingEdge(); + state = RADIO_LISTEN; + } + } else { + + call XE1205PatternConf.loadAckPatternHasBus(); + armPatternDetect(); + call SpiResourceTX.release(); + + call Alarm32khz16.start(usecs_to_jiffies(8000)); + atomic { + call Interrupt0.enableRisingEdge(); + state = RADIO_RX_ACK; + } + } + + return; + + default: + return; + } + } + + + + async event void XE1205Fifo.readDone(error_t error) { + + switch(state) { + case RADIO_RX_HEADER: + rxFrameLen = signal XE1205PhyRxTx.rxFrameBegin(rxFrame, headerLen); + if (rxFrameLen <= headerLen) { + call Interrupt1.disable(); + call Alarm32khz16.stop(); + + signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL); + call XE1205PatternConf.loadDataPatternHasBus(); + armPatternDetect(); + call SpiResourceRX.release(); + atomic { + state = RADIO_LISTEN; + call Interrupt0.enableRisingEdge(); + } + return; + } + atomic { + if(rssiRange==RSSI_OFF) { + getRssi(); + } + } + rxFrameIndex = headerLen; + computeNextRxLength(); + state = RADIO_RX_PACKET; + + return; + + case RADIO_RX_PACKET_LAST: + call Alarm32khz16.stop(); + + atomic { + call XE1205PatternConf.loadDataPatternHasBus(); + armPatternDetect(); + state = RADIO_LISTEN; + call Interrupt0.enableRisingEdge(); + call SpiResourceRX.release(); + } + if( enableAck == FALSE) { + signal XE1205PhyRxTx.rxFrameEnd(rxFrame, rxFrameLen + headerLen, SUCCESS); + + } else { + enableAck = FALSE; + signal XE1205PhyRxTx.sendFrameDone(SUCCESS); + } + + + + + + return; + + case RADIO_RX_PACKET: + + call Interrupt1.enableRisingEdge(); + return; + + default: + xe1205check(10, FAIL); + return; + } + } + + async event void XE1205Fifo.writeDone(error_t error) __attribute__ ((noinline)) { + + } + + + async event void Alarm32khz16.fired() { + + switch(state) { + + case RADIO_STARTING: + call SpiResourceConfig.request(); + return; + + case RADIO_LISTEN: + case RADIO_RX_HEADER: + case RADIO_RX_PACKET: + if (rssiRange!=RSSI_OFF) { + readRssi(); + return; + } + stats_rxOverruns++; + + signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL); + call XE1205PatternConf.loadDataPatternHasBus(); + armPatternDetect(); + call SpiResourceRX.release(); + + atomic { + state = RADIO_LISTEN; + call Interrupt0.enableRisingEdge(); + } + + return; + + case RADIO_RSSI: + readRssi(); + return; + + case RADIO_RX_ACK: // ack timeout + + enableAck = FALSE; + call SpiResourceRX.immediateRequest(); + + signal XE1205PhyRxTx.rxFrameEnd(NULL, 0, FAIL); + + call XE1205PatternConf.loadDataPatternHasBus(); + + armPatternDetect(); + + call SpiResourceRX.release(); + + atomic { + state = RADIO_LISTEN; + call Interrupt0.enableRisingEdge(); + + } + + signal XE1205PhyRxTx.sendFrameDone(FAIL); + return; + default: + + + return; + } - } + } } diff --git a/tos/chips/xe1205/phy/XE1205PhyRssi.nc b/tos/chips/xe1205/phy/XE1205PhyRssi.nc new file mode 100644 index 00000000..6e0fc60a --- /dev/null +++ b/tos/chips/xe1205/phy/XE1205PhyRssi.nc @@ -0,0 +1,6 @@ +interface XE1205PhyRssi { + + async command error_t getRssi(); + command uint8_t readRxRssi(); + async event void rssiDone(uint8_t _rssi); +} diff --git a/tos/chips/xe1205/phy/XE1205PhyRxTx.nc b/tos/chips/xe1205/phy/XE1205PhyRxTx.nc index 19ac314c..c3d464d1 100644 --- a/tos/chips/xe1205/phy/XE1205PhyRxTx.nc +++ b/tos/chips/xe1205/phy/XE1205PhyRxTx.nc @@ -64,7 +64,7 @@ interface XE1205PhyRxTx { * the client module returned NULL to continueSendBuf(). * */ - async event void sendFrameDone(); + async event void sendFrameDone(error_t err); /** @@ -129,4 +129,5 @@ interface XE1205PhyRxTx { + async command void enableAck(bool onOff); } diff --git a/tos/chips/xe1205/xe1205debug.h b/tos/chips/xe1205/xe1205debug.h index a649d021..c2a3a014 100644 --- a/tos/chips/xe1205/xe1205debug.h +++ b/tos/chips/xe1205/xe1205debug.h @@ -4,7 +4,7 @@ uint16_t lasterr; void xe1205error(uint8_t loc, uint8_t value_) __attribute__ ((noinline)) { // this is just to make sure the compiler doesn't optimize // out calls to this function, since we use it as a gdb breakpoint - atomic var += value_ + loc; + atomic var += value_ + loc; } diff --git a/tos/platforms/tinynode/chips/xe1205/Xe1205Spi0C.nc b/tos/platforms/tinynode/chips/xe1205/Xe1205Spi0C.nc new file mode 100644 index 00000000..c528654b --- /dev/null +++ b/tos/platforms/tinynode/chips/xe1205/Xe1205Spi0C.nc @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2005-2006 Arched Rock Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * - Neither the name of the Arched Rock Corporation nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE + */ + +/** + * An implementation of the SPI on USART0 for the MSP430. The current + * implementation defaults not using the DMA and performing the SPI + * transfers in software. To utilize the DMA, use Msp430SpiDma0P in + * place of Msp430SpiNoDma0P. + * + * @author Jonathan Hui + * @version $Revision$ $Date$ + */ + +#include "msp430usart.h" + +generic configuration Xe1205Spi0C() { + + provides interface Resource; + provides interface SpiByte; + provides interface SpiPacket; + + uses interface Msp430SpiConfigure; +} + +implementation { + + enum { + CLIENT_ID = unique( MSP430_SPIO_BUS ), + }; + + components Xe1205SpiNoDma0P as SpiP; + Resource = SpiP.Resource[ CLIENT_ID ]; + SpiByte = SpiP.SpiByte; + SpiPacket = SpiP.SpiPacket[ CLIENT_ID ]; + Msp430SpiConfigure = SpiP.Msp430SpiConfigure[ CLIENT_ID ]; + + components new Msp430Usart0C() as UsartC; + SpiP.ResourceConfigure[ CLIENT_ID ] <- UsartC.ResourceConfigure; + SpiP.UsartResource[ CLIENT_ID ] -> UsartC.Resource; + SpiP.UsartInterrupts -> UsartC.HplMsp430UsartInterrupts; + +} diff --git a/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDma0P.nc b/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDma0P.nc new file mode 100644 index 00000000..60ca5af9 --- /dev/null +++ b/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDma0P.nc @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2005-2006 Arched Rock Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * - Neither the name of the Arched Rock Corporation nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE + */ + +/** + * @author Jonathan Hui + * @version $Revision$ $Date$ + */ + +configuration Xe1205SpiNoDma0P { + + provides interface Resource[ uint8_t id ]; + provides interface ResourceConfigure[uint8_t id ]; + provides interface SpiByte; + provides interface SpiPacket[ uint8_t id ]; + + uses interface Resource as UsartResource[ uint8_t id ]; + uses interface Msp430SpiConfigure[ uint8_t id ]; + uses interface HplMsp430UsartInterrupts as UsartInterrupts; + +} + +implementation { + + components new Xe1205SpiNoDmaP() as SpiP; + Resource = SpiP.Resource; + ResourceConfigure = SpiP.ResourceConfigure; + Msp430SpiConfigure = SpiP.Msp430SpiConfigure; + SpiByte = SpiP.SpiByte; + SpiPacket = SpiP.SpiPacket; + UsartResource = SpiP.UsartResource; + UsartInterrupts = SpiP.UsartInterrupts; + + components HplMsp430Usart0C as UsartC; + SpiP.Usart -> UsartC; + + components LedsC as Leds; + SpiP.Leds -> Leds; + +} diff --git a/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDmaP.nc b/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDmaP.nc new file mode 100644 index 00000000..dd408069 --- /dev/null +++ b/tos/platforms/tinynode/chips/xe1205/Xe1205SpiNoDmaP.nc @@ -0,0 +1,245 @@ +/** + * Copyright (c) 2005-2006 Arched Rock Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * - Neither the name of the Arched Rock Corporation nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE + */ + +/** + * @author Jonathan Hui + * @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 ) {} + +}