--- /dev/null
+/*
+ * Copyright (c) 2002, 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, Brano Kusy, Janos Sallai
+ * Date last modified: 3/17/03
+ * Ported to T2: 3/17/08 by Brano Kusy (branislav.kusy@gmail.com)
+ * Adapted for 32kHz and LPL: 6/16/09 by Thomas Schmid (thomas.schmid@ucla.edu)
+ */
+
+#include "TimeSyncMsg.h"
+
+configuration TimeSync32kC
+{
+ uses interface Boot;
+ provides interface Init;
+ provides interface StdControl;
+ provides interface GlobalTime<T32khz>;
+
+ //interfaces for extra fcionality: need not to be wired
+ provides interface TimeSyncInfo;
+ provides interface TimeSyncMode;
+ provides interface TimeSyncNotify;
+}
+
+implementation
+{
+ components new TimeSyncP(T32khz) as TimeSyncP;
+
+ GlobalTime = TimeSyncP;
+ StdControl = TimeSyncP;
+ Init = TimeSyncP;
+ Boot = TimeSyncP;
+ TimeSyncInfo = TimeSyncP;
+ TimeSyncMode = TimeSyncP;
+ TimeSyncNotify = TimeSyncP;
+
+ components TimeSyncMessageC as ActiveMessageC;
+ TimeSyncP.RadioControl -> ActiveMessageC;
+ TimeSyncP.Send -> ActiveMessageC.TimeSyncAMSend32khz[AM_TIMESYNCMSG];
+ TimeSyncP.Receive -> ActiveMessageC.Receive[AM_TIMESYNCMSG];
+ TimeSyncP.TimeSyncPacket -> ActiveMessageC;
+
+ components Counter32khz32C, new CounterToLocalTimeC(T32khz) as LocalTime32khzC;
+ LocalTime32khzC.Counter -> Counter32khz32C;
+ TimeSyncP.LocalTime -> LocalTime32khzC;
+
+ components new TimerMilliC() as TimerC;
+ TimeSyncP.Timer -> TimerC;
+
+#if defined(TIMESYNC_LEDS)
+ components LedsC;
+#else
+ components NoLedsC as LedsC;
+#endif
+ TimeSyncP.Leds -> LedsC;
+
+#ifdef LOW_POWER_LISTENING
+ components CC2420ActiveMessageC;
+ TimeSyncP.LowPowerListening -> CC2420ActiveMessageC;
+#endif
+
+
+}
#endif
TimeSyncP.Leds -> LedsC;
+#ifdef LOW_POWER_LISTENING
+ components CC2420ActiveMessageC;
+ TimeSyncP.LowPowerListening -> CC2420ActiveMessageC;
+#endif
+
}
nx_uint16_t nodeID; // the node if of the sender
nx_uint8_t seqNum; // sequence number for the root
- /* This field is initially set to the offset between global time and local
- * time. The TimeStamping component will add the current local time when the
- * message is actually transmitted. Thus the receiver will receive the
- * global time of the sender when the message is actually sent. */
+ /*
+ * After TEP 133, the message timestamp contains the difference between
+ * event time and the time the message was actually sent out. TimeSyncP
+ * sends the local time associated with this globalTime to the
+ * TimeStamping mechanism, which then calculates the difference.
+ *
+ * On the receiving side, the difference is applied to the local
+ * timestamp. The receiving timestamp thus represents the time on the
+ * receiving clock when the remote globalTime was taken.
+ */
nx_uint32_t globalTime;
//just for convenience
interface Leds;
interface TimeSyncPacket<precision_tag,uint32_t>;
interface LocalTime<precision_tag> as LocalTime;
+
+
+#ifdef LOW_POWER_LISTENING
+ interface LowPowerListening;
+#endif
+
}
}
implementation
IGNORE_ROOT_MSG = 4, // after becoming the root ignore other roots messages (in send period)
ENTRY_VALID_LIMIT = 4, // number of entries to become synchronized
ENTRY_SEND_LIMIT = 3, // number of entries to send sync messages
- ENTRY_THROWOUT_LIMIT = 100, // if time sync error is bigger than this clear the table
+ ENTRY_THROWOUT_LIMIT = 500, // if time sync error is bigger than this clear the table
};
typedef struct TableItem
float newSkew = skew;
uint32_t newLocalAverage;
int32_t newOffsetAverage;
+ int32_t localAverageRest;
+ int32_t offsetAverageRest;
int64_t localSum;
int64_t offsetSum;
newOffsetAverage = table[i].timeOffset;
localSum = 0;
+ localAverageRest = 0;
offsetSum = 0;
+ offsetAverageRest = 0;
while( ++i < MAX_ENTRIES )
if( table[i].state == ENTRY_FULL ) {
+ /*
+ This only works because C ISO 1999 defines the signe for modulo the same as for the Dividend!
+ */
localSum += (int32_t)(table[i].localTime - newLocalAverage) / tableEntries;
+ localAverageRest += (table[i].localTime - newLocalAverage) % tableEntries;
offsetSum += (int32_t)(table[i].timeOffset - newOffsetAverage) / tableEntries;
+ offsetAverageRest += (table[i].timeOffset - newOffsetAverage) % tableEntries;
}
- newLocalAverage += localSum;
- newOffsetAverage += offsetSum;
+ newLocalAverage += localSum + localAverageRest / tableEntries;
+ newOffsetAverage += offsetSum + offsetAverageRest / tableEntries;
localSum = offsetSum = 0;
for(i = 0; i < MAX_ENTRIES; ++i)
uint32_t age, oldestTime = 0;
int32_t timeError;
- tableEntries = 0;
-
// clear table if the received entry's been inconsistent for some time
timeError = msg->localTime;
call GlobalTime.local2Global((uint32_t*)(&timeError));
{
if (++numErrors>3)
clearTable();
+ return; // don't incorporate a bad reading
}
- else
- numErrors = 0;
+ tableEntries = 0; // don't reset table size unless you're recounting
+ numErrors = 0;
for(i = 0; i < MAX_ENTRIES; ++i) {
age = msg->localTime - table[i].localTime;
if( diff < -16 || diff > 16 )
return msg;
#endif
- if( (state & STATE_PROCESSING) == 0 ) {
+ if( (state & STATE_PROCESSING) == 0
+ && call TimeSyncPacket.isValid(msg)) {
message_t* old = processedMsg;
processedMsg = msg;
outgoingMsg->globalTime = globalTime;
+#ifdef LOW_POWER_LISTENING
+ call LowPowerListening.setRxSleepInterval(&outgoingMsgBuffer, LPL_INTERVAL);
+#endif
// we don't send time sync msg, if we don't have enough data
if( numEntries < ENTRY_SEND_LIMIT && outgoingMsg->rootID != TOS_NODE_ID ){
++heartBeats;
if (mode == mode_)
return SUCCESS;
- if (mode_ == TS_USER_MODE){
+ if (mode_ == TS_TIMER_MODE){
call Timer.startPeriodic((uint32_t)1000 * BEACON_RATE);
}
else