+++ /dev/null
-/*
- * 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 __DEFAULTMAC_H__
-#define __DEFAULTMAC_H__
-
-#include <IEEE154Packet.h>
-
-typedef ieee154_header_t defaultmac_header_t;
-
-typedef nx_struct defaultmac_metadata_t
-{
- nx_uint8_t flags;
- nx_uint8_t lqi;
- nx_uint16_t timestamp;
-} defaultmac_metadata_t;
-
-enum defaultmac_metadata_flags
-{
- DEFAULTMAC_WAS_ACKED = 0x01,
- DEFAULTMAC_SCHEDULED_TX = 0x02,
-};
-
-/* This is the default value of the TX_PWR field of the PHY_TX_PWR register. */
-#ifndef RF230_DEF_RFPOWER
-#define RF230_DEF_RFPOWER 0
-#endif
-
-/* This is the default value of the CHANNEL field of the PHY_CC_CCA register. */
-#ifndef RF230_DEF_CHANNEL
-#define RF230_DEF_CHANNEL 11
-#endif
-
-#endif//__DEFAULTMAC_H__
interface PacketField<uint8_t> as PacketLinkQuality;
interface PacketTimeStamp<TRF230, uint16_t>;
- interface PacketTimeSynch<TRF230, uint16_t>;
}
}
PacketAcknowledgements = DefaultPacketC;
PacketLinkQuality = DefaultPacketC.PacketLinkQuality;
PacketTimeStamp = DefaultPacketC.PacketTimeStamp;
- PacketTimeSynch = DefaultPacketC.PacketTimeSynch;
components ActiveMessageLayerC;
components MessageBufferLayerC;
RF230LayerC.RF230Config -> DefaultMacP;
RF230LayerC.PacketLinkQuality -> DefaultPacketC.PacketLinkQuality;
RF230LayerC.PacketTransmitPower -> DefaultPacketC.PacketTransmitPower;
- RF230LayerC.PacketTimeStamping -> DefaultPacketC.PacketTimeStamping;
- RF230LayerC.PacketTimeSynchron -> DefaultPacketC.PacketTimeSynchron;
+ RF230LayerC.PacketTimeStamp -> DefaultPacketC.PacketTimeStamp;
}
DEFPACKET_CLEAR_METADATA = 0x00,
};
-typedef nx_struct defpacket_footer_t
-{
- nx_uint16_t timeoffset;
-} defpacket_footer_t;
-
-enum defpacket_footer_enum
-{
- // just to signal missing time offsets
- DEFPACKET_INVALID_TIMEOFFSET = 0x7317,
-};
-
#endif//__DEFAULTPACKET_H__
interface PacketAcknowledgements;
interface PacketField<uint8_t> as PacketLinkQuality;
interface PacketField<uint8_t> as PacketTransmitPower;
- interface PacketField<uint16_t> as PacketTimeStamping;
- interface PacketField<uint16_t> as PacketTimeSynchron;
interface PacketTimeStamp<TRF230, uint16_t>;
- interface PacketTimeSynch<TRF230, uint16_t>;
}
}
PacketAcknowledgements = DefaultPacketP;
PacketLinkQuality = DefaultPacketP.PacketLinkQuality;
PacketTransmitPower = DefaultPacketP.PacketTransmitPower;
- PacketTimeStamping = DefaultPacketP.PacketTimeStamping;
- PacketTimeSynchron = DefaultPacketP.PacketTimeSynchron;
-
PacketTimeStamp = DefaultPacketP.PacketTimeStamp;
- PacketTimeSynch = DefaultPacketP.PacketTimeSynch;
}
interface Packet;
interface PacketField<uint8_t> as PacketLinkQuality;
interface PacketField<uint8_t> as PacketTransmitPower;
- interface PacketField<uint16_t> as PacketTimeStamping;
- interface PacketField<uint16_t> as PacketTimeSynchron;
interface PacketTimeStamp<TRF230, uint16_t>;
- interface PacketTimeSynch<TRF230, uint16_t>;
}
uses
implementation
{
-/*----------------- Async Packet -----------------*/
-
-#define PACKET_OVERHEAD ((sizeof(ieee154_header_t) - 1) + sizeof(defpacket_footer_t) + sizeof(ieee154_footer_t))
-
- // async Packet.payloadLength
- inline uint8_t getPayloadLength(message_t* msg)
- {
- // sizeof(ieee154_header_t) - 1 : the ieee154 header minus the length field
- // sizeof(defpacket_footer_t) : footer containing the embedded time offset
- // sizeof(ieee154_footer_t) : the size of the CRC (not transmitted)
-
- return call IEEE154Packet.getLength(msg) - PACKET_OVERHEAD;
- }
-
- // async Pakcet.maxPayloadLength
- inline uint8_t getMaxPayloadLength()
+ enum
{
- return TOSH_DATA_LENGTH;
- }
-
-/*----------------- Accessors -----------------*/
+ PACKET_LENGTH_INCREASE =
+ sizeof(defpacket_header_t) - 1 // the 8-bit length field is not counted
+ + sizeof(ieee154_footer_t), // the CRC is not stored in memory
+ };
inline defpacket_metadata_t* getMeta(message_t* msg)
{
return (defpacket_metadata_t*)(msg->metadata);
}
- inline defpacket_footer_t* getFooter(message_t* msg)
- {
- return (defpacket_footer_t*)(msg->data + getPayloadLength(msg));
- }
-
/*----------------- Packet -----------------*/
command void Packet.clear(message_t* msg)
getMeta(msg)->flags = DEFPACKET_CLEAR_METADATA;
}
-
+
inline command void Packet.setPayloadLength(message_t* msg, uint8_t len)
{
- call IEEE154Packet.setLength(msg, len + PACKET_OVERHEAD);
+ call IEEE154Packet.setLength(msg, len + PACKET_LENGTH_INCREASE);
}
-
+
+ // TODO: make Packet.payloadLength async
inline command uint8_t Packet.payloadLength(message_t* msg)
{
- return getPayloadLength(msg);
+ return call IEEE154Packet.getLength(msg) - PACKET_LENGTH_INCREASE;
}
-
+
+ // TODO: make Packet.maxPayloadLength async
inline command uint8_t Packet.maxPayloadLength()
{
- return getMaxPayloadLength();
+ return TOSH_DATA_LENGTH;
}
-
+
command void* Packet.getPayload(message_t* msg, uint8_t len)
{
if( len > TOSH_DATA_LENGTH )
/*----------------- PacketTimeStamp -----------------*/
- async command bool PacketTimeStamping.isSet(message_t* msg)
+ async command bool PacketTimeStamp.isSet(message_t* msg)
{
return getMeta(msg)->flags & DEFPACKET_TIMESTAMP;
}
- async command uint16_t PacketTimeStamping.get(message_t* msg)
+ async command uint16_t PacketTimeStamp.get(message_t* msg)
{
return getMeta(msg)->timestamp;
}
- async command void PacketTimeStamping.clear(message_t* msg)
+ async command void PacketTimeStamp.clear(message_t* msg)
{
getMeta(msg)->flags &= ~DEFPACKET_TIMESTAMP;
}
- async command void PacketTimeStamping.set(message_t* msg, uint16_t value)
+ async command void PacketTimeStamp.set(message_t* msg, uint16_t value)
{
getMeta(msg)->flags |= DEFPACKET_TIMESTAMP;
getMeta(msg)->timestamp = value;
}
- inline async command bool PacketTimeStamp.isSet(message_t* msg)
- {
- return call PacketTimeStamping.isSet(msg);
- }
-
- inline async command uint16_t PacketTimeStamp.get(message_t* msg)
- {
- return call PacketTimeStamping.get(msg);
- }
-
- inline async command void PacketTimeStamp.clear(message_t* msg)
- {
- call PacketTimeStamping.clear(msg);
- }
-
- inline async command void PacketTimeStamp.set(message_t* msg, uint16_t value)
- {
- call PacketTimeStamping.set(msg, value);
- }
-
-/*----------------- PacketTimeSynch -----------------*/
-
- async command bool PacketTimeSynchron.isSet(message_t* msg)
- {
- // just sanity check if the length is not initialized
- if( getPayloadLength(msg) > getMaxPayloadLength() )
- return FALSE;
-
- return getFooter(msg)->timeoffset != DEFPACKET_INVALID_TIMEOFFSET;
- }
-
- async command uint16_t PacketTimeSynchron.get(message_t* msg)
- {
- return getFooter(msg)->timeoffset;
- }
-
- async command void PacketTimeSynchron.clear(message_t* msg)
- {
- // just sanity check if the length is not initialized
- if( getPayloadLength(msg) <= getMaxPayloadLength() )
- getFooter(msg)->timeoffset = DEFPACKET_INVALID_TIMEOFFSET;
- }
-
- async command void PacketTimeSynchron.set(message_t* msg, uint16_t value)
- {
- if( getPayloadLength(msg) > getMaxPayloadLength() )
- return;
-
- if( value == DEFPACKET_INVALID_TIMEOFFSET )
- ++value;
-
- getFooter(msg)->timeoffset = value;
- }
-
- inline async command bool PacketTimeSynch.isSet(message_t* msg)
- {
- return call PacketTimeSynchron.isSet(msg);
- }
-
- inline async command uint16_t PacketTimeSynch.get(message_t* msg)
- {
- return call PacketTimeSynchron.get(msg);
- }
-
- inline async command void PacketTimeSynch.clear(message_t* msg)
- {
- call PacketTimeSynchron.clear(msg);
- }
-
- inline async command void PacketTimeSynch.set(message_t* msg, uint16_t value)
- {
- call PacketTimeSynchron.set(msg, value);
- }
-
/*----------------- Global fields -----------------*/
uint8_t flags;
--- /dev/null
+/*
+ * 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
+ */
+
+interface PacketLastTouch
+{
+ /**
+ * Requests the touch event to be called back just before the message
+ * transmission starts.
+ */
+ async command void request(message_t* msg);
+
+ /**
+ * Cancels any pending requests.
+ */
+ async command void cancel(message_t* msg);
+
+ /**
+ * This event is called by the MAC layer when the tranmission of the
+ * message starts (the SFD byte is already transmitted and the packet
+ * is already time stamped). In this method the packet payload can be
+ * updated. This method MUST do absolutely minimal processing, and
+ * should complete in 1-2 microseconds.
+ */
+ async event void touch(message_t* msg);
+}
interface RF230Config;
interface PacketField<uint8_t> as PacketLinkQuality;
interface PacketField<uint8_t> as PacketTransmitPower;
- interface PacketField<uint16_t> as PacketTimeStamping;
- interface PacketField<uint16_t> as PacketTimeSynchron;
+ interface PacketTimeStamp<TRF230, uint16_t>;
}
}
RF230Config = RF230LayerP;
PacketLinkQuality = RF230LayerP.PacketLinkQuality;
PacketTransmitPower = RF230LayerP.PacketTransmitPower;
- PacketTimeStamping = RF230LayerP.PacketTimeStamping;
- PacketTimeSynchron = RF230LayerP.PacketTimeSynchron;
+ PacketTimeStamp = RF230LayerP.PacketTimeStamp;
RF230LayerP.RadioAlarm -> RadioAlarmC.RadioAlarm[unique("RadioAlarm")];
RadioAlarmC.Alarm -> HplRF230C.Alarm;
interface RF230Config;
interface PacketField<uint8_t> as PacketLinkQuality;
- interface PacketField<uint16_t> as PacketTimeStamping;
- interface PacketField<uint16_t> as PacketTimeSynchron;
interface PacketField<uint8_t> as PacketTransmitPower;
+ interface PacketTimeStamp<TRF230, uint16_t>;
interface Tasklet;
interface RadioAlarm;
// the FCS is atomatically generated
length -= 2;
- // calculate and embed the time offset
- if( call PacketTimeSynchron.isSet(msg) )
- call PacketTimeSynchron.set(msg, call PacketTimeSynchron.get(msg) - time);
-
do {
call HplRF230.spiSplitReadWrite(*(data++));
}
return FAIL;
}
- // TODO: be nicer for retransmissions
- // clear the embedded time stamp field
- call PacketTimeSynchron.clear(msg);
-
- call PacketTimeStamping.set(msg, time);
+ call PacketTimeStamp.set(msg, time);
// wait for the TRX_END interrupt
state = STATE_BUSY_TX_2_RX_ON;
state = STATE_RX_ON;
cmd = CMD_NONE;
- // we need a correct time stamp of the message
- if( call PacketTimeSynchron.isSet(rxMsg) && call PacketTimeStamping.isSet(rxMsg) )
- call PacketTimeSynchron.set(rxMsg, call PacketTimeSynchron.get(rxMsg) + call PacketTimeStamping.get(rxMsg));
-
// signal only if it has passed the CRC check
if( crc == 0 )
rxMsg = signal RadioReceive.receive(rxMsg);
* CMD_TRANSMIT.
*/
if( irq == RF230_IRQ_RX_START ) // just to be cautious
- call PacketTimeStamping.set(rxMsg, time - RX_SFD_DELAY);
+ call PacketTimeStamp.set(rxMsg, time - RX_SFD_DELAY);
else
- call PacketTimeStamping.clear(rxMsg);
+ call PacketTimeStamp.clear(rxMsg);
cmd = CMD_RECEIVE;
}
--- /dev/null
+/*
+ * 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 <Timer.h>
+#include <AM.h>
+
+configuration TimeSyncMessageC
+{
+ provides
+ {
+ interface TimeSyncSend<TMicro> as TimeSyncSendMicro[am_id_t id];
+ interface TimeSyncPacket<TMicro> as TimeSyncPacketMicro;
+ interface LocalTime<TMicro> as LocalTimeMicro;
+
+ interface TimeSyncSend<TMilli> as TimeSyncSendMilli[am_id_t id];
+ interface TimeSyncPacket<TMilli> as TimeSyncPacketMilli;
+ interface LocalTime<TMilli> as LocalTimeMilli;
+
+ interface SplitControl;
+ interface Receive[uint8_t id];
+ interface Receive as Snoop[am_id_t id];
+ interface Packet;
+ interface AMPacket;
+ interface PacketAcknowledgements;
+ }
+}
+
+implementation
+{
+ components TimeSyncMessageP, ActiveMessageC, LocalTimeMilliC;
+
+ TimeSyncSendMicro = TimeSyncMessageP;
+ TimeSyncPacketMicro = TimeSyncMessageP;
+ LocalTimeMicro = ActiveMessageC;
+
+ TimeSyncSendMilli = TimeSyncMessageP;
+ TimeSyncPacketMilli = TimeSyncMessageP;
+ LocalTimeMilli = LocalTimeMilliC;
+
+ Packet = TimeSyncMessageP;
+ TimeSyncMessageP.SubSend -> ActiveMessageC.AMSend;
+ TimeSyncMessageP.SubPacket -> ActiveMessageC.Packet;
+
+ TimeSyncMessageP.LocalTimeMilli -> LocalTimeMilliC;
+
+ SplitControl = ActiveMessageC;
+ Receive = ActiveMessageC.Receive;
+ Snoop = ActiveMessageC.Snoop;
+ AMPacket = ActiveMessageC;
+ PacketAcknowledgements = ActiveMessageC;
+}
--- /dev/null
+/*
+ * 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
+ */
+
+module TimeSyncMessageP
+{
+ provides
+ {
+ interface TimeSyncSend<TMicro> as TimeSyncSendMicro[uint8_t id];
+ interface TimeSyncSend<TMilli> as TimeSyncSendMilli[uint8_t id];
+ interface Packet;
+ interface TimeSyncPacket<TMicro> as TimeSyncPacketMicro;
+ interface TimeSyncPacket<TMilli> as TimeSyncPacketMilli;
+ }
+
+ uses
+ {
+ interface AMSend as SubSend[uint8_t id];
+ interface Packet as SubPacket;
+ interface PacketTimeStamp<TMicro,uint32_t>;
+ interface PacketLastTouch;
+
+ interface LocalTime<TMicro> as LocalTimeMicro;
+ interface LocalTime<TMilli> as LocalTimeMilli;
+ }
+}
+
+implementation
+{
+/*----------------- Packet -----------------*/
+
+ typedef nx_struct timesync_footer_t
+ {
+ nx_uint32_t time_offset; // in micorsec
+ } timesync_footer_t;
+
+ typedef struct timesync_local_t
+ {
+ uint32_t event_time; // in microsec
+ } timesync_local_t;
+
+ inline timesync_footer_t* getFooter(message_t* msg)
+ {
+ return (timesync_footer_t*)(msg->data + call SubPacket.payloadLength(msg) - sizeof(timesync_footer_t));
+ }
+
+ inline timesync_local_t* getLocal(message_t* msg)
+ {
+ return (timesync_local_t*)(msg->data + call SubPacket.maxPayloadLength() - sizeof(timesync_local_t));
+ }
+
+ command void Packet.clear(message_t* msg)
+ {
+ call SubPacket.clear(msg);
+ call PacketLastTouch.cancel(msg); // TODO: check if we need to do this
+ }
+
+ command void Packet.setPayloadLength(message_t* msg, uint8_t len)
+ {
+ call SubPacket.setPayloadLength(msg, len + sizeof(timesync_footer_t));
+ }
+
+ command uint8_t Packet.payloadLength(message_t* msg)
+ {
+ return call SubPacket.payloadLength(msg) - sizeof(timesync_footer_t);
+ }
+
+ command uint8_t Packet.maxPayloadLength()
+ {
+ return call SubPacket.maxPayloadLength() - sizeof(timesync_footer_t) - sizeof(timesync_local_t);
+ }
+
+ command void* Packet.getPayload(message_t* msg, uint8_t len)
+ {
+ return call SubPacket.getPayload(msg, len + sizeof(timesync_footer_t) + sizeof(timesync_local_t));
+ }
+
+/*----------------- TimeSyncSendMicro -----------------*/
+
+ command error_t TimeSyncSendMicro.send[am_id_t id](uint32_t event_time, am_addr_t addr, message_t* msg, uint8_t len)
+ {
+ timesync_local_t* local = getLocal(msg);
+
+ local->event_time = event_time;
+
+ call PacketLastTouch.request(msg);
+
+ return call SubSend.send[id](addr, msg, len);
+ }
+
+ command error_t TimeSyncSendMicro.cancel[am_id_t id](message_t* msg)
+ {
+ call PacketLastTouch.cancel(msg);
+ return call SubSend.cancel[id](msg);
+ }
+
+ default event void TimeSyncSendMicro.sendDone[am_id_t id](message_t* msg, error_t error)
+ {
+ }
+
+ command uint8_t TimeSyncSendMicro.maxPayloadLength[am_id_t id]()
+ {
+ return call SubSend.maxPayloadLength[id]() - sizeof(timesync_footer_t);
+ }
+
+ command void* TimeSyncSendMicro.getPayload[am_id_t id](message_t* msg, uint8_t len)
+ {
+ return call SubSend.getPayload[id](msg, len + sizeof(timesync_footer_t));
+ }
+
+/*----------------- TimeSyncSendMilli -----------------*/
+
+ command error_t TimeSyncSendMilli.send[am_id_t id](uint32_t event_time, am_addr_t addr, message_t* msg, uint8_t len)
+ {
+ timesync_local_t* local = getLocal(msg);
+
+ // compute elapsed time in millisecond
+ event_time = ((event_time - call LocalTimeMilli.get()) << 10) + call LocalTimeMicro.get();
+
+ local->event_time = event_time;
+
+ call PacketLastTouch.request(msg);
+
+ return call SubSend.send[id](addr, msg, len);
+ }
+
+ command error_t TimeSyncSendMilli.cancel[am_id_t id](message_t* msg)
+ {
+ return call SubSend.cancel[id](msg);
+ }
+
+ default event void TimeSyncSendMilli.sendDone[am_id_t id](message_t* msg, error_t error)
+ {
+ }
+
+ command uint8_t TimeSyncSendMilli.maxPayloadLength[am_id_t id]()
+ {
+ return call SubSend.maxPayloadLength[id]() - sizeof(timesync_footer_t);
+ }
+
+ command void* TimeSyncSendMilli.getPayload[am_id_t id](message_t* msg, uint8_t len)
+ {
+ return call SubSend.getPayload[id](msg, len + sizeof(timesync_footer_t));
+ }
+
+ /*----------------- SubSend.sendDone -------------------*/
+
+ event void SubSend.sendDone[am_id_t id](message_t* msg, error_t error)
+ {
+ signal TimeSyncSendMicro.sendDone[id](msg, error);
+ signal TimeSyncSendMilli.sendDone[id](msg, error);
+ }
+
+ /*----------------- PacketLastTouch.touch -------------------*/
+
+ enum
+ {
+ TIMESYNC_INVALID_STAMP = 0x80000000L,
+ };
+
+ async event void PacketLastTouch.touch(message_t* msg)
+ {
+ timesync_footer_t* footer = footer = getFooter(msg);
+ timesync_local_t* local;
+
+ if( call PacketTimeStamp.isSet(msg) )
+ {
+ local = getLocal(msg);
+
+ footer->time_offset = local->event_time - call PacketTimeStamp.get(msg);
+ }
+ else
+ footer->time_offset = TIMESYNC_INVALID_STAMP;
+ }
+
+ /*----------------- TimeSyncPacketMicro -----------------*/
+
+ async command bool TimeSyncPacketMicro.hasValidTime(message_t* msg)
+ {
+ timesync_footer_t* footer = getFooter(msg);
+
+ return call PacketTimeStamp.isSet(msg) && footer->time_offset != TIMESYNC_INVALID_STAMP;
+ }
+
+ async command uint32_t TimeSyncPacketMicro.getEventTime(message_t* msg)
+ {
+ timesync_footer_t* footer = getFooter(msg);
+
+ return (uint32_t)(footer->time_offset) + call PacketTimeStamp.get(msg);
+ }
+
+ /*----------------- TimeSyncPacketMilli -----------------*/
+
+ async command bool TimeSyncPacketMilli.hasValidTime(message_t* msg)
+ {
+ timesync_footer_t* footer = getFooter(msg);
+
+ return call PacketTimeStamp.isSet(msg) && footer->time_offset != TIMESYNC_INVALID_STAMP;
+ }
+
+ async command uint32_t TimeSyncPacketMilli.getEventTime(message_t* msg)
+ {
+ timesync_footer_t* footer = getFooter(msg);
+
+ // time offset compared to now in microsec, important that this is signed
+ int32_t elapsed = (uint32_t)(footer->time_offset) + call PacketTimeStamp.get(msg) - call LocalTimeMicro.get();
+
+ return (elapsed >> 10) + call LocalTimeMilli.get();
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+
+interface TimeSyncPacket<precision_tag>
+{
+ /**
+ * Returns TRUE if the value returned by <tt>getTime</tt> can be trusted.
+ * Under certain circumstances the received message cannot be properly
+ * time stamped, so the sender-receiver synchronization cannot be finished
+ * on the receiver side. In this case, this command returns FALSE.
+ * This command MUST BE called only on the receiver side and only for
+ * messages transmitted via the TimeSyncSend interface.
+ */
+ async command bool hasValidTime(message_t* msg);
+
+ /**
+ * This command should be called by the receiver of a message. The time
+ * of the synchronization event is returned as expressed in the local
+ * clock of the caller. This command MUST BE called only on the receiver
+ * side and only for messages transmitted via the TimeSyncSend interface.
+ */
+ async command uint32_t getEventTime(message_t* msg);
+}
--- /dev/null
+/*
+ * 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 Philip Levis
+ * @author Miklos Maroti
+ *
+ * @see TimeSyncPacket
+ */
+
+#include <TinyError.h>
+#include <message.h>
+#include <AM.h>
+
+interface TimeSyncSend<precision_tag>
+{
+ /**
+ * This command sends a regular message just like <tt>AMSend.send</tt>, but
+ * it also performs sender-receiver time synchronization. The <tt>event_time</tt>
+ * parameter holds the time of some event as expressed in the local clock of
+ * the sender. The receiver can obtain the time of this event (expressed in its
+ * own local time) via the <tt>TimeSyncPacket</tt> interface.
+ *
+ * @param addr address to which to send the packet
+ * @param msg the packet
+ * @param len the length of the data in the packet payload
+ * @param time the synchronization point to be transfered with the message
+ * @return SUCCESS if the request to send succeeded and a
+ * sendDone will be signaled later, EBUSY if the
+ * abstraction cannot send now but will be able to
+ * later, or FAIL if the communication layer is not
+ * in a state that can send (e.g., off).
+ * @see sendDone
+ */
+ command error_t send(uint32_t event_time, am_addr_t addr, message_t* msg, uint8_t len);
+
+ /**
+ * Cancel a requested transmission. Returns SUCCESS if the
+ * transmission was canceled properly (not sent in its
+ * entirety). Note that the component may not know
+ * if the send was successfully canceled, if the radio is
+ * handling much of the logic; in this case, a component
+ * should be conservative and return an appropriate error code.
+ * A successful call to cancel must always result in a
+ * sendFailed event, and never a sendSucceeded event.
+ *
+ * @param msg the packet whose transmission should be cancelled.
+ * @return SUCCESS if the transmission was cancelled, FAIL otherwise.
+ * @see sendDone
+ */
+ command error_t cancel(message_t* msg);
+
+ /**
+ * Signaled in response to an accepted send request. <tt>msg</tt> is
+ * the message buffer sent, and <tt>error</tt> indicates whether
+ * the send was successful.
+ *
+ * @param msg the packet which was submitted as a send request
+ * @param error SUCCESS if it was sent successfully, FAIL if it was not,
+ * ECANCEL if it was cancelled
+ * @see send
+ * @see cancel
+ */
+ event void sendDone(message_t* msg, error_t error);
+
+ /**
+ * Return the maximum payload length that this communication layer
+ * can provide. This command behaves identically to
+ * <tt>Packet.maxPayloadLength</tt> and is included in this
+ * interface as a convenience.
+ *
+ * @return the maximum payload length
+ */
+ command uint8_t maxPayloadLength();
+
+ /**
+ * Return a pointer to a protocol's payload region in a packet.
+ * This command behaves identically to <tt>Packet.getPayload</tt>
+ * (minus the length parameter) and is included in this interface
+ * as a convenience.
+ *
+ * @param msg the packet
+ * @return the payload of the packet
+ */
+ command void* getPayload(message_t* msg, uint8_t len);
+}
+++ /dev/null
-
-1. to support multiple sends through the ascynronous radio send interface
-the send() must return error_t to indicate it cannot service more
-
-2. to have guaranteed timing we need guaranteed access to the send interface,
-so we cannot have multiple sends through the radio send interface.
-
-3. time critical tasks:
- CCA -> TX-DATA
- RX-DATA -> TX-ACK
- TX-DATA -> RX-ACK
-
-4. after the CCA we need to send data, but then TX-DATA cannot wait for the
-completion of a receieved packet (maybe we should), so maybe we should not
-have concurrent receives with everything else, enable receive only when
-needed
-
-5. if there are no multiple sends in the radio send interface, then to have
-robustness, the separate interfaces should record the requests until they are
-ready to service them
-
-6. to support receiving messages in the TX-DATA -> RX-ACK gap that need to be
-acknowledged we must have a TX-ACK queue (we do not want to saturate the
-channel while waiting for ACK). If this gap is large, then many messages
-could accumulate that have not been acked, which can get out of control
-
-7. for low power listeing the TX-DATA -> RX-ACK -> TX-DATA gap should be
-minimal to have the best duty cycle possible (maybe with a pair of CCA
-checks it is possible to cover the gap).
-
-8. if only single requests are serviced by the radio send interface, then
-there is no need for the message pointer in the sendDone event.
-
-9. the receive buffer cannot service the higher layer via the asynchronous
-radio receive interface (or there should be another buffering down the road)
-that is pumped with a task. Also, the sendDone event must be fired from a
-task too.
-
-10. if a valid packet is received in the TX-DATA -> RX-ACK gap, then we could
-fail the TX-DATA but accept the RX-DATA. This requires two events to be
-fiered: sendDone(FAIL) and receive(msg). We cannot fire the sendDone first
-because then our component does not become ready, and the higher layer might
-want to transmit again instead of listening (needs buffering)
-
-11. four ways to handle the receive data while waiting for ACK problem
- a) drop these packets,
- b) drop only those that need acknowledgements,
- c) buffer them at the acked send layer (needs message_t) and deliver them
- when receiving is allowed again
- d) deliver them before signaling the sendDone(FAIL), but then we have to
- allow concurrent receives with sends
-
-12. It is very problematic to receive unexpected packets, what to do with
-these? They could occur in the following gaps
- a) CCA -> TX-DATA
- b) RX-DATA -> TX-ACK
- c) TX-DATA -> RX-ACK
-
-13. The hidden terminal problem can occur at 12b), i.e. NodeA transmits that
-is received by NodeB but not heard by NodeC, which starts to transmit before
-NodeB could send an acknowledgment.
-
-14. with dedicated receive start calls,
- a) we could set the channel there,
- b) would have no problem with unexpected receives
- c) could set a timeout parameter
- d) need cancel command in the asynchronous receive interface
- e) after receive we could go to PLL_ON state, could always download frame
-
-15. async send done could return an error code to indicate that something
-went wrong, for example the CCA did not complete or the channel was busy
-
-16. If we want to cancel the receive process, then it is not clear what to do
-in the BUSY_RX case. We could either go with FORCE_TRX_OFF and then PLL_ON,
-or do a PLL_ON and wait for the completion of the received message. Therefore
-once we are in the RX_ON state, we cannot guarantee to start TX_ON precisely.
-We need to verify this.
-
-17. We need to transmit and cancel the listening process because of user
-input. The listening cancelling is not atomic (we might need to receive
-messages) and then send acknowledgment etc. Either we are always listening
-(conccurent receive / transmit) or call cancel and wait for receive(ECANCEL).
-
-18. The CC2420 has a receive queue, that needs to be flushed. This mean that
-we might not able to prevent more than one message to arrive when listening.
-So we are either always on, or need purge functionality to receive all
-messages from the receive queue.
-
-19. The RF230 does not support promisculous mode, so in general we cannot
-use the hardware TX-ACK feature with the RX_AACK command.
-
-20. With software acknowledgements on the RF230 we cannot reply to a RX-DATA
-with a TX-ACK faster than at least 200 microsec, because we need to download
-the full frame, check the CRC and only then we can send the ACK to avoid
-acking corrupted frames. This means that item 13 is a real problem, and we
-should go with item 11 d). Receiving a data packet while waiting for an ACK
-should fail the previous transmission and send an ack for the incoming frame.
-
-21. We cannot receive a message while a transmission is in progress because
-what would an ack layer do in this case? It cannot send the acknowledgment
-because a send is in progress. So send should return an error_t and while
-a send is in progress no receive is going to be fired.
-
-22. If we use dedicated receive start calls, then an uxpected message can
-arrive (such as when waiting for ACK but getting some DATA), in which case
-the returned message_t pointer might be something else than the one with
-which the receive command was called. So in this case we need to return
-the message with the messageDone event.
-
-23. What do we do with a received DATA packet while waiting for an ACK
-packet? We cannot signal higher layers that we have received it because
-the receive command was not called, so we have to buffer it, which can
-be problematic.
interface GpioCapture as IRQ;
interface Alarm<TRF230, uint16_t> as Alarm;
+ interface LocalTime<TRF230>;
interface HplRF230;
}
components RealMainP;
RealMainP.PlatformInit -> HplRF230P.PlatformInit;
+
+ components CounterOne16C;
+ components new TransformCounterC(TRF230, uint32_t, TRF230, uint16_t, 0, uint32_t);
+ components new CounterToLocalTimeC(TRF230);
+
+ LocalTime = CounterToLocalTimeC;
+ CounterToLocalTimeC.Counter -> TransformCounterC;
+ TransformCounterC.CounterFrom -> CounterOne16C;
}