Contiki 2.5
codeprop-otf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005, 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  * @(#)$Id: codeprop-otf.c,v 1.2 2010/10/19 18:29:04 adamdunkels Exp $
32  */
33 
34 /** \addtogroup esb
35  * @{ */
36 
37 /**
38  *
39  * \file
40  * Code propagation and storage.
41  * \author
42  * Adam Dunkels <adam@sics.se>
43  *
44  * This file implements a simple form of code propagation, which
45  * allows a binary program to be downloaded and propagated throughout
46  * a network of devices.
47  *
48  * Features:
49  *
50  * Commands: load code, start code
51  * Point-to-point download over TCP
52  * Point-to-multipoint delivery over UDP broadcasts
53  * Versioning of code modules
54  *
55  * Procedure:
56  *
57  * 1. Receive code over TCP
58  * 2. Send code packets over UDP
59  *
60  * When a code packet is deemed to be missed, a NACK is sent. If a
61  * NACK is received, the sending restarts at the point in the
62  * binary where the NACK pointed to. (This is *not* very efficient,
63  * but simple to implement...)
64  *
65  * States:
66  *
67  * Receiving code header -> receiving code -> sending code
68  *
69  */
70 
71 #include <stdio.h>
72 
73 #include "contiki-net.h"
74 #include "cfs/cfs.h"
75 #include "codeprop-otf.h"
76 #include "loader/elfloader-otf.h"
77 #include <string.h>
78 
79 static const char *err_msgs[] =
80  {"OK\r\n", "Bad ELF header\r\n", "No symtab\r\n", "No strtab\r\n",
81  "No text\r\n", "Symbol not found\r\n", "Segment not found\r\n",
82  "No startpoint\r\n", "Unhandled relocation\r\n",
83  "Relocation out of range\r\n", "Relocations not sorted\r\n",
84  "Input error\r\n" , "Ouput error\r\n" };
85 
86 #define CODEPROP_DATA_PORT 6510
87 
88 /*static int random_rand(void) { return 1; }*/
89 
90 #if 0
91 #define PRINTF(x) printf x
92 #else
93 #define PRINTF(x)
94 #endif
95 
96 #define START_TIMEOUT 12 * CLOCK_SECOND
97 #define MISS_NACK_TIMEOUT (CLOCK_SECOND / 8) * (random_rand() % 8)
98 #define HIT_NACK_TIMEOUT (CLOCK_SECOND / 8) * (8 + random_rand() % 16)
99 #define NACK_REXMIT_TIMEOUT CLOCK_SECOND * (4 + random_rand() % 4)
100 
101 #define WAITING_TIME CLOCK_SECOND * 10
102 
103 #define NUM_SEND_DUPLICATES 2
104 
105 #define UDPHEADERSIZE 8
106 #define UDPDATASIZE 32
107 
108 struct codeprop_udphdr {
109  u16_t id;
110  u16_t type;
111 #define TYPE_DATA 0x0001
112 #define TYPE_NACK 0x0002
113  u16_t addr;
114  u16_t len;
115  u8_t data[UDPDATASIZE];
116 };
117 
118 struct codeprop_tcphdr {
119  u16_t len;
120  u16_t pad;
121 };
122 
123 static void uipcall(void *state);
124 
125 PROCESS(codeprop_process, "Code propagator");
126 
127 struct codeprop_state {
128  u8_t state;
129 #define STATE_NONE 0
130 #define STATE_RECEIVING_TCPDATA 1
131 #define STATE_RECEIVING_UDPDATA 2
132 #define STATE_SENDING_UDPDATA 3
133  u16_t count;
134  u16_t addr;
135  u16_t len;
136  u16_t id;
137  struct etimer sendtimer;
138  struct timer nacktimer, timer, starttimer;
139  u8_t received;
140  u8_t send_counter;
141  struct pt tcpthread_pt;
142  struct pt udpthread_pt;
143  struct pt recv_udpthread_pt;
144 };
145 
146 static int fd;
147 
148 static struct uip_udp_conn *udp_conn;
149 
150 static struct codeprop_state s;
151 
152 void system_log(char *msg);
153 
154 static clock_time_t send_time;
155 
156 #define CONNECTION_TIMEOUT (30 * CLOCK_SECOND)
157 
158 /*---------------------------------------------------------------------*/
159 void
160 codeprop_set_rate(clock_time_t time)
161 {
162  send_time = time;
163 }
164 /*---------------------------------------------------------------------*/
165 PROCESS_THREAD(codeprop_process, ev, data)
166 {
167  PROCESS_BEGIN();
168 
169  elfloader_init();
170 
171  s.id = 0/*random_rand()*/;
172 
173  send_time = CLOCK_SECOND/4;
174 
175  PT_INIT(&s.udpthread_pt);
176  PT_INIT(&s.recv_udpthread_pt);
177 
178  tcp_listen(UIP_HTONS(CODEPROP_DATA_PORT));
179 
180  udp_conn = udp_broadcast_new(UIP_HTONS(CODEPROP_DATA_PORT), NULL);
181 
182  s.state = STATE_NONE;
183  s.received = 0;
184  s.addr = 0;
185  s.len = 0;
186 
187  fd = cfs_open("codeprop-image", CFS_READ | CFS_WRITE);
188 
189  while(1) {
190 
191  PROCESS_YIELD();
192 
193  if(ev == tcpip_event) {
194  uipcall(data);
195  } else if(ev == PROCESS_EVENT_TIMER) {
196  tcpip_poll_udp(udp_conn);
197  }
198  }
199 
200  PROCESS_END();
201 }
202 /*---------------------------------------------------------------------*/
203 static u16_t
204 send_udpdata(struct codeprop_udphdr *uh)
205 {
206  u16_t len;
207 
208  uh->type = UIP_HTONS(TYPE_DATA);
209  uh->addr = uip_htons(s.addr);
210  uh->id = uip_htons(s.id);
211 
212  if(s.len - s.addr > UDPDATASIZE) {
213  len = UDPDATASIZE;
214  } else {
215  len = s.len - s.addr;
216  }
217 
218  cfs_seek(fd, s.addr, CFS_SEEK_SET);
219  cfs_read(fd, (char*)&uh->data[0], len);
220  /* eeprom_read(EEPROMFS_ADDR_CODEPROP + s.addr,
221  &uh->data[0], len);*/
222 
223  uh->len = uip_htons(s.len);
224 
225  PRINTF(("codeprop: sending packet from address 0x%04x\n", s.addr));
226  uip_udp_send(len + UDPHEADERSIZE);
227 
228  return len;
229 }
230 /*---------------------------------------------------------------------*/
231 static
232 PT_THREAD(send_udpthread(struct pt *pt))
233 {
234  int len;
235  struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata;
236 
237 
238  PT_BEGIN(pt);
239 
240  while(1) {
241  PT_WAIT_UNTIL(pt, s.state == STATE_SENDING_UDPDATA);
242 
243  for(s.addr = 0; s.addr < s.len; ) {
244  len = send_udpdata(uh);
245  s.addr += len;
246 
247  etimer_set(&s.sendtimer, CLOCK_SECOND/4);
248  do {
249  PT_WAIT_UNTIL(pt, uip_newdata() || etimer_expired(&s.sendtimer));
250 
251  if(uip_newdata()) {
252  if(uh->type == UIP_HTONS(TYPE_NACK)) {
253  PRINTF(("send_udpthread: got NACK for address 0x%x (now 0x%x)\n",
254  uip_htons(uh->addr), s.addr));
255  /* Only accept a NACK if it points to a lower byte. */
256  if(uip_htons(uh->addr) <= s.addr) {
257  /* beep();*/
258  s.addr = uip_htons(uh->addr);
259  }
260  }
261  PT_YIELD(pt);
262  }
263  } while(!etimer_expired(&s.sendtimer));
264  }
265 
266  s.state = STATE_NONE;
267 
268 /* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */
269  }
270  PT_END(pt);
271 }
272 /*---------------------------------------------------------------------*/
273 static void
274 send_nack(struct codeprop_udphdr *uh, unsigned short addr)
275 {
276  uh->type = UIP_HTONS(TYPE_NACK);
277  uh->addr = uip_htons(addr);
278  uip_udp_send(UDPHEADERSIZE);
279 }
280 /*---------------------------------------------------------------------*/
281 static
282 PT_THREAD(recv_udpthread(struct pt *pt))
283 {
284  int len;
285  struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata;
286 
287  /* if(uip_newdata()) {
288  PRINTF(("recv_udpthread: id %d uh->id %d\n", s.id, uip_htons(uh->id)));
289  }*/
290 
291  PT_BEGIN(pt);
292 
293  while(1) {
294 
295  do {
296  PT_WAIT_UNTIL(pt, uip_newdata() &&
297  uh->type == UIP_HTONS(TYPE_DATA) &&
298  uip_htons(uh->id) > s.id);
299 
300  if(uip_htons(uh->addr) != 0) {
301  s.addr = 0;
302  send_nack(uh, 0);
303  }
304 
305  } while(uip_htons(uh->addr) != 0);
306 
307  /* leds_on(LEDS_YELLOW);
308  beep_down(10000);*/
309 
310  s.addr = 0;
311  s.id = uip_htons(uh->id);
312  s.len = uip_htons(uh->len);
313 
314  timer_set(&s.timer, CONNECTION_TIMEOUT);
315 /* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */
316 
317  while(s.addr < s.len) {
318 
319  if(uip_htons(uh->addr) == s.addr) {
320  /* leds_blink();*/
321  len = uip_datalen() - UDPHEADERSIZE;
322  if(len > 0) {
323  /* eeprom_write(EEPROMFS_ADDR_CODEPROP + s.addr,
324  &uh->data[0], len);*/
325  cfs_seek(fd, s.addr, CFS_SEEK_SET);
326  cfs_write(fd, (char*)&uh->data[0], len);
327 
328  /* beep();*/
329  PRINTF(("Saved %d bytes at address %d, %d bytes left\n",
330  uip_datalen() - UDPHEADERSIZE, s.addr,
331  s.len - s.addr));
332 
333  s.addr += len;
334  }
335 
336  } else if(uip_htons(uh->addr) > s.addr) {
337  PRINTF(("sending nack since 0x%x != 0x%x\n", uip_htons(uh->addr), s.addr));
338  send_nack(uh, s.addr);
339  }
340 
341  if(s.addr < s.len) {
342 
343  /* timer_set(&s.nacktimer, NACK_TIMEOUT);*/
344 
345  do {
346  timer_set(&s.nacktimer, HIT_NACK_TIMEOUT);
347  PT_YIELD_UNTIL(pt, timer_expired(&s.nacktimer) ||
348  (uip_newdata() &&
349  uh->type == UIP_HTONS(TYPE_DATA) &&
350  uip_htons(uh->id) == s.id));
351  if(timer_expired(&s.nacktimer)) {
352  send_nack(uh, s.addr);
353  }
354  } while(timer_expired(&s.nacktimer));
355  }
356 
357  }
358 
359  /* leds_off(LEDS_YELLOW);
360  beep_quick(2);*/
361  /* printf("Received entire bunary over udr\n");*/
362  codeprop_start_program();
363  PT_EXIT(pt);
364  }
365 
366  PT_END(pt);
367 }
368 /*---------------------------------------------------------------------*/
369 
370 #define CODEPROP_TCPHDR_SIZE sizeof(struct codeprop_tcphdr)
371 
372 static
373 PT_THREAD(recv_tcpthread(struct pt *pt))
374 {
375  struct codeprop_tcphdr *th;
376  int datalen = uip_datalen();
377  PT_BEGIN(pt);
378 
379  while(1) {
380 
382 
383  codeprop_exit_program();
384 
385  s.state = STATE_RECEIVING_TCPDATA;
386 
387  s.addr = 0;
388  s.count = 0;
389 
390  /* Read the header. */
391  PT_WAIT_UNTIL(pt, uip_newdata() && uip_datalen() > 0);
392 
393  if(uip_datalen() < CODEPROP_TCPHDR_SIZE) {
394  PRINTF(("codeprop: header not found in first tcp segment\n"));
395  uip_abort();
396  }
397  th = (struct codeprop_tcphdr *)uip_appdata;
398  s.len = uip_htons(th->len);
399  s.addr = 0;
400  uip_appdata += CODEPROP_TCPHDR_SIZE;
401  datalen -= CODEPROP_TCPHDR_SIZE;
402 
403  /* Read the rest of the data. */
404  do {
405  if(datalen > 0) {
406  /* printf("Got %d bytes\n", datalen); */
407 
408  if (cfs_seek(fd, s.addr, CFS_SEEK_SET) != s.addr) {
409  PRINTF(("codeprop: seek in buffer file failed\n"));
410  uip_abort();
411  }
412 
413  if (cfs_write(fd, uip_appdata, datalen) != datalen) {
414  PRINTF(("codeprop: write to buffer file failed\n"));
415  uip_abort();
416  }
417  s.addr += datalen;
418  }
419  if(s.addr < s.len) {
421  }
422  } while(s.addr < s.len);
423 #if 1
424 
425  {
426  static int err;
427 
428  err = codeprop_start_program();
429 
430  /* Print out the "OK"/error message. */
431  do {
432  if (err >= 0 && err < sizeof(err_msgs)/sizeof(char*)) {
433  uip_send(err_msgs[err], strlen(err_msgs[err]));
434  } else {
435  uip_send("Unknown error\r\n", 15);
436  }
437  PT_WAIT_UNTIL(pt, uip_acked() || uip_rexmit() || uip_closed());
438  } while(uip_rexmit());
439 
440  /* Close the connection. */
441  uip_close();
442  }
443 #endif
444  ++s.id;
445  s.state = STATE_SENDING_UDPDATA;
446  tcpip_poll_udp(udp_conn);
447 
448  PT_WAIT_UNTIL(pt, s.state != STATE_SENDING_UDPDATA);
449  /* printf("recv_tcpthread: unblocked\n");*/
450  }
451 
452  PT_END(pt);
453 }
454 /*---------------------------------------------------------------------*/
455 void
456 codeprop_start_broadcast(unsigned int len)
457 {
458  s.addr = 0;
459  s.len = len;
460  ++s.id;
461  s.state = STATE_SENDING_UDPDATA;
462  tcpip_poll_udp(udp_conn);
463 }
464 /*---------------------------------------------------------------------*/
465 void
466 codeprop_exit_program(void)
467 {
469  autostart_exit(elfloader_autostart_processes);
470  }
471 }
472 /*---------------------------------------------------------------------*/
473 int
474 codeprop_start_program(void)
475 {
476  int err;
477 
478  codeprop_exit_program();
479 
480  err = elfloader_load(fd, codeprop_output);
481  if(err == ELFLOADER_OK) {
482  PRINTF(("codeprop: starting %s\n",
484  autostart_start(elfloader_autostart_processes);
485  }
486  return err;
487 }
488 /*---------------------------------------------------------------------*/
489 static void
490 uipcall(void *state)
491 {
492  if(uip_udpconnection()) {
493  recv_udpthread(&s.recv_udpthread_pt);
494  send_udpthread(&s.udpthread_pt);
495  } else {
496  if(uip_conn->lport == UIP_HTONS(CODEPROP_DATA_PORT)) {
497  if(uip_connected()) {
498 
499  if(state == NULL) {
500  s.addr = 0;
501  s.count = 0;
502  PT_INIT(&s.tcpthread_pt);
503  process_poll(&codeprop_process);
504  tcp_markconn(uip_conn, &s);
505 /* process_post(PROCESS_BROADCAST, codeprop_event_quit, */
506 /* (process_data_t)NULL); */
507  } else {
508  PRINTF(("codeprop: uip_connected() and state != NULL\n"));
509  uip_abort();
510  }
511  }
512  recv_tcpthread(&s.tcpthread_pt);
513 
514 
515  if(uip_closed() || uip_aborted() || uip_timedout()) {
516  PRINTF(("codeprop: connection down\n"));
517  tcp_markconn(uip_conn, NULL);
518  }
519  }
520  }
521 }
522 /*---------------------------------------------------------------------*/
523 /** @} */