Contiki 2.5
timesynch.c
Go to the documentation of this file.
1 /**
2  * \addtogroup timesynch
3  * @{
4  */
5 
6 
7 /*
8  * Copyright (c) 2007, Swedish Institute of Computer Science.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in the
18  * documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the Institute nor the names of its contributors
20  * may be used to endorse or promote products derived from this software
21  * without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * This file is part of the Contiki operating system.
36  *
37  * $Id: timesynch.c,v 1.11 2010/12/16 22:47:38 adamdunkels Exp $
38  */
39 
40 /**
41  * \file
42  * A simple time synchronization mechanism
43  * \author
44  * Adam Dunkels <adam@sics.se>
45  */
46 
47 #include "contiki.h"
48 #include "lib/random.h"
49 #include "net/rime.h"
50 #include "net/rime/timesynch.h"
51 
52 #if TIMESYNCH_CONF_ENABLED
53 static int authority_level;
54 static rtimer_clock_t offset;
55 
56 #define TIMESYNCH_CHANNEL 7
57 
58 struct timesynch_msg {
59  uint8_t authority_level;
60  uint8_t dummy;
61  uint16_t authority_offset;
62  uint16_t clock_fine;
63  clock_time_t clock_time;
64  uint32_t seconds;
65  /* We need some padding so that the radio has time to update the
66  timestamp at the end of the packet, after the transmission has
67  started. */
68  uint8_t padding[16];
69 
70  /* The timestamp must be the last two bytes. */
71  uint16_t timestamp;
72 };
73 
74 PROCESS(timesynch_process, "Timesynch process");
75 
76 #define MIN_INTERVAL CLOCK_SECOND * 8
77 #define MAX_INTERVAL CLOCK_SECOND * 60 * 5
78 /*---------------------------------------------------------------------------*/
79 int
81 {
82  return authority_level;
83 }
84 /*---------------------------------------------------------------------------*/
85 void
87 {
88  int old_level = authority_level;
89 
90  authority_level = level;
91 
92  if(old_level != authority_level) {
93  /* Restart the timesynch process to restart with a low
94  transmission interval. */
95  process_exit(&timesynch_process);
96  process_start(&timesynch_process, NULL);
97  }
98 }
99 /*---------------------------------------------------------------------------*/
100 rtimer_clock_t
101 timesynch_time(void)
102 {
103  return RTIMER_NOW() + offset;
104 }
105 /*---------------------------------------------------------------------------*/
106 rtimer_clock_t
107 timesynch_time_to_rtimer(rtimer_clock_t synched_time)
108 {
109  return synched_time - offset;
110 }
111 /*---------------------------------------------------------------------------*/
112 rtimer_clock_t
113 timesynch_rtimer_to_time(rtimer_clock_t rtimer_time)
114 {
115  return rtimer_time + offset;
116 }
117 /*---------------------------------------------------------------------------*/
118 rtimer_clock_t
119 timesynch_offset(void)
120 {
121  return offset;
122 }
123 /*---------------------------------------------------------------------------*/
124 static void
125 adjust_offset(rtimer_clock_t authoritative_time, rtimer_clock_t local_time)
126 {
127  offset = authoritative_time - local_time;
128 }
129 /*---------------------------------------------------------------------------*/
130 static void
131 broadcast_recv(struct broadcast_conn *c, const rimeaddr_t *from)
132 {
133  struct timesynch_msg msg;
134 
135  memcpy(&msg, packetbuf_dataptr(), sizeof(msg));
136 
137  /* We check the authority level of the sender of the incoming
138  packet. If the sending node has a lower authority level than we
139  have, we synchronize to the time of the sending node and set our
140  own authority level to be one more than the sending node. */
141  if(msg.authority_level < authority_level) {
142  adjust_offset(msg.timestamp + msg.authority_offset,
143  packetbuf_attr(PACKETBUF_ATTR_TIMESTAMP));
144  timesynch_set_authority_level(msg.authority_level + 1);
145  }
146 }
147 static const struct broadcast_callbacks broadcast_call = {broadcast_recv};
148 static struct broadcast_conn broadcast;
149 /*---------------------------------------------------------------------------*/
150 PROCESS_THREAD(timesynch_process, ev, data)
151 {
152  static struct etimer sendtimer, intervaltimer;
153  static clock_time_t interval;
154  struct timesynch_msg msg;
155 
157 
158  PROCESS_BEGIN();
159 
160  broadcast_open(&broadcast, TIMESYNCH_CHANNEL, &broadcast_call);
161 
162  interval = MIN_INTERVAL;
163 
164  while(1) {
165  etimer_set(&intervaltimer, interval);
166  etimer_set(&sendtimer, random_rand() % interval);
167 
168  PROCESS_WAIT_UNTIL(etimer_expired(&sendtimer));
169 
170  msg.authority_level = authority_level;
171  msg.dummy = 0;
172  msg.authority_offset = offset;
173  msg.clock_fine = clock_fine();
174  msg.clock_time = clock_time();
175  msg.seconds = clock_seconds();
176  msg.timestamp = 0;
177  packetbuf_copyfrom(&msg, sizeof(msg));
178  packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE,
179  PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP);
180  broadcast_send(&broadcast);
181 
182  PROCESS_WAIT_UNTIL(etimer_expired(&intervaltimer));
183  interval *= 2;
184  if(interval >= MAX_INTERVAL) {
185  interval = MAX_INTERVAL;
186  }
187  }
188 
189  PROCESS_END();
190 }
191 /*---------------------------------------------------------------------------*/
192 void
193 timesynch_init(void)
194 {
195  process_start(&timesynch_process, NULL);
196 }
197 /*---------------------------------------------------------------------------*/
198 #endif /* TIMESYNCH_CONF_ENABLED */
199 /** @} */