Contiki 2.6
|
00001 /* 00002 * Copyright (c) 2010, Loughborough University - 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 00032 /** 00033 * \file 00034 * Disco server sources 00035 * (embedded part of the DISCOBALL project) 00036 * 00037 * It objective is to receive a code file over UDP, store it in 00038 * external flash and disseminate it to other nodes of the 00039 * 6LoWPAN network. 00040 * 00041 * For this to work, the image must be co-hosted with the BooTTY! 00042 * bootloader, which will move the image from external to internal 00043 * flash. 00044 * 00045 * To link this application in your contiki image, all you need to 00046 * do is to add this line: 00047 * OFFSET_FIRMWARE=1 00048 * to your project's makefile 00049 * 00050 * \author 00051 * George Oikonomou - <oikonomou@users.sourceforge.net> 00052 */ 00053 00054 #include "contiki.h" 00055 #include "contiki-net.h" 00056 #include "sys/clock.h" 00057 #include "sys/ctimer.h" 00058 #include "dev/watchdog.h" 00059 00060 #include "dev/n740.h" 00061 #include "dev/m25p16.h" 00062 00063 #include "disco.h" 00064 /*---------------------------------------------------------------------------*/ 00065 #define DEBUG DEBUG_NONE 00066 #include "net/uip-debug.h" 00067 /*---------------------------------------------------------------------------*/ 00068 #if BATMON_CONF_ENABLED 00069 void batmon_log(uint8_t trigger); 00070 00071 #define LOG_TRIGGER_OAP_DISCO_START 0x01 00072 #define LOG_TRIGGER_OAP_DISCO_DONE 0x02 00073 #define LOG_TRIGGER_OAP_DISCO_ABORT 0x03 00074 #else 00075 #define batmon_log(t) do { } while(0); 00076 #endif 00077 /*---------------------------------------------------------------------------*/ 00078 static struct uip_udp_conn *server_conn; 00079 static struct disco_request_pdu * req; 00080 static struct disco_response_pdu resp; 00081 static struct disco_seed seed; 00082 static uint8_t state; 00083 static uint8_t sector; 00084 static uint16_t interval; 00085 static struct ctimer disco_timer; 00086 00087 #define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) 00088 #define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) 00089 00090 extern uint16_t uip_len; 00091 extern void *uip_appdata; 00092 00093 __xdata __at(BOOTTY_CMD_LOCATION) static uint8_t bd; 00094 /*---------------------------------------------------------------------------*/ 00095 static void timer_handler(void * p); 00096 /*---------------------------------------------------------------------------*/ 00097 static void 00098 abort() CC_NON_BANKED 00099 { 00100 PRINTF("Disco: Abort @ %lu\n", clock_seconds()); 00101 n740_analog_deactivate(); 00102 m25p16_dp(); 00103 n740_analog_activate(); 00104 state = DISCO_STATE_LISTENING; 00105 memset(&seed, 0, sizeof(seed)); 00106 ctimer_stop(&disco_timer); 00107 batmon_log(LOG_TRIGGER_OAP_DISCO_ABORT); 00108 } 00109 /*---------------------------------------------------------------------------*/ 00110 static void 00111 restart_timer(uint16_t t) CC_NON_BANKED 00112 { 00113 interval = t; 00114 ctimer_stop(&disco_timer); 00115 ctimer_set(&disco_timer, interval, timer_handler, &state); 00116 } 00117 /*---------------------------------------------------------------------------*/ 00118 static void 00119 timer_handler(void * p) 00120 { 00121 uint8_t * s = p; 00122 uint8_t wip; 00123 00124 PRINTF("Disco: @ %lu, s: %u\n", clock_seconds(), *s); 00125 00126 if(*s == DISCO_STATE_PREPARING) { 00127 n740_analog_deactivate(); 00128 wip = M25P16_WIP(); 00129 n740_analog_activate(); 00130 00131 if(wip) { 00132 restart_timer(DISCO_TIMEOUT_PREPARE); 00133 } else { 00134 PRINTF("Disco: Erased %u\n", sector); 00135 if((sector & 1) == 0) { 00136 sector++; 00137 PRINTF("Disco: Next %u\n", sector); 00138 n740_analog_deactivate(); 00139 m25p16_se(sector); 00140 n740_analog_activate(); 00141 restart_timer(DISCO_TIMEOUT_PREPARE); 00142 } else { 00143 PRINTF("Disco: Ready\n"); 00144 *s = DISCO_STATE_READY; 00145 resp.status = DISCO_CMD_INIT; 00146 restart_timer(DISCO_TIMEOUT_ABORT); 00147 server_conn->rport = seed.port; 00148 uip_ipaddr_copy(&server_conn->ripaddr, &seed.addr); 00149 uip_udp_packet_send(server_conn, &resp, DISCO_RESP_LEN_INIT); 00150 00151 /* Restore server connection to allow data from any node */ 00152 uip_create_unspecified(&server_conn->ripaddr); 00153 server_conn->rport = 0; 00154 } 00155 } 00156 } else if(*s == DISCO_STATE_READY) { 00157 abort(); 00158 } else if(*s == DISCO_STATE_REBOOTING) { 00159 watchdog_reboot(); 00160 } 00161 } 00162 /*---------------------------------------------------------------------------*/ 00163 static uint8_t 00164 is_protected(uint8_t a) CC_NON_BANKED 00165 { 00166 uint8_t bp = M25P16_BP() >> 2; 00167 00168 if(bp > 5) { 00169 return SECTOR_PROTECTED; 00170 } 00171 00172 bp -= 1; 00173 00174 if(a >= (32 - (1 << bp))) { 00175 return SECTOR_PROTECTED; 00176 } 00177 return SECTOR_UNPROTECTED; 00178 } 00179 /*---------------------------------------------------------------------------*/ 00180 static uint8_t 00181 cmd_init() CC_NON_BANKED 00182 { 00183 PRINTF("Disco: Init 0x%02x\n", req->addr[0]); 00184 if(uip_datalen() != DISCO_LEN_INIT) { 00185 PRINTF("Disco: Bad len (%u)\n", uip_datalen()); 00186 resp.status = DISCO_ERR_BAD_LEN; 00187 return DISCO_RESP_LEN_ERR; 00188 } 00189 n740_analog_deactivate(); 00190 m25p16_res(); 00191 sector = 2 * req->addr[0]; 00192 if(is_protected(sector) == SECTOR_PROTECTED 00193 || is_protected(sector + 1) == SECTOR_PROTECTED) { 00194 resp.status = DISCO_ERR_PROTECTED; 00195 n740_analog_activate(); 00196 return DISCO_RESP_LEN_ERR; 00197 } 00198 m25p16_se(sector); 00199 n740_analog_activate(); 00200 state = DISCO_STATE_PREPARING; 00201 restart_timer(DISCO_TIMEOUT_PREPARE); 00202 00203 /* Store the sender's address/port so we can reply when ready */ 00204 seed.port = UIP_UDP_BUF->srcport; 00205 uip_ipaddr_copy(&seed.addr, &UIP_IP_BUF->srcipaddr); 00206 PRINTF("Disco: OK\n"); 00207 00208 batmon_log(LOG_TRIGGER_OAP_DISCO_START); 00209 00210 return DISCO_RESPONSE_NONE; 00211 } 00212 /*---------------------------------------------------------------------------*/ 00213 static uint8_t 00214 cmd_write() CC_NON_BANKED 00215 { 00216 PRINTF("Disco: Write 0x%02x%02x%02x\n", req->addr[0], req->addr[1], req->addr[2]); 00217 if(uip_datalen() != DISCO_LEN_WRITE) { 00218 resp.status = DISCO_ERR_BAD_LEN; 00219 return DISCO_RESP_LEN_ERR; 00220 } 00221 restart_timer(DISCO_TIMEOUT_ABORT); 00222 n740_analog_deactivate(); 00223 m25p16_pp(req->addr, req->data, DISCO_FLEN_DATA); 00224 watchdog_periodic(); 00225 while(M25P16_WIP()); 00226 n740_analog_activate(); 00227 resp.status = DISCO_CMD_WRITE; 00228 memcpy(resp.addr, req->addr, DISCO_FLEN_ADDR); 00229 return DISCO_RESP_LEN_WRITE; 00230 } 00231 /*---------------------------------------------------------------------------*/ 00232 static uint8_t 00233 cmd_switch() CC_NON_BANKED 00234 { 00235 PRINTF("Disco: Switch 0x%02x\n", req->addr[0]); 00236 if(uip_datalen() != DISCO_LEN_SWITCH) { 00237 resp.status = DISCO_ERR_BAD_LEN; 00238 return DISCO_RESP_LEN_ERR; 00239 } 00240 if(req->addr[0] > 15) { 00241 resp.status = DISCO_ERR_BAD_OFFSET; 00242 return DISCO_RESP_LEN_ERR; 00243 } 00244 00245 bd = BOOTTY_CMD_COPY_IMAGE; 00246 bd |= req->addr[0]; 00247 00248 resp.status = DISCO_CMD_SWITCH; 00249 resp.addr[0] = req->addr[0]; 00250 00251 restart_timer(DISCO_TIMEOUT_REBOOT); 00252 state = DISCO_STATE_REBOOTING; 00253 00254 return DISCO_RESP_LEN_SWITCH; 00255 } 00256 /*---------------------------------------------------------------------------*/ 00257 static uint8_t 00258 cmd_done() CC_NON_BANKED 00259 { 00260 PRINTF("Disco: Done\n"); 00261 if(uip_datalen() != DISCO_LEN_DONE) { 00262 resp.status = DISCO_ERR_BAD_LEN; 00263 return DISCO_RESP_LEN_ERR; 00264 } 00265 resp.status = DISCO_CMD_DONE; 00266 00267 batmon_log(LOG_TRIGGER_OAP_DISCO_DONE); 00268 00269 return DISCO_RESP_LEN_DONE; 00270 } 00271 /*---------------------------------------------------------------------------*/ 00272 static uint8_t 00273 event_handler(process_event_t ev) CC_NON_BANKED 00274 { 00275 uint8_t rv = DISCO_RESPONSE_NONE; 00276 00277 if(ev != tcpip_event) { 00278 return rv; 00279 } 00280 00281 /* Always accept CMD_DONE */ 00282 if(req->cmd == DISCO_CMD_DONE) { 00283 return cmd_done(); 00284 } 00285 00286 /* Always accept switch too */ 00287 if(req->cmd == DISCO_CMD_SWITCH) { 00288 return cmd_switch(); 00289 } 00290 00291 switch(state) { 00292 case DISCO_STATE_LISTENING: 00293 req = uip_appdata; 00294 if(req->cmd == DISCO_CMD_INIT) { 00295 rv = cmd_init(); 00296 } 00297 break; 00298 case DISCO_STATE_PREPARING: 00299 PRINTF("Disco: Not Ready\n"); 00300 resp.status = DISCO_ERR_NOT_READY; 00301 rv = DISCO_RESP_LEN_ERR; 00302 break; 00303 case DISCO_STATE_READY: 00304 req = uip_appdata; 00305 if(req->cmd == DISCO_CMD_WRITE) { 00306 rv = cmd_write(); 00307 } else if(req->cmd == DISCO_CMD_INIT) { 00308 resp.status = DISCO_ERR_INIT_DONE; 00309 rv = DISCO_RESP_LEN_ERR; 00310 } else if(req->cmd == DISCO_CMD_SWITCH) { 00311 rv = cmd_switch(); 00312 } 00313 break; 00314 } 00315 return rv; 00316 } 00317 /*---------------------------------------------------------------------------*/ 00318 PROCESS(disco_process, "Disco Server Process"); 00319 /*---------------------------------------------------------------------------*/ 00320 PROCESS_THREAD(disco_process, ev, data) 00321 { 00322 uint8_t len; 00323 00324 PROCESS_BEGIN(); 00325 00326 PRINTF("Disco Server\n"); 00327 00328 server_conn = udp_new(NULL, UIP_HTONS(0), NULL); 00329 udp_bind(server_conn, UIP_HTONS(DISCO_UDP_PORT)); 00330 00331 state = DISCO_STATE_LISTENING; 00332 00333 while(1) { 00334 PROCESS_YIELD(); 00335 len = event_handler(ev); 00336 00337 if(len > 0) { 00338 server_conn->rport = UIP_UDP_BUF->srcport; 00339 uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr); 00340 uip_udp_packet_send(server_conn, &resp, len); 00341 /* Restore server connection to allow data from any node */ 00342 uip_create_unspecified(&server_conn->ripaddr); 00343 server_conn->rport = 0; 00344 } 00345 } 00346 00347 PROCESS_END(); 00348 } 00349 /*---------------------------------------------------------------------------*/