From 5ecd2a1e9510379117ec59881b2934bc18652a0e Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Wed, 18 Apr 2012 15:31:10 +0100 Subject: [PATCH] Add an example demonstrating trickle timers --- examples/trickle-library/Makefile | 9 + examples/trickle-library/trickle-library.c | 194 +++++++++++++++++++ examples/trickle-library/trickle-library.csc | 154 +++++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 examples/trickle-library/Makefile create mode 100644 examples/trickle-library/trickle-library.c create mode 100644 examples/trickle-library/trickle-library.csc 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 + + +