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