]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
initial RF212 support
authormmaroti <mmaroti>
Tue, 10 Mar 2009 21:43:26 +0000 (21:43 +0000)
committermmaroti <mmaroti>
Tue, 10 Mar 2009 21:43:26 +0000 (21:43 +0000)
tos/chips/rf2xx/rf212/RF212.h [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212ActiveMessageC.nc [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212ActiveMessageP.nc [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212DriverConfig.nc [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212DriverLayerC.nc [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212DriverLayerP-comp.nc [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212DriverLayerP.nc [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212Packet.h [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212PacketC.nc [new file with mode: 0644]
tos/chips/rf2xx/rf212/RF212PacketP.nc [new file with mode: 0644]

diff --git a/tos/chips/rf2xx/rf212/RF212.h b/tos/chips/rf2xx/rf212/RF212.h
new file mode 100644 (file)
index 0000000..7afb78f
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#ifndef __RF212_H__
+#define __RF212_H__
+
+enum rf212_registers_enum
+{
+       RF212_TRX_STATUS = 0x01,
+       RF212_TRX_STATE = 0x02,
+       RF212_TRX_CTRL_0 = 0x03,
+       RF212_TRX_CTRL_1 = 0x04,
+       RF212_PHY_TX_PWR = 0x05,
+       RF212_PHY_RSSI = 0x06,
+       RF212_PHY_ED_LEVEL = 0x07,
+       RF212_PHY_CC_CCA = 0x08,
+       RF212_CCA_THRES = 0x09,
+       RF212_IRQ_MASK = 0x0E,
+       RF212_IRQ_STATUS = 0x0F,
+       RF212_VREG_CTRL = 0x10,
+       RF212_BATMON = 0x11,
+       RF212_XOSC_CTRL = 0x12,
+       RF212_PLL_CF = 0x1A,
+       RF212_PLL_DCU = 0x1B,
+       RF212_PART_NUM = 0x1C,
+       RF212_VERSION_NUM = 0x1D,
+       RF212_MAN_ID_0 = 0x1E,
+       RF212_MAN_ID_1 = 0x1F,
+       RF212_SHORT_ADDR_0 = 0x20,
+       RF212_SHORT_ADDR_1 = 0x21,
+       RF212_PAN_ID_0 = 0x22,
+       RF212_PAN_ID_1 = 0x23,
+       RF212_IEEE_ADDR_0 = 0x24,
+       RF212_IEEE_ADDR_1 = 0x25,
+       RF212_IEEE_ADDR_2 = 0x26,
+       RF212_IEEE_ADDR_3 = 0x27,
+       RF212_IEEE_ADDR_4 = 0x28,
+       RF212_IEEE_ADDR_5 = 0x29,
+       RF212_IEEE_ADDR_6 = 0x2A,
+       RF212_IEEE_ADDR_7 = 0x2B,
+       RF212_XAH_CTRL = 0x2C,
+       RF212_CSMA_SEED_0 = 0x2D,
+       RF212_CSMA_SEED_1 = 0x2E,
+};
+
+enum rf212_trx_status_enums
+{
+       RF212_CCA_DONE = 1 << 7,
+       RF212_CCA_STATUS = 1 << 6,
+       RF212_TRX_STATUS_MASK = 0x1F,
+       RF212_P_ON = 0,
+       RF212_BUSY_RX = 1,
+       RF212_BUSY_TX = 2,
+       RF212_RX_ON = 6,
+       RF212_TRX_OFF = 8,
+       RF212_PLL_ON = 9,
+       RF212_SLEEP = 15,
+       RF212_BUSY_RX_AACK = 16,
+       RF212_BUSR_TX_ARET = 17,
+       RF212_RX_AACK_ON = 22,
+       RF212_TX_ARET_ON = 25,
+       RF212_RX_ON_NOCLK = 28,
+       RF212_AACK_ON_NOCLK = 29,
+       RF212_BUSY_RX_AACK_NOCLK = 30,
+       RF212_STATE_TRANSITION_IN_PROGRESS = 31,
+};
+
+enum rf212_trx_state_enums
+{
+       RF212_TRAC_STATUS_MASK = 0xE0,
+       RF212_TRAC_SUCCESS = 0,
+       RF212_TRAC_CHANNEL_ACCESS_FAILURE = 3 << 5,
+       RF212_TRAC_NO_ACK = 5 << 5,
+       RF212_TRX_CMD_MASK = 0x1F,
+       RF212_NOP = 0,
+       RF212_TX_START = 2,
+       RF212_FORCE_TRX_OFF = 3,
+};
+
+enum rf212_phy_rssi_enums
+{
+       RF212_RX_CRC_VALID = 1 << 7,
+       RF212_RSSI_MASK = 0x1F,
+};
+
+enum rf212_phy_cc_cca_enums
+{
+       RF212_CCA_REQUEST = 1 << 7,
+       RF212_CCA_MODE_0 = 0 << 5,
+       RF212_CCA_MODE_1 = 1 << 5,
+       RF212_CCA_MODE_2 = 2 << 5,
+       RF212_CCA_MODE_3 = 3 << 5,
+       RF212_CHANNEL_DEFAULT = 11,
+       RF212_CHANNEL_MASK = 0x1F,
+};
+
+enum rf212_irq_register_enums
+{
+       RF212_IRQ_BAT_LOW = 1 << 7,
+       RF212_IRQ_TRX_UR = 1 << 6,
+       RF212_IRQ_AMI = 1 << 5,
+       RF212_IRQ_CCA_ED_DONE = 1 << 4,
+       RF212_IRQ_TRX_END = 1 << 3,
+       RF212_IRQ_RX_START = 1 << 2,
+       RF212_IRQ_PLL_UNLOCK = 1 << 1,
+       RF212_IRQ_PLL_LOCK = 1 << 0,
+};
+
+enum rf212_batmon_enums
+{
+       RF212_BATMON_OK = 1 << 5,
+       RF212_BATMON_VHR = 1 << 4,
+       RF212_BATMON_VTH_MASK = 0x0F,
+};
+
+enum rf212_vreg_ctrl_enums
+{
+       RF212_AVREG_EXT = 1 << 7,
+       RF212_AVDD_OK = 1 << 6,
+       RF212_DVREG_EXT = 1 << 3,
+       RF212_DVDD_OK = 1 << 2,
+};
+
+enum rf212_xosc_ctrl_enums
+{
+       RF212_XTAL_MODE_OFF = 0 << 4,
+       RF212_XTAL_MODE_EXTERNAL = 4 << 4,
+       RF212_XTAL_MODE_INTERNAL = 15 << 4,
+};
+
+enum rf212_spi_command_enums
+{
+       RF212_CMD_REGISTER_READ = 0x80,
+       RF212_CMD_REGISTER_WRITE = 0xC0,
+       RF212_CMD_REGISTER_MASK = 0x3F,
+       RF212_CMD_FRAME_READ = 0x20,
+       RF212_CMD_FRAME_WRITE = 0x60,
+       RF212_CMD_SRAM_READ = 0x00,
+       RF212_CMD_SRAM_WRITE = 0x40,
+};
+
+#endif//__RF212_H__
diff --git a/tos/chips/rf2xx/rf212/RF212ActiveMessageC.nc b/tos/chips/rf2xx/rf212/RF212ActiveMessageC.nc
new file mode 100644 (file)
index 0000000..6a79f85
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#include <RadioConfig.h>
+
+configuration RF212ActiveMessageC
+{
+       provides 
+       {
+               interface SplitControl;
+
+               interface AMSend[am_id_t id];
+               interface Receive[am_id_t id];
+               interface Receive as Snoop[am_id_t id];
+
+               interface Packet;
+               interface AMPacket;
+               interface PacketAcknowledgements;
+               interface LowPowerListening;
+               interface RadioChannel;
+
+               interface PacketField<uint8_t> as PacketLinkQuality;
+               interface PacketField<uint8_t> as PacketTransmitPower;
+               interface PacketField<uint8_t> as PacketRSSI;
+
+               interface PacketTimeStamp<TRadio, uint32_t> as PacketTimeStampRadio;
+               interface PacketTimeStamp<TMilli, uint32_t> as PacketTimeStampMilli;
+       }
+}
+
+implementation
+{
+       components RF212ActiveMessageP, RF212PacketC, IEEE154PacketC, RadioAlarmC;
+
+#ifdef RADIO_DEBUG
+       components AssertC;
+#endif
+
+       RF212ActiveMessageP.IEEE154Packet -> IEEE154PacketC;
+       RF212ActiveMessageP.Packet -> RF212PacketC;
+       RF212ActiveMessageP.RadioAlarm -> RadioAlarmC.RadioAlarm[unique("RadioAlarm")];
+
+       Packet = RF212PacketC;
+       AMPacket = RF212PacketC;
+       PacketAcknowledgements = RF212PacketC;
+       PacketLinkQuality = RF212PacketC.PacketLinkQuality;
+       PacketTransmitPower = RF212PacketC.PacketTransmitPower;
+       PacketRSSI = RF212PacketC.PacketRSSI;
+       PacketTimeStampRadio = RF212PacketC;
+       PacketTimeStampMilli = RF212PacketC;
+       LowPowerListening = LowPowerListeningLayerC;
+       RadioChannel = MessageBufferLayerC;
+
+       components ActiveMessageLayerC;
+#ifdef TFRAMES_ENABLED
+       components new DummyLayerC() as IEEE154NetworkLayerC;
+#else
+       components IEEE154NetworkLayerC;
+#endif
+#ifdef LOW_POWER_LISTENING
+       components LowPowerListeningLayerC;
+#else  
+       components new DummyLayerC() as LowPowerListeningLayerC;
+#endif
+       components MessageBufferLayerC;
+       components UniqueLayerC;
+       components TrafficMonitorLayerC;
+#ifdef SLOTTED_MAC
+       components SlottedCollisionLayerC as CollisionAvoidanceLayerC;
+#else
+       components RandomCollisionLayerC as CollisionAvoidanceLayerC;
+#endif
+       components SoftwareAckLayerC;
+       components new DummyLayerC() as CsmaLayerC;
+       components RF212DriverLayerC;
+
+       SplitControl = LowPowerListeningLayerC;
+       AMSend = ActiveMessageLayerC;
+       Receive = ActiveMessageLayerC.Receive;
+       Snoop = ActiveMessageLayerC.Snoop;
+
+       ActiveMessageLayerC.Config -> RF212ActiveMessageP;
+       ActiveMessageLayerC.AMPacket -> IEEE154PacketC;
+       ActiveMessageLayerC.SubSend -> IEEE154NetworkLayerC;
+       ActiveMessageLayerC.SubReceive -> IEEE154NetworkLayerC;
+
+       IEEE154NetworkLayerC.SubSend -> UniqueLayerC;
+       IEEE154NetworkLayerC.SubReceive -> LowPowerListeningLayerC;
+
+       // the UniqueLayer is wired at two points
+       UniqueLayerC.Config -> RF212ActiveMessageP;
+       UniqueLayerC.SubSend -> LowPowerListeningLayerC;
+
+       LowPowerListeningLayerC.SubControl -> MessageBufferLayerC;
+       LowPowerListeningLayerC.SubSend -> MessageBufferLayerC;
+       LowPowerListeningLayerC.SubReceive -> MessageBufferLayerC;
+#ifdef LOW_POWER_LISTENING
+       LowPowerListeningLayerC.PacketSleepInterval -> RF212PacketC;
+       LowPowerListeningLayerC.IEEE154Packet -> IEEE154PacketC;
+       LowPowerListeningLayerC.PacketAcknowledgements -> RF212PacketC;
+#endif
+
+       MessageBufferLayerC.Packet -> RF212PacketC;
+       MessageBufferLayerC.RadioSend -> TrafficMonitorLayerC;
+       MessageBufferLayerC.RadioReceive -> UniqueLayerC;
+       MessageBufferLayerC.RadioState -> TrafficMonitorLayerC;
+
+       UniqueLayerC.SubReceive -> TrafficMonitorLayerC;
+
+       TrafficMonitorLayerC.Config -> RF212ActiveMessageP;
+       TrafficMonitorLayerC.SubSend -> CollisionAvoidanceLayerC;
+       TrafficMonitorLayerC.SubReceive -> CollisionAvoidanceLayerC;
+       TrafficMonitorLayerC.SubState -> RF212DriverLayerC;
+
+       CollisionAvoidanceLayerC.Config -> RF212ActiveMessageP;
+       CollisionAvoidanceLayerC.SubSend -> SoftwareAckLayerC;
+       CollisionAvoidanceLayerC.SubReceive -> SoftwareAckLayerC;
+
+       SoftwareAckLayerC.Config -> RF212ActiveMessageP;
+       SoftwareAckLayerC.SubSend -> CsmaLayerC;
+       SoftwareAckLayerC.SubReceive -> RF212DriverLayerC;
+
+       CsmaLayerC.Config -> RF212ActiveMessageP;
+       CsmaLayerC -> RF212DriverLayerC.RadioSend;
+       CsmaLayerC -> RF212DriverLayerC.RadioCCA;
+
+       RF212DriverLayerC.RF212DriverConfig -> RF212ActiveMessageP;
+}
diff --git a/tos/chips/rf2xx/rf212/RF212ActiveMessageP.nc b/tos/chips/rf2xx/rf212/RF212ActiveMessageP.nc
new file mode 100644 (file)
index 0000000..34391da
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#include <RF212Packet.h>
+#include <RadioConfig.h>
+#include <Tasklet.h>
+
+module RF212ActiveMessageP
+{
+       provides
+       {
+               interface RF212DriverConfig;
+               interface SoftwareAckConfig;
+               interface UniqueConfig;
+               interface CsmaConfig;
+               interface TrafficMonitorConfig;
+               interface RandomCollisionConfig;
+               interface SlottedCollisionConfig;
+               interface ActiveMessageConfig;
+               interface DummyConfig;
+       }
+
+       uses
+       {
+               interface IEEE154Packet;
+               interface Packet;
+               interface RadioAlarm;
+       }
+}
+
+implementation
+{
+/*----------------- RF212DriverConfig -----------------*/
+
+       async command uint8_t RF212DriverConfig.getLength(message_t* msg)
+       {
+               return call IEEE154Packet.getLength(msg);
+       }
+
+       async command void RF212DriverConfig.setLength(message_t* msg, uint8_t len)
+       {
+               call IEEE154Packet.setLength(msg, len);
+       }
+
+       async command uint8_t* RF212DriverConfig.getPayload(message_t* msg)
+       {
+               return ((uint8_t*)(call IEEE154Packet.getHeader(msg))) + 1;
+       }
+
+       inline rf212packet_metadata_t* getMeta(message_t* msg)
+       {
+               return (rf212packet_metadata_t*)(msg->metadata);
+       }
+
+       async command uint8_t RF212DriverConfig.getHeaderLength()
+       {
+               // we need the fcf, dsn, destpan and dest
+               return 7;
+       }
+
+       async command uint8_t RF212DriverConfig.getMaxLength()
+       {
+               // note, that the ieee154_footer_t is not stored, but we should include it here
+               return sizeof(rf212packet_header_t) - 1 + TOSH_DATA_LENGTH + sizeof(ieee154_footer_t);
+       }
+
+       async command uint8_t RF212DriverConfig.getDefaultChannel()
+       {
+               return RF212_DEF_CHANNEL;
+       }
+
+       async command bool RF212DriverConfig.requiresRssiCca(message_t* msg)
+       {
+               return call IEEE154Packet.isDataFrame(msg);
+       }
+
+/*----------------- SoftwareAckConfig -----------------*/
+
+       async command bool SoftwareAckConfig.requiresAckWait(message_t* msg)
+       {
+               return call IEEE154Packet.requiresAckWait(msg);
+       }
+
+       async command bool SoftwareAckConfig.isAckPacket(message_t* msg)
+       {
+               return call IEEE154Packet.isAckFrame(msg);
+       }
+
+       async command bool SoftwareAckConfig.verifyAckPacket(message_t* data, message_t* ack)
+       {
+               return call IEEE154Packet.verifyAckReply(data, ack);
+       }
+
+       async command bool SoftwareAckConfig.requiresAckReply(message_t* msg)
+       {
+               return call IEEE154Packet.requiresAckReply(msg);
+       }
+
+       async command void SoftwareAckConfig.createAckPacket(message_t* data, message_t* ack)
+       {
+               call IEEE154Packet.createAckReply(data, ack);
+       }
+
+       async command void SoftwareAckConfig.setAckReceived(message_t* msg, bool acked)
+       {
+               if( acked )
+                       getMeta(msg)->flags |= RF212PACKET_WAS_ACKED;
+               else
+                       getMeta(msg)->flags &= ~RF212PACKET_WAS_ACKED;
+       }
+
+       async command uint16_t SoftwareAckConfig.getAckTimeout()
+       {
+               return (uint16_t)(800 * RADIO_ALARM_MICROSEC);
+       }
+
+       tasklet_async command void SoftwareAckConfig.reportChannelError()
+       {
+               signal TrafficMonitorConfig.channelError();
+       }
+
+/*----------------- UniqueConfig -----------------*/
+
+       async command uint8_t UniqueConfig.getSequenceNumber(message_t* msg)
+       {
+               return call IEEE154Packet.getDSN(msg);
+       }
+
+       async command void UniqueConfig.setSequenceNumber(message_t* msg, uint8_t dsn)
+       {
+               call IEEE154Packet.setDSN(msg, dsn);
+       }
+
+       async command am_addr_t UniqueConfig.getSender(message_t* msg)
+       {
+               return call IEEE154Packet.getSrcAddr(msg);
+       }
+
+       tasklet_async command void UniqueConfig.reportChannelError()
+       {
+               signal TrafficMonitorConfig.channelError();
+       }
+
+/*----------------- ActiveMessageConfig -----------------*/
+
+       command error_t ActiveMessageConfig.checkPacket(message_t* msg)
+       {
+               // the user forgot to call clear, we should return EINVAL
+               if( ! call IEEE154Packet.isDataFrame(msg) )
+                       call Packet.clear(msg);
+
+               return SUCCESS;
+       }
+
+/*----------------- CsmaConfig -----------------*/
+
+       async command bool CsmaConfig.requiresSoftwareCCA(message_t* msg)
+       {
+               return call IEEE154Packet.isDataFrame(msg);
+       }
+
+/*----------------- TrafficMonitorConfig -----------------*/
+
+       enum
+       {
+               TRAFFIC_UPDATE_PERIOD = 100,    // in milliseconds
+               TRAFFIC_MAX_BYTES = (uint16_t)(TRAFFIC_UPDATE_PERIOD * 1000UL / 32),    // 3125
+       };
+
+       async command uint16_t TrafficMonitorConfig.getUpdatePeriod()
+       {
+               return TRAFFIC_UPDATE_PERIOD;
+       }
+
+       async command uint16_t TrafficMonitorConfig.getChannelTime(message_t* msg)
+       {
+               /* We count in bytes, one byte is 32 microsecond. We are conservative here.
+                *
+                * pure airtime: preable (4 bytes), SFD (1 byte), length (1 byte), payload + CRC (len bytes)
+                * frame separation: 5-10 bytes
+                * ack required: 8-16 byte separation, 11 bytes airtime, 5-10 bytes separation
+                */
+
+               uint8_t len = call IEEE154Packet.getLength(msg);
+               return call IEEE154Packet.getAckRequired(msg) ? len + 6 + 16 + 11 + 10 : len + 6 + 10;
+       }
+
+       async command am_addr_t TrafficMonitorConfig.getSender(message_t* msg)
+       {
+               return call IEEE154Packet.getSrcAddr(msg);
+       }
+
+       tasklet_async command void TrafficMonitorConfig.timerTick()
+       {
+               signal SlottedCollisionConfig.timerTick();
+       }
+
+/*----------------- RandomCollisionConfig -----------------*/
+
+       /*
+        * We try to use the same values as in CC2420
+        *
+        * CC2420_MIN_BACKOFF = 10 jiffies = 320 microsec
+        * CC2420_BACKOFF_PERIOD = 10 jiffies
+        * initial backoff = 0x1F * CC2420_BACKOFF_PERIOD = 310 jiffies = 9920 microsec
+        * congestion backoff = 0x7 * CC2420_BACKOFF_PERIOD = 70 jiffies = 2240 microsec
+        */
+
+       async command uint16_t RandomCollisionConfig.getMinimumBackoff()
+       {
+               return (uint16_t)(320 * RADIO_ALARM_MICROSEC);
+       }
+
+       async command uint16_t RandomCollisionConfig.getInitialBackoff(message_t* msg)
+       {
+               return (uint16_t)(9920 * RADIO_ALARM_MICROSEC);
+       }
+
+       async command uint16_t RandomCollisionConfig.getCongestionBackoff(message_t* msg)
+       {
+               return (uint16_t)(2240 * RADIO_ALARM_MICROSEC);
+       }
+
+       async command uint16_t RandomCollisionConfig.getTransmitBarrier(message_t* msg)
+       {
+               uint16_t time;
+
+               // TODO: maybe we should use the embedded timestamp of the message
+               time = call RadioAlarm.getNow();
+
+               // estimated response time (download the message, etc) is 5-8 bytes
+               if( call IEEE154Packet.requiresAckReply(msg) )
+                       time += (uint16_t)(32 * (-5 + 16 + 11 + 5) * RADIO_ALARM_MICROSEC);
+               else
+                       time += (uint16_t)(32 * (-5 + 5) * RADIO_ALARM_MICROSEC);
+
+               return time;
+       }
+
+       tasklet_async event void RadioAlarm.fired()     { }
+
+/*----------------- SlottedCollisionConfig -----------------*/
+
+       async command uint16_t SlottedCollisionConfig.getInitialDelay()
+       {
+               return 300;
+       }
+
+       async command uint8_t SlottedCollisionConfig.getScheduleExponent()
+       {
+               return 1 + RADIO_ALARM_MILLI_EXP;
+       }
+
+       async command uint16_t SlottedCollisionConfig.getTransmitTime(message_t* msg)
+       {
+               // TODO: check if the timestamp is correct
+               return getMeta(msg)->timestamp;
+       }
+
+       async command uint16_t SlottedCollisionConfig.getCollisionWindowStart(message_t* msg)
+       {
+               // the preamble (4 bytes), SFD (1 byte), plus two extra for safety
+               return getMeta(msg)->timestamp - (uint16_t)(7 * 32 * RADIO_ALARM_MICROSEC);
+       }
+
+       async command uint16_t SlottedCollisionConfig.getCollisionWindowLength(message_t* msg)
+       {
+               return (uint16_t)(2 * 7 * 32 * RADIO_ALARM_MICROSEC);
+       }
+
+       default tasklet_async event void SlottedCollisionConfig.timerTick() { }
+
+/*----------------- Dummy -----------------*/
+
+       async command void DummyConfig.nothing()
+       {
+       }
+}
diff --git a/tos/chips/rf2xx/rf212/RF212DriverConfig.nc b/tos/chips/rf2xx/rf212/RF212DriverConfig.nc
new file mode 100644 (file)
index 0000000..49d53b3
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+/**
+ * This interface needs to be implemented by the MAC to control the behaviour 
+ * of the RF212DriverLayerC component.
+ */
+interface RF212DriverConfig
+{
+       /**
+        * Returns the length of the PHY payload (including the FCF field).
+        * This value must be in the range [3, 127].
+        */
+       async command uint8_t getLength(message_t* msg);
+
+       /**
+        * Sets the length of the PHY payload.
+        */
+       async command void setLength(message_t* msg, uint8_t len);
+
+       /**
+        * Returns a pointer to the start of the PHY payload that contains 
+        * getLength()-2 number of bytes. The FCF field (CRC-16) is not stored,
+        * but automatically appended / verified.
+        */
+       async command uint8_t* getPayload(message_t* msg);
+
+       /**
+        * Gets the number of bytes we should read before the RadioReceive.header
+        * event is fired. If the length of the packet is less than this amount, 
+        * then that event is fired earlier. The header length must be at least one.
+        */
+       async command uint8_t getHeaderLength();
+
+       /**
+        * Returns the maximum PHY length that can be set via the setLength command
+        */
+       async command uint8_t getMaxLength();
+
+       /**
+        * This command is used at power up to set the default channel.
+        * The default CC2420 channel is 26.
+        */
+       async command uint8_t getDefaultChannel();
+
+       /**
+        * Returns TRUE if before sending this message we should make sure that
+        * the channel is clear via a very basic (and quick) RSSI check.
+        */
+       async command bool requiresRssiCca(message_t* msg);
+}
diff --git a/tos/chips/rf2xx/rf212/RF212DriverLayerC.nc b/tos/chips/rf2xx/rf212/RF212DriverLayerC.nc
new file mode 100644 (file)
index 0000000..d847e6f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+configuration RF212DriverLayerC
+{
+       provides
+       {
+               interface RadioState;
+               interface RadioSend;
+               interface RadioReceive;
+               interface RadioCCA;
+       }
+
+       uses interface RF212DriverConfig;
+}
+
+implementation
+{
+       components RF212DriverLayerP, HplRF212C, BusyWaitMicroC, TaskletC, MainC, RadioAlarmC, RF212PacketC, LocalTimeMicroC as LocalTimeRadioC;
+
+       RadioState = RF212DriverLayerP;
+       RadioSend = RF212DriverLayerP;
+       RadioReceive = RF212DriverLayerP;
+       RadioCCA = RF212DriverLayerP;
+
+       RF212DriverConfig = RF212DriverLayerP;
+
+       RF212DriverLayerP.PacketLinkQuality -> RF212PacketC.PacketLinkQuality;
+       RF212DriverLayerP.PacketTransmitPower -> RF212PacketC.PacketTransmitPower;
+       RF212DriverLayerP.PacketRSSI -> RF212PacketC.PacketRSSI;
+       RF212DriverLayerP.PacketTimeSyncOffset -> RF212PacketC.PacketTimeSyncOffset;
+       RF212DriverLayerP.PacketTimeStamp -> RF212PacketC;
+       RF212DriverLayerP.LocalTime -> LocalTimeRadioC;
+
+       RF212DriverLayerP.RadioAlarm -> RadioAlarmC.RadioAlarm[unique("RadioAlarm")];
+       RadioAlarmC.Alarm -> HplRF212C.Alarm;
+
+       RF212DriverLayerP.SELN -> HplRF212C.SELN;
+       RF212DriverLayerP.SpiResource -> HplRF212C.SpiResource;
+       RF212DriverLayerP.FastSpiByte -> HplRF212C;
+
+       RF212DriverLayerP.SLP_TR -> HplRF212C.SLP_TR;
+       RF212DriverLayerP.RSTN -> HplRF212C.RSTN;
+
+       RF212DriverLayerP.IRQ -> HplRF212C.IRQ;
+       RF212DriverLayerP.Tasklet -> TaskletC;
+       RF212DriverLayerP.BusyWait -> BusyWaitMicroC;
+
+#ifdef RADIO_DEBUG
+       components DiagMsgC;
+       RF212DriverLayerP.DiagMsg -> DiagMsgC;
+#endif
+
+       MainC.SoftwareInit -> RF212DriverLayerP.SoftwareInit;
+
+       components RealMainP;
+       RealMainP.PlatformInit -> RF212DriverLayerP.PlatformInit;
+}
diff --git a/tos/chips/rf2xx/rf212/RF212DriverLayerP-comp.nc b/tos/chips/rf2xx/rf212/RF212DriverLayerP-comp.nc
new file mode 100644 (file)
index 0000000..d86ae2a
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#include <RF230.h>
+#include <Tasklet.h>
+#include <RadioAssert.h>
+#include <GenericTimeSyncMessage.h>
+#include <RadioConfig.h>
+
+module RF230DriverLayerP
+{
+       provides
+       {
+               interface Init as PlatformInit @exactlyonce();
+               interface Init as SoftwareInit @exactlyonce();
+
+               interface RadioState;
+               interface RadioSend;
+               interface RadioReceive;
+               interface RadioCCA;
+       }
+
+       uses
+       {
+               interface GeneralIO as SELN;
+               interface Resource as SpiResource;
+
+               interface FastSpiByte;
+
+               interface GeneralIO as SLP_TR;
+               interface GeneralIO as RSTN;
+
+               interface GpioCapture as IRQ;
+
+               interface BusyWait<TMicro, uint16_t>;
+
+               interface PacketField<uint8_t> as PacketLinkQuality;
+               interface PacketField<uint8_t> as PacketTransmitPower;
+               interface PacketField<uint8_t> as PacketRSSI;
+               interface PacketField<uint8_t> as PacketTimeSyncOffset;
+
+               interface PacketTimeStamp<TRadio, uint32_t>;
+               interface LocalTime<TRadio>;
+
+               interface RF230DriverConfig;
+               interface Tasklet;
+               interface RadioAlarm;
+
+#ifdef RADIO_DEBUG
+               interface DiagMsg;
+#endif
+       }
+}
+
+implementation
+{
+/*----------------- STATE -----------------*/
+
+       tasklet_norace uint8_t state;
+       enum
+       {
+               STATE_P_ON = 0,
+               STATE_SLEEP = 1,
+               STATE_SLEEP_2_TRX_OFF = 2,
+               STATE_TRX_OFF = 3,
+               STATE_TRX_OFF_2_RX_ON = 4,
+               STATE_RX_ON = 5,
+               STATE_BUSY_TX_2_RX_ON = 6,
+               STATE_PLL_ON_2_RX_ON = 7,
+       };
+
+       tasklet_norace uint8_t cmd;
+       enum
+       {
+               CMD_NONE = 0,                   // the state machine has stopped
+               CMD_TURNOFF = 1,                // goto SLEEP state
+               CMD_STANDBY = 2,                // goto TRX_OFF state
+               CMD_TURNON = 3,                 // goto RX_ON state
+               CMD_TRANSMIT = 4,               // currently transmitting a message
+               CMD_RECEIVE = 5,                // currently receiving a message
+               CMD_CCA = 6,                    // performing clear chanel assesment
+               CMD_CHANNEL = 7,                // changing the channel
+               CMD_SIGNAL_DONE = 8,            // signal the end of the state transition
+               CMD_DOWNLOAD = 9,               // download the received message
+       };
+
+       norace bool radioIrq;
+
+       tasklet_norace uint8_t txPower;
+       tasklet_norace uint8_t channel;
+
+       tasklet_norace message_t* rxMsg;
+       message_t rxMsgBuffer;
+
+       uint16_t capturedTime;  // the current time when the last interrupt has occured
+
+       tasklet_norace uint8_t rssiClear;
+       tasklet_norace uint8_t rssiBusy;
+
+/*----------------- REGISTER -----------------*/
+
+       inline void writeRegister(uint8_t reg, uint8_t value)
+       {
+               ASSERT( call SpiResource.isOwner() );
+               ASSERT( reg == (reg & RF230_CMD_REGISTER_MASK) );
+
+               call SELN.clr();
+               call FastSpiByte.splitWrite(RF230_CMD_REGISTER_WRITE | reg);
+               call FastSpiByte.splitReadWrite(value);
+               call FastSpiByte.splitRead();
+               call SELN.set();
+       }
+
+       inline uint8_t readRegister(uint8_t reg)
+       {
+               ASSERT( call SpiResource.isOwner() );
+               ASSERT( reg == (reg & RF230_CMD_REGISTER_MASK) );
+
+               call SELN.clr();
+               call FastSpiByte.splitWrite(RF230_CMD_REGISTER_READ | reg);
+               call FastSpiByte.splitReadWrite(0);
+               reg = call FastSpiByte.splitRead();
+               call SELN.set();
+
+               return reg;
+       }
+
+/*----------------- ALARM -----------------*/
+
+       enum
+       {
+               SLEEP_WAKEUP_TIME = (uint16_t)(880 * RADIO_ALARM_MICROSEC),
+               CCA_REQUEST_TIME = (uint16_t)(140 * RADIO_ALARM_MICROSEC),
+
+               TX_SFD_DELAY = (uint16_t)(176 * RADIO_ALARM_MICROSEC),
+               RX_SFD_DELAY = (uint16_t)(8 * RADIO_ALARM_MICROSEC),
+       };
+
+       tasklet_async event void RadioAlarm.fired()
+       {
+               if( state == STATE_SLEEP_2_TRX_OFF )
+                       state = STATE_TRX_OFF;
+               else if( cmd == CMD_CCA )
+               {
+                       uint8_t cca;
+
+                       ASSERT( state == STATE_RX_ON );
+
+                       cmd = CMD_NONE;
+                       cca = readRegister(RF230_TRX_STATUS);
+
+                       ASSERT( (cca & RF230_TRX_STATUS_MASK) == RF230_RX_ON );
+
+                       signal RadioCCA.done( (cca & RF230_CCA_DONE) ? ((cca & RF230_CCA_STATUS) ? SUCCESS : EBUSY) : FAIL );
+               }
+               else
+                       ASSERT(FALSE);
+
+               // make sure the rest of the command processing is called
+               call Tasklet.schedule();
+       }
+
+/*----------------- INIT -----------------*/
+
+       command error_t PlatformInit.init()
+       {
+               call SELN.makeOutput();
+               call SELN.set();
+               call SLP_TR.makeOutput();
+               call SLP_TR.clr();
+               call RSTN.makeOutput();
+               call RSTN.set();
+
+               rxMsg = &rxMsgBuffer;
+
+               // these are just good approximates
+               rssiClear = 0;
+               rssiBusy = 90;
+
+               return SUCCESS;
+       }
+
+       command error_t SoftwareInit.init()
+       {
+               // for powering up the radio
+               return call SpiResource.request();
+       }
+
+       void initRadio()
+       {
+               call BusyWait.wait(510);
+
+               call RSTN.clr();
+               call SLP_TR.clr();
+               call BusyWait.wait(6);
+               call RSTN.set();
+
+               writeRegister(RF230_TRX_CTRL_0, RF230_TRX_CTRL_0_VALUE);
+               writeRegister(RF230_TRX_STATE, RF230_TRX_OFF);
+
+               call BusyWait.wait(510);
+
+               writeRegister(RF230_IRQ_MASK, RF230_IRQ_TRX_UR | RF230_IRQ_PLL_LOCK | RF230_IRQ_TRX_END | RF230_IRQ_RX_START);
+               writeRegister(RF230_CCA_THRES, RF230_CCA_THRES_VALUE);
+               writeRegister(RF230_PHY_TX_PWR, RF230_DEF_RFPOWER);
+
+               txPower = RF230_DEF_RFPOWER;
+               channel = call RF230DriverConfig.getDefaultChannel() & RF230_CHANNEL_MASK;
+               writeRegister(RF230_PHY_CC_CCA, RF230_CCA_MODE_VALUE | channel);
+
+               call SLP_TR.set();
+               state = STATE_SLEEP;
+       }
+
+/*----------------- SPI -----------------*/
+
+       event void SpiResource.granted()
+       {
+               call SELN.makeOutput();
+               call SELN.set();
+
+               if( state == STATE_P_ON )
+               {
+                       initRadio();
+                       call SpiResource.release();
+               }
+               else
+                       call Tasklet.schedule();
+       }
+
+       bool isSpiAcquired()
+       {
+               if( call SpiResource.isOwner() )
+                       return TRUE;
+
+               if( call SpiResource.immediateRequest() == SUCCESS )
+               {
+                       call SELN.makeOutput();
+                       call SELN.set();
+
+                       return TRUE;
+               }
+
+               call SpiResource.request();
+               return FALSE;
+       }
+
+/*----------------- CHANNEL -----------------*/
+
+       tasklet_async command uint8_t RadioState.getChannel()
+       {
+               return channel;
+       }
+
+       tasklet_async command error_t RadioState.setChannel(uint8_t c)
+       {
+               c &= RF230_CHANNEL_MASK;
+
+               if( cmd != CMD_NONE )
+                       return EBUSY;
+               else if( channel == c )
+                       return EALREADY;
+
+               channel = c;
+               cmd = CMD_CHANNEL;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+
+       inline void changeChannel()
+       {
+               ASSERT( cmd == CMD_CHANNEL );
+               ASSERT( state == STATE_SLEEP || state == STATE_TRX_OFF || state == STATE_RX_ON );
+
+               if( isSpiAcquired() )
+               {
+                       writeRegister(RF230_PHY_CC_CCA, RF230_CCA_MODE_VALUE | channel);
+
+                       if( state == STATE_RX_ON )
+                               state = STATE_TRX_OFF_2_RX_ON;
+                       else
+                               cmd = CMD_SIGNAL_DONE;
+               }
+       }
+
+/*----------------- TURN ON/OFF -----------------*/
+
+       inline void changeState()
+       {
+               if( (cmd == CMD_STANDBY || cmd == CMD_TURNON)
+                       && state == STATE_SLEEP && call RadioAlarm.isFree() )
+               {
+                       call SLP_TR.clr();
+
+                       call RadioAlarm.wait(SLEEP_WAKEUP_TIME);
+                       state = STATE_SLEEP_2_TRX_OFF;
+               }
+               else if( cmd == CMD_TURNON && state == STATE_TRX_OFF && isSpiAcquired() )
+               {
+                       ASSERT( ! radioIrq );
+
+                       readRegister(RF230_IRQ_STATUS); // clear the interrupt register
+                       call IRQ.captureRisingEdge();
+
+                       // setChannel was ignored in SLEEP because the SPI was not working, so do it here
+                       writeRegister(RF230_PHY_CC_CCA, RF230_CCA_MODE_VALUE | channel);
+
+                       writeRegister(RF230_TRX_STATE, RF230_RX_ON);
+                       state = STATE_TRX_OFF_2_RX_ON;
+               }
+               else if( (cmd == CMD_TURNOFF || cmd == CMD_STANDBY) 
+                       && state == STATE_RX_ON && isSpiAcquired() )
+               {
+                       writeRegister(RF230_TRX_STATE, RF230_FORCE_TRX_OFF);
+
+                       call IRQ.disable();
+                       radioIrq = FALSE;
+
+                       state = STATE_TRX_OFF;
+               }
+
+               if( cmd == CMD_TURNOFF && state == STATE_TRX_OFF )
+               {
+                       call SLP_TR.set();
+                       state = STATE_SLEEP;
+                       cmd = CMD_SIGNAL_DONE;
+               }
+               else if( cmd == CMD_STANDBY && state == STATE_TRX_OFF )
+                       cmd = CMD_SIGNAL_DONE;
+       }
+
+       tasklet_async command error_t RadioState.turnOff()
+       {
+               if( cmd != CMD_NONE )
+                       return EBUSY;
+               else if( state == STATE_SLEEP )
+                       return EALREADY;
+
+               cmd = CMD_TURNOFF;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+       
+       tasklet_async command error_t RadioState.standby()
+       {
+               if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) )
+                       return EBUSY;
+               else if( state == STATE_TRX_OFF )
+                       return EALREADY;
+
+               cmd = CMD_STANDBY;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+
+       tasklet_async command error_t RadioState.turnOn()
+       {
+               if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) )
+                       return EBUSY;
+               else if( state == STATE_RX_ON )
+                       return EALREADY;
+
+               cmd = CMD_TURNON;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+
+       default tasklet_async event void RadioState.done() { }
+
+/*----------------- TRANSMIT -----------------*/
+
+       tasklet_async command error_t RadioSend.send(message_t* msg)
+       {
+               uint16_t time;
+               uint8_t length;
+               uint8_t* data;
+               uint8_t header;
+               uint32_t time32;
+               void* timesync;
+
+               if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || radioIrq )
+                       return EBUSY;
+
+               length = call PacketTransmitPower.isSet(msg) ?
+                       call PacketTransmitPower.get(msg) : RF230_DEF_RFPOWER;
+
+               if( length != txPower )
+               {
+                       txPower = length;
+                       writeRegister(RF230_PHY_TX_PWR, txPower);
+               }
+
+               if( call RF230DriverConfig.requiresRssiCca(msg) 
+                               && (readRegister(RF230_PHY_RSSI) & RF230_RSSI_MASK) > ((rssiClear + rssiBusy) >> 3) )
+                       return EBUSY;
+
+               writeRegister(RF230_TRX_STATE, RF230_PLL_ON);
+
+               // do something useful, just to wait a little
+               time32 = call LocalTime.get();
+               timesync = call PacketTimeSyncOffset.isSet(msg) ? msg->data + call PacketTimeSyncOffset.get(msg) : 0;
+
+               // we have missed an incoming message in this short amount of time
+               if( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) != RF230_PLL_ON )
+               {
+                       ASSERT( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) == RF230_BUSY_RX );
+
+                       state = STATE_PLL_ON_2_RX_ON;
+                       return EBUSY;
+               }
+
+               atomic
+               {
+                       call SLP_TR.set();
+                       time = call RadioAlarm.getNow() + TX_SFD_DELAY;
+               }
+               call SLP_TR.clr();
+
+               ASSERT( ! radioIrq );
+
+               call SELN.clr();
+               call FastSpiByte.splitWrite(RF230_CMD_FRAME_WRITE);
+
+               length = call RF230DriverConfig.getLength(msg);
+               data = call RF230DriverConfig.getPayload(msg);
+
+               // length | data[0] ... data[length-3] | automatically generated FCS
+               call FastSpiByte.splitReadWrite(length);
+
+               // the FCS is atomatically generated (2 bytes)
+               length -= 2;
+
+               header = call RF230DriverConfig.getHeaderLength();
+               if( header > length )
+                       header = length;
+
+               length -= header;
+
+               // first upload the header to gain some time
+               do {
+                       call FastSpiByte.splitReadWrite(*(data++));
+               }
+               while( --header != 0 );
+
+               time32 += (int16_t)(time) - (int16_t)(time32);
+
+               if( timesync != 0 )
+                       *(timesync_relative_t*)timesync = (*(timesync_absolute_t*)timesync) - time32;
+
+               do {
+                       call FastSpiByte.splitReadWrite(*(data++));
+               }
+               while( --length != 0 );
+
+               // wait for the SPI transfer to finish
+               call FastSpiByte.splitRead();
+               call SELN.set();
+
+               /*
+                * There is a very small window (~1 microsecond) when the RF230 went 
+                * into PLL_ON state but was somehow not properly initialized because 
+                * of an incoming message and could not go into BUSY_TX. I think the
+                * radio can even receive a message, and generate a TRX_UR interrupt
+                * because of concurrent access, but that message probably cannot be
+                * recovered.
+                *
+                * TODO: this needs to be verified, and make sure that the chip is 
+                * not locked up in this case.
+                */
+
+               // go back to RX_ON state when finished
+               writeRegister(RF230_TRX_STATE, RF230_RX_ON);
+
+#ifdef RADIO_DEBUG_MESSAGES
+               if( call DiagMsg.record() )
+               {
+                       length = call RF230DriverConfig.getLength(msg);
+
+                       call DiagMsg.str("tx");
+                       call DiagMsg.uint16(time);
+                       call DiagMsg.uint8(length);
+                       call DiagMsg.hex8s(data, length - 2);
+                       call DiagMsg.send();
+               }
+#endif
+
+               if( timesync != 0 )
+                       *(timesync_absolute_t*)timesync = (*(timesync_relative_t*)timesync) + time32;
+
+               call PacketTimeStamp.set(msg, time32);
+
+               // wait for the TRX_END interrupt
+               state = STATE_BUSY_TX_2_RX_ON;
+               cmd = CMD_TRANSMIT;
+
+               return SUCCESS;
+       }
+
+       default tasklet_async event void RadioSend.sendDone(error_t error) { }
+       default tasklet_async event void RadioSend.ready() { }
+
+/*----------------- CCA -----------------*/
+
+       tasklet_async command error_t RadioCCA.request()
+       {
+               if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || ! call RadioAlarm.isFree() )
+                       return EBUSY;
+
+               // see Errata B7 of the datasheet
+               // writeRegister(RF230_TRX_STATE, RF230_PLL_ON);
+               // writeRegister(RF230_TRX_STATE, RF230_RX_ON);
+
+               writeRegister(RF230_PHY_CC_CCA, RF230_CCA_REQUEST | RF230_CCA_MODE_VALUE | channel);
+               call RadioAlarm.wait(CCA_REQUEST_TIME);
+               cmd = CMD_CCA;
+               
+               return SUCCESS;
+       }
+
+       default tasklet_async event void RadioCCA.done(error_t error) { }
+
+/*----------------- RECEIVE -----------------*/
+
+       inline void downloadMessage()
+       {
+               uint8_t length;
+               uint8_t crc;
+
+               call SELN.clr();
+               call FastSpiByte.write(RF230_CMD_FRAME_READ);
+
+               // read the length byte
+               length = call FastSpiByte.write(0);
+
+               // if correct length
+               if( length >= 3 && length <= call RF230DriverConfig.getMaxLength() )
+               {
+                       uint8_t read;
+                       uint8_t* data;
+
+                       // initiate the reading
+                       call FastSpiByte.splitWrite(0);
+
+                       call RF230DriverConfig.setLength(rxMsg, length);
+                       data = call RF230DriverConfig.getPayload(rxMsg);
+                       crc = 0;
+
+                       // we do not store the CRC field
+                       length -= 2;
+
+                       read = call RF230DriverConfig.getHeaderLength();
+                       if( length < read )
+                               read = length;
+
+                       length -= read;
+
+                       do {
+                               *(data++) = call FastSpiByte.splitReadWrite(0);
+                       }
+                       while( --read != 0  );
+
+                       if( signal RadioReceive.header(rxMsg) )
+                       {
+                               while( length-- != 0 )
+                                       *(data++) = call FastSpiByte.splitReadWrite(0);
+
+                               call FastSpiByte.splitReadWrite(0);     // two CRC bytes
+                               call FastSpiByte.splitReadWrite(0);
+
+                               call PacketLinkQuality.set(rxMsg, call FastSpiByte.splitReadWrite(0));
+                               call FastSpiByte.splitReadWrite(0);     // ED
+                               crc = call FastSpiByte.splitRead() & RF230_RX_CRC_VALID;        // RX_STATUS
+                       }
+               }
+
+               call SELN.set();
+               state = STATE_RX_ON;
+
+#ifdef RADIO_DEBUG_MESSAGES
+               if( call DiagMsg.record() )
+               {
+                       length = call RF230DriverConfig.getLength(rxMsg);
+
+                       call DiagMsg.str("rx");
+                       call DiagMsg.uint32(call PacketTimeStamp.isValid(rxMsg) ? call PacketTimeStamp.timestamp(rxMsg) : 0);
+                       call DiagMsg.uint16(call RadioAlarm.getNow());
+                       call DiagMsg.uint8(crc != 0);
+                       call DiagMsg.uint8(length);
+                       call DiagMsg.hex8s(call RF230DriverConfig.getPayload(rxMsg), length - 2);
+                       call DiagMsg.send();
+               }
+#endif
+               
+               cmd = CMD_NONE;
+
+               // signal only if it has passed the CRC check
+               if( crc != 0 )
+                       rxMsg = signal RadioReceive.receive(rxMsg);
+       }
+
+/*----------------- IRQ -----------------*/
+
+       async event void IRQ.captured(uint16_t time)
+       {
+               ASSERT( ! radioIrq );
+
+               atomic
+               {
+                       capturedTime = time;
+                       radioIrq = TRUE;
+               }
+
+               call Tasklet.schedule();
+       }
+
+       void serviceRadio()
+       {
+               if( isSpiAcquired() )
+               {
+                       uint16_t time;
+                       uint32_t time32;
+                       uint8_t irq;
+                       uint8_t temp;
+                       
+                       atomic time = capturedTime;
+                       radioIrq = FALSE;
+                       irq = readRegister(RF230_IRQ_STATUS);
+
+#ifdef RADIO_DEBUG
+                       // TODO: handle this interrupt
+                       if( irq & RF230_IRQ_TRX_UR )
+                       {
+                               if( call DiagMsg.record() )
+                               {
+                                       call DiagMsg.str("assert ur");
+                                       call DiagMsg.uint16(call RadioAlarm.getNow());
+                                       call DiagMsg.hex8(readRegister(RF230_TRX_STATUS));
+                                       call DiagMsg.hex8(readRegister(RF230_TRX_STATE));
+                                       call DiagMsg.hex8(irq);
+                                       call DiagMsg.uint8(state);
+                                       call DiagMsg.uint8(cmd);
+                                       call DiagMsg.send();
+                               }
+                       }
+#endif
+
+                       if( irq & RF230_IRQ_PLL_LOCK )
+                       {
+                               if( cmd == CMD_TURNON || cmd == CMD_CHANNEL )
+                               {
+                                       ASSERT( state == STATE_TRX_OFF_2_RX_ON );
+
+                                       state = STATE_RX_ON;
+                                       cmd = CMD_SIGNAL_DONE;
+                               }
+                               else if( cmd == CMD_TRANSMIT )
+                               {
+                                       ASSERT( state == STATE_BUSY_TX_2_RX_ON );
+                               }
+                               else
+                                       ASSERT(FALSE);
+                       }
+
+                       if( irq & RF230_IRQ_RX_START )
+                       {
+                               if( cmd == CMD_CCA )
+                               {
+                                       signal RadioCCA.done(FAIL);
+                                       cmd = CMD_NONE;
+                               }
+
+                               if( cmd == CMD_NONE )
+                               {
+                                       ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
+
+                                       // the most likely place for busy channel, with no TRX_END interrupt
+                                       if( irq == RF230_IRQ_RX_START )
+                                       {
+                                               temp = readRegister(RF230_PHY_RSSI) & RF230_RSSI_MASK;
+                                               rssiBusy += temp - (rssiBusy >> 2);
+#ifndef RF230_RSSI_ENERGY
+                                               call PacketRSSI.set(rxMsg, temp);
+                                       }
+                                       else
+                                       {
+                                               call PacketRSSI.clear(rxMsg);
+#endif
+                                       }
+
+                                       /*
+                                        * The timestamp corresponds to the first event which could not
+                                        * have been a PLL_LOCK because then cmd != CMD_NONE, so we must
+                                        * have received a message (and could also have received the 
+                                        * TRX_END interrupt in the mean time, but that is fine. Also,
+                                        * we could not be after a transmission, because then cmd = 
+                                        * CMD_TRANSMIT.
+                                        */
+                                       if( irq == RF230_IRQ_RX_START ) // just to be cautious
+                                       {
+                                               time32 = call LocalTime.get();
+                                               time32 += (int16_t)(time - RX_SFD_DELAY) - (int16_t)(time32);
+                                               call PacketTimeStamp.set(rxMsg, time32);
+                                       }
+                                       else
+                                               call PacketTimeStamp.clear(rxMsg);
+
+                                       cmd = CMD_RECEIVE;
+                               }
+                               else
+                                       ASSERT( cmd == CMD_TURNOFF );
+                       }
+
+                       if( irq & RF230_IRQ_TRX_END )
+                       {
+                               if( cmd == CMD_TRANSMIT )
+                               {
+                                       ASSERT( state == STATE_BUSY_TX_2_RX_ON );
+
+                                       state = STATE_RX_ON;
+                                       cmd = CMD_NONE;
+                                       signal RadioSend.sendDone(SUCCESS);
+
+                                       // TODO: we could have missed a received message
+                                       ASSERT( ! (irq & RF230_IRQ_RX_START) );
+                               }
+                               else if( cmd == CMD_RECEIVE )
+                               {
+                                       ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
+#ifdef RF230_RSSI_ENERGY
+                                       if( irq == RF230_IRQ_TRX_END )
+                                               call PacketRSSI.set(rxMsg, readRegister(RF230_PHY_ED_LEVEL));
+                                       else
+                                               call PacketRSSI.clear(rxMsg);
+#endif
+                                       if( state == STATE_PLL_ON_2_RX_ON )
+                                       {
+                                               ASSERT( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) == RF230_PLL_ON );
+
+                                               writeRegister(RF230_TRX_STATE, RF230_RX_ON);
+                                               state = STATE_RX_ON;
+                                       }
+                                       else
+                                       {
+                                               // the most likely place for clear channel (hope to avoid acks)
+                                               rssiClear += (readRegister(RF230_PHY_RSSI) & RF230_RSSI_MASK) - (rssiClear >> 2);
+                                       }
+
+                                       cmd = CMD_DOWNLOAD;
+                               }
+                               else
+                                       ASSERT(FALSE);
+                       }
+               }
+       }
+
+       default tasklet_async event bool RadioReceive.header(message_t* msg)
+       {
+               return TRUE;
+       }
+
+       default tasklet_async event message_t* RadioReceive.receive(message_t* msg)
+       {
+               return msg;
+       }
+
+/*----------------- TASKLET -----------------*/
+
+       tasklet_async event void Tasklet.run()
+       {
+               if( radioIrq )
+                       serviceRadio();
+
+               if( cmd != CMD_NONE )
+               {
+                       if( cmd == CMD_DOWNLOAD )
+                               downloadMessage();
+                       else if( CMD_TURNOFF <= cmd && cmd <= CMD_TURNON )
+                               changeState();
+                       else if( cmd == CMD_CHANNEL )
+                               changeChannel();
+                       
+                       if( cmd == CMD_SIGNAL_DONE )
+                       {
+                               cmd = CMD_NONE;
+                               signal RadioState.done();
+                       }
+               }
+
+               if( cmd == CMD_NONE && state == STATE_RX_ON && ! radioIrq )
+                       signal RadioSend.ready();
+
+               if( cmd == CMD_NONE )
+                       call SpiResource.release();
+       }
+}
diff --git a/tos/chips/rf2xx/rf212/RF212DriverLayerP.nc b/tos/chips/rf2xx/rf212/RF212DriverLayerP.nc
new file mode 100644 (file)
index 0000000..e594bab
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#include <RF212.h>
+#include <Tasklet.h>
+#include <RadioAssert.h>
+#include <GenericTimeSyncMessage.h>
+#include <RadioConfig.h>
+
+module RF212DriverLayerP
+{
+       provides
+       {
+               interface Init as PlatformInit @exactlyonce();
+               interface Init as SoftwareInit @exactlyonce();
+
+               interface RadioState;
+               interface RadioSend;
+               interface RadioReceive;
+               interface RadioCCA;
+       }
+
+       uses
+       {
+               interface GeneralIO as SELN;
+               interface Resource as SpiResource;
+
+               interface FastSpiByte;
+
+               interface GeneralIO as SLP_TR;
+               interface GeneralIO as RSTN;
+
+               interface GpioCapture as IRQ;
+
+               interface BusyWait<TMicro, uint16_t>;
+
+               interface PacketField<uint8_t> as PacketLinkQuality;
+               interface PacketField<uint8_t> as PacketTransmitPower;
+               interface PacketField<uint8_t> as PacketRSSI;
+               interface PacketField<uint8_t> as PacketTimeSyncOffset;
+
+               interface PacketTimeStamp<TRadio, uint32_t>;
+               interface LocalTime<TRadio>;
+
+               interface RF212DriverConfig;
+               interface Tasklet;
+               interface RadioAlarm;
+
+#ifdef RADIO_DEBUG
+               interface DiagMsg;
+#endif
+       }
+}
+
+implementation
+{
+/*----------------- STATE -----------------*/
+
+       tasklet_norace uint8_t state;
+       enum
+       {
+               STATE_P_ON = 0,
+               STATE_SLEEP = 1,
+               STATE_SLEEP_2_TRX_OFF = 2,
+               STATE_TRX_OFF = 3,
+               STATE_TRX_OFF_2_RX_ON = 4,
+               STATE_RX_ON = 5,
+               STATE_BUSY_TX_2_RX_ON = 6,
+               STATE_PLL_ON_2_RX_ON = 7,
+       };
+
+       tasklet_norace uint8_t cmd;
+       enum
+       {
+               CMD_NONE = 0,                   // the state machine has stopped
+               CMD_TURNOFF = 1,                // goto SLEEP state
+               CMD_STANDBY = 2,                // goto TRX_OFF state
+               CMD_TURNON = 3,                 // goto RX_ON state
+               CMD_TRANSMIT = 4,               // currently transmitting a message
+               CMD_RECEIVE = 5,                // currently receiving a message
+               CMD_CCA = 6,                    // performing clear chanel assesment
+               CMD_CHANNEL = 7,                // changing the channel
+               CMD_SIGNAL_DONE = 8,            // signal the end of the state transition
+               CMD_DOWNLOAD = 9,               // download the received message
+       };
+
+       norace bool radioIrq;
+
+       tasklet_norace uint8_t txPower;
+       tasklet_norace uint8_t channel;
+
+       tasklet_norace message_t* rxMsg;
+       message_t rxMsgBuffer;
+
+       uint16_t capturedTime;  // the current time when the last interrupt has occured
+
+       tasklet_norace uint8_t rssiClear;
+       tasklet_norace uint8_t rssiBusy;
+
+/*----------------- REGISTER -----------------*/
+
+       inline void writeRegister(uint8_t reg, uint8_t value)
+       {
+               ASSERT( call SpiResource.isOwner() );
+               ASSERT( reg == (reg & RF212_CMD_REGISTER_MASK) );
+
+               call SELN.clr();
+               call FastSpiByte.splitWrite(RF212_CMD_REGISTER_WRITE | reg);
+               call FastSpiByte.splitReadWrite(value);
+               call FastSpiByte.splitRead();
+               call SELN.set();
+       }
+
+       inline uint8_t readRegister(uint8_t reg)
+       {
+               ASSERT( call SpiResource.isOwner() );
+               ASSERT( reg == (reg & RF212_CMD_REGISTER_MASK) );
+
+               call SELN.clr();
+               call FastSpiByte.splitWrite(RF212_CMD_REGISTER_READ | reg);
+               call FastSpiByte.splitReadWrite(0);
+               reg = call FastSpiByte.splitRead();
+               call SELN.set();
+
+               return reg;
+       }
+
+/*----------------- ALARM -----------------*/
+
+       enum
+       {
+               SLEEP_WAKEUP_TIME = (uint16_t)(880 * RADIO_ALARM_MICROSEC),
+               CCA_REQUEST_TIME = (uint16_t)(140 * RADIO_ALARM_MICROSEC),
+
+               TX_SFD_DELAY = (uint16_t)(176 * RADIO_ALARM_MICROSEC),
+               RX_SFD_DELAY = (uint16_t)(8 * RADIO_ALARM_MICROSEC),
+       };
+
+       tasklet_async event void RadioAlarm.fired()
+       {
+               if( state == STATE_SLEEP_2_TRX_OFF )
+                       state = STATE_TRX_OFF;
+               else if( cmd == CMD_CCA )
+               {
+                       uint8_t cca;
+
+                       ASSERT( state == STATE_RX_ON );
+
+                       cmd = CMD_NONE;
+                       cca = readRegister(RF212_TRX_STATUS);
+
+                       ASSERT( (cca & RF212_TRX_STATUS_MASK) == RF212_RX_ON );
+
+                       signal RadioCCA.done( (cca & RF212_CCA_DONE) ? ((cca & RF212_CCA_STATUS) ? SUCCESS : EBUSY) : FAIL );
+               }
+               else
+                       ASSERT(FALSE);
+
+               // make sure the rest of the command processing is called
+               call Tasklet.schedule();
+       }
+
+/*----------------- INIT -----------------*/
+
+       command error_t PlatformInit.init()
+       {
+               call SELN.makeOutput();
+               call SELN.set();
+               call SLP_TR.makeOutput();
+               call SLP_TR.clr();
+               call RSTN.makeOutput();
+               call RSTN.set();
+
+               rxMsg = &rxMsgBuffer;
+
+               // these are just good approximates
+               rssiClear = 0;
+               rssiBusy = 90;
+
+               return SUCCESS;
+       }
+
+       command error_t SoftwareInit.init()
+       {
+               // for powering up the radio
+               return call SpiResource.request();
+       }
+
+       void initRadio()
+       {
+               call BusyWait.wait(510);
+
+               call RSTN.clr();
+               call SLP_TR.clr();
+               call BusyWait.wait(6);
+               call RSTN.set();
+
+               writeRegister(RF212_TRX_CTRL_0, RF212_TRX_CTRL_0_VALUE);
+               writeRegister(RF212_TRX_STATE, RF212_TRX_OFF);
+
+               call BusyWait.wait(510);
+
+               writeRegister(RF212_IRQ_MASK, RF212_IRQ_TRX_UR | RF212_IRQ_PLL_LOCK | RF212_IRQ_TRX_END | RF212_IRQ_RX_START);
+               writeRegister(RF212_CCA_THRES, RF212_CCA_THRES_VALUE);
+               writeRegister(RF212_PHY_TX_PWR, RF212_DEF_RFPOWER);
+
+               txPower = RF212_DEF_RFPOWER;
+               channel = call RF212DriverConfig.getDefaultChannel() & RF212_CHANNEL_MASK;
+               writeRegister(RF212_PHY_CC_CCA, RF212_CCA_MODE_VALUE | channel);
+
+               call SLP_TR.set();
+               state = STATE_SLEEP;
+       }
+
+/*----------------- SPI -----------------*/
+
+       event void SpiResource.granted()
+       {
+               call SELN.makeOutput();
+               call SELN.set();
+
+               if( state == STATE_P_ON )
+               {
+                       initRadio();
+                       call SpiResource.release();
+               }
+               else
+                       call Tasklet.schedule();
+       }
+
+       bool isSpiAcquired()
+       {
+               if( call SpiResource.isOwner() )
+                       return TRUE;
+
+               if( call SpiResource.immediateRequest() == SUCCESS )
+               {
+                       call SELN.makeOutput();
+                       call SELN.set();
+
+                       return TRUE;
+               }
+
+               call SpiResource.request();
+               return FALSE;
+       }
+
+/*----------------- CHANNEL -----------------*/
+
+       tasklet_async command uint8_t RadioState.getChannel()
+       {
+               return channel;
+       }
+
+       tasklet_async command error_t RadioState.setChannel(uint8_t c)
+       {
+               c &= RF212_CHANNEL_MASK;
+
+               if( cmd != CMD_NONE )
+                       return EBUSY;
+               else if( channel == c )
+                       return EALREADY;
+
+               channel = c;
+               cmd = CMD_CHANNEL;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+
+       inline void changeChannel()
+       {
+               ASSERT( cmd == CMD_CHANNEL );
+               ASSERT( state == STATE_SLEEP || state == STATE_TRX_OFF || state == STATE_RX_ON );
+
+               if( isSpiAcquired() )
+               {
+                       writeRegister(RF212_PHY_CC_CCA, RF212_CCA_MODE_VALUE | channel);
+
+                       if( state == STATE_RX_ON )
+                               state = STATE_TRX_OFF_2_RX_ON;
+                       else
+                               cmd = CMD_SIGNAL_DONE;
+               }
+       }
+
+/*----------------- TURN ON/OFF -----------------*/
+
+       inline void changeState()
+       {
+               if( (cmd == CMD_STANDBY || cmd == CMD_TURNON)
+                       && state == STATE_SLEEP && call RadioAlarm.isFree() )
+               {
+                       call SLP_TR.clr();
+
+                       call RadioAlarm.wait(SLEEP_WAKEUP_TIME);
+                       state = STATE_SLEEP_2_TRX_OFF;
+               }
+               else if( cmd == CMD_TURNON && state == STATE_TRX_OFF && isSpiAcquired() )
+               {
+                       ASSERT( ! radioIrq );
+
+                       readRegister(RF212_IRQ_STATUS); // clear the interrupt register
+                       call IRQ.captureRisingEdge();
+
+                       // setChannel was ignored in SLEEP because the SPI was not working, so do it here
+                       writeRegister(RF212_PHY_CC_CCA, RF212_CCA_MODE_VALUE | channel);
+
+                       writeRegister(RF212_TRX_STATE, RF212_RX_ON);
+                       state = STATE_TRX_OFF_2_RX_ON;
+               }
+               else if( (cmd == CMD_TURNOFF || cmd == CMD_STANDBY) 
+                       && state == STATE_RX_ON && isSpiAcquired() )
+               {
+                       writeRegister(RF212_TRX_STATE, RF212_FORCE_TRX_OFF);
+
+                       call IRQ.disable();
+                       radioIrq = FALSE;
+
+                       state = STATE_TRX_OFF;
+               }
+
+               if( cmd == CMD_TURNOFF && state == STATE_TRX_OFF )
+               {
+                       call SLP_TR.set();
+                       state = STATE_SLEEP;
+                       cmd = CMD_SIGNAL_DONE;
+               }
+               else if( cmd == CMD_STANDBY && state == STATE_TRX_OFF )
+                       cmd = CMD_SIGNAL_DONE;
+       }
+
+       tasklet_async command error_t RadioState.turnOff()
+       {
+               if( cmd != CMD_NONE )
+                       return EBUSY;
+               else if( state == STATE_SLEEP )
+                       return EALREADY;
+
+               cmd = CMD_TURNOFF;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+       
+       tasklet_async command error_t RadioState.standby()
+       {
+               if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) )
+                       return EBUSY;
+               else if( state == STATE_TRX_OFF )
+                       return EALREADY;
+
+               cmd = CMD_STANDBY;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+
+       tasklet_async command error_t RadioState.turnOn()
+       {
+               if( cmd != CMD_NONE || (state == STATE_SLEEP && ! call RadioAlarm.isFree()) )
+                       return EBUSY;
+               else if( state == STATE_RX_ON )
+                       return EALREADY;
+
+               cmd = CMD_TURNON;
+               call Tasklet.schedule();
+
+               return SUCCESS;
+       }
+
+       default tasklet_async event void RadioState.done() { }
+
+/*----------------- TRANSMIT -----------------*/
+
+       tasklet_async command error_t RadioSend.send(message_t* msg)
+       {
+               uint16_t time;
+               uint8_t length;
+               uint8_t* data;
+               uint8_t header;
+               uint32_t time32;
+               void* timesync;
+
+               if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || radioIrq )
+                       return EBUSY;
+
+               length = call PacketTransmitPower.isSet(msg) ?
+                       call PacketTransmitPower.get(msg) : RF212_DEF_RFPOWER;
+
+               if( length != txPower )
+               {
+                       txPower = length;
+                       writeRegister(RF212_PHY_TX_PWR, txPower);
+               }
+
+               if( call RF212DriverConfig.requiresRssiCca(msg) 
+                               && (readRegister(RF212_PHY_RSSI) & RF212_RSSI_MASK) > ((rssiClear + rssiBusy) >> 3) )
+                       return EBUSY;
+
+               writeRegister(RF212_TRX_STATE, RF212_PLL_ON);
+
+               // do something useful, just to wait a little
+               time32 = call LocalTime.get();
+               timesync = call PacketTimeSyncOffset.isSet(msg) ? msg->data + call PacketTimeSyncOffset.get(msg) : 0;
+
+               // we have missed an incoming message in this short amount of time
+               if( (readRegister(RF212_TRX_STATUS) & RF212_TRX_STATUS_MASK) != RF212_PLL_ON )
+               {
+                       ASSERT( (readRegister(RF212_TRX_STATUS) & RF212_TRX_STATUS_MASK) == RF212_BUSY_RX );
+
+                       state = STATE_PLL_ON_2_RX_ON;
+                       return EBUSY;
+               }
+
+               atomic
+               {
+                       call SLP_TR.set();
+                       time = call RadioAlarm.getNow() + TX_SFD_DELAY;
+               }
+               call SLP_TR.clr();
+
+               ASSERT( ! radioIrq );
+
+               call SELN.clr();
+               call FastSpiByte.splitWrite(RF212_CMD_FRAME_WRITE);
+
+               length = call RF212DriverConfig.getLength(msg);
+               data = call RF212DriverConfig.getPayload(msg);
+
+               // length | data[0] ... data[length-3] | automatically generated FCS
+               call FastSpiByte.splitReadWrite(length);
+
+               // the FCS is atomatically generated (2 bytes)
+               length -= 2;
+
+               header = call RF212DriverConfig.getHeaderLength();
+               if( header > length )
+                       header = length;
+
+               length -= header;
+
+               // first upload the header to gain some time
+               do {
+                       call FastSpiByte.splitReadWrite(*(data++));
+               }
+               while( --header != 0 );
+
+               time32 += (int16_t)(time) - (int16_t)(time32);
+
+               if( timesync != 0 )
+                       *(timesync_relative_t*)timesync = (*(timesync_absolute_t*)timesync) - time32;
+
+               do {
+                       call FastSpiByte.splitReadWrite(*(data++));
+               }
+               while( --length != 0 );
+
+               // wait for the SPI transfer to finish
+               call FastSpiByte.splitRead();
+               call SELN.set();
+
+               /*
+                * There is a very small window (~1 microsecond) when the RF212 went 
+                * into PLL_ON state but was somehow not properly initialized because 
+                * of an incoming message and could not go into BUSY_TX. I think the
+                * radio can even receive a message, and generate a TRX_UR interrupt
+                * because of concurrent access, but that message probably cannot be
+                * recovered.
+                *
+                * TODO: this needs to be verified, and make sure that the chip is 
+                * not locked up in this case.
+                */
+
+               // go back to RX_ON state when finished
+               writeRegister(RF212_TRX_STATE, RF212_RX_ON);
+
+#ifdef RADIO_DEBUG_MESSAGES
+               if( call DiagMsg.record() )
+               {
+                       length = call RF212DriverConfig.getLength(msg);
+
+                       call DiagMsg.str("tx");
+                       call DiagMsg.uint16(time);
+                       call DiagMsg.uint8(length);
+                       call DiagMsg.hex8s(data, length - 2);
+                       call DiagMsg.send();
+               }
+#endif
+
+               if( timesync != 0 )
+                       *(timesync_absolute_t*)timesync = (*(timesync_relative_t*)timesync) + time32;
+
+               call PacketTimeStamp.set(msg, time32);
+
+               // wait for the TRX_END interrupt
+               state = STATE_BUSY_TX_2_RX_ON;
+               cmd = CMD_TRANSMIT;
+
+               return SUCCESS;
+       }
+
+       default tasklet_async event void RadioSend.sendDone(error_t error) { }
+       default tasklet_async event void RadioSend.ready() { }
+
+/*----------------- CCA -----------------*/
+
+       tasklet_async command error_t RadioCCA.request()
+       {
+               if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || ! call RadioAlarm.isFree() )
+                       return EBUSY;
+
+               // see Errata B7 of the datasheet
+               // writeRegister(RF212_TRX_STATE, RF212_PLL_ON);
+               // writeRegister(RF212_TRX_STATE, RF212_RX_ON);
+
+               writeRegister(RF212_PHY_CC_CCA, RF212_CCA_REQUEST | RF212_CCA_MODE_VALUE | channel);
+               call RadioAlarm.wait(CCA_REQUEST_TIME);
+               cmd = CMD_CCA;
+               
+               return SUCCESS;
+       }
+
+       default tasklet_async event void RadioCCA.done(error_t error) { }
+
+/*----------------- RECEIVE -----------------*/
+
+       inline void downloadMessage()
+       {
+               uint8_t length;
+               uint8_t crc;
+
+               call SELN.clr();
+               call FastSpiByte.write(RF212_CMD_FRAME_READ);
+
+               // read the length byte
+               length = call FastSpiByte.write(0);
+
+               // if correct length
+               if( length >= 3 && length <= call RF212DriverConfig.getMaxLength() )
+               {
+                       uint8_t read;
+                       uint8_t* data;
+
+                       // initiate the reading
+                       call FastSpiByte.splitWrite(0);
+
+                       call RF212DriverConfig.setLength(rxMsg, length);
+                       data = call RF212DriverConfig.getPayload(rxMsg);
+                       crc = 0;
+
+                       // we do not store the CRC field
+                       length -= 2;
+
+                       read = call RF212DriverConfig.getHeaderLength();
+                       if( length < read )
+                               read = length;
+
+                       length -= read;
+
+                       do {
+                               *(data++) = call FastSpiByte.splitReadWrite(0);
+                       }
+                       while( --read != 0  );
+
+                       if( signal RadioReceive.header(rxMsg) )
+                       {
+                               while( length-- != 0 )
+                                       *(data++) = call FastSpiByte.splitReadWrite(0);
+
+                               call FastSpiByte.splitReadWrite(0);     // two CRC bytes
+                               call FastSpiByte.splitReadWrite(0);
+
+                               call PacketLinkQuality.set(rxMsg, call FastSpiByte.splitReadWrite(0));
+                               call FastSpiByte.splitReadWrite(0);     // ED
+                               crc = call FastSpiByte.splitRead() & RF212_RX_CRC_VALID;        // RX_STATUS
+                       }
+               }
+
+               call SELN.set();
+               state = STATE_RX_ON;
+
+#ifdef RADIO_DEBUG_MESSAGES
+               if( call DiagMsg.record() )
+               {
+                       length = call RF212DriverConfig.getLength(rxMsg);
+
+                       call DiagMsg.str("rx");
+                       call DiagMsg.uint32(call PacketTimeStamp.isValid(rxMsg) ? call PacketTimeStamp.timestamp(rxMsg) : 0);
+                       call DiagMsg.uint16(call RadioAlarm.getNow());
+                       call DiagMsg.uint8(crc != 0);
+                       call DiagMsg.uint8(length);
+                       call DiagMsg.hex8s(call RF212DriverConfig.getPayload(rxMsg), length - 2);
+                       call DiagMsg.send();
+               }
+#endif
+               
+               cmd = CMD_NONE;
+
+               // signal only if it has passed the CRC check
+               if( crc != 0 )
+                       rxMsg = signal RadioReceive.receive(rxMsg);
+       }
+
+/*----------------- IRQ -----------------*/
+
+       async event void IRQ.captured(uint16_t time)
+       {
+               ASSERT( ! radioIrq );
+
+               atomic
+               {
+                       capturedTime = time;
+                       radioIrq = TRUE;
+               }
+
+               call Tasklet.schedule();
+       }
+
+       void serviceRadio()
+       {
+               if( isSpiAcquired() )
+               {
+                       uint16_t time;
+                       uint32_t time32;
+                       uint8_t irq;
+                       uint8_t temp;
+                       
+                       atomic time = capturedTime;
+                       radioIrq = FALSE;
+                       irq = readRegister(RF212_IRQ_STATUS);
+
+#ifdef RADIO_DEBUG
+                       // TODO: handle this interrupt
+                       if( irq & RF212_IRQ_TRX_UR )
+                       {
+                               if( call DiagMsg.record() )
+                               {
+                                       call DiagMsg.str("assert ur");
+                                       call DiagMsg.uint16(call RadioAlarm.getNow());
+                                       call DiagMsg.hex8(readRegister(RF212_TRX_STATUS));
+                                       call DiagMsg.hex8(readRegister(RF212_TRX_STATE));
+                                       call DiagMsg.hex8(irq);
+                                       call DiagMsg.uint8(state);
+                                       call DiagMsg.uint8(cmd);
+                                       call DiagMsg.send();
+                               }
+                       }
+#endif
+
+                       if( irq & RF212_IRQ_PLL_LOCK )
+                       {
+                               if( cmd == CMD_TURNON || cmd == CMD_CHANNEL )
+                               {
+                                       ASSERT( state == STATE_TRX_OFF_2_RX_ON );
+
+                                       state = STATE_RX_ON;
+                                       cmd = CMD_SIGNAL_DONE;
+                               }
+                               else if( cmd == CMD_TRANSMIT )
+                               {
+                                       ASSERT( state == STATE_BUSY_TX_2_RX_ON );
+                               }
+                               else
+                                       ASSERT(FALSE);
+                       }
+
+                       if( irq & RF212_IRQ_RX_START )
+                       {
+                               if( cmd == CMD_CCA )
+                               {
+                                       signal RadioCCA.done(FAIL);
+                                       cmd = CMD_NONE;
+                               }
+
+                               if( cmd == CMD_NONE )
+                               {
+                                       ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
+
+                                       // the most likely place for busy channel, with no TRX_END interrupt
+                                       if( irq == RF212_IRQ_RX_START )
+                                       {
+                                               temp = readRegister(RF212_PHY_RSSI) & RF212_RSSI_MASK;
+                                               rssiBusy += temp - (rssiBusy >> 2);
+#ifndef RF212_RSSI_ENERGY
+                                               call PacketRSSI.set(rxMsg, temp);
+                                       }
+                                       else
+                                       {
+                                               call PacketRSSI.clear(rxMsg);
+#endif
+                                       }
+
+                                       /*
+                                        * The timestamp corresponds to the first event which could not
+                                        * have been a PLL_LOCK because then cmd != CMD_NONE, so we must
+                                        * have received a message (and could also have received the 
+                                        * TRX_END interrupt in the mean time, but that is fine. Also,
+                                        * we could not be after a transmission, because then cmd = 
+                                        * CMD_TRANSMIT.
+                                        */
+                                       if( irq == RF212_IRQ_RX_START ) // just to be cautious
+                                       {
+                                               time32 = call LocalTime.get();
+                                               time32 += (int16_t)(time - RX_SFD_DELAY) - (int16_t)(time32);
+                                               call PacketTimeStamp.set(rxMsg, time32);
+                                       }
+                                       else
+                                               call PacketTimeStamp.clear(rxMsg);
+
+                                       cmd = CMD_RECEIVE;
+                               }
+                               else
+                                       ASSERT( cmd == CMD_TURNOFF );
+                       }
+
+                       if( irq & RF212_IRQ_TRX_END )
+                       {
+                               if( cmd == CMD_TRANSMIT )
+                               {
+                                       ASSERT( state == STATE_BUSY_TX_2_RX_ON );
+
+                                       state = STATE_RX_ON;
+                                       cmd = CMD_NONE;
+                                       signal RadioSend.sendDone(SUCCESS);
+
+                                       // TODO: we could have missed a received message
+                                       ASSERT( ! (irq & RF212_IRQ_RX_START) );
+                               }
+                               else if( cmd == CMD_RECEIVE )
+                               {
+                                       ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
+#ifdef RF212_RSSI_ENERGY
+                                       if( irq == RF212_IRQ_TRX_END )
+                                               call PacketRSSI.set(rxMsg, readRegister(RF212_PHY_ED_LEVEL));
+                                       else
+                                               call PacketRSSI.clear(rxMsg);
+#endif
+                                       if( state == STATE_PLL_ON_2_RX_ON )
+                                       {
+                                               ASSERT( (readRegister(RF212_TRX_STATUS) & RF212_TRX_STATUS_MASK) == RF212_PLL_ON );
+
+                                               writeRegister(RF212_TRX_STATE, RF212_RX_ON);
+                                               state = STATE_RX_ON;
+                                       }
+                                       else
+                                       {
+                                               // the most likely place for clear channel (hope to avoid acks)
+                                               rssiClear += (readRegister(RF212_PHY_RSSI) & RF212_RSSI_MASK) - (rssiClear >> 2);
+                                       }
+
+                                       cmd = CMD_DOWNLOAD;
+                               }
+                               else
+                                       ASSERT(FALSE);
+                       }
+               }
+       }
+
+       default tasklet_async event bool RadioReceive.header(message_t* msg)
+       {
+               return TRUE;
+       }
+
+       default tasklet_async event message_t* RadioReceive.receive(message_t* msg)
+       {
+               return msg;
+       }
+
+/*----------------- TASKLET -----------------*/
+
+       tasklet_async event void Tasklet.run()
+       {
+               if( radioIrq )
+                       serviceRadio();
+
+               if( cmd != CMD_NONE )
+               {
+                       if( cmd == CMD_DOWNLOAD )
+                               downloadMessage();
+                       else if( CMD_TURNOFF <= cmd && cmd <= CMD_TURNON )
+                               changeState();
+                       else if( cmd == CMD_CHANNEL )
+                               changeChannel();
+                       
+                       if( cmd == CMD_SIGNAL_DONE )
+                       {
+                               cmd = CMD_NONE;
+                               signal RadioState.done();
+                       }
+               }
+
+               if( cmd == CMD_NONE && state == STATE_RX_ON && ! radioIrq )
+                       signal RadioSend.ready();
+
+               if( cmd == CMD_NONE )
+                       call SpiResource.release();
+       }
+}
diff --git a/tos/chips/rf2xx/rf212/RF212Packet.h b/tos/chips/rf2xx/rf212/RF212Packet.h
new file mode 100644 (file)
index 0000000..5b7a68b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#ifndef __RF212PACKET_H__
+#define __RF212PACKET_H__
+
+#include <IEEE154Packet.h>
+
+typedef ieee154_header_t rf212packet_header_t;
+
+typedef nx_struct rf212packet_footer_t
+{
+       // the time stamp is not recorded here, time stamped messaged cannot have max length
+} rf212packet_footer_t;
+
+typedef struct rf212packet_metadata_t
+{
+       uint8_t flags;
+       uint8_t lqi;
+       uint8_t power;                          // shared between TXPOWER and RSSI
+#ifdef LOW_POWER_LISTENING
+       uint16_t lpl_sleepint;
+#endif
+       uint32_t timestamp;
+} rf212packet_metadata_t;
+
+enum rf212packet_metadata_flags
+{
+       RF212PACKET_WAS_ACKED = 0x01,           // PacketAcknowledgements
+       RF212PACKET_TIMESTAMP = 0x02,           // PacketTimeStamp
+       RF212PACKET_TXPOWER = 0x04,             // PacketTransmitPower
+       RF212PACKET_RSSI = 0x08,                // PacketRSSI
+       RF212PACKET_TIMESYNC = 0x10,            // PacketTimeSync (update timesync_footer)
+       RF212PACKET_LPL_SLEEPINT = 0x20,        // LowPowerListening
+
+       RF212PACKET_CLEAR_METADATA = 0x00,
+};
+
+#endif//__RF212PACKET_H__
diff --git a/tos/chips/rf2xx/rf212/RF212PacketC.nc b/tos/chips/rf2xx/rf212/RF212PacketC.nc
new file mode 100644 (file)
index 0000000..68eb9b2
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+configuration RF212PacketC
+{
+       provides
+       {
+               interface Packet;
+               interface AMPacket;
+               interface PacketAcknowledgements;
+               interface PacketField<uint8_t> as PacketLinkQuality;
+               interface PacketField<uint8_t> as PacketTransmitPower;
+               interface PacketField<uint8_t> as PacketRSSI;
+               interface PacketField<uint16_t> as PacketSleepInterval;
+               interface PacketField<uint8_t> as PacketTimeSyncOffset;
+
+               interface PacketTimeStamp<TRadio, uint32_t> as PacketTimeStampRadio;
+               interface PacketTimeStamp<TMilli, uint32_t> as PacketTimeStampMilli;
+       }
+}
+
+implementation
+{
+       components RF212PacketP, IEEE154PacketC, LocalTimeMicroC, LocalTimeMilliC;
+
+       RF212PacketP.IEEE154Packet -> IEEE154PacketC;
+       RF212PacketP.LocalTimeRadio -> LocalTimeMicroC;
+       RF212PacketP.LocalTimeMilli -> LocalTimeMilliC;
+
+       Packet = RF212PacketP;
+       AMPacket = IEEE154PacketC;
+
+       PacketAcknowledgements  = RF212PacketP;
+       PacketLinkQuality       = RF212PacketP.PacketLinkQuality;
+       PacketTransmitPower     = RF212PacketP.PacketTransmitPower;
+       PacketRSSI              = RF212PacketP.PacketRSSI;
+       PacketSleepInterval     = RF212PacketP.PacketSleepInterval;
+       PacketTimeSyncOffset    = RF212PacketP.PacketTimeSyncOffset;
+
+       PacketTimeStampRadio    = RF212PacketP;
+       PacketTimeStampMilli    = RF212PacketP;
+}
diff --git a/tos/chips/rf2xx/rf212/RF212PacketP.nc b/tos/chips/rf2xx/rf212/RF212PacketP.nc
new file mode 100644 (file)
index 0000000..0fb8cea
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2007, Vanderbilt University
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ * 
+ * IN NO EVENT SHALL THE VANDERBILT UNIVERSITY BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE VANDERBILT
+ * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * THE VANDERBILT UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE VANDERBILT UNIVERSITY HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Author: Miklos Maroti
+ */
+
+#include <RF212Packet.h>
+#include <GenericTimeSyncMessage.h>
+#include <RadioConfig.h>
+
+module RF212PacketP
+{
+       provides
+       {
+               interface PacketAcknowledgements;
+               interface Packet;
+               interface PacketField<uint8_t> as PacketLinkQuality;
+               interface PacketField<uint8_t> as PacketTransmitPower;
+               interface PacketField<uint8_t> as PacketRSSI;
+               interface PacketField<uint16_t> as PacketSleepInterval;
+               interface PacketField<uint8_t> as PacketTimeSyncOffset;
+
+               interface PacketTimeStamp<TRadio, uint32_t> as PacketTimeStampRadio;
+               interface PacketTimeStamp<TMilli, uint32_t> as PacketTimeStampMilli;
+       }
+
+       uses
+       {
+               interface IEEE154Packet;
+
+               interface LocalTime<TRadio> as LocalTimeRadio;
+               interface LocalTime<TMilli> as LocalTimeMilli;
+       }
+}
+
+implementation
+{
+       enum
+       {
+               PACKET_LENGTH_INCREASE = 
+                       sizeof(rf212packet_header_t) - 1        // the 8-bit length field is not counted
+                       + sizeof(ieee154_footer_t),             // the CRC is not stored in memory
+       };
+
+       inline rf212packet_metadata_t* getMeta(message_t* msg)
+       {
+               return (rf212packet_metadata_t*)(msg->metadata);
+       }
+
+/*----------------- Packet -----------------*/
+
+       command void Packet.clear(message_t* msg) 
+       {
+               call IEEE154Packet.createDataFrame(msg);
+
+               getMeta(msg)->flags = RF212PACKET_CLEAR_METADATA;
+       }
+
+       inline command void Packet.setPayloadLength(message_t* msg, uint8_t len) 
+       {
+               call IEEE154Packet.setLength(msg, len + PACKET_LENGTH_INCREASE);
+       }
+
+       inline command uint8_t Packet.payloadLength(message_t* msg) 
+       {
+               return call IEEE154Packet.getLength(msg) - PACKET_LENGTH_INCREASE;
+       }
+
+       inline command uint8_t Packet.maxPayloadLength()
+       {
+               return TOSH_DATA_LENGTH;
+       }
+
+       command void* Packet.getPayload(message_t* msg, uint8_t len)
+       {
+               if( len > TOSH_DATA_LENGTH )
+                       return NULL;
+
+               return msg->data;
+       }
+
+/*----------------- PacketAcknowledgements -----------------*/
+
+       async command error_t PacketAcknowledgements.requestAck(message_t* msg)
+       {
+               call IEEE154Packet.setAckRequired(msg, TRUE);
+
+               return SUCCESS;
+       }
+
+       async command error_t PacketAcknowledgements.noAck(message_t* msg)
+       {
+               call IEEE154Packet.setAckRequired(msg, FALSE);
+
+               return SUCCESS;
+       }
+
+       async command bool PacketAcknowledgements.wasAcked(message_t* msg)
+       {
+               return getMeta(msg)->flags & RF212PACKET_WAS_ACKED;
+       }
+
+/*----------------- PacketLinkQuality -----------------*/
+
+       async command bool PacketLinkQuality.isSet(message_t* msg)
+       {
+               return TRUE;
+       }
+
+       async command uint8_t PacketLinkQuality.get(message_t* msg)
+       {
+               return getMeta(msg)->lqi;
+       }
+
+       async command void PacketLinkQuality.clear(message_t* msg)
+       {
+       }
+
+       async command void PacketLinkQuality.set(message_t* msg, uint8_t value)
+       {
+               getMeta(msg)->lqi = value;
+       }
+
+/*----------------- PacketTimeStampRadio -----------------*/
+
+       async command bool PacketTimeStampRadio.isValid(message_t* msg)
+       {
+               return getMeta(msg)->flags & RF212PACKET_TIMESTAMP;
+       }
+
+       async command uint32_t PacketTimeStampRadio.timestamp(message_t* msg)
+       {
+               return getMeta(msg)->timestamp;
+       }
+
+       async command void PacketTimeStampRadio.clear(message_t* msg)
+       {
+               getMeta(msg)->flags &= ~RF212PACKET_TIMESTAMP;
+       }
+
+       async command void PacketTimeStampRadio.set(message_t* msg, uint32_t value)
+       {
+               getMeta(msg)->flags |= RF212PACKET_TIMESTAMP;
+               getMeta(msg)->timestamp = value;
+       }
+
+/*----------------- PacketTimeStampMilli -----------------*/
+
+       async command bool PacketTimeStampMilli.isValid(message_t* msg)
+       {
+               return call PacketTimeStampRadio.isValid(msg);
+       }
+
+       async command uint32_t PacketTimeStampMilli.timestamp(message_t* msg)
+       {
+               int32_t offset = call PacketTimeStampRadio.timestamp(msg) - call LocalTimeRadio.get();
+
+               return (offset >> RADIO_ALARM_MILLI_EXP) + call LocalTimeMilli.get();
+       }
+
+       async command void PacketTimeStampMilli.clear(message_t* msg)
+       {
+               call PacketTimeStampRadio.clear(msg);
+       }
+
+       async command void PacketTimeStampMilli.set(message_t* msg, uint32_t value)
+       {
+               int32_t offset = (value - call LocalTimeMilli.get()) << RADIO_ALARM_MILLI_EXP;
+
+               call PacketTimeStampRadio.set(msg, offset + call LocalTimeRadio.get());
+       }
+
+/*----------------- PacketTransmitPower -----------------*/
+
+       async command bool PacketTransmitPower.isSet(message_t* msg)
+       {
+               return getMeta(msg)->flags & RF212PACKET_TXPOWER;
+       }
+
+       async command uint8_t PacketTransmitPower.get(message_t* msg)
+       {
+               return getMeta(msg)->power;
+       }
+
+       async command void PacketTransmitPower.clear(message_t* msg)
+       {
+               getMeta(msg)->flags &= ~RF212PACKET_TXPOWER;
+       }
+
+       async command void PacketTransmitPower.set(message_t* msg, uint8_t value)
+       {
+               getMeta(msg)->flags &= ~RF212PACKET_RSSI;
+               getMeta(msg)->flags |= RF212PACKET_TXPOWER;
+               getMeta(msg)->power = value;
+       }
+
+/*----------------- PacketRSSI -----------------*/
+
+       async command bool PacketRSSI.isSet(message_t* msg)
+       {
+               return getMeta(msg)->flags & RF212PACKET_RSSI;
+       }
+
+       async command uint8_t PacketRSSI.get(message_t* msg)
+       {
+               return getMeta(msg)->power;
+       }
+
+       async command void PacketRSSI.clear(message_t* msg)
+       {
+               getMeta(msg)->flags &= ~RF212PACKET_RSSI;
+       }
+
+       async command void PacketRSSI.set(message_t* msg, uint8_t value)
+       {
+               getMeta(msg)->flags &= ~RF212PACKET_TXPOWER;
+               getMeta(msg)->flags |= RF212PACKET_RSSI;
+               getMeta(msg)->power = value;
+       }
+
+/*----------------- PacketTimeSyncOffset -----------------*/
+
+       async command bool PacketTimeSyncOffset.isSet(message_t* msg)
+       {
+               return getMeta(msg)->flags & RF212PACKET_TIMESYNC;
+       }
+
+       async command uint8_t PacketTimeSyncOffset.get(message_t* msg)
+       {
+               return call IEEE154Packet.getLength(msg) - PACKET_LENGTH_INCREASE - sizeof(timesync_absolute_t);
+       }
+
+       async command void PacketTimeSyncOffset.clear(message_t* msg)
+       {
+               getMeta(msg)->flags &= ~RF212PACKET_TIMESYNC;
+       }
+
+       async command void PacketTimeSyncOffset.set(message_t* msg, uint8_t value)
+       {
+               // the value is ignored, the offset always points to the timesync footer at the end of the payload
+               getMeta(msg)->flags |= RF212PACKET_TIMESYNC;
+       }
+
+/*----------------- PacketSleepInterval -----------------*/
+
+       async command bool PacketSleepInterval.isSet(message_t* msg)
+       {
+               return getMeta(msg)->flags & RF212PACKET_LPL_SLEEPINT;
+       }
+
+       async command uint16_t PacketSleepInterval.get(message_t* msg)
+       {
+#ifdef LOW_POWER_LISTENING
+               return getMeta(msg)->lpl_sleepint;
+#else
+               return 0;
+#endif
+       }
+
+       async command void PacketSleepInterval.clear(message_t* msg)
+       {
+               getMeta(msg)->flags &= ~RF212PACKET_LPL_SLEEPINT;
+       }
+
+       async command void PacketSleepInterval.set(message_t* msg, uint16_t value)
+       {
+               getMeta(msg)->flags |= RF212PACKET_LPL_SLEEPINT;
+
+#ifdef LOW_POWER_LISTENING
+               getMeta(msg)->lpl_sleepint = value;
+#endif
+       }
+}