]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
FTSP related updates from CVS head, after tag release_tinyos_2_1_0_0. patchset/2.1.0-4
authorR. Steve McKown <rsmckown@gmail.com>
Tue, 25 Aug 2009 03:13:21 +0000 (21:13 -0600)
committerR. Steve McKown <rsmckown@gmail.com>
Thu, 22 Apr 2010 22:43:15 +0000 (16:43 -0600)
* Changes on CVS head through 8/23/09 for tos/lib/ftsp only.
* Upstream commits to tos/chips/cc2420, Aug 7 2008 thru Jul 16 2009, EXCEPT:
    kusy <kusy> Wed Aug 13 07:37:05 2008 +0000
    Fixing T32khz to TMilli conversion - coeficient 32 needs to be...
* Substitue for newest getTime32() by Miklos.

13 files changed:
tos/chips/cc2420/CC2420.h
tos/chips/cc2420/CC2420ActiveMessageP.nc
tos/chips/cc2420/CC2420TimeSyncMessageC.nc
tos/chips/cc2420/CC2420TimeSyncMessageP.nc
tos/chips/cc2420/csma/CC2420CsmaP.nc
tos/chips/cc2420/lpl/DefaultLplP.nc
tos/chips/cc2420/receive/CC2420ReceiveP.nc
tos/chips/cc2420/spi/CC2420SpiC.nc
tos/chips/cc2420/transmit/CC2420TransmitP.nc
tos/lib/ftsp/TimeSync32kC.nc [new file with mode: 0644]
tos/lib/ftsp/TimeSyncC.nc
tos/lib/ftsp/TimeSyncMsg.h
tos/lib/ftsp/TimeSyncP.nc

index 1d607b921763c87608ea2e6e4266c17359c25901..798107f0ebcb0367ee9e7822cfc8d1b5d0ca095c 100644 (file)
@@ -43,8 +43,43 @@ typedef uint8_t cc2420_status_t;
 #endif
 
 /**
- * CC2420 header.  An I-frame (interoperability frame) header has an 
- * extra network byte specified by 6LowPAN
+ * CC2420 header definition.
+ * 
+ * An I-frame (interoperability frame) header has an extra network 
+ * byte specified by 6LowPAN
+ * 
+ * Length = length of the header + payload of the packet, minus the size
+ *   of the length byte itself (1).  This is what allows for variable 
+ *   length packets.
+ * 
+ * FCF = Frame Control Field, defined in the 802.15.4 specs and the
+ *   CC2420 datasheet.
+ *
+ * DSN = Data Sequence Number, a number incremented for each packet sent
+ *   by a particular node.  This is used in acknowledging that packet, 
+ *   and also filtering out duplicate packets.
+ *
+ * DestPan = The destination PAN (personal area network) ID, so your 
+ *   network can sit side by side with another TinyOS network and not
+ *   interfere.
+ * 
+ * Dest = The destination address of this packet. 0xFFFF is the broadcast
+ *   address.
+ *
+ * Src = The local node ID that generated the message.
+ * 
+ * Network = The TinyOS network ID, for interoperability with other types
+ *   of 802.15.4 networks. 
+ * 
+ * Type = TinyOS AM type.  When you create a new AMSenderC(AM_MYMSG), 
+ *   the AM_MYMSG definition is the type of packet.
+ * 
+ * TOSH_DATA_LENGTH defaults to 28, it represents the maximum size of 
+ * the payload portion of the packet, and is specified in the 
+ * tos/types/message.h file.
+ *
+ * All of these fields will be filled in automatically by the radio stack 
+ * when you attempt to send a message.
  */
 typedef nx_struct cc2420_header_t {
   nxle_uint8_t length;
index be40963711905e0cd6ab4cc049dbf23c8fa3ee30..0db2423c7b83167d7bf41b4797e85c117b52cb8f 100644 (file)
@@ -62,6 +62,11 @@ implementation {
                                          message_t* msg,
                                          uint8_t len) {
     cc2420_header_t* header = call CC2420PacketBody.getHeader( msg );
+    
+    if (len > call Packet.maxPayloadLength()) {
+      return ESIZE;
+    }
+    
     header->type = id;
     header->dest = addr;
     header->destpan = call CC2420Config.getPanAddr();
index 745bd08eac17e4f09591ffba5eb3983e30f36c5f..94ed0c9ab45e467b32983baf8954fb387530a667 100644 (file)
@@ -60,8 +60,11 @@ implementation
         TimeSyncPacketMilli = CC2420TimeSyncMessageP;
 
         Packet = CC2420TimeSyncMessageP;
-        CC2420TimeSyncMessageP.SubSend -> CC2420ActiveMessageC.AMSend;
-        CC2420TimeSyncMessageP.SubPacket -> CC2420ActiveMessageC.Packet;
+        // use the AMSenderC infrastructure to avoid concurrent send clashes
+        components AMQueueP, ActiveMessageC;
+        CC2420TimeSyncMessageP.SubSend -> AMQueueP.Send[unique(UQ_AMQUEUE_SEND)];
+        CC2420TimeSyncMessageP.AMPacket -> ActiveMessageC;
+        CC2420TimeSyncMessageP.SubPacket -> ActiveMessageC;
 
         CC2420TimeSyncMessageP.PacketTimeStamp32khz -> CC2420PacketC;
         CC2420TimeSyncMessageP.PacketTimeStampMilli -> CC2420PacketC;
index a4e11573e17c831a31b28d808f994753bda4d19d..70e677ae111f712854dcd52c38f6389cdf143740 100644 (file)
@@ -37,7 +37,8 @@ module CC2420TimeSyncMessageP
 
     uses
     {
-        interface AMSend as SubSend[uint8_t id];
+        interface Send as SubSend;
+        interface AMPacket;
         interface Packet as SubPacket;
 
         interface PacketTimeStamp<T32khz,uint32_t> as PacketTimeStamp32khz;
@@ -93,7 +94,9 @@ implementation
         void * timesync = msg->data + len;
         *(timesync_radio_t*)timesync = event_time;
 
-        err = call SubSend.send[id](addr, msg, len + sizeof(timesync_radio_t));
+        call AMPacket.setDestination(msg, addr);
+        call AMPacket.setType(msg, id);
+        err = call SubSend.send(msg, len + sizeof(timesync_radio_t));
         call PacketTimeSyncOffset.set(msg);
         return err;
     }
@@ -101,19 +104,19 @@ implementation
     command error_t TimeSyncAMSend32khz.cancel[am_id_t id](message_t* msg)
     {
         call PacketTimeSyncOffset.cancel(msg);
-        return call SubSend.cancel[id](msg);
+        return call SubSend.cancel(msg);
     }
 
     default event void TimeSyncAMSend32khz.sendDone[am_id_t id](message_t* msg, error_t error) {}
 
     command uint8_t TimeSyncAMSend32khz.maxPayloadLength[am_id_t id]()
     {
-        return call SubSend.maxPayloadLength[id]() - sizeof(timesync_radio_t);
+        return call SubSend.maxPayloadLength() - sizeof(timesync_radio_t);
     }
 
     command void* TimeSyncAMSend32khz.getPayload[am_id_t id](message_t* msg, uint8_t len)
     {
-        return call SubSend.getPayload[id](msg, len + sizeof(timesync_radio_t));
+        return call SubSend.getPayload(msg, len + sizeof(timesync_radio_t));
     }
 
 /*----------------- TimeSyncAMSendMilli -----------------*/
@@ -142,8 +145,9 @@ implementation
     }
 
 /*----------------- SubSend.sendDone -------------------*/
-    event void SubSend.sendDone[am_id_t id](message_t* msg, error_t error)
+    event void SubSend.sendDone(message_t* msg, error_t error)
     {
+        am_id_t id = call AMPacket.type(msg);
         signal TimeSyncAMSend32khz.sendDone[id](msg, error);
         signal TimeSyncAMSendMilli.sendDone[id](msg, error);
     }
index 670b718129140bf7be3630637eb90fe3a9bb9622..e67f921763774af7c11d0e2492e7a9973083b020 100644 (file)
@@ -72,7 +72,6 @@ implementation {
   
   /****************** Prototypes ****************/
   task void startDone_task();
-  task void startDone_task();
   task void stopDone_task();
   task void sendDone_task();
   
@@ -144,7 +143,7 @@ implementation {
     metadata->ack = FALSE;
     metadata->rssi = 0;
     metadata->lqi = 0;
-    metadata->timesync = FALSE;
+    //metadata->timesync = FALSE;
     metadata->timestamp = CC2420_INVALID_TIMESTAMP;
 
     ccaOn = TRUE;
index d93debb0fa79192c262359b0ecc7c6499df36a5d..3ada9db65353e9e75ee182fecf2c558124f87ac0 100644 (file)
@@ -230,7 +230,7 @@ implementation {
       return 0;
     }
     
-    return (DUTY_ON_TIME * (10000 - dutyCycle)) / dutyCycle;
+    return ((uint32_t)DUTY_ON_TIME * (10000 - dutyCycle)) / dutyCycle;
   }
   
   /**
@@ -245,7 +245,7 @@ implementation {
       return 10000;
     }
     
-    return getActualDutyCycle((DUTY_ON_TIME * 10000) 
+    return getActualDutyCycle(((uint32_t)DUTY_ON_TIME * 10000) 
         / (sleepInterval + DUTY_ON_TIME));
   }
 
index 30a421914b9da6a819bfe2e3db99dc92b7ba03c2..5bd4e852e54eb383c85a67d7be24b94a80e15a47 100644 (file)
@@ -126,6 +126,10 @@ implementation {
       reset_state();
       m_state = S_STARTED;
       atomic receivingPacket = FALSE;
+      /* Note:
+         We use the falling edge because the FIFOP polarity is reversed. 
+         This is done in CC2420Power.startOscillator from CC2420ControlP.nc.
+       */
       call InterruptFIFOP.enableFallingEdge();
     }
     return SUCCESS;
@@ -281,16 +285,25 @@ implementation {
         call SpiResource.release();
       }
       
-      if ( m_timestamp_size ) {
-        if ( rxFrameLength > 10 ) {
-          call PacketTimeStamp.set(m_p_rx_buf, m_timestamp_queue[ m_timestamp_head ]);
+      //new packet is buffered up, or we don't have timestamp in fifo, or ack
+      if ( ( m_missed_packets && call FIFO.get() ) || !call FIFOP.get()
+            || !m_timestamp_size
+            || rxFrameLength <= 10) {
+        call PacketTimeStamp.clear(m_p_rx_buf);
+      }
+      else {
+          if (m_timestamp_size==1)
+            call PacketTimeStamp.set(m_p_rx_buf, m_timestamp_queue[ m_timestamp_head ]);
           m_timestamp_head = ( m_timestamp_head + 1 ) % TIMESTAMP_QUEUE_SIZE;
           m_timestamp_size--;
-        }
-      } else {
-        call PacketTimeStamp.clear(m_p_rx_buf);
+
+          if (m_timestamp_size>0) {
+            call PacketTimeStamp.clear(m_p_rx_buf);
+            m_timestamp_head = 0;
+            m_timestamp_size = 0;
+          }
       }
-      
+
       // We may have received an ack that should be processed by Transmit
       // buf[rxFrameLength] >> 7 checks the CRC
       if ( ( buf[ rxFrameLength ] >> 7 ) && rx_buf ) {
index 13e17c4f63e9154531da48c7e84ed8f8852b424c..50e015e9a9bc3ccbf899c925dedebd6bf689854c 100644 (file)
@@ -79,6 +79,7 @@ generic configuration CC2420SpiC() {
   provides interface CC2420Register as MANAND;
   provides interface CC2420Register as MANOR;
   provides interface CC2420Register as AGCCTRL;
+  provides interface CC2420Register as RXFIFO_REGISTER;
 
   // ram
   provides interface CC2420Ram as IEEEADR;
@@ -142,6 +143,7 @@ implementation {
   MANAND = Spi.Reg[ CC2420_MANAND ];
   MANOR = Spi.Reg[ CC2420_MANOR ];
   AGCCTRL = Spi.Reg[ CC2420_AGCCTRL ];
+  RXFIFO_REGISTER = Spi.Reg[ CC2420_RXFIFO ];
   
   // ram
   IEEEADR = Spi.Ram[ CC2420_RAM_IEEEADR ];
index 1b6cd48f5e0b5dd0b816d2db0c192e17c262fd2d..cd640b1e7f29336bdbcef0a65e8a46bf238496cd 100644 (file)
@@ -236,12 +236,11 @@ implementation {
   }
   
   
-  inline uint32_t time16to32(uint16_t time, uint32_t recent_time)
+  inline uint32_t getTime32(uint16_t time)
   {
-    if ((recent_time&0xFFFF)<time)
-      return ((recent_time-0x10000UL)&0xFFFF0000UL)|time;
-    else
-      return (recent_time&0xFFFF0000UL)|time;
+    uint32_t recent_time = call BackoffTimer.getNow();
+
+    return recent_time - (uint16_t)(recent_time - time);
   }
 
   /**
@@ -258,23 +257,30 @@ implementation {
    * would have picked up and executed had our microcontroller been fast enough.
    */
   async event void CaptureSFD.captured( uint16_t time ) {
-    uint32_t time32 = time16to32(time, call BackoffTimer.getNow());
+    uint32_t time32;
+    uint8_t sfd_state = 0;
     atomic {
+      time32 = getTime32(time);
       switch( m_state ) {
         
       case S_SFD:
         m_state = S_EFD;
         sfdHigh = TRUE;
+        // in case we got stuck in the receive SFD interrupts, we can reset
+        // the state here since we know that we are not receiving anymore
+        m_receiving = FALSE;
         call CaptureSFD.captureFallingEdge();
         call PacketTimeStamp.set(m_msg, time32);
         if (call PacketTimeSyncOffset.isSet(m_msg)) {
-           nx_uint8_t *taddr = m_msg->data + (call PacketTimeSyncOffset.get(m_msg) - sizeof(cc2420_header_t));
-           timesync_radio_t *timesync = (timesync_radio_t*)taddr;
+           uint8_t absOffset = sizeof(message_header_t)-sizeof(cc2420_header_t)+call PacketTimeSyncOffset.get(m_msg);
+           timesync_radio_t *timesync = (timesync_radio_t *)((nx_uint8_t*)m_msg+absOffset);
            // set timesync event time as the offset between the event time and the SFD interrupt time (TEP  133)
            *timesync  -= time32;
            call CSN.clr();
-           call TXFIFO_RAM.write( call PacketTimeSyncOffset.get(m_msg), (uint8_t*)timesync, sizeof(timesync_radio_t) );
+           call TXFIFO_RAM.write( absOffset, (uint8_t*)timesync, sizeof(timesync_radio_t) );
            call CSN.set();
+           //restoring the event time to the original value
+           *timesync  += time32;
         }
 
         if ( (call CC2420PacketBody.getHeader( m_msg ))->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
@@ -284,16 +290,11 @@ implementation {
         releaseSpiResource();
         call BackoffTimer.stop();
 
-        
-        if ( ( ( (call CC2420PacketBody.getHeader( m_msg ))->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == IEEE154_TYPE_DATA ) {
-          call PacketTimeStamp.set(m_msg, time32);
-        }
-        
         if ( call SFD.get() ) {
           break;
         }
         /** Fall Through because the next interrupt was already received */
-        
+
       case S_EFD:
         sfdHigh = FALSE;
         call CaptureSFD.captureRisingEdge();
@@ -311,9 +312,12 @@ implementation {
         /** Fall Through because the next interrupt was already received */
         
       default:
-        if ( !m_receiving ) {
+        /* this is the SFD for received messages */
+        if ( !m_receiving && sfdHigh == FALSE ) {
           sfdHigh = TRUE;
           call CaptureSFD.captureFallingEdge();
+          // safe the SFD pin status for later use
+          sfd_state = call SFD.get();
           call CC2420Receive.sfd( time32 );
           m_receiving = TRUE;
           m_prev_time = time;
@@ -321,18 +325,29 @@ implementation {
             // wait for the next interrupt before moving on
             return;
           }
+          // if SFD.get() = 0, then an other interrupt happened since we
+          // reconfigured CaptureSFD! Fall through
         }
         
-        sfdHigh = FALSE;
-        call CaptureSFD.captureRisingEdge();
-        m_receiving = FALSE;
-        if ( time - m_prev_time < 10 ) {
-          call CC2420Receive.sfd_dropped();
-         if (m_msg)
-           call PacketTimeStamp.clear(m_msg);
+        if ( sfdHigh == TRUE ) {
+          sfdHigh = FALSE;
+          call CaptureSFD.captureRisingEdge();
+          m_receiving = FALSE;
+          /* if sfd_state is 1, then we fell through, but at the time of
+           * saving the time stamp the SFD was still high. Thus, the timestamp
+           * is valid.
+           * if the sfd_state is 0, then either we fell through and SFD
+           * was low while we safed the time stamp, or we didn't fall through.
+           * Thus, we check for the time between the two interrupts.
+           * FIXME: Why 10 tics? Seams like some magic number...
+           */
+          if ((sfd_state == 0) && (time - m_prev_time < 10) ) {
+            call CC2420Receive.sfd_dropped();
+            if (m_msg)
+              call PacketTimeStamp.clear(m_msg);
+          }
+          break;
         }
-        break;
-      
       }
     }
   }
diff --git a/tos/lib/ftsp/TimeSync32kC.nc b/tos/lib/ftsp/TimeSync32kC.nc
new file mode 100644 (file)
index 0000000..f709829
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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
+
+
+}
index 58af71d282c36e84bc0b91f458f5a874e1f8b108..8022d8a9f6a354fcb06023aa9c1c191ff30a0e65 100644 (file)
@@ -69,4 +69,9 @@ implementation
 #endif
   TimeSyncP.Leds  ->  LedsC;
 
+#ifdef LOW_POWER_LISTENING
+  components CC2420ActiveMessageC;
+  TimeSyncP.LowPowerListening -> CC2420ActiveMessageC;
+#endif
+
 }
index a9e6e393e57c5a3e250f2e545fea7a319fda2cb0..f45c2b346f68aa5da56be9b38f2d833f1b5fb66c 100644 (file)
@@ -32,10 +32,16 @@ typedef nx_struct TimeSyncMsg
        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
index fc2ef9944e57cc1a05c1a7c9782cd2dc318f96ce..3c3affe83d12528d0d7ef1ece43dfbe316742875 100644 (file)
@@ -46,6 +46,12 @@ generic module TimeSyncP(typedef precision_tag)
         interface Leds;
         interface TimeSyncPacket<precision_tag,uint32_t>;
         interface LocalTime<precision_tag> as LocalTime;
+
+
+#ifdef LOW_POWER_LISTENING
+        interface LowPowerListening;
+#endif
+
     }
 }
 implementation
@@ -61,7 +67,7 @@ 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
@@ -150,6 +156,8 @@ implementation
         float newSkew = skew;
         uint32_t newLocalAverage;
         int32_t newOffsetAverage;
+        int32_t localAverageRest;
+        int32_t offsetAverageRest;
 
         int64_t localSum;
         int64_t offsetSum;
@@ -169,16 +177,23 @@ implementation
         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)
@@ -218,8 +233,6 @@ implementation
         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));
@@ -229,10 +242,11 @@ implementation
         {
             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;
@@ -302,7 +316,8 @@ implementation
         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;
@@ -344,6 +359,9 @@ implementation
 
         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;
@@ -399,7 +417,7 @@ implementation
         if (mode == mode_)
             return SUCCESS;
 
-        if (mode_ == TS_USER_MODE){
+        if (mode_ == TS_TIMER_MODE){
             call Timer.startPeriodic((uint32_t)1000 * BEACON_RATE);
         }
         else