Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2005, Swedish Institute of Computer Science 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions 00007 * are met: 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 3. Neither the name of the Institute nor the names of its contributors 00014 * may be used to endorse or promote products derived from this software 00015 * without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 00018 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 00021 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00023 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00024 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00027 * SUCH DAMAGE. 00028 * 00029 * This file is part of the Contiki operating system. 00030 * 00031 * @(#)$Id: codeprop-otf.c,v 1.2 2010/10/19 18:29:04 adamdunkels Exp $ 00032 */ 00033 00034 /** \addtogroup esb 00035 * @{ */ 00036 00037 /** 00038 * 00039 * \file 00040 * Code propagation and storage. 00041 * \author 00042 * Adam Dunkels <adam@sics.se> 00043 * 00044 * This file implements a simple form of code propagation, which 00045 * allows a binary program to be downloaded and propagated throughout 00046 * a network of devices. 00047 * 00048 * Features: 00049 * 00050 * Commands: load code, start code 00051 * Point-to-point download over TCP 00052 * Point-to-multipoint delivery over UDP broadcasts 00053 * Versioning of code modules 00054 * 00055 * Procedure: 00056 * 00057 * 1. Receive code over TCP 00058 * 2. Send code packets over UDP 00059 * 00060 * When a code packet is deemed to be missed, a NACK is sent. If a 00061 * NACK is received, the sending restarts at the point in the 00062 * binary where the NACK pointed to. (This is *not* very efficient, 00063 * but simple to implement...) 00064 * 00065 * States: 00066 * 00067 * Receiving code header -> receiving code -> sending code 00068 * 00069 */ 00070 00071 #include <stdio.h> 00072 00073 #include "contiki-net.h" 00074 #include "cfs/cfs.h" 00075 #include "codeprop-otf.h" 00076 #include "loader/elfloader-otf.h" 00077 #include <string.h> 00078 00079 static const char *err_msgs[] = 00080 {"OK\r\n", "Bad ELF header\r\n", "No symtab\r\n", "No strtab\r\n", 00081 "No text\r\n", "Symbol not found\r\n", "Segment not found\r\n", 00082 "No startpoint\r\n", "Unhandled relocation\r\n", 00083 "Relocation out of range\r\n", "Relocations not sorted\r\n", 00084 "Input error\r\n" , "Ouput error\r\n" }; 00085 00086 #define CODEPROP_DATA_PORT 6510 00087 00088 /*static int random_rand(void) { return 1; }*/ 00089 00090 #if 0 00091 #define PRINTF(x) printf x 00092 #else 00093 #define PRINTF(x) 00094 #endif 00095 00096 #define START_TIMEOUT 12 * CLOCK_SECOND 00097 #define MISS_NACK_TIMEOUT (CLOCK_SECOND / 8) * (random_rand() % 8) 00098 #define HIT_NACK_TIMEOUT (CLOCK_SECOND / 8) * (8 + random_rand() % 16) 00099 #define NACK_REXMIT_TIMEOUT CLOCK_SECOND * (4 + random_rand() % 4) 00100 00101 #define WAITING_TIME CLOCK_SECOND * 10 00102 00103 #define NUM_SEND_DUPLICATES 2 00104 00105 #define UDPHEADERSIZE 8 00106 #define UDPDATASIZE 32 00107 00108 struct codeprop_udphdr { 00109 uint16_t id; 00110 uint16_t type; 00111 #define TYPE_DATA 0x0001 00112 #define TYPE_NACK 0x0002 00113 uint16_t addr; 00114 uint16_t len; 00115 uint8_t data[UDPDATASIZE]; 00116 }; 00117 00118 struct codeprop_tcphdr { 00119 uint16_t len; 00120 uint16_t pad; 00121 }; 00122 00123 static void uipcall(void *state); 00124 00125 PROCESS(codeprop_process, "Code propagator"); 00126 00127 struct codeprop_state { 00128 uint8_t state; 00129 #define STATE_NONE 0 00130 #define STATE_RECEIVING_TCPDATA 1 00131 #define STATE_RECEIVING_UDPDATA 2 00132 #define STATE_SENDING_UDPDATA 3 00133 uint16_t count; 00134 uint16_t addr; 00135 uint16_t len; 00136 uint16_t id; 00137 struct etimer sendtimer; 00138 struct timer nacktimer, timer, starttimer; 00139 uint8_t received; 00140 uint8_t send_counter; 00141 struct pt tcpthread_pt; 00142 struct pt udpthread_pt; 00143 struct pt recv_udpthread_pt; 00144 }; 00145 00146 static int fd; 00147 00148 static struct uip_udp_conn *udp_conn; 00149 00150 static struct codeprop_state s; 00151 00152 void system_log(char *msg); 00153 00154 static clock_time_t send_time; 00155 00156 #define CONNECTION_TIMEOUT (30 * CLOCK_SECOND) 00157 00158 /*---------------------------------------------------------------------*/ 00159 void 00160 codeprop_set_rate(clock_time_t time) 00161 { 00162 send_time = time; 00163 } 00164 /*---------------------------------------------------------------------*/ 00165 PROCESS_THREAD(codeprop_process, ev, data) 00166 { 00167 PROCESS_BEGIN(); 00168 00169 elfloader_init(); 00170 00171 s.id = 0/*random_rand()*/; 00172 00173 send_time = CLOCK_SECOND/4; 00174 00175 PT_INIT(&s.udpthread_pt); 00176 PT_INIT(&s.recv_udpthread_pt); 00177 00178 tcp_listen(UIP_HTONS(CODEPROP_DATA_PORT)); 00179 00180 udp_conn = udp_broadcast_new(UIP_HTONS(CODEPROP_DATA_PORT), NULL); 00181 00182 s.state = STATE_NONE; 00183 s.received = 0; 00184 s.addr = 0; 00185 s.len = 0; 00186 00187 fd = cfs_open("codeprop-image", CFS_READ | CFS_WRITE); 00188 00189 while(1) { 00190 00191 PROCESS_YIELD(); 00192 00193 if(ev == tcpip_event) { 00194 uipcall(data); 00195 } else if(ev == PROCESS_EVENT_TIMER) { 00196 tcpip_poll_udp(udp_conn); 00197 } 00198 } 00199 00200 PROCESS_END(); 00201 } 00202 /*---------------------------------------------------------------------*/ 00203 static uint16_t 00204 send_udpdata(struct codeprop_udphdr *uh) 00205 { 00206 uint16_t len; 00207 00208 uh->type = UIP_HTONS(TYPE_DATA); 00209 uh->addr = uip_htons(s.addr); 00210 uh->id = uip_htons(s.id); 00211 00212 if(s.len - s.addr > UDPDATASIZE) { 00213 len = UDPDATASIZE; 00214 } else { 00215 len = s.len - s.addr; 00216 } 00217 00218 cfs_seek(fd, s.addr, CFS_SEEK_SET); 00219 cfs_read(fd, (char*)&uh->data[0], len); 00220 /* eeprom_read(EEPROMFS_ADDR_CODEPROP + s.addr, 00221 &uh->data[0], len);*/ 00222 00223 uh->len = uip_htons(s.len); 00224 00225 PRINTF(("codeprop: sending packet from address 0x%04x\n", s.addr)); 00226 uip_udp_send(len + UDPHEADERSIZE); 00227 00228 return len; 00229 } 00230 /*---------------------------------------------------------------------*/ 00231 static 00232 PT_THREAD(send_udpthread(struct pt *pt)) 00233 { 00234 int len; 00235 struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata; 00236 00237 00238 PT_BEGIN(pt); 00239 00240 while(1) { 00241 PT_WAIT_UNTIL(pt, s.state == STATE_SENDING_UDPDATA); 00242 00243 for(s.addr = 0; s.addr < s.len; ) { 00244 len = send_udpdata(uh); 00245 s.addr += len; 00246 00247 etimer_set(&s.sendtimer, CLOCK_SECOND/4); 00248 do { 00249 PT_WAIT_UNTIL(pt, uip_newdata() || etimer_expired(&s.sendtimer)); 00250 00251 if(uip_newdata()) { 00252 if(uh->type == UIP_HTONS(TYPE_NACK)) { 00253 PRINTF(("send_udpthread: got NACK for address 0x%x (now 0x%x)\n", 00254 uip_htons(uh->addr), s.addr)); 00255 /* Only accept a NACK if it points to a lower byte. */ 00256 if(uip_htons(uh->addr) <= s.addr) { 00257 /* beep();*/ 00258 s.addr = uip_htons(uh->addr); 00259 } 00260 } 00261 PT_YIELD(pt); 00262 } 00263 } while(!etimer_expired(&s.sendtimer)); 00264 } 00265 00266 s.state = STATE_NONE; 00267 00268 /* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */ 00269 } 00270 PT_END(pt); 00271 } 00272 /*---------------------------------------------------------------------*/ 00273 static void 00274 send_nack(struct codeprop_udphdr *uh, unsigned short addr) 00275 { 00276 uh->type = UIP_HTONS(TYPE_NACK); 00277 uh->addr = uip_htons(addr); 00278 uip_udp_send(UDPHEADERSIZE); 00279 } 00280 /*---------------------------------------------------------------------*/ 00281 static 00282 PT_THREAD(recv_udpthread(struct pt *pt)) 00283 { 00284 int len; 00285 struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata; 00286 00287 /* if(uip_newdata()) { 00288 PRINTF(("recv_udpthread: id %d uh->id %d\n", s.id, uip_htons(uh->id))); 00289 }*/ 00290 00291 PT_BEGIN(pt); 00292 00293 while(1) { 00294 00295 do { 00296 PT_WAIT_UNTIL(pt, uip_newdata() && 00297 uh->type == UIP_HTONS(TYPE_DATA) && 00298 uip_htons(uh->id) > s.id); 00299 00300 if(uip_htons(uh->addr) != 0) { 00301 s.addr = 0; 00302 send_nack(uh, 0); 00303 } 00304 00305 } while(uip_htons(uh->addr) != 0); 00306 00307 /* leds_on(LEDS_YELLOW); 00308 beep_down(10000);*/ 00309 00310 s.addr = 0; 00311 s.id = uip_htons(uh->id); 00312 s.len = uip_htons(uh->len); 00313 00314 timer_set(&s.timer, CONNECTION_TIMEOUT); 00315 /* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */ 00316 00317 while(s.addr < s.len) { 00318 00319 if(uip_htons(uh->addr) == s.addr) { 00320 /* leds_blink();*/ 00321 len = uip_datalen() - UDPHEADERSIZE; 00322 if(len > 0) { 00323 /* eeprom_write(EEPROMFS_ADDR_CODEPROP + s.addr, 00324 &uh->data[0], len);*/ 00325 cfs_seek(fd, s.addr, CFS_SEEK_SET); 00326 cfs_write(fd, (char*)&uh->data[0], len); 00327 00328 /* beep();*/ 00329 PRINTF(("Saved %d bytes at address %d, %d bytes left\n", 00330 uip_datalen() - UDPHEADERSIZE, s.addr, 00331 s.len - s.addr)); 00332 00333 s.addr += len; 00334 } 00335 00336 } else if(uip_htons(uh->addr) > s.addr) { 00337 PRINTF(("sending nack since 0x%x != 0x%x\n", uip_htons(uh->addr), s.addr)); 00338 send_nack(uh, s.addr); 00339 } 00340 00341 if(s.addr < s.len) { 00342 00343 /* timer_set(&s.nacktimer, NACK_TIMEOUT);*/ 00344 00345 do { 00346 timer_set(&s.nacktimer, HIT_NACK_TIMEOUT); 00347 PT_YIELD_UNTIL(pt, timer_expired(&s.nacktimer) || 00348 (uip_newdata() && 00349 uh->type == UIP_HTONS(TYPE_DATA) && 00350 uip_htons(uh->id) == s.id)); 00351 if(timer_expired(&s.nacktimer)) { 00352 send_nack(uh, s.addr); 00353 } 00354 } while(timer_expired(&s.nacktimer)); 00355 } 00356 00357 } 00358 00359 /* leds_off(LEDS_YELLOW); 00360 beep_quick(2);*/ 00361 /* printf("Received entire bunary over udr\n");*/ 00362 codeprop_start_program(); 00363 PT_EXIT(pt); 00364 } 00365 00366 PT_END(pt); 00367 } 00368 /*---------------------------------------------------------------------*/ 00369 00370 #define CODEPROP_TCPHDR_SIZE sizeof(struct codeprop_tcphdr) 00371 00372 static 00373 PT_THREAD(recv_tcpthread(struct pt *pt)) 00374 { 00375 struct codeprop_tcphdr *th; 00376 int datalen = uip_datalen(); 00377 PT_BEGIN(pt); 00378 00379 while(1) { 00380 00381 PT_WAIT_UNTIL(pt, uip_connected()); 00382 00383 codeprop_exit_program(); 00384 00385 s.state = STATE_RECEIVING_TCPDATA; 00386 00387 s.addr = 0; 00388 s.count = 0; 00389 00390 /* Read the header. */ 00391 PT_WAIT_UNTIL(pt, uip_newdata() && uip_datalen() > 0); 00392 00393 if(uip_datalen() < CODEPROP_TCPHDR_SIZE) { 00394 PRINTF(("codeprop: header not found in first tcp segment\n")); 00395 uip_abort(); 00396 } 00397 th = (struct codeprop_tcphdr *)uip_appdata; 00398 s.len = uip_htons(th->len); 00399 s.addr = 0; 00400 uip_appdata += CODEPROP_TCPHDR_SIZE; 00401 datalen -= CODEPROP_TCPHDR_SIZE; 00402 00403 /* Read the rest of the data. */ 00404 do { 00405 if(datalen > 0) { 00406 /* printf("Got %d bytes\n", datalen); */ 00407 00408 if (cfs_seek(fd, s.addr, CFS_SEEK_SET) != s.addr) { 00409 PRINTF(("codeprop: seek in buffer file failed\n")); 00410 uip_abort(); 00411 } 00412 00413 if (cfs_write(fd, uip_appdata, datalen) != datalen) { 00414 PRINTF(("codeprop: write to buffer file failed\n")); 00415 uip_abort(); 00416 } 00417 s.addr += datalen; 00418 } 00419 if(s.addr < s.len) { 00420 PT_YIELD_UNTIL(pt, uip_newdata()); 00421 } 00422 } while(s.addr < s.len); 00423 #if 1 00424 00425 { 00426 static int err; 00427 00428 err = codeprop_start_program(); 00429 00430 /* Print out the "OK"/error message. */ 00431 do { 00432 if (err >= 0 && err < sizeof(err_msgs)/sizeof(char*)) { 00433 uip_send(err_msgs[err], strlen(err_msgs[err])); 00434 } else { 00435 uip_send("Unknown error\r\n", 15); 00436 } 00437 PT_WAIT_UNTIL(pt, uip_acked() || uip_rexmit() || uip_closed()); 00438 } while(uip_rexmit()); 00439 00440 /* Close the connection. */ 00441 uip_close(); 00442 } 00443 #endif 00444 ++s.id; 00445 s.state = STATE_SENDING_UDPDATA; 00446 tcpip_poll_udp(udp_conn); 00447 00448 PT_WAIT_UNTIL(pt, s.state != STATE_SENDING_UDPDATA); 00449 /* printf("recv_tcpthread: unblocked\n");*/ 00450 } 00451 00452 PT_END(pt); 00453 } 00454 /*---------------------------------------------------------------------*/ 00455 void 00456 codeprop_start_broadcast(unsigned int len) 00457 { 00458 s.addr = 0; 00459 s.len = len; 00460 ++s.id; 00461 s.state = STATE_SENDING_UDPDATA; 00462 tcpip_poll_udp(udp_conn); 00463 } 00464 /*---------------------------------------------------------------------*/ 00465 void 00466 codeprop_exit_program(void) 00467 { 00468 if(elfloader_autostart_processes != NULL) { 00469 autostart_exit(elfloader_autostart_processes); 00470 } 00471 } 00472 /*---------------------------------------------------------------------*/ 00473 int 00474 codeprop_start_program(void) 00475 { 00476 int err; 00477 00478 codeprop_exit_program(); 00479 00480 err = elfloader_load(fd, codeprop_output); 00481 if(err == ELFLOADER_OK) { 00482 PRINTF(("codeprop: starting %s\n", 00483 elfloader_autostart_processes[0]->name)); 00484 autostart_start(elfloader_autostart_processes); 00485 } 00486 return err; 00487 } 00488 /*---------------------------------------------------------------------*/ 00489 static void 00490 uipcall(void *state) 00491 { 00492 if(uip_udpconnection()) { 00493 recv_udpthread(&s.recv_udpthread_pt); 00494 send_udpthread(&s.udpthread_pt); 00495 } else { 00496 if(uip_conn->lport == UIP_HTONS(CODEPROP_DATA_PORT)) { 00497 if(uip_connected()) { 00498 00499 if(state == NULL) { 00500 s.addr = 0; 00501 s.count = 0; 00502 PT_INIT(&s.tcpthread_pt); 00503 process_poll(&codeprop_process); 00504 tcp_markconn(uip_conn, &s); 00505 /* process_post(PROCESS_BROADCAST, codeprop_event_quit, */ 00506 /* (process_data_t)NULL); */ 00507 } else { 00508 PRINTF(("codeprop: uip_connected() and state != NULL\n")); 00509 uip_abort(); 00510 } 00511 } 00512 recv_tcpthread(&s.tcpthread_pt); 00513 00514 00515 if(uip_closed() || uip_aborted() || uip_timedout()) { 00516 PRINTF(("codeprop: connection down\n")); 00517 tcp_markconn(uip_conn, NULL); 00518 } 00519 } 00520 } 00521 } 00522 /*---------------------------------------------------------------------*/ 00523 /** @} */