Contiki 2.6

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 #include <string.h>
00052 
00053 #if TIMESYNCH_CONF_ENABLED
00054 static int authority_level;
00055 static rtimer_clock_t offset;
00056 
00057 #define TIMESYNCH_CHANNEL  7
00058 
00059 struct timesynch_msg {
00060   uint8_t authority_level;
00061   uint8_t dummy;
00062   uint16_t authority_offset;
00063   uint16_t clock_fine;
00064   clock_time_t clock_time;
00065   uint32_t seconds;
00066   /* We need some padding so that the radio has time to update the
00067      timestamp at the end of the packet, after the transmission has
00068      started. */
00069   uint8_t padding[16];
00070 
00071   /* The timestamp must be the last two bytes. */
00072   uint16_t timestamp;
00073 };
00074 
00075 PROCESS(timesynch_process, "Timesynch process");
00076 
00077 #define MIN_INTERVAL CLOCK_SECOND * 8
00078 #define MAX_INTERVAL CLOCK_SECOND * 60 * 5
00079 /*---------------------------------------------------------------------------*/
00080 int
00081 timesynch_authority_level(void)
00082 {
00083   return authority_level;
00084 }
00085 /*---------------------------------------------------------------------------*/
00086 void
00087 timesynch_set_authority_level(int level)
00088 {
00089   int old_level = authority_level;
00090 
00091   authority_level = level;
00092 
00093   if(old_level != authority_level) {
00094     /* Restart the timesynch process to restart with a low
00095        transmission interval. */
00096     process_exit(&timesynch_process);
00097     process_start(&timesynch_process, NULL);
00098   }
00099 }
00100 /*---------------------------------------------------------------------------*/
00101 rtimer_clock_t
00102 timesynch_time(void)
00103 {
00104   return RTIMER_NOW() + offset;
00105 }
00106 /*---------------------------------------------------------------------------*/
00107 rtimer_clock_t
00108 timesynch_time_to_rtimer(rtimer_clock_t synched_time)
00109 {
00110   return synched_time - offset;
00111 }
00112 /*---------------------------------------------------------------------------*/
00113 rtimer_clock_t
00114 timesynch_rtimer_to_time(rtimer_clock_t rtimer_time)
00115 {
00116   return rtimer_time + offset;
00117 }
00118 /*---------------------------------------------------------------------------*/
00119 rtimer_clock_t
00120 timesynch_offset(void)
00121 {
00122   return offset;
00123 }
00124 /*---------------------------------------------------------------------------*/
00125 static void
00126 adjust_offset(rtimer_clock_t authoritative_time, rtimer_clock_t local_time)
00127 {
00128   offset = authoritative_time - local_time;
00129 }
00130 /*---------------------------------------------------------------------------*/
00131 static void
00132 broadcast_recv(struct broadcast_conn *c, const rimeaddr_t *from)
00133 {
00134   struct timesynch_msg msg;
00135 
00136   memcpy(&msg, packetbuf_dataptr(), sizeof(msg));
00137 
00138   /* We check the authority level of the sender of the incoming
00139        packet. If the sending node has a lower authority level than we
00140        have, we synchronize to the time of the sending node and set our
00141        own authority level to be one more than the sending node. */
00142   if(msg.authority_level < authority_level) {
00143     adjust_offset(msg.timestamp + msg.authority_offset,
00144                   packetbuf_attr(PACKETBUF_ATTR_TIMESTAMP));
00145     timesynch_set_authority_level(msg.authority_level + 1);
00146   }
00147 }
00148 static const struct broadcast_callbacks broadcast_call = {broadcast_recv};
00149 static struct broadcast_conn broadcast;
00150 /*---------------------------------------------------------------------------*/
00151 PROCESS_THREAD(timesynch_process, ev, data)
00152 {
00153   static struct etimer sendtimer, intervaltimer;
00154   static clock_time_t interval;
00155   struct timesynch_msg msg;
00156 
00157   PROCESS_EXITHANDLER(broadcast_close(&broadcast);)
00158 
00159   PROCESS_BEGIN();
00160 
00161   broadcast_open(&broadcast, TIMESYNCH_CHANNEL, &broadcast_call);
00162 
00163   interval = MIN_INTERVAL;
00164 
00165   while(1) {
00166     etimer_set(&intervaltimer, interval);
00167     etimer_set(&sendtimer, random_rand() % interval);
00168 
00169     PROCESS_WAIT_UNTIL(etimer_expired(&sendtimer));
00170 
00171     msg.authority_level = authority_level;
00172     msg.dummy = 0;
00173     msg.authority_offset = offset;
00174     msg.clock_fine = clock_fine();
00175     msg.clock_time = clock_time();
00176     msg.seconds = clock_seconds();
00177     msg.timestamp = 0;
00178     packetbuf_copyfrom(&msg, sizeof(msg));
00179     packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
00180                        PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP);
00181     broadcast_send(&broadcast);
00182 
00183     PROCESS_WAIT_UNTIL(etimer_expired(&intervaltimer));
00184     interval *= 2;
00185     if(interval >= MAX_INTERVAL) {
00186       interval = MAX_INTERVAL;
00187     }
00188   }
00189 
00190   PROCESS_END();
00191 }
00192 /*---------------------------------------------------------------------------*/
00193 void
00194 timesynch_init(void)
00195 {
00196   process_start(&timesynch_process, NULL);
00197 }
00198 /*---------------------------------------------------------------------------*/
00199 #endif /* TIMESYNCH_CONF_ENABLED */
00200 /** @} */