Contiki 3.x
rudolph1.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  * Rudolph1: a simple block data flooding protocol
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 /**
41  * \addtogroup rudolph1
42  * @{
43  */
44 
45 #include <stdio.h>
46 #include <stddef.h> /* for offsetof */
47 
48 #include "net/rime/rime.h"
49 #include "net/rime/rudolph1.h"
50 #include "cfs/cfs.h"
51 
52 #define DEFAULT_SEND_INTERVAL CLOCK_SECOND * 2
53 #define TRICKLE_INTERVAL CLOCK_SECOND / 2
54 #define NACK_TIMEOUT CLOCK_SECOND / 4
55 #define REPAIR_TIMEOUT CLOCK_SECOND / 4
56 
57 struct rudolph1_hdr {
58  uint8_t type;
59  uint8_t version;
60  uint16_t chunk;
61 };
62 
63 #define RUDOLPH1_DATASIZE 64
64 
65 struct rudolph1_datapacket {
66  struct rudolph1_hdr h;
67  uint8_t datalen;
68  uint8_t data[RUDOLPH1_DATASIZE];
69 };
70 
71 enum {
72  TYPE_DATA,
73  TYPE_NACK,
74 };
75 
76 #define DEBUG 0
77 #if DEBUG
78 #include <stdio.h>
79 #define PRINTF(...) printf(__VA_ARGS__)
80 #else
81 #define PRINTF(...)
82 #endif
83 
84 #define LT(a, b) ((signed char)((a) - (b)) < 0)
85 
86 /*---------------------------------------------------------------------------*/
87 static int
88 read_data(struct rudolph1_conn *c, uint8_t *dataptr, int chunk)
89 {
90  int len = 0;
91 
92  if(c->cb->read_chunk) {
93  len = c->cb->read_chunk(c, chunk * RUDOLPH1_DATASIZE,
94  dataptr, RUDOLPH1_DATASIZE);
95  }
96  return len;
97 }
98 /*---------------------------------------------------------------------------*/
99 static int
100 format_data(struct rudolph1_conn *c, int chunk)
101 {
102  struct rudolph1_datapacket *p;
103 
104  packetbuf_clear();
105  p = packetbuf_dataptr();
106  p->h.type = TYPE_DATA;
107  p->h.version = c->version;
108  p->h.chunk = chunk;
109  p->datalen = read_data(c, p->data, chunk);
110  packetbuf_set_datalen(sizeof(struct rudolph1_datapacket) -
111  (RUDOLPH1_DATASIZE - p->datalen));
112 
113  return p->datalen;
114 }
115 /*---------------------------------------------------------------------------*/
116 static void
117 write_data(struct rudolph1_conn *c, int chunk, uint8_t *data, int datalen)
118 {
119  if(chunk == 0) {
120  c->cb->write_chunk(c, 0, RUDOLPH1_FLAG_NEWFILE, data, 0);
121  }
122 
123  if(datalen < RUDOLPH1_DATASIZE) {
124  PRINTF("%d.%d: get %d bytes, file complete\n",
126  datalen);
127  c->cb->write_chunk(c, chunk * RUDOLPH1_DATASIZE,
128  RUDOLPH1_FLAG_LASTCHUNK, data, datalen);
129  } else {
130  c->cb->write_chunk(c, chunk * RUDOLPH1_DATASIZE,
131  RUDOLPH1_FLAG_NONE, data, datalen);
132  }
133 }
134 /*---------------------------------------------------------------------------*/
135 static void
136 send_nack(struct rudolph1_conn *c)
137 {
138  struct rudolph1_hdr *hdr;
139  packetbuf_clear();
140  packetbuf_hdralloc(sizeof(struct rudolph1_hdr));
141  hdr = packetbuf_hdrptr();
142 
143  hdr->type = TYPE_NACK;
144  hdr->version = c->version;
145  hdr->chunk = c->chunk;
146 
147  PRINTF("%d.%d: Sending nack for %d:%d\n",
149  hdr->version, hdr->chunk);
150  ipolite_send(&c->ipolite, NACK_TIMEOUT, sizeof(struct rudolph1_hdr));
151 }
152 /*---------------------------------------------------------------------------*/
153 static void
154 handle_data(struct rudolph1_conn *c, struct rudolph1_datapacket *p)
155 {
156  if(LT(c->version, p->h.version)) {
157  PRINTF("%d.%d: rudolph1 new version %d, chunk %d\n",
159  p->h.version, p->h.chunk);
160  c->version = p->h.version;
161  c->highest_chunk_heard = c->chunk = 0;
162  if(p->h.chunk != 0) {
163  send_nack(c);
164  } else {
165  write_data(c, 0, p->data, p->datalen);
166  c->chunk = 1; /* Next chunk is 1. */
167  }
168  /* }*/
169  } else if(p->h.version == c->version) {
170  PRINTF("%d.%d: got chunk %d (%d) highest heard %d\n",
172  p->h.chunk, c->chunk, c->highest_chunk_heard);
173 
174  if(p->h.chunk == c->chunk) {
175  PRINTF("%d.%d: received chunk %d\n",
177  p->h.chunk);
178  write_data(c, p->h.chunk, p->data, p->datalen);
179  if(c->highest_chunk_heard < c->chunk) {
180  c->highest_chunk_heard = c->chunk;
181  }
182  c->chunk++;
183  } else if(p->h.chunk > c->chunk) {
184  PRINTF("%d.%d: received chunk %d > %d, sending NACK\n",
186  p->h.chunk, c->chunk);
187  send_nack(c);
188  c->highest_chunk_heard = p->h.chunk;
189  } else if(p->h.chunk < c->chunk) {
190  /* Ignore packets with a lower chunk number */
191  }
192 
193  /* If we have heard a higher chunk number, we send a NACK so that
194  we get a repair for the next packet. */
195 
196  if(c->highest_chunk_heard > p->h.chunk) {
197  send_nack(c);
198  }
199  } else { /* p->h.version < c->current.h.version */
200  /* Ignore packets with old version */
201  }
202 
203 }
204 /*---------------------------------------------------------------------------*/
205 static void
206 recv_trickle(struct trickle_conn *trickle)
207 {
208  struct rudolph1_conn *c = (struct rudolph1_conn *)trickle;
209  struct rudolph1_datapacket *p = packetbuf_dataptr();
210 
211  if(p->h.type == TYPE_DATA) {
212  PRINTF("%d.%d: received trickle with chunk %d\n",
214  p->h.chunk);
215  handle_data(c, p);
216  }
217 }
218 /*---------------------------------------------------------------------------*/
219 static void
220 sent_ipolite(struct ipolite_conn *ipolite)
221 {
222  PRINTF("%d.%d: Sent ipolite\n",
224 }
225 /*---------------------------------------------------------------------------*/
226 static void
227 dropped_ipolite(struct ipolite_conn *ipolite)
228 {
229  PRINTF("%d.%d: dropped ipolite\n",
231 }
232 /*---------------------------------------------------------------------------*/
233 static void
234 recv_ipolite(struct ipolite_conn *ipolite, const linkaddr_t *from)
235 {
236  struct rudolph1_conn *c = (struct rudolph1_conn *)
237  ((char *)ipolite - offsetof(struct rudolph1_conn, ipolite));
238  struct rudolph1_datapacket *p = packetbuf_dataptr();
239 
240  PRINTF("%d.%d: Got ipolite type %d\n",
242  p->h.type);
243 
244  c->nacks++;
245 
246  if(p->h.type == TYPE_NACK) {
247  PRINTF("%d.%d: Got NACK for %d:%d (%d:%d)\n",
249  p->h.version, p->h.chunk,
250  c->version, c->chunk);
251  if(p->h.version == c->version) {
252  if(p->h.chunk < c->chunk) {
253  /* Format and send a repair packet */
254  PRINTF("%d.%d: sending repair for chunk %d\n",
256  p->h.chunk);
257  format_data(c, p->h.chunk);
258  ipolite_send(&c->ipolite, REPAIR_TIMEOUT, sizeof(struct rudolph1_hdr));
259  }
260  } else if(LT(p->h.version, c->version)) {
261  format_data(c, 0);
262  ipolite_send(&c->ipolite, c->send_interval / 2, sizeof(struct rudolph1_hdr));
263  }
264  } else if(p->h.type == TYPE_DATA) {
265  /* This is a repair packet from someone else. */
266  PRINTF("%d.%d: got repair for chunk %d\n",
268  p->h.chunk);
269  handle_data(c, p);
270  }
271 }
272 /*---------------------------------------------------------------------------*/
273 static void
274 send_next_packet(void *ptr)
275 {
276  struct rudolph1_conn *c = ptr;
277  int len;
278  if(c->nacks == 0) {
279  len = format_data(c, c->chunk);
280  trickle_send(&c->trickle);
281  if(len == RUDOLPH1_DATASIZE) {
282  ctimer_set(&c->t, c->send_interval, send_next_packet, c);
283  }
284  PRINTF("%d.%d: send_next_packet chunk %d, next %d\n",
286  c->chunk, c->chunk + 1);
287 
288  c->highest_chunk_heard = c->chunk;
289  c->chunk++;
290 
291  } else {
292  ctimer_set(&c->t, c->send_interval, send_next_packet, c);
293  }
294  c->nacks = 0;
295 }
296 /*---------------------------------------------------------------------------*/
297 static const struct ipolite_callbacks ipolite = { recv_ipolite, sent_ipolite,
298  dropped_ipolite };
299 static const struct trickle_callbacks trickle = { recv_trickle };
300 /*---------------------------------------------------------------------------*/
301 void
302 rudolph1_open(struct rudolph1_conn *c, uint16_t channel,
303  const struct rudolph1_callbacks *cb)
304 {
305  trickle_open(&c->trickle, TRICKLE_INTERVAL, channel, &trickle);
306  ipolite_open(&c->ipolite, channel + 1, 1, &ipolite);
307  c->cb = cb;
308  c->version = 0;
309  c->send_interval = DEFAULT_SEND_INTERVAL;
310 }
311 /*---------------------------------------------------------------------------*/
312 void
313 rudolph1_close(struct rudolph1_conn *c)
314 {
315  trickle_close(&c->trickle);
316  ipolite_close(&c->ipolite);
317 }
318 /*---------------------------------------------------------------------------*/
319 void
320 rudolph1_send(struct rudolph1_conn *c, clock_time_t send_interval)
321 {
322  c->version++;
323  c->chunk = c->highest_chunk_heard = 0;
324  /* c->trickle_interval = TRICKLE_INTERVAL;*/
325  format_data(c, 0);
326  trickle_send(&c->trickle);
327  c->chunk++;
328  c->send_interval = send_interval;
329  ctimer_set(&c->t, send_interval, send_next_packet, c);
330 }
331 /*---------------------------------------------------------------------------*/
332 void
333 rudolph1_stop(struct rudolph1_conn *c)
334 {
335  ctimer_stop(&c->t);
336 }
337 /*---------------------------------------------------------------------------*/
338 /** @} */
A structure with callback functions for an ipolite connection.
Definition: ipolite.h:113
int packetbuf_hdralloc(int size)
Extend the header of the packetbuf, for outbound packets.
Definition: packetbuf.c:172
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
void packetbuf_set_datalen(uint16_t len)
Set the length of the data in the packetbuf.
Definition: packetbuf.c:200
Header file for the Rime stack
void ipolite_close(struct ipolite_conn *c)
Close an ipolite connection.
Definition: ipolite.c:133
void ipolite_open(struct ipolite_conn *c, uint16_t channel, uint8_t dups, const struct ipolite_callbacks *cb)
Open an ipolite connection.
Definition: ipolite.c:123
void ctimer_set(struct ctimer *c, clock_time_t t, void(*f)(void *), void *ptr)
Set a callback timer.
Definition: ctimer.c:99
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:213
An opaque structure with no user-visible elements that holds the state of an ipolite connection...
Definition: ipolite.h:135
void packetbuf_clear(void)
Clear and reset the packetbuf.
Definition: packetbuf.c:77
Header file for the multi-hop reliable bulk data transfer mechanism
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:207
int ipolite_send(struct ipolite_conn *c, clock_time_t interval, uint8_t hdrsize)
Send a packet on an ipolite connection.
Definition: ipolite.c:144
void ctimer_stop(struct ctimer *c)
Stop a pending callback timer.
Definition: ctimer.c:142
CFS header file.