From dfc42b47c11051bae3026948c390e7bbeae4b854 Mon Sep 17 00:00:00 2001 From: mmaroti Date: Wed, 12 Mar 2008 19:42:56 +0000 Subject: [PATCH] updated TimeSyncMessage implementation --- tos/chips/rf230/DefaultMacC.nc | 5 +- tos/chips/rf230/DefaultPacket.h | 11 - tos/chips/rf230/DefaultPacketC.nc | 7 - tos/chips/rf230/DefaultPacketP.nc | 131 ++-------- .../{DefaultMac.h => PacketLastTouch.nc} | 51 ++-- tos/chips/rf230/RF230LayerC.nc | 6 +- tos/chips/rf230/RF230LayerP.nc | 21 +- tos/chips/rf230/TimeSyncMessageC.nc | 71 ++++++ tos/chips/rf230/TimeSyncMessageP.nc | 229 ++++++++++++++++++ tos/chips/rf230/TimeSyncPacket.nc | 43 ++++ tos/chips/rf230/TimeSyncSend.nc | 104 ++++++++ tos/chips/rf230/notes.txt | 113 --------- tos/platforms/iris/chips/rf230/HplRF230C.nc | 9 + 13 files changed, 502 insertions(+), 299 deletions(-) rename tos/chips/rf230/{DefaultMac.h => PacketLastTouch.nc} (62%) create mode 100644 tos/chips/rf230/TimeSyncMessageC.nc create mode 100644 tos/chips/rf230/TimeSyncMessageP.nc create mode 100644 tos/chips/rf230/TimeSyncPacket.nc create mode 100644 tos/chips/rf230/TimeSyncSend.nc delete mode 100644 tos/chips/rf230/notes.txt diff --git a/tos/chips/rf230/DefaultMacC.nc b/tos/chips/rf230/DefaultMacC.nc index 2f6ca524..2143adc3 100644 --- a/tos/chips/rf230/DefaultMacC.nc +++ b/tos/chips/rf230/DefaultMacC.nc @@ -39,7 +39,6 @@ configuration DefaultMacC interface PacketField as PacketLinkQuality; interface PacketTimeStamp; - interface PacketTimeSynch; } } @@ -60,7 +59,6 @@ implementation PacketAcknowledgements = DefaultPacketC; PacketLinkQuality = DefaultPacketC.PacketLinkQuality; PacketTimeStamp = DefaultPacketC.PacketTimeStamp; - PacketTimeSynch = DefaultPacketC.PacketTimeSynch; components ActiveMessageLayerC; components MessageBufferLayerC; @@ -112,6 +110,5 @@ implementation RF230LayerC.RF230Config -> DefaultMacP; RF230LayerC.PacketLinkQuality -> DefaultPacketC.PacketLinkQuality; RF230LayerC.PacketTransmitPower -> DefaultPacketC.PacketTransmitPower; - RF230LayerC.PacketTimeStamping -> DefaultPacketC.PacketTimeStamping; - RF230LayerC.PacketTimeSynchron -> DefaultPacketC.PacketTimeSynchron; + RF230LayerC.PacketTimeStamp -> DefaultPacketC.PacketTimeStamp; } diff --git a/tos/chips/rf230/DefaultPacket.h b/tos/chips/rf230/DefaultPacket.h index 819b5bd4..dcf62d3c 100644 --- a/tos/chips/rf230/DefaultPacket.h +++ b/tos/chips/rf230/DefaultPacket.h @@ -43,15 +43,4 @@ enum defpacket_metadata_flags 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__ diff --git a/tos/chips/rf230/DefaultPacketC.nc b/tos/chips/rf230/DefaultPacketC.nc index f02f3e65..3c32ee33 100644 --- a/tos/chips/rf230/DefaultPacketC.nc +++ b/tos/chips/rf230/DefaultPacketC.nc @@ -32,11 +32,8 @@ configuration DefaultPacketC interface PacketAcknowledgements; interface PacketField as PacketLinkQuality; interface PacketField as PacketTransmitPower; - interface PacketField as PacketTimeStamping; - interface PacketField as PacketTimeSynchron; interface PacketTimeStamp; - interface PacketTimeSynch; } } @@ -51,9 +48,5 @@ implementation PacketAcknowledgements = DefaultPacketP; PacketLinkQuality = DefaultPacketP.PacketLinkQuality; PacketTransmitPower = DefaultPacketP.PacketTransmitPower; - PacketTimeStamping = DefaultPacketP.PacketTimeStamping; - PacketTimeSynchron = DefaultPacketP.PacketTimeSynchron; - PacketTimeStamp = DefaultPacketP.PacketTimeStamp; - PacketTimeSynch = DefaultPacketP.PacketTimeSynch; } diff --git a/tos/chips/rf230/DefaultPacketP.nc b/tos/chips/rf230/DefaultPacketP.nc index 1c2358df..a0cb16f3 100644 --- a/tos/chips/rf230/DefaultPacketP.nc +++ b/tos/chips/rf230/DefaultPacketP.nc @@ -31,11 +31,8 @@ module DefaultPacketP interface Packet; interface PacketField as PacketLinkQuality; interface PacketField as PacketTransmitPower; - interface PacketField as PacketTimeStamping; - interface PacketField as PacketTimeSynchron; interface PacketTimeStamp; - interface PacketTimeSynch; } uses @@ -46,38 +43,18 @@ module DefaultPacketP 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) @@ -90,22 +67,24 @@ implementation 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 ) @@ -158,101 +137,27 @@ implementation /*----------------- 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; diff --git a/tos/chips/rf230/DefaultMac.h b/tos/chips/rf230/PacketLastTouch.nc similarity index 62% rename from tos/chips/rf230/DefaultMac.h rename to tos/chips/rf230/PacketLastTouch.nc index 3547bde9..af51caf7 100644 --- a/tos/chips/rf230/DefaultMac.h +++ b/tos/chips/rf230/PacketLastTouch.nc @@ -21,34 +21,25 @@ * Author: Miklos Maroti */ -#ifndef __DEFAULTMAC_H__ -#define __DEFAULTMAC_H__ - -#include - -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 +interface PacketLastTouch { - 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__ + /** + * 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); +} diff --git a/tos/chips/rf230/RF230LayerC.nc b/tos/chips/rf230/RF230LayerC.nc index 596928a6..7e12df94 100644 --- a/tos/chips/rf230/RF230LayerC.nc +++ b/tos/chips/rf230/RF230LayerC.nc @@ -36,8 +36,7 @@ configuration RF230LayerC interface RF230Config; interface PacketField as PacketLinkQuality; interface PacketField as PacketTransmitPower; - interface PacketField as PacketTimeStamping; - interface PacketField as PacketTimeSynchron; + interface PacketTimeStamp; } } @@ -53,8 +52,7 @@ implementation 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; diff --git a/tos/chips/rf230/RF230LayerP.nc b/tos/chips/rf230/RF230LayerP.nc index c11a1729..2796fd4e 100644 --- a/tos/chips/rf230/RF230LayerP.nc +++ b/tos/chips/rf230/RF230LayerP.nc @@ -56,9 +56,8 @@ module RF230LayerP interface RF230Config; interface PacketField as PacketLinkQuality; - interface PacketField as PacketTimeStamping; - interface PacketField as PacketTimeSynchron; interface PacketField as PacketTransmitPower; + interface PacketTimeStamp; interface Tasklet; interface RadioAlarm; @@ -431,10 +430,6 @@ implementation // 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++)); } @@ -476,11 +471,7 @@ implementation 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; @@ -569,10 +560,6 @@ implementation 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); @@ -664,9 +651,9 @@ implementation * 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; } diff --git a/tos/chips/rf230/TimeSyncMessageC.nc b/tos/chips/rf230/TimeSyncMessageC.nc new file mode 100644 index 00000000..5876b0cf --- /dev/null +++ b/tos/chips/rf230/TimeSyncMessageC.nc @@ -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 + */ + +#include +#include + +configuration TimeSyncMessageC +{ + provides + { + interface TimeSyncSend as TimeSyncSendMicro[am_id_t id]; + interface TimeSyncPacket as TimeSyncPacketMicro; + interface LocalTime as LocalTimeMicro; + + interface TimeSyncSend as TimeSyncSendMilli[am_id_t id]; + interface TimeSyncPacket as TimeSyncPacketMilli; + interface LocalTime 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; +} diff --git a/tos/chips/rf230/TimeSyncMessageP.nc b/tos/chips/rf230/TimeSyncMessageP.nc new file mode 100644 index 00000000..8b99ccc8 --- /dev/null +++ b/tos/chips/rf230/TimeSyncMessageP.nc @@ -0,0 +1,229 @@ +/* + * 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 as TimeSyncSendMicro[uint8_t id]; + interface TimeSyncSend as TimeSyncSendMilli[uint8_t id]; + interface Packet; + interface TimeSyncPacket as TimeSyncPacketMicro; + interface TimeSyncPacket as TimeSyncPacketMilli; + } + + uses + { + interface AMSend as SubSend[uint8_t id]; + interface Packet as SubPacket; + interface PacketTimeStamp; + interface PacketLastTouch; + + interface LocalTime as LocalTimeMicro; + interface LocalTime 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(); + } +} diff --git a/tos/chips/rf230/TimeSyncPacket.nc b/tos/chips/rf230/TimeSyncPacket.nc new file mode 100644 index 00000000..7264ecbf --- /dev/null +++ b/tos/chips/rf230/TimeSyncPacket.nc @@ -0,0 +1,43 @@ +/* + * 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 +{ + /** + * Returns TRUE if the value returned by getTime 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); +} diff --git a/tos/chips/rf230/TimeSyncSend.nc b/tos/chips/rf230/TimeSyncSend.nc new file mode 100644 index 00000000..267d5551 --- /dev/null +++ b/tos/chips/rf230/TimeSyncSend.nc @@ -0,0 +1,104 @@ +/* + * 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 +#include +#include + +interface TimeSyncSend +{ + /** + * This command sends a regular message just like AMSend.send, but + * it also performs sender-receiver time synchronization. The event_time + * 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 TimeSyncPacket 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. msg is + * the message buffer sent, and error 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 + * Packet.maxPayloadLength 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 Packet.getPayload + * (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); +} diff --git a/tos/chips/rf230/notes.txt b/tos/chips/rf230/notes.txt deleted file mode 100644 index b5bdd65b..00000000 --- a/tos/chips/rf230/notes.txt +++ /dev/null @@ -1,113 +0,0 @@ - -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. diff --git a/tos/platforms/iris/chips/rf230/HplRF230C.nc b/tos/platforms/iris/chips/rf230/HplRF230C.nc index 113d47cd..65459b40 100644 --- a/tos/platforms/iris/chips/rf230/HplRF230C.nc +++ b/tos/platforms/iris/chips/rf230/HplRF230C.nc @@ -36,6 +36,7 @@ configuration HplRF230C interface GpioCapture as IRQ; interface Alarm as Alarm; + interface LocalTime; interface HplRF230; } @@ -70,4 +71,12 @@ implementation 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; } -- 2.39.2