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