Contiki 2.5
trickle.c
Go to the documentation of this file.
1 /**
2  * \addtogroup trickle
3  * @{
4  */
5 
6 /*
7  * Copyright (c) 2007, Swedish Institute of Computer Science.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the Institute nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * This file is part of the Contiki operating system.
35  *
36  * $Id: trickle.c,v 1.18 2009/11/08 19:40:18 adamdunkels Exp $
37  */
38 
39 /**
40  * \file
41  * Trickle (reliable single source flooding) for Rime
42  * \author
43  * Adam Dunkels <adam@sics.se>
44  */
45 
46 #include "net/rime/trickle.h"
47 #include "lib/random.h"
48 
49 #if CONTIKI_TARGET_NETSIM
50 #include "ether.h"
51 #endif
52 
53 #define INTERVAL_MIN 1
54 #define INTERVAL_MAX 4
55 
56 #define DUPLICATE_THRESHOLD 1
57 
58 #define SEQNO_LT(a, b) ((signed char)((a) - (b)) < 0)
59 
60 static const struct packetbuf_attrlist attributes[] =
61  {
62  TRICKLE_ATTRIBUTES PACKETBUF_ATTR_LAST
63  };
64 
65 
66 #define DEBUG 0
67 #if DEBUG
68 #include <stdio.h>
69 #define PRINTF(...) printf(__VA_ARGS__)
70 #else
71 #define PRINTF(...)
72 #endif
73 
74 static int run_trickle(struct trickle_conn *c);
75 /*---------------------------------------------------------------------------*/
76 static void
77 send(void *ptr)
78 {
79  struct trickle_conn *c = ptr;
80 
81  if(c->q != NULL) {
82  queuebuf_to_packetbuf(c->q);
83  broadcast_send(&c->c);
84  } else {
85  PRINTF("%d.%d: trickle send but c->q == NULL\n",
87  }
88 }
89 /*---------------------------------------------------------------------------*/
90 static void
91 timer_callback(void *ptr)
92 {
93  struct trickle_conn *c = ptr;
94  run_trickle(c);
95 }
96 /*---------------------------------------------------------------------------*/
97 static void
98 reset_interval(struct trickle_conn *c)
99 {
100  PT_INIT(&c->pt);
101  run_trickle(c);
102 }
103 /*---------------------------------------------------------------------------*/
104 static void
105 set_timer(struct trickle_conn *c, struct ctimer *t, clock_time_t i)
106 {
107  ctimer_set(t, i, timer_callback, c);
108 }
109 /*---------------------------------------------------------------------------*/
110 static int
111 run_trickle(struct trickle_conn *c)
112 {
113  clock_time_t interval;
114  PT_BEGIN(&c->pt);
115 
116  while(1) {
117  interval = c->interval << c->interval_scaling;
118  set_timer(c, &c->interval_timer, interval);
119  set_timer(c, &c->t, interval / 2 + (random_rand() % (interval / 2)));
120 
121  c->duplicates = 0;
122  PT_YIELD(&c->pt); /* Wait until listen timeout */
123  if(c->duplicates < DUPLICATE_THRESHOLD) {
124  send(c);
125  }
126  PT_YIELD(&c->pt); /* Wait until interval timer expired. */
127  if(c->interval_scaling < INTERVAL_MAX) {
128  c->interval_scaling++;
129  }
130  }
131 
132  PT_END(&c->pt);
133 }
134 /*---------------------------------------------------------------------------*/
135 static void
136 recv(struct broadcast_conn *bc, const rimeaddr_t *from)
137 {
138  struct trickle_conn *c = (struct trickle_conn *)bc;
139  uint16_t seqno = packetbuf_attr(PACKETBUF_ATTR_EPACKET_ID);
140 
141  PRINTF("%d.%d: trickle recv seqno %d from %d.%d our %d data len %d channel %d\n",
143  seqno,
144  from->u8[0], from->u8[1],
145  c->seqno,
147  packetbuf_attr(PACKETBUF_ATTR_CHANNEL));
148 
149  if(seqno == c->seqno) {
150  /* c->cb->recv(c);*/
151  ++c->duplicates;
152  } else if(SEQNO_LT(seqno, c->seqno)) {
153  c->interval_scaling = 0;
154  send(c);
155  } else { /* hdr->seqno > c->seqno */
156 #if CONTIKI_TARGET_NETSIM
157  /* ether_set_line(from->u8[0], from->u8[1]);*/
158 #endif /* CONTIKI_TARGET_NETSIM */
159  c->seqno = seqno;
160  /* Store the incoming data in the queuebuf */
161  if(c->q != NULL) {
162  queuebuf_free(c->q);
163  }
164  c->q = queuebuf_new_from_packetbuf();
165  c->interval_scaling = 0;
166  reset_interval(c);
167  ctimer_set(&c->first_transmission_timer, random_rand() % c->interval,
168  send, c);
169  c->cb->recv(c);
170  }
171 }
172 /*---------------------------------------------------------------------------*/
173 static CC_CONST_FUNCTION struct broadcast_callbacks bc = { recv };
174 /*---------------------------------------------------------------------------*/
175 void
176 trickle_open(struct trickle_conn *c, clock_time_t interval,
177  uint16_t channel, const struct trickle_callbacks *cb)
178 {
179  broadcast_open(&c->c, channel, &bc);
180  c->cb = cb;
181  c->q = NULL;
182  c->interval = interval;
183  c->interval_scaling = 0;
184  channel_set_attributes(channel, attributes);
185 }
186 /*---------------------------------------------------------------------------*/
187 void
188 trickle_close(struct trickle_conn *c)
189 {
190  broadcast_close(&c->c);
191  ctimer_stop(&c->t);
192  ctimer_stop(&c->interval_timer);
193 }
194 /*---------------------------------------------------------------------------*/
195 void
196 trickle_send(struct trickle_conn *c)
197 {
198  if(c->q != NULL) {
199  queuebuf_free(c->q);
200  }
201  c->seqno++;
202  packetbuf_set_attr(PACKETBUF_ATTR_EPACKET_ID, c->seqno);
203  c->q = queuebuf_new_from_packetbuf();
204  PRINTF("%d.%d: trickle send seqno %d\n",
206  c->seqno);
207  reset_interval(c);
208  send(c);
209 }
210 /*---------------------------------------------------------------------------*/
211 /** @} */