From 4914739e5d21090467e21a7061233695071658ee Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Thu, 16 Dec 2010 22:47:38 +0000 Subject: [PATCH] Revived the timesynch module, which has been switched off since the introduction of the new radio API after Contiki 2.4. The new code uses explicit timestamp messages instead of piggybacking timestamps on every transmission. It is also significantly better in terms of exactness. --- core/net/rime/timesynch.c | 112 ++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 24 deletions(-) diff --git a/core/net/rime/timesynch.c b/core/net/rime/timesynch.c index f85acea61..83ca2fd30 100644 --- a/core/net/rime/timesynch.c +++ b/core/net/rime/timesynch.c @@ -34,7 +34,7 @@ * * This file is part of the Contiki operating system. * - * $Id: timesynch.c,v 1.10 2010/06/14 19:19:17 adamdunkels Exp $ + * $Id: timesynch.c,v 1.11 2010/12/16 22:47:38 adamdunkels Exp $ */ /** @@ -44,15 +44,37 @@ * Adam Dunkels */ -#include "net/rime/timesynch.h" -#include "net/packetbuf.h" +#include "contiki.h" +#include "lib/random.h" #include "net/rime.h" -#include "dev/cc2420.h" +#include "net/rime/timesynch.h" #if TIMESYNCH_CONF_ENABLED static int authority_level; static rtimer_clock_t offset; +#define TIMESYNCH_CHANNEL 7 + +struct timesynch_msg { + uint8_t authority_level; + uint8_t dummy; + uint16_t authority_offset; + uint16_t clock_fine; + clock_time_t clock_time; + uint32_t seconds; + /* We need some padding so that the radio has time to update the + timestamp at the end of the packet, after the transmission has + started. */ + uint8_t padding[16]; + + /* The timestamp must be the last two bytes. */ + uint16_t timestamp; +}; + +PROCESS(timesynch_process, "Timesynch process"); + +#define MIN_INTERVAL CLOCK_SECOND * 8 +#define MAX_INTERVAL CLOCK_SECOND * 60 * 5 /*---------------------------------------------------------------------------*/ int timesynch_authority_level(void) @@ -63,7 +85,16 @@ timesynch_authority_level(void) void timesynch_set_authority_level(int level) { + int old_level = authority_level; + authority_level = level; + + if(old_level != authority_level) { + /* Restart the timesynch process to restart with a low + transmission interval. */ + process_exit(×ynch_process); + process_start(×ynch_process, NULL); + } } /*---------------------------------------------------------------------------*/ rtimer_clock_t @@ -93,42 +124,75 @@ timesynch_offset(void) static void adjust_offset(rtimer_clock_t authoritative_time, rtimer_clock_t local_time) { - offset = offset + authoritative_time - local_time; + offset = authoritative_time - local_time; } /*---------------------------------------------------------------------------*/ static void -incoming_packet(void) +broadcast_recv(struct broadcast_conn *c, const rimeaddr_t *from) { - if(packetbuf_totlen() != 0) { - /* We check the authority level of the sender of the incoming + struct timesynch_msg msg; + + memcpy(&msg, packetbuf_dataptr(), sizeof(msg)); + + /* We check the authority level of the sender of the incoming packet. If the sending node has a lower authority level than we have, we synchronize to the time of the sending node and set our own authority level to be one more than the sending node. */ - if(cc2420_authority_level_of_sender < authority_level) { - adjust_offset(cc2420_time_of_departure, - cc2420_time_of_arrival); - if(cc2420_authority_level_of_sender + 1 != authority_level) { - authority_level = cc2420_authority_level_of_sender + 1; - } - } + if(msg.authority_level < authority_level) { + adjust_offset(msg.timestamp + msg.authority_offset, + packetbuf_attr(PACKETBUF_ATTR_TIMESTAMP)); + timesynch_set_authority_level(msg.authority_level + 1); } } +static const struct broadcast_callbacks broadcast_call = {broadcast_recv}; +static struct broadcast_conn broadcast; /*---------------------------------------------------------------------------*/ -#if 0 -static void -periodic_authority_increase(void *ptr) +PROCESS_THREAD(timesynch_process, ev, data) { - /* XXX the authority level should be increased over time except - for the sink node (which has authority 0). */ + static struct etimer sendtimer, intervaltimer; + static clock_time_t interval; + struct timesynch_msg msg; + + PROCESS_EXITHANDLER(broadcast_close(&broadcast);) + + PROCESS_BEGIN(); + + broadcast_open(&broadcast, TIMESYNCH_CHANNEL, &broadcast_call); + + interval = MIN_INTERVAL; + + while(1) { + etimer_set(&intervaltimer, interval); + etimer_set(&sendtimer, random_rand() % interval); + + PROCESS_WAIT_UNTIL(etimer_expired(&sendtimer)); + + msg.authority_level = authority_level; + msg.dummy = 0; + msg.authority_offset = offset; + msg.clock_fine = clock_fine(); + msg.clock_time = clock_time(); + msg.seconds = clock_seconds(); + msg.timestamp = 0; + packetbuf_copyfrom(&msg, sizeof(msg)); + packetbuf_set_attr(PACKETBUF_ATTR_PACKET_TYPE, + PACKETBUF_ATTR_PACKET_TYPE_TIMESTAMP); + broadcast_send(&broadcast); + + PROCESS_WAIT_UNTIL(etimer_expired(&intervaltimer)); + interval *= 2; + if(interval >= MAX_INTERVAL) { + interval = MAX_INTERVAL; + } + } + + PROCESS_END(); } -#endif -/*---------------------------------------------------------------------------*/ -RIME_SNIFFER(sniffer, incoming_packet, NULL); /*---------------------------------------------------------------------------*/ void timesynch_init(void) { - rime_sniffer_add(&sniffer); + process_start(×ynch_process, NULL); } /*---------------------------------------------------------------------------*/ #endif /* TIMESYNCH_CONF_ENABLED */