Contiki 2.6

trickle.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup trickle
00003  * @{
00004  */
00005 
00006 /*
00007  * Copyright (c) 2007, Swedish Institute of Computer Science.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted provided that the following conditions
00012  * are met:
00013  * 1. Redistributions of source code must retain the above copyright
00014  *    notice, this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in the
00017  *    documentation and/or other materials provided with the distribution.
00018  * 3. Neither the name of the Institute nor the names of its contributors
00019  *    may be used to endorse or promote products derived from this software
00020  *    without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00023  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00025  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00026  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00028  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00029  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00031  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00032  * SUCH DAMAGE.
00033  *
00034  * This file is part of the Contiki operating system.
00035  *
00036  * $Id: trickle.c,v 1.18 2009/11/08 19:40:18 adamdunkels Exp $
00037  */
00038 
00039 /**
00040  * \file
00041  *         Trickle (reliable single source flooding) for Rime
00042  * \author
00043  *         Adam Dunkels <adam@sics.se>
00044  */
00045 
00046 #include "net/rime/trickle.h"
00047 #include "lib/random.h"
00048 
00049 #if CONTIKI_TARGET_NETSIM
00050 #include "ether.h"
00051 #endif
00052 
00053 #define INTERVAL_MIN 1
00054 #define INTERVAL_MAX 4
00055 
00056 #define DUPLICATE_THRESHOLD 1
00057 
00058 #define SEQNO_LT(a, b) ((signed char)((a) - (b)) < 0)
00059 
00060 static const struct packetbuf_attrlist attributes[] =
00061   {
00062     TRICKLE_ATTRIBUTES PACKETBUF_ATTR_LAST
00063   };
00064 
00065 
00066 #define DEBUG 0
00067 #if DEBUG
00068 #include <stdio.h>
00069 #define PRINTF(...) printf(__VA_ARGS__)
00070 #else
00071 #define PRINTF(...)
00072 #endif
00073 
00074 static int run_trickle(struct trickle_conn *c);
00075 /*---------------------------------------------------------------------------*/
00076 static void
00077 send(void *ptr)
00078 {
00079   struct trickle_conn *c = ptr;
00080 
00081   if(c->q != NULL) {
00082     queuebuf_to_packetbuf(c->q);
00083     broadcast_send(&c->c);
00084   } else {
00085     PRINTF("%d.%d: trickle send but c->q == NULL\n",
00086          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1]);
00087   }
00088 }
00089 /*---------------------------------------------------------------------------*/
00090 static void
00091 timer_callback(void *ptr)
00092 {
00093   struct trickle_conn *c = ptr;
00094   run_trickle(c);
00095 }
00096 /*---------------------------------------------------------------------------*/
00097 static void
00098 reset_interval(struct trickle_conn *c)
00099 {
00100   PT_INIT(&c->pt);
00101   run_trickle(c);
00102 }
00103 /*---------------------------------------------------------------------------*/
00104 static void
00105 set_timer(struct trickle_conn *c, struct ctimer *t, clock_time_t i)
00106 {
00107   ctimer_set(t, i, timer_callback, c);
00108 }
00109 /*---------------------------------------------------------------------------*/
00110 static int
00111 run_trickle(struct trickle_conn *c)
00112 {
00113   clock_time_t interval;
00114   PT_BEGIN(&c->pt);
00115 
00116   while(1) {
00117     interval = c->interval << c->interval_scaling;
00118     set_timer(c, &c->interval_timer, interval);
00119     set_timer(c, &c->t, interval / 2 + (random_rand() % (interval / 2)));
00120 
00121     c->duplicates = 0;
00122     PT_YIELD(&c->pt); /* Wait until listen timeout */
00123     if(c->duplicates < DUPLICATE_THRESHOLD) {
00124       send(c);
00125     }
00126     PT_YIELD(&c->pt); /* Wait until interval timer expired. */
00127     if(c->interval_scaling < INTERVAL_MAX) {
00128       c->interval_scaling++;
00129     }
00130   }
00131   
00132   PT_END(&c->pt);
00133 }
00134 /*---------------------------------------------------------------------------*/
00135 static void
00136 recv(struct broadcast_conn *bc, const rimeaddr_t *from)
00137 {
00138   struct trickle_conn *c = (struct trickle_conn *)bc;
00139   uint16_t seqno = packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID);
00140 
00141   PRINTF("%d.%d: trickle recv seqno %d from %d.%d our %d data len %d channel %d\n",
00142          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00143          seqno,
00144          from->u8[0], from->u8[1],
00145          c->seqno,
00146          packetbuf_datalen(),
00147          packetbuf_attr(PACKETBUF_ATTR_CHANNEL));
00148 
00149   if(seqno == c->seqno) {
00150     /*    c->cb->recv(c);*/
00151     ++c->duplicates;
00152   } else if(SEQNO_LT(seqno, c->seqno)) {
00153     c->interval_scaling = 0;
00154     send(c);
00155   } else { /* hdr->seqno > c->seqno */
00156 #if CONTIKI_TARGET_NETSIM
00157     /*    ether_set_line(from->u8[0], from->u8[1]);*/
00158 #endif /* CONTIKI_TARGET_NETSIM */
00159     c->seqno = seqno;
00160     /* Store the incoming data in the queuebuf */
00161     if(c->q != NULL) {
00162       queuebuf_free(c->q);
00163     }
00164     c->q = queuebuf_new_from_packetbuf();
00165     c->interval_scaling = 0;
00166     reset_interval(c);
00167     ctimer_set(&c->first_transmission_timer, random_rand() % c->interval,
00168                send, c);
00169     c->cb->recv(c);
00170   }
00171 }
00172 /*---------------------------------------------------------------------------*/
00173 static CC_CONST_FUNCTION struct broadcast_callbacks bc = { recv };
00174 /*---------------------------------------------------------------------------*/
00175 void
00176 trickle_open(struct trickle_conn *c, clock_time_t interval,
00177              uint16_t channel, const struct trickle_callbacks *cb)
00178 {
00179   broadcast_open(&c->c, channel, &bc);
00180   c->cb = cb;
00181   c->q = NULL;
00182   c->interval = interval;
00183   c->interval_scaling = 0;
00184   channel_set_attributes(channel, attributes);
00185 }
00186 /*---------------------------------------------------------------------------*/
00187 void
00188 trickle_close(struct trickle_conn *c)
00189 {
00190   broadcast_close(&c->c);
00191   ctimer_stop(&c->t);
00192   ctimer_stop(&c->interval_timer);
00193 }
00194 /*---------------------------------------------------------------------------*/
00195 void
00196 trickle_send(struct trickle_conn *c)
00197 {
00198   if(c->q != NULL) {
00199     queuebuf_free(c->q);
00200   }
00201   c->seqno++;
00202   packetbuf_set_attr(PACKETBUF_ATTR_EPACKET_ID, c->seqno);
00203   c->q = queuebuf_new_from_packetbuf();
00204   PRINTF("%d.%d: trickle send seqno %d\n",
00205          rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],
00206          c->seqno);
00207   reset_interval(c);
00208   send(c);
00209 }
00210 /*---------------------------------------------------------------------------*/
00211 /** @} */