Contiki 2.6
|
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(×ynch_process); 00097 process_start(×ynch_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(×ynch_process, NULL); 00197 } 00198 /*---------------------------------------------------------------------------*/ 00199 #endif /* TIMESYNCH_CONF_ENABLED */ 00200 /** @} */