Contiki 2.6

codeprop-otf.c

Go to the documentation of this file.
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 /** @} */