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