diff --git a/Makefile.include b/Makefile.include index 68b35e62d..3abdbb493 100644 --- a/Makefile.include +++ b/Makefile.include @@ -59,7 +59,7 @@ include $(CONTIKI)/core/net/mac/Makefile.mac SYSTEM = process.c procinit.c autostart.c elfloader.c profile.c \ timetable.c timetable-aggregate.c compower.c serial-line.c THREADS = mt.c -LIBS = memb.c mmem.c timer.c list.c etimer.c ctimer.c energest.c rtimer.c stimer.c \ +LIBS = memb.c mmem.c timer.c list.c etimer.c ctimer.c energest.c rtimer.c stimer.c trickle-timer.c \ print-stats.c ifft.c crc16.c random.c checkpoint.c ringbuf.c settings.c DEV = nullradio.c diff --git a/core/lib/trickle-timer.c b/core/lib/trickle-timer.c new file mode 100755 index 000000000..1297fdb4d --- /dev/null +++ b/core/lib/trickle-timer.c @@ -0,0 +1,407 @@ +/** + * \addtogroup trickle-timer + * @{ + */ + +/** + * \file + * Trickle timer library implementation. + * \author + * George Oikonomou - + */ + +/* + * Copyright (c) 2012, George Oikonomou - + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "contiki-conf.h" +#include "lib/trickle-timer.h" +#include "sys/ctimer.h" +#include "sys/cc.h" +#include "lib/random.h" +/*---------------------------------------------------------------------------*/ +#define DEBUG 0 + +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif +/*---------------------------------------------------------------------------*/ +/** + * \brief Wide randoms for platforms using a 4-byte wide clock + * (see ::TRICKLE_TIMER_WIDE_RAND) + */ +#if TRICKLE_TIMER_WIDE_RAND +#define tt_rand() wide_rand() +#else +#define tt_rand() random_rand() +#endif +/*---------------------------------------------------------------------------*/ +/* Declarations of variables of local interest */ +/*---------------------------------------------------------------------------*/ +static struct trickle_timer *loctt; /* Pointer to a struct for local use */ +static clock_time_t loc_clock; /* A local, general-purpose placeholder */ + +static void fire(void *ptr); +static void double_interval(void *ptr); +/*---------------------------------------------------------------------------*/ +/* Local utilities and functions to be used as ctimer callbacks */ +/*---------------------------------------------------------------------------*/ +#if TRICKLE_TIMER_WIDE_RAND +/* Returns a 4-byte wide, unsigned random number */ +static uint32_t +wide_rand() +{ + return ((uint32_t)random_rand() << 16 | random_rand()); +} +#endif +/*---------------------------------------------------------------------------*/ +/* + * Returns the maximum sane Imax value for a given Imin + * + * This function is a variant of a fairly standard 'Count Leading Zeros'. It + * has three flavours. The most suitable one for a specific platform can be + * configured by changing the value of TRICKLE_TIMER_CONF_MAX_IMAX_WIDTH + * in the platform's contiki-conf.h + */ +#if TRICKLE_TIMER_ERROR_CHECKING +static uint8_t +max_imax(clock_time_t value) +{ + uint8_t zeros = 0; +#if (TRICKLE_TIMER_MAX_IMAX_WIDTH==TRICKLE_TIMER_MAX_IMAX_GENERIC) + uint8_t i; + clock_time_t mask = 0xFFFF; + + value--; + + for(i = sizeof(clock_time_t) << 2; i > 0; i >>= 1) { + if((value & (mask <<= i)) == 0) { + zeros += i; + value <<= i; + } + } + +#elif (TRICKLE_TIMER_MAX_IMAX_WIDTH==TRICKLE_TIMER_MAX_IMAX_16_BIT) + if((value & 0xFF00) == 0) { + zeros += 8; + value <<= 8; + } + if((value & 0xF000) == 0) { + zeros += 4; + value <<= 4; + } + if((value & 0xC000) == 0) { + zeros += 2; + value <<= 2; + } + if((value & 0x8000) == 0) { + zeros++; + } +#elif (TRICKLE_TIMER_MAX_IMAX_WIDTH==TRICKLE_TIMER_MAX_IMAX_32_BIT) + if((value & 0xFFFF0000) == 0) { + zeros += 16; + value <<= 16; + } + if((value & 0xFF000000) == 0) { + zeros += 8; + value <<= 8; + } + if((value & 0xF0000000) == 0) { + zeros += 4; + value <<= 4; + } + if((value & 0xC0000000) == 0) { + zeros += 2; + value <<= 2; + } + if((value & 0x80000000) == 0) { + zeros += 1; + } +#endif + + return zeros - 1; /* Always non-negative due to the range of 'value' */ +} +#endif /* TRICKLE_TIMER_ERROR_CHECKING */ +/*---------------------------------------------------------------------------*/ +/* Returns a random time point t in [I/2 , I) */ +static clock_time_t +get_t(clock_time_t i_cur) +{ + i_cur >>= 1; + + PRINTF("trickle_timer get t: [%lu, %lu)\n", (unsigned long)i_cur, + (unsigned long)(i_cur << 1)); + + return i_cur + (tt_rand() % i_cur); +} +/*---------------------------------------------------------------------------*/ +static void +schedule_for_end(struct trickle_timer *tt) +{ + /* Reset our ctimer, schedule interval_end to run at time I */ + clock_time_t now = clock_time(); + + loc_clock = TRICKLE_TIMER_INTERVAL_END(tt) - now; + + PRINTF("trickle_timer sched for end: at %lu, end in %ld\n", + (unsigned long)clock_time(), (signed long)loc_clock); + + /* Interval's end will happen in loc_clock ticks. Make sure this isn't in + * the past... */ + if(loc_clock > (TRICKLE_TIMER_CLOCK_MAX >> 1)) { + loc_clock = 0; /* Interval ended in the past, schedule for in 0 */ + PRINTF("trickle_timer doubling: Was in the past. Compensating\n"); + } + + ctimer_set(&tt->ct, loc_clock, double_interval, tt); +} +/*---------------------------------------------------------------------------*/ +/* This is used as a ctimer callback, thus its argument must be void *. ptr is + * a pointer to the struct trickle_timer that fired */ +static void +double_interval(void *ptr) +{ + clock_time_t last_end; + + /* 'cast' ptr to a struct trickle_timer */ + loctt = (struct trickle_timer *)ptr; + + loctt->c = 0; + + PRINTF("trickle_timer doubling: at %lu, (was for %lu), ", + (unsigned long)clock_time(), + (unsigned long)TRICKLE_TIMER_INTERVAL_END(loctt)); + + /* Remember the previous interval's end (absolute time), before we double */ + last_end = TRICKLE_TIMER_INTERVAL_END(loctt); + + /* Double the interval if we have to */ + if(loctt->i_cur <= TRICKLE_TIMER_INTERVAL_MAX(loctt) >> 1) { + /* If I <= Imax/2, we double */ + loctt->i_cur <<= 1; + PRINTF("I << 1 = %lu\n", (unsigned long)loctt->i_cur); + } else { + /* We may have I > Imax/2 but I <> Imax, in which case we set to Imax + * This will happen when I didn't start as Imin (before the first reset) */ + loctt->i_cur = TRICKLE_TIMER_INTERVAL_MAX(loctt); + PRINTF("I = Imax = %lu\n", (unsigned long)loctt->i_cur); + } + + /* Random t in [I/2, I) */ + loc_clock = get_t(loctt->i_cur); + + PRINTF("trickle_timer doubling: t=%lu\n", (unsigned long)loc_clock); + +#if TRICKLE_TIMER_COMPENSATE_DRIFT + /* Schedule for t ticks after the previous interval's end, not after now. If + * that is in the past, schedule in 0 */ + loc_clock = (last_end + loc_clock) - clock_time(); + PRINTF("trickle_timer doubling: at %lu, in %ld ticks\n", + (unsigned long)clock_time(), (signed long)loc_clock); + if(loc_clock > (TRICKLE_TIMER_CLOCK_MAX >> 1)) { + /* Oops, that's in the past */ + loc_clock = 0; + PRINTF("trickle_timer doubling: Was in the past. Compensating\n"); + } + ctimer_set(&loctt->ct, loc_clock, fire, loctt); + + /* Store the actual interval start (absolute time), we need it later. + * We pretend that it started at the same time when the last one ended */ + loctt->i_start = last_end; +#else + /* Assumed that the previous interval's end is 'now' and schedule in t ticks + * after 'now', ignoring potential offsets */ + ctimer_set(&loctt->ct, loc_clock, fire, loctt); + /* Store the actual interval start (absolute time), we need it later */ + loctt->i_start = loctt->ct.etimer.timer.start; +#endif + + PRINTF("trickle_timer doubling: Last end %lu, new end %lu, for %lu, I=%lu\n", + (unsigned long)last_end, + (unsigned long)TRICKLE_TIMER_INTERVAL_END(loctt), + (unsigned long)(loctt->ct.etimer.timer.start + + loctt->ct.etimer.timer.interval), + (unsigned long)(loctt->i_cur)); +} +/*---------------------------------------------------------------------------*/ +/* Called by the ctimer module at time t within the current interval. ptr is + * a pointer to the struct trickle_timer of interest */ +static void +fire(void *ptr) +{ + /* 'cast' c to a struct trickle_timer */ + loctt = (struct trickle_timer *)ptr; + + PRINTF("trickle_timer fire: at %lu (was for %lu)\n", + (unsigned long)clock_time(), + (unsigned long)(loctt->ct.etimer.timer.start + + loctt->ct.etimer.timer.interval)); + + if(loctt->cb) { + /* + * Call the protocol's TX callback, with the suppression status as an + * argument. + */ + PRINTF("trickle_timer fire: Suppression Status %u (%u < %u)\n", + TRICKLE_TIMER_PROTO_TX_ALLOW(loctt), loctt->c, loctt->k); + loctt->cb(loctt->cb_arg, TRICKLE_TIMER_PROTO_TX_ALLOW(loctt)); + } + + schedule_for_end(loctt); +} +/*---------------------------------------------------------------------------*/ +/* New trickle interval, either due to a newly set trickle timer or due to an + * inconsistency. Schedule 'fire' to be called in t ticks. */ +static void +new_interval(struct trickle_timer *tt) +{ + tt->c = 0; + + /* Random t in [I/2, I) */ + loc_clock = get_t(tt->i_cur); + + ctimer_set(&tt->ct, loc_clock, fire, tt); + + /* Store the actual interval start (absolute time), we need it later */ + tt->i_start = tt->ct.etimer.timer.start; + PRINTF("trickle_timer new interval: at %lu, ends %lu, ", + (unsigned long)clock_time(), + (unsigned long)TRICKLE_TIMER_INTERVAL_END(tt)); + PRINTF("t=%lu, I=%lu\n", (unsigned long)loc_clock, (unsigned long)tt->i_cur); +} +/*---------------------------------------------------------------------------*/ +/* Functions to be called by the protocol implementation */ +/*---------------------------------------------------------------------------*/ +void +trickle_timer_consistency(struct trickle_timer *tt) +{ + if(tt->c < 0xFF) { + tt->c++; + } + PRINTF("trickle_timer consistency: c=%u\n", tt->c); +} +/*---------------------------------------------------------------------------*/ +void +trickle_timer_inconsistency(struct trickle_timer *tt) +{ + /* "If I is equal to Imin when Trickle hears an "inconsistent" transmission, + * Trickle does nothing." */ + if(tt->i_cur != tt->i_min) { + PRINTF("trickle_timer inconsistency\n"); + tt->i_cur = tt->i_min; + + new_interval(tt); + } +} +/*---------------------------------------------------------------------------*/ +uint8_t +trickle_timer_config(struct trickle_timer *tt, clock_time_t i_min, + uint8_t i_max, uint8_t k) +{ +#if TRICKLE_TIMER_ERROR_CHECKING + /* + * Although in theory Imin=1 is a valid value, it would break get_t() and + * doesn't make sense anyway. Thus Valid Imin values are in the range: + * 1 < Imin <= (TRICKLE_TIMER_CLOCK_MAX >> 1) + 1 + */ + if(TRICKLE_TIMER_IMIN_IS_BAD(i_min)) { + PRINTF("trickle_timer config: Bad Imin value\n"); + return TRICKLE_TIMER_ERROR; + } + + if(tt == NULL || i_max == 0 || k == 0) { + PRINTF("trickle_timer config: Bad arguments\n"); + return TRICKLE_TIMER_ERROR; + } + + /* + * If clock_time_t is not wide enough to store Imin << Imax, we adjust Imax + * + * This means that 'we' are likely to have a different Imax than 'them' + * See RFC 6206, sec 6.3 for the consequences of this situation + */ + if(TRICKLE_TIMER_IPAIR_IS_BAD(i_min, i_max)) { + PRINTF("trickle_timer config: %lu << %u would exceed clock boundaries. ", + (unsigned long)i_min, i_max); + + /* For this Imin, get the maximum sane Imax */ + i_max = max_imax(i_min); + PRINTF("trickle_timer config: Using Imax=%u\n", i_max); + } +#endif + + tt->i_min = i_min; + tt->i_max = i_max; + tt->i_max_abs = i_min << i_max; + tt->k = k; + + PRINTF("trickle_timer config: Imin=%lu, Imax=%u, k=%u\n", + (unsigned long)tt->i_min, tt->i_max, tt->k); + + return TRICKLE_TIMER_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +uint8_t +trickle_timer_set(struct trickle_timer *tt, trickle_timer_cb_t proto_cb, + void *ptr) +{ +#if TRICKLE_TIMER_ERROR_CHECKING + /* Sanity checks */ + if(tt == NULL || proto_cb == NULL) { + PRINTF("trickle_timer set: Bad arguments\n"); + return TRICKLE_TIMER_ERROR; + } +#endif + + tt->cb = proto_cb; + tt->cb_arg = ptr; + + /* Random I in [Imin , Imax] */ + tt->i_cur = tt->i_min + + (tt_rand() % (TRICKLE_TIMER_INTERVAL_MAX(tt) - tt->i_min + 1)); + + PRINTF("trickle_timer set: I=%lu in [%lu , %lu]\n", (unsigned long)tt->i_cur, + (unsigned long)tt->i_min, + (unsigned long)TRICKLE_TIMER_INTERVAL_MAX(tt)); + + new_interval(tt); + + PRINTF("trickle_timer set: at %lu, ends %lu, t=%lu in [%lu , %lu)\n", + (unsigned long)tt->i_start, + (unsigned long)TRICKLE_TIMER_INTERVAL_END(tt), + (unsigned long)tt->ct.etimer.timer.interval, + (unsigned long)tt->i_cur >> 1, (unsigned long)tt->i_cur); + + return TRICKLE_TIMER_SUCCESS; +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/core/lib/trickle-timer.h b/core/lib/trickle-timer.h new file mode 100755 index 000000000..c7c004748 --- /dev/null +++ b/core/lib/trickle-timer.h @@ -0,0 +1,491 @@ +/** \addtogroup lib + * @{ */ + +/** + * \defgroup trickle-timer Trickle timers + * + * This library implements timers which behave in accordance with RFC 6206 + * "The Trickle Algorithm" (http://tools.ietf.org/html/rfc6206) + * + * Protocols wishing to use trickle timers, may use this library instead of + * implementing the trickle algorithm internally. + * + * The protocol implementation will declare one (or more) variable(s) of type + * struct ::trickle_timer and will then populate its fields by calling + * trickle_timer_config(). trickle_timer_set() will start the timer. + * + * When the timer reaches time t within the current trickle interval, the + * library will call a protocol-provided callback, which will signal to the + * protocol that it is time to TX (see algorithm step 4 in the RFC). + * + * The proto does not need to check the suppression conditions. This is done by + * the library and if TX must be suppressed, the callback won't be called at + * all. + * + * The library also provides functions to be called when the protocol hears a + * 'consistent' or 'inconsistent' message and when an 'external event' occurs + * (in this context, those terms have the exact same meaning as in the RFC). + * + * @{ + */ + + +/** + * \file + * Trickle timer library header file. + * + * \author + * George Oikonomou - + */ + +/* + * Copyright (c) 2012, George Oikonomou - + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __TRICKLE_TIMER_H__ +#define __TRICKLE_TIMER_H__ + +#include "contiki-conf.h" +#include "sys/ctimer.h" +/*---------------------------------------------------------------------------*/ +/* Trickle Timer Library Constants */ +/*---------------------------------------------------------------------------*/ +/** + * \name Trickle Timer Library: Constants + * @{ + */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Set as value of k to disable suppression + */ +#define TRICKLE_TIMER_INFINITE_REDUNDANCY 0x00 + +#define TRICKLE_TIMER_ERROR 0 +#define TRICKLE_TIMER_SUCCESS 1 + +/** + * \brief Use as the value of TRICKLE_TIMER_MAX_IMAX_WIDTH to enable the + * generic 'Find max Imax' routine + */ +#define TRICKLE_TIMER_MAX_IMAX_GENERIC 0 +/** + * \brief Use as the value of TRICKLE_TIMER_MAX_IMAX_WIDTH to enable the 16-bit + * 'Find max Imax' routine + */ +#define TRICKLE_TIMER_MAX_IMAX_16_BIT 1 +/** + * \brief Use as the value of TRICKLE_TIMER_MAX_IMAX_WIDTH to enable the 32-bit + * 'Find max Imax' routine + */ +#define TRICKLE_TIMER_MAX_IMAX_32_BIT 2 + +/** + * \brief Constants used as values for the \e suppress param of + * trickle_timer_cb_t + */ +#define TRICKLE_TIMER_TX_SUPPRESS 0 +#define TRICKLE_TIMER_TX_OK 1 +/** @} */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Controls whether the library will try to compensate for time drifts + * caused by getting called later than scheduled. + * + * 1: Enabled (default). 0: Disabled + * + * To override the default, define TRICKLE_TIMER_CONF_COMPENSATE_DRIFT in + * contiki-conf.h + * + * Bear in mind that this controls the behaviour of the entire library (i.e. + * all trickle timers) and not of an individual timer + */ +#ifdef TRICKLE_TIMER_CONF_COMPENSATE_DRIFT +#define TRICKLE_TIMER_COMPENSATE_DRIFT TRICKLE_TIMER_CONF_COMPENSATE_DRIFT +#else +#define TRICKLE_TIMER_COMPENSATE_DRIFT 1 +#endif +/*---------------------------------------------------------------------------*/ +/** + * \brief Turns on support for 4-byte wide, unsigned random numbers + * + * We need this for platforms which have a 4-byte wide clock_time_t. For those + * platforms and if Imin << Imax is GT 0xFFFF, random_rand alone is not always + * enough to generate a correct t in [I/2, I). Specifically, we need wide + * randoms when I > 0x1FFFF. + * + * For platforms with a 2-byte wide clock_time_t, this can be defined as 0 + * to reduce code footprint and increase speed. + */ +#ifdef TRICKLE_TIMER_CONF_WIDE_RAND +#define TRICKLE_TIMER_WIDE_RAND TRICKLE_TIMER_CONF_WIDE_RAND +#else +#define TRICKLE_TIMER_WIDE_RAND 1 +#endif +/*---------------------------------------------------------------------------*/ +/** + * \brief Selects a flavor for the 'Find maximum Imax' (max_imax) function. + * + * When configuring a new trickle timer, the library verifies that the (Imin , + * Imax) pair will fit in the platform's clock_time_t boundaries. If this is + * not the case, Imax will be adjusted down. In order to achieve this, we use + * an internal function which is a slight variant of a standard 'Count Leading + * Zeros'. + * + * This functionality is disabled when ::TRICKLE_TIMER_ERROR_CHECKING is 0 + * + * This define helps us generate, at the pre-processing stage, the desired + * version of this function. We start with a generic version by default. The + * platform's contiki-conf.h can change this to use the 16- or 32-bit specific + * flavor by defining TRICKLE_TIMER_CONF_MAX_IMAX_WIDTH. + * + * Depending on the toolchain, the generic variant may actually result in a + * smaller code size. Do your own experiments. + * + * TRICKLE_TIMER_MAX_IMAX_GENERIC (0): Generic function which will work + * regardless whether the platform uses a 16 or 32 bit wide clock type + * + * TRICKLE_TIMER_MAX_IMAX_16_BIT (1): You can select this in your + * contiki-conf.h if your platform's clock_time_t is 16 bits wide + * + * TRICKLE_TIMER_MAX_IMAX_32_BIT (2): You can select this in your + * contiki-conf.h if your platform's clock_time_t is 32 bits wide + */ +#ifdef TRICKLE_TIMER_CONF_MAX_IMAX_WIDTH +#define TRICKLE_TIMER_MAX_IMAX_WIDTH TRICKLE_TIMER_CONF_MAX_IMAX_WIDTH +#else +#define TRICKLE_TIMER_MAX_IMAX_WIDTH TRICKLE_TIMER_MAX_IMAX_GENERIC +#endif + +/** + * \brief Enables/Disables error checking + * + * 1: Enabled (default). The library checks the validity of Imin and Imax + * 0: Disabled. All error checking is turned off. This reduces code size. + */ +#ifdef TRICKLE_TIMER_CONF_ERROR_CHECKING +#define TRICKLE_TIMER_ERROR_CHECKING TRICKLE_TIMER_CONF_ERROR_CHECKING +#else +#define TRICKLE_TIMER_ERROR_CHECKING 1 +#endif +/*---------------------------------------------------------------------------*/ +/* Trickle Timer Library Macros */ +/*---------------------------------------------------------------------------*/ +/** + * \name Trickle Timer Library: Macros + * @{ + */ +/** + * \brief cross-platform method to get the maximum clock_time_t value + */ +#define TRICKLE_TIMER_CLOCK_MAX ((clock_time_t)~0) + + +/** + * \brief Checks if the trickle timer's suppression feature is enabled + * + * \param tt A pointer to a ::trickle_timer structure + * + * \retval non-zero Suppression is enabled + * \retval 0 Suppression is disabled + */ +#define TRICKLE_TIMER_SUPPRESSION_ENABLED(tt) \ + ((tt)->k != TRICKLE_TIMER_INFINITE_REDUNDANCY) + +/** + * \brief Checks if the trickle timer's suppression feature is disabled + * + * \param tt A pointer to a ::trickle_timer structure + * + * \retval non-zero Suppression is disabled + * \retval 0 Suppression is enabled + */ +#define TRICKLE_TIMER_SUPPRESSION_DISABLED(tt) \ + ((tt)->k == TRICKLE_TIMER_INFINITE_REDUNDANCY) + +/** + * \brief Determines whether the protocol must go ahead with a transmission + * + * \param tt A pointer to a ::trickle_timer structure + * + * \retval non-zero Go ahead with TX + * \retval 0 Suppress + */ +#define TRICKLE_TIMER_PROTO_TX_ALLOW(tt) \ + (TRICKLE_TIMER_SUPPRESSION_DISABLED(tt) || ((tt)->c < (tt)->k)) + +/** + * \brief Determines whether the protocol must suppress a transmission + * + * \param tt A pointer to a ::trickle_timer structure + * + * \retval non-zero Suppress + * \retval 0 Go ahead with TX + */ +#define TRICKLE_TIMER_PROTO_TX_SUPPRESS(tt) \ + (TRICKLE_TIMER_SUPPRESSION_ENABLED(tt) && ((tt)->c >= (tt)->k)) + +/** + * \brief Returns a timer's maximum interval size (Imin << Imax) as a number of + * clock ticks + * + * \param tt A pointer to a ::trickle_timer structure + * + * \return Maximum trickle interval length in clock ticks + */ +#define TRICKLE_TIMER_INTERVAL_MAX(tt) ((tt)->i_max_abs) + +/** + * \brief Returns the current trickle interval's end (absolute time in ticks) + * + * \param tt A pointer to a ::trickle_timer structure + * + * \return The absolute number of clock ticks when the current trickle interval + * will expire + */ +#define TRICKLE_TIMER_INTERVAL_END(tt) ((tt)->i_start + (tt)->i_cur) + +/** + * \brief Checks whether an Imin value is suitable considering the various + * restrictions imposed by our platform's clock as well as by the library itself + * + * \param imin An Imin value in clock ticks + * + * \retval 1 The Imin value is valid + * \retval 0 The Imin value is invalid + */ +#define TRICKLE_TIMER_IMIN_IS_OK(imin) \ + ((imin > 1) && (i_min <= (TRICKLE_TIMER_CLOCK_MAX >> 1))) + +/** + * \brief Checks whether an Imin value is invalid considering the various + * restrictions imposed by our platform's clock as well as by the library itself + * + * \param imin An Imin value in clock ticks + * + * \retval 1 The Imin value is invalid + * \retval 0 The Imin value is valid + */ +#define TRICKLE_TIMER_IMIN_IS_BAD(imin) \ + ((imin < 2) || (i_min > (TRICKLE_TIMER_CLOCK_MAX >> 1))) + +/** + * \brief Checks whether Imin << Imax is unsuitable considering the boundaries + * of our platform's clock_time_t + * + * \param i_min Imin value + * \param i_max Maximum number of doublings + * + * \retval non-zero The pair would exceed clock boundaries + * \retval 0 The pair is suitable for the platform + * + * Timers scheduled far in the future can be perceived as being scheduled in + * the past. + * Thus, we limit Imin << Imax to be LEQ(TRICKLE_TIMER_CLOCK_MAX >> 1) + 1 + */ +#define TRICKLE_TIMER_IPAIR_IS_BAD(i_min, i_max) \ + ((TRICKLE_TIMER_CLOCK_MAX >> (i_max + 1)) < i_min - 1) +/** @} */ +/*---------------------------------------------------------------------------*/ +/* Trickle Timer Library Data Representation */ +/*---------------------------------------------------------------------------*/ +/** + * \name Trickle Timer Library: Data Representation + * @{ + */ + +/** + * \brief typedef for a callback function to be defined in the protocol's + * implementation. + * + * Those callbaks are stored as a function pointer inside a ::trickle_timer + * structure and are called by the library at time t within the current trickle + * interval. + * + * Some protocols may rely on multiple trickle timers. For this reason, this + * function's argument will be an opaque pointer, aiming to help the protocol + * determine which timer triggered the call. + * + * The \e suppress argument is used so that the library can signal the protocol + * whether it should TX or suppress + */ +typedef void (* trickle_timer_cb_t)(void *ptr, uint8_t suppress); + +/** + * \struct trickle_timer + * + * A trickle timer. + * + * This structure is used for declaring a trickle timer. In order for the timer + * to start running, the protocol must first populate the structure's fields + * by calling trickle_timer_set(). Protocol implementations must NOT modify the + * contents of this structure directly. + * + * Protocol developers must also be careful to specify the values of Imin and + * Imax in such a way that the maximum interval size does not exceed the + * boundaries of clock_time_t + */ +struct trickle_timer { + clock_time_t i_min; /**< Imin: Clock ticks */ + clock_time_t i_cur; /**< I: Current interval in clock_ticks */ + clock_time_t i_start; /**< Start of this interval (absolute clock_time) */ + clock_time_t i_max_abs; /**< Maximum interval size in clock ticks (and not in + number of doublings). This is a cached value of + Imin << Imax used internally, so that we can + have direct access to the maximum interval size + without having to calculate it all the time */ + struct ctimer ct; /**< A \ref ctimer used internally */ + trickle_timer_cb_t cb; /**< Protocol's own callback, invoked at time t + within the current interval */ + void *cb_arg; /**< Opaque pointer to be used as the argument of the + protocol's callback */ + uint8_t i_max; /**< Imax: Max number of doublings */ + uint8_t k; /**< k: Redundancy Constant */ + uint8_t c; /**< c: Consistency Counter */ +}; +/** @} */ +/*---------------------------------------------------------------------------*/ +/* Trickle Timer Library Functions */ +/*---------------------------------------------------------------------------*/ +/** + * \name Trickle Timer Library: Functions called by protocol implementations + * @{ + */ + +/** + * \brief Configure a trickle timer + * \param tt A pointer to a ::trickle_timer structure + * \param i_min The timer's Imin configuration parameter, in units of + * clock_time_t + * \param i_max The timer's Imax configuration parameter (maximum number of + * doublings), specified as number of doublings + * \param k The timer's K (redundancy constant). If the value of K + * equals #TRICKLE_TIMER_INFINITE_REDUNDANCY, message + * suppression will be disabled + * \retval 0 Error (Bad argument) + * \retval non-zero Success. + * + * This function is used to set the initial configuration for a trickle timer. + * A trickle timer MUST be configured before the protocol calls + * trickle_timer_set(). + * + * If Imin<ct) + +/** + * \brief To be called by the protocol when it hears a consistent + * transmission + * \param tt A pointer to a ::trickle_timer structure + * + * When the trickle-based protocol hears a consistent transmission it must call + * this function to increment trickle's consistency counter, which is later + * used to determine whether the protocol must suppress or go ahead with its + * own transmissions. + * + * As the trickle timer library implementation may change in the future to + * perform further tasks upon reception of a consistent transmission, the + * protocol's implementation MUST use this call to increment the consistency + * counter instead of directly writing to the structure's field. + */ +void trickle_timer_consistency(struct trickle_timer *tt); + +/** + * \brief To be called by the protocol when it hears an inconsistent + * transmission + * \param tt A pointer to a ::trickle_timer structure + * + * When the protocol hears an inconsistent transmission, it must call this + * function to notify the library that the timer must be reset. + * + * Before resetting the timer, the library will perform a set of checks. + * Therefore, it is important that the protocol calls this function instead of + * trying to reset the timer by itself. + */ +void trickle_timer_inconsistency(struct trickle_timer *tt); + +/** + * \brief To be called by the protocol when an external event occurs that + * should trigger a timer reset + * \param tt A pointer to a ::trickle_timer structure + * + * When an external event occurs that should result in a timer reset, the + * protocol implementation must call this function to notify the library. + * + * Before resetting the timer, the library will perform a set of checks. + * Therefore, it is important that the protocol calls this function instead of + * trying to reset the timer by itself. + */ +#define trickle_timer_reset_event(tt) trickle_timer_inconsistency(tt) + +/** @} */ + +#endif /* __TRICKLE_TIMER_H__ */ +/** @} */ +/** @} */ diff --git a/examples/trickle-library/Makefile b/examples/trickle-library/Makefile new file mode 100644 index 000000000..69a4e0402 --- /dev/null +++ b/examples/trickle-library/Makefile @@ -0,0 +1,9 @@ +UIP_CONF_IPV6=1 + +CONTIKI_PROJECT = trickle-library + +all: $(CONTIKI_PROJECT) + +CONTIKI = ../.. + +include $(CONTIKI)/Makefile.include diff --git a/examples/trickle-library/trickle-library.c b/examples/trickle-library/trickle-library.c new file mode 100644 index 000000000..0cbc9a7ec --- /dev/null +++ b/examples/trickle-library/trickle-library.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2012, George Oikonomou - + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Example trickle-based protocol demonstrating the functionality of the + * trickle (trickle_timer) library (RFC 6206) */ +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" + +#include "lib/trickle-timer.h" +#include "dev/leds.h" +#include "lib/random.h" + +#include + +#define DEBUG DEBUG_PRINT +#include "net/uip-debug.h" + +/* Trickle variables and constants */ +static struct trickle_timer tt; + +#define IMIN 16 /* ticks */ +#define IMAX 10 /* doublings */ +#define REDUNDANCY_CONST 2 + +/* Networking */ +#define TRICKLE_PROTO_PORT 30001 +static struct uip_udp_conn *trickle_conn; +static uip_ipaddr_t ipaddr; /* destination: link-local all-nodes multicast */ + +/* + * For this 'protocol', nodes exchange a token (1 byte) at a frequency + * governed by trickle. A node detects an inconsistency when it receives a + * token different than the one it knows. + * In this case, either: + * - 'they' have a 'newer' token and we also update our own value, or + * - 'we' have a 'newer' token, in which case we trigger an inconsistency + * without updating our value. + * In this context, 'newer' is defined in serial number arithmetic terms. + * + * Every NEW_TOKEN_INTERVAL clock ticks each node will generate a new token + * with probability 1/NEW_TOKEN_PROB. This is controlled by etimer et. + */ +#define NEW_TOKEN_INTERVAL 10 * CLOCK_SECOND +#define NEW_TOKEN_PROB 0x80 +static uint8_t token; +static struct etimer et; /* Used to periodically generate inconsistencies */ +/*---------------------------------------------------------------------------*/ +PROCESS(trickle_protocol_process, "Trickle Protocol process"); +AUTOSTART_PROCESSES(&trickle_protocol_process); +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + leds_on(LEDS_GREEN); + if(uip_newdata()) { + PRINTF("At %lu (I=%lu, c=%u): ", + (unsigned long)clock_time(), (unsigned long)tt.i_cur, tt.c); + PRINTF("Our token=0x%02x, theirs=0x%02x\n", token, + ((uint8_t *)uip_appdata)[0]); + if(token == ((uint8_t *)uip_appdata)[0]) { + PRINTF("Consistent RX\n"); + trickle_timer_consistency(&tt); + } else { + if((signed char)(token - ((uint8_t *)uip_appdata)[0]) < 0) { + PRINTF("Theirs is newer. Update\n"); + token = ((uint8_t *)uip_appdata)[0]; + } else { + PRINTF("They are behind\n"); + } + trickle_timer_inconsistency(&tt); + + /* + * Here tt.ct.etimer.timer.{start + interval} points to time t in the + * current interval. However, between t and I it points to the interval's + * end so if you're going to use this, do so with caution. + */ + PRINTF("At %lu: Trickle inconsistency. Scheduled TX for %lu\n", + (unsigned long)clock_time(), + (unsigned long)(tt.ct.etimer.timer.start + + tt.ct.etimer.timer.interval)); + } + } + leds_off(LEDS_GREEN); + return; +} +/*---------------------------------------------------------------------------*/ +static void +trickle_tx(void *ptr, uint8_t suppress) +{ + /* *ptr is a pointer to the trickle_timer that triggered this callback. In + * his example we know that ptr points to tt. However, we pretend that we did + * not know (which would be the case if we e.g. had multiple trickle timers) + * and cast it to a local struct trickle_timer* */ + struct trickle_timer *loc_tt = (struct trickle_timer *)ptr; + + if(suppress == TRICKLE_TIMER_TX_SUPPRESS) { + return; + } + + leds_on(LEDS_RED); + + PRINTF("At %lu (I=%lu, c=%u): ", + (unsigned long)clock_time(), (unsigned long)loc_tt->i_cur, + loc_tt->c); + PRINTF("Trickle TX token 0x%02x\n", token); + + /* Instead of changing ->ripaddr around by ourselves, we could have used + * uip_udp_packet_sendto which would have done it for us. However it puts an + * extra ~20 bytes on stack and the cc2x3x micros hate it, so we stick with + * send() */ + + /* Destination IP: link-local all-nodes multicast */ + uip_ipaddr_copy(&trickle_conn->ripaddr, &ipaddr); + uip_udp_packet_send(trickle_conn, &token, sizeof(token)); + + /* Restore to 'accept incoming from any IP' */ + uip_create_unspecified(&trickle_conn->ripaddr); + + leds_off(LEDS_RED); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(trickle_protocol_process, ev, data) +{ + PROCESS_BEGIN(); + + PRINTF("Trickle protocol started\n"); + + uip_create_linklocal_allnodes_mcast(&ipaddr); /* Store for later */ + + trickle_conn = udp_new(NULL, UIP_HTONS(TRICKLE_PROTO_PORT), NULL); + udp_bind(trickle_conn, UIP_HTONS(TRICKLE_PROTO_PORT)); + + PRINTF("Connection: local/remote port %u/%u\n", + UIP_HTONS(trickle_conn->lport), UIP_HTONS(trickle_conn->rport)); + + token = 0; + + trickle_timer_config(&tt, IMIN, IMAX, REDUNDANCY_CONST); + trickle_timer_set(&tt, trickle_tx, &tt); + /* + * At this point trickle is started and is running the first interval. All + * nodes 'agree' that token == 0. This will change when one of them randomly + * decides to generate a new one + */ + etimer_set(&et, NEW_TOKEN_INTERVAL); + + while(1) { + PROCESS_YIELD(); + if(ev == tcpip_event) { + tcpip_handler(); + } else if(etimer_expired(&et)) { + /* Periodically (and randomly) generate a new token. This will trigger + * a trickle inconsistency */ + if((random_rand() & NEW_TOKEN_PROB) == 0) { + token++; + PRINTF("At %lu: Generating a new token 0x%02x\n", + (unsigned long)clock_time(), token); + trickle_timer_reset_event(&tt); + } + etimer_set(&et, NEW_TOKEN_INTERVAL); + } + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/trickle-library/trickle-library.csc b/examples/trickle-library/trickle-library.csc new file mode 100644 index 000000000..9987cedd7 --- /dev/null +++ b/examples/trickle-library/trickle-library.csc @@ -0,0 +1,154 @@ + + + [CONTIKI_DIR]/tools/cooja/apps/mrm + [CONTIKI_DIR]/tools/cooja/apps/mspsim + [CONTIKI_DIR]/tools/cooja/apps/avrora + [CONTIKI_DIR]/tools/cooja/apps/serial_socket + [CONTIKI_DIR]/tools/cooja/apps/collect-view + [CONTIKI_DIR]/tools/cooja/apps/powertracker + + Example Demonstrating the Trickle Library's Functionality + 0 + generated + 1000000 + + se.sics.cooja.radiomediums.UDGM + 50.0 + 100.0 + 1.0 + 1.0 + + + 40000 + + + se.sics.cooja.mspmote.SkyMoteType + sky1 + trickle-tester + [CONTIKI_DIR]/examples/trickle-library/trickle-library.c + make trickle-library.sky TARGET=sky + [CONTIKI_DIR]/examples/trickle-library/trickle-library.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.SkyByteRadio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + + + se.sics.cooja.interfaces.Position + 96.8286491032791 + 44.83363764767495 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 1 + + sky1 + + + + + se.sics.cooja.interfaces.Position + 26.625418506201424 + 62.32118900834971 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 2 + + sky1 + + + + + se.sics.cooja.interfaces.Position + 12.373988266345922 + 40.21870711164037 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 3 + + sky1 + + + + + se.sics.cooja.interfaces.Position + 38.44294323221424 + 17.14724376428426 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 4 + + sky1 + + + + + se.sics.cooja.interfaces.Position + 68.38248149463341 + 23.506083749222842 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 5 + + sky1 + + + + se.sics.cooja.plugins.Visualizer + + se.sics.cooja.plugins.skins.UDGMVisualizerSkin + se.sics.cooja.plugins.skins.TrafficVisualizerSkin + se.sics.cooja.plugins.skins.IDVisualizerSkin + 5.862188489126289 0.0 0.0 5.862188489126289 -4.083221885224075 -86.33855683341153 + + 642 + 0 + 369 + 447 + 10 + + + se.sics.cooja.plugins.LogListener + + + + + + 1235 + 2 + 285 + 4 + 389 + + + se.sics.cooja.plugins.SimControl + 318 + 1 + 192 + 60 + 60 + + +