timesynch.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup timesynch
00003  * @{
00004  */
00005 
00006 
00007 /*
00008  * Copyright (c) 2007, Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  * 1. Redistributions of source code must retain the above copyright
00015  *    notice, this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright
00017  *    notice, this list of conditions and the following disclaimer in the
00018  *    documentation and/or other materials provided with the distribution.
00019  * 3. Neither the name of the Institute nor the names of its contributors
00020  *    may be used to endorse or promote products derived from this software
00021  *    without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  * This file is part of the Contiki operating system.
00036  *
00037  * $Id: timesynch.c,v 1.11 2010/12/16 22:47:38 adamdunkels Exp $
00038  */
00039 
00040 /**
00041  * \file
00042  *         A simple time synchronization mechanism
00043  * \author
00044  *         Adam Dunkels <adam@sics.se>
00045  */
00046 
00047 #include "contiki.h"
00048 #include "lib/random.h"
00049 #include "net/rime.h"
00050 #include "net/rime/timesynch.h"
00051 
00052 #if TIMESYNCH_CONF_ENABLED
00053 static int authority_level;
00054 static rtimer_clock_t offset;
00055 
00056 #define TIMESYNCH_CHANNEL  7
00057 
00058 struct timesynch_msg {
00059   uint8_t authority_level;
00060   uint8_t dummy;
00061   uint16_t authority_offset;
00062   uint16_t clock_fine;
00063   clock_time_t clock_time;
00064   uint32_t seconds;
00065   /* We need some padding so that the radio has time to update the
00066      timestamp at the end of the packet, after the transmission has
00067      started. */
00068   uint8_t padding[16];
00069 
00070   /* The timestamp must be the last two bytes. */
00071   uint16_t timestamp;
00072 };
00073 
00074 PROCESS(timesynch_process, "Timesynch process");
00075 
00076 #define MIN_INTERVAL CLOCK_SECOND * 8
00077 #define MAX_INTERVAL CLOCK_SECOND * 60 * 5
00078 /*---------------------------------------------------------------------------*/
00079 int
00080 timesynch_authority_level(void)
00081 {
00082   return authority_level;
00083 }
00084 /*---------------------------------------------------------------------------*/
00085 void
00086 timesynch_set_authority_level(int level)
00087 {
00088   int old_level = authority_level;
00089 
00090   authority_level = level;
00091 
00092   if(old_level != authority_level) {
00093     /* Restart the timesynch process to restart with a low
00094        transmission interval. */
00095     process_exit(&timesynch_process);
00096     process_start(&timesynch_process, NULL);
00097   }
00098 }
00099 /*---------------------------------------------------------------------------*/
00100 rtimer_clock_t
00101 timesynch_time(void)
00102 {
00103   return RTIMER_NOW() + offset;
00104 }
00105 /*---------------------------------------------------------------------------*/
00106 rtimer_clock_t
00107 timesynch_time_to_rtimer(rtimer_clock_t synched_time)
00108 {
00109   return synched_time - offset;
00110 }
00111 /*---------------------------------------------------------------------------*/
00112 rtimer_clock_t
00113 timesynch_rtimer_to_time(rtimer_clock_t rtimer_time)
00114 {
00115   return rtimer_time + offset;
00116 }
00117 /*---------------------------------------------------------------------------*/
00118 rtimer_clock_t
00119 timesynch_offset(void)
00120 {
00121   return offset;
00122 }
00123 /*---------------------------------------------------------------------------*/
00124 static void
00125 adjust_offset(rtimer_clock_t authoritative_time, rtimer_clock_t local_time)
00126 {
00127   offset = authoritative_time - local_time;
00128 }
00129 /*---------------------------------------------------------------------------*/
00130 static void
00131 broadcast_recv(struct broadcast_conn *c, const rimeaddr_t *from)
00132 {
00133   struct timesynch_msg msg;
00134 
00135   memcpy(&msg, packetbuf_dataptr(), sizeof(msg));
00136 
00137   /* We check the authority level of the sender of the incoming
00138        packet. If the sending node has a lower authority level than we
00139        have, we synchronize to the time of the sending node and set our
00140        own authority level to be one more than the sending node. */
00141   if(msg.authority_level < authority_level) {
00142     adjust_offset(msg.timestamp + msg.authority_offset,
00143                   packetbuf_attr(PACKETBUF_ATTR_TIMESTAMP));
00144     timesynch_set_authority_level(msg.authority_level + 1);
00145   }
00146 }
00147 static const struct broadcast_callbacks broadcast_call = {broadcast_recv};
00148 static struct broadcast_conn broadcast;
00149 /*---------------------------------------------------------------------------*/
00150 PROCESS_THREAD(timesynch_process, ev, data)
00151 {
00152   static struct etimer sendtimer, intervaltimer;
00153   static clock_time_t interval;
00154   struct timesynch_msg msg;
00155 
00156   PROCESS_EXITHANDLER(broadcast_close(&broadcast);)
00157 
00158   PROCESS_BEGIN();
00159 
00160   broadcast_open(&broadcast, TIMESYNCH_CHANNEL, &broadcast_call);
00161 
00162   interval = MIN_INTERVAL;
00163 
00164   while(1) {
00165     etimer_set(&intervaltimer, interval);
00166     etimer_set(&sendtimer, random_rand() % interval);
00167 
00168     PROCESS_WAIT_UNTIL(etimer_expired(&sendtimer));
00169 
00170     msg.authority_level = authority_level;
00171     msg.dummy = 0;
00172     msg.authority_offset = offset;
00173     msg.clock_fine = clock_fine();
00174     msg.clock_time = clock_time();
00175     msg.seconds = clock_seconds();
00176     msg.timestamp = 0;
00177     packetbuf_copyfrom(&msg, sizeof(msg));
00178     packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
00179                        PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP);
00180     broadcast_send(&broadcast);
00181 
00182     PROCESS_WAIT_UNTIL(etimer_expired(&intervaltimer));
00183     interval *= 2;
00184     if(interval >= MAX_INTERVAL) {
00185       interval = MAX_INTERVAL;
00186     }
00187   }
00188 
00189   PROCESS_END();
00190 }
00191 /*---------------------------------------------------------------------------*/
00192 void
00193 timesynch_init(void)
00194 {
00195   process_start(&timesynch_process, NULL);
00196 }
00197 /*---------------------------------------------------------------------------*/
00198 #endif /* TIMESYNCH_CONF_ENABLED */
00199 /** @} */

Generated on Mon Apr 11 14:23:31 2011 for Contiki 2.5 by  doxygen 1.6.1