00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "contiki.h"
00042
00043 #include "lib/crc16.h"
00044 #include "lib/checkpoint.h"
00045
00046 #include "sys/rtimer.h"
00047 #include "sys/mt.h"
00048 #include "sys/energest.h"
00049 #include "sys/compower.h"
00050 #include "dev/leds.h"
00051 #include "dev/watchdog.h"
00052 #include "dev/serial-line.h"
00053 #include "dev/uart1.h"
00054 #include "dev/cc2420.h"
00055 #include "dev/button-sensor.h"
00056 #include "cfs/cfs.h"
00057 #include "cfs/cfs-coffee.h"
00058
00059 #include <io.h>
00060 #include <signal.h>
00061 #include <stdio.h>
00062
00063 #define DEBUG 0
00064 #if DEBUG
00065 #define PRINTF(...) printf(__VA_ARGS__)
00066 #else
00067 #define PRINTF(...)
00068 #endif
00069
00070 #ifndef CHECKPOINT_ROLLBACK_BUTTON
00071 #define CHECKPOINT_ROLLBACK_BUTTON 1
00072 #endif
00073
00074 #if CHECKPOINT_ROLLBACK_BUTTON
00075 PROCESS(checkpoint_button_process, "Rollback on button");
00076 #endif
00077
00078 #define WITH_SERIAL_COMMANDS 0
00079 #if WITH_SERIAL_COMMANDS
00080 #if UART1_CONF_TX_WITH_INTERRUPT
00081 #error TX_WITH_INTERRUPTS must be 0
00082 #endif
00083 #define PRINTF_COMMAND(...) printf(__VA_ARGS__)
00084 #else
00085 #define PRINTF_COMMAND(...)
00086 #endif
00087
00088 #define COMMAND_ROLLBACK 1
00089 #define COMMAND_CHECKPOINT 2
00090 #define COMMAND_METRICS 3
00091
00092 #define INCLUDE_RAM 1
00093 #define INCLUDE_TIMERS 1
00094 #define INCLUDE_LEDS 1
00095
00096
00097
00098 #define RAM_START 0x1100
00099 #define RAM_END 0x3900
00100
00101 #define PAUSE_TIME() \
00102 TACTL &= ~(MC1); \
00103 TBCTL &= ~(MC1); \
00104 watchdog_stop();
00105 #define RESUME_TIME() \
00106 TACTL |= MC1; \
00107 TBCTL |= MC1; \
00108 TACCR1 = clock_fine_max(); \
00109 watchdog_start();
00110 #define PAUSE_TIME_INT() \
00111 dint(); \
00112 PAUSE_TIME();
00113 #define RESUME_TIME_INT() \
00114 RESUME_TIME(); \
00115 eint();
00116
00117 static struct mt_thread checkpoint_thread;
00118 static uint8_t preset_cmd;
00119 static int preset_fd;
00120
00121
00122 #if WITH_SERIAL_COMMANDS
00123 static int nr_pongs=0;
00124 #endif
00125 static int nr_checkpoints=0, nr_rollbacks=0, nr_metrics=0;
00126
00127
00128 typedef union {
00129 unsigned char u8[2];
00130 unsigned short u16;
00131 } word_union_t;
00132
00133 static int
00134 write_byte(int fd, uint8_t c)
00135 {
00136 return cfs_write(fd, &c, 1);
00137 }
00138
00139 static void
00140 write_word(int fd, uint16_t w)
00141 {
00142 word_union_t tmp;
00143 tmp.u16 = w;
00144 write_byte(fd, tmp.u8[0]);
00145 write_byte(fd, tmp.u8[1]);
00146 }
00147
00148 static uint8_t
00149 read_byte(int fd)
00150 {
00151 uint8_t c;
00152 cfs_read(fd, &c, 1);
00153 return c;
00154 }
00155
00156 static uint16_t
00157 read_word(int fd)
00158 {
00159 word_union_t tmp;
00160 tmp.u8[0] = read_byte(fd);
00161 tmp.u8[1] = read_byte(fd);
00162 return tmp.u16;
00163 }
00164
00165 static void
00166 thread_checkpoint(int fd)
00167 {
00168 #if INCLUDE_RAM
00169 unsigned char *addr;
00170 uint16_t size = 0;
00171 unsigned char *thread_mem_start = (unsigned char *)&checkpoint_thread.thread.stack;
00172 unsigned char *thread_mem_end = thread_mem_start + sizeof(checkpoint_thread.thread.stack) - 1;
00173 unsigned char *coffee_mem_start = cfs_coffee_get_protected_mem(&size);
00174 unsigned char *coffee_mem_end = coffee_mem_start + size - 1;
00175 #endif
00176
00177
00178
00179
00180
00181 #if INCLUDE_RAM
00182 for(addr = (unsigned char *)RAM_START;
00183 addr < (unsigned char *)RAM_END;
00184 addr++) {
00185
00186 if((addr >= thread_mem_start && addr <= thread_mem_end)) {
00187
00188 continue;
00189 }
00190
00191 if((addr >= coffee_mem_start && addr <= coffee_mem_end)) {
00192
00193 continue;
00194 }
00195
00196
00197 write_byte(fd, *addr);
00198
00199
00200
00201
00202 }
00203
00204 #endif
00205
00206
00207 #if INCLUDE_TIMERS
00208 write_word(fd, TACTL);
00209 write_word(fd, TACCTL1);
00210 write_word(fd, TACCR1);
00211 write_word(fd, TAR);
00212
00213 write_word(fd, TBCTL);
00214 write_word(fd, TBCCTL1);
00215 write_word(fd, TBCCR1);
00216 write_word(fd, TBR);
00217 #endif
00218
00219
00220 #if INCLUDE_LEDS
00221 write_byte(fd, leds_arch_get());
00222 #endif
00223
00224
00225
00226
00227
00228 write_byte(fd, -1);
00229 }
00230
00231 static void
00232 thread_rollback(int fd)
00233 {
00234 #if INCLUDE_RAM
00235 unsigned char *addr;
00236 uint16_t size = 0;
00237 unsigned char *thread_mem_start = (unsigned char *)&checkpoint_thread.thread.stack;
00238 unsigned char *thread_mem_end = thread_mem_start + sizeof(checkpoint_thread.thread.stack) - 1;
00239 unsigned char *coffee_mem_start = cfs_coffee_get_protected_mem(&size);
00240 unsigned char *coffee_mem_end = coffee_mem_start + size - 1;
00241 #endif
00242
00243
00244
00245
00246
00247 #if INCLUDE_RAM
00248 for(addr = (unsigned char *)RAM_START;
00249 addr < (unsigned char *)RAM_END;
00250 addr++) {
00251 if((addr >= thread_mem_start && addr <= thread_mem_end)) {
00252
00253 continue;
00254 }
00255
00256 if((addr >= coffee_mem_start && addr <= coffee_mem_end)) {
00257
00258 continue;
00259 }
00260
00261 *addr = read_byte(fd);
00262 }
00263 #endif
00264
00265
00266 #if INCLUDE_TIMERS
00267 TACTL = read_word(fd);
00268 TACCTL1 = read_word(fd);
00269 TACCR1 = read_word(fd);
00270 TAR = read_word(fd);
00271
00272 TBCTL = read_word(fd);
00273 TBCCTL1 = read_word(fd);
00274 TBCCR1 = read_word(fd);
00275 TBR = read_word(fd);
00276 #endif
00277
00278
00279 #if INCLUDE_LEDS
00280 leds_arch_set(read_byte(fd));
00281 #endif
00282
00283
00284
00285
00286
00287 read_byte(fd);
00288 }
00289
00290 #if WITH_SERIAL_COMMANDS
00291 static uint32_t
00292 thread_metric_tx(void)
00293 {
00294 energest_flush();
00295 return energest_type_time(ENERGEST_TYPE_TRANSMIT);
00296 }
00297
00298 static uint32_t
00299 thread_metric_rx(void)
00300 {
00301 energest_flush();
00302 return energest_type_time(ENERGEST_TYPE_LISTEN);
00303 }
00304 #endif
00305
00306 static void
00307 thread_metrics(void)
00308 {
00309 PRINTF_COMMAND("METRICS:START\n");
00310 PRINTF_COMMAND("M:RTIMER_NOW:%u\n", RTIMER_NOW());
00311 PRINTF_COMMAND("M:ENERGY_TX:%lu\n", thread_metric_tx());
00312 PRINTF_COMMAND("M:ENERGY_RX:%lu\n", thread_metric_rx());
00313 PRINTF_COMMAND("M:RTIMER_NOW2:%u\n", RTIMER_NOW());
00314 nr_metrics++;
00315 PRINTF_COMMAND("METRICS:DONE %u\n", nr_metrics);
00316 }
00317
00318 static void
00319 checkpoint_thread_loop(void *data)
00320 {
00321 uint8_t cmd;
00322 int fd;
00323
00324 while(1) {
00325
00326 cmd = preset_cmd;
00327 fd = preset_fd;
00328
00329
00330 if(cmd == COMMAND_ROLLBACK) {
00331 PRINTF_COMMAND("RB:START\n");
00332 thread_rollback(fd);
00333 nr_rollbacks++;
00334 PRINTF_COMMAND("RB:DONE %u\n", nr_rollbacks);
00335
00336 } else if(cmd == COMMAND_CHECKPOINT) {
00337 PRINTF_COMMAND("CP:START\n");
00338 thread_checkpoint(fd);
00339 thread_metrics();
00340 nr_checkpoints++;
00341 PRINTF_COMMAND("CP:DONE %u\n", nr_checkpoints);
00342 } else if(cmd == COMMAND_METRICS) {
00343 thread_metrics();
00344 } else {
00345 printf("ERROR: Unknown thread command: %u\n", cmd);
00346 }
00347
00348
00349 mt_yield();
00350 }
00351 }
00352
00353 int
00354 checkpoint_arch_size()
00355 {
00356 return 10258;
00357 }
00358
00359 void
00360 checkpoint_arch_checkpoint(int fd)
00361 {
00362 PAUSE_TIME_INT();
00363
00364 preset_cmd = COMMAND_CHECKPOINT;
00365 preset_fd = fd;
00366 mt_exec(&checkpoint_thread);
00367
00368 RESUME_TIME_INT();
00369 }
00370
00371 void
00372 checkpoint_arch_rollback(int fd)
00373 {
00374 PAUSE_TIME_INT();
00375
00376 preset_cmd = COMMAND_ROLLBACK;
00377 preset_fd = fd;
00378 mt_exec(&checkpoint_thread);
00379
00380 RESUME_TIME_INT();
00381 }
00382
00383 static uint8_t inited = 0;
00384 void
00385 checkpoint_arch_init(void)
00386 {
00387 if(inited) {
00388 return;
00389 }
00390
00391 mt_init();
00392 mt_start(&checkpoint_thread, checkpoint_thread_loop, NULL);
00393 inited = 1;
00394
00395 #if CHECKPOINT_ROLLBACK_BUTTON
00396 process_start(&checkpoint_button_process, NULL);
00397 #endif
00398
00399
00400
00401 }
00402
00403 struct power_log {
00404 uint32_t transmit;
00405 uint32_t listen;
00406 };
00407
00408 #if WITH_SERIAL_COMMANDS
00409 static void
00410 serial_interrupt_checkpoint()
00411 {
00412 int fd = 0;
00413 PAUSE_TIME();
00414
00415 if(SPI_IS_ENABLED()) {
00416
00417 PRINTF_COMMAND("CP:SPIBUSY\n");
00418 RESUME_TIME();
00419 return;
00420 }
00421
00422
00423 cfs_remove("cp");
00424 cfs_coffee_reserve("cp", checkpoint_arch_size());
00425 fd = cfs_open("cp", CFS_WRITE);
00426
00427 if(fd < 0) {
00428 printf("ERROR: No file access (cp)\n");
00429 RESUME_TIME();
00430 return;
00431 }
00432
00433
00434 preset_cmd = COMMAND_CHECKPOINT;
00435 preset_fd = fd;
00436 mt_exec(&checkpoint_thread);
00437
00438
00439 cfs_close(fd);
00440
00441 RESUME_TIME();
00442 }
00443
00444 static void
00445 serial_interrupt_rollback()
00446 {
00447 int fd = 0;
00448 PAUSE_TIME();
00449
00450 if(SPI_IS_ENABLED()) {
00451
00452 PRINTF_COMMAND("RB:SPIBUSY\n");
00453 RESUME_TIME();
00454 return;
00455 }
00456
00457
00458 fd = cfs_open("cp", CFS_READ);
00459
00460 if(fd < 0) {
00461 printf("ERROR: No file access (rb)\n");
00462 RESUME_TIME();
00463 return;
00464 }
00465
00466
00467 preset_cmd = COMMAND_ROLLBACK;
00468 preset_fd = fd;
00469 mt_exec(&checkpoint_thread);
00470
00471
00472 cfs_close(fd);
00473
00474 RESUME_TIME();
00475 }
00476
00477 static void
00478 serial_interrupt_metrics()
00479 {
00480 PAUSE_TIME();
00481
00482 preset_cmd = COMMAND_METRICS;
00483 preset_fd = -1;
00484 mt_exec(&checkpoint_thread);
00485
00486 RESUME_TIME();
00487 }
00488
00489 static const unsigned char command_checkpoint[] = { 'c', 'p', '\n' };
00490 static const unsigned char command_rollback[] = { 'r', 'b', '\n' };
00491 static const unsigned char command_metrics[] = { 'm', 't', '\n' };
00492 static volatile int command_checkpoint_state = 0;
00493 static volatile int command_rollback_state = 0;
00494 static volatile int command_metrics_state = 0;
00495
00496 static int
00497 serial_input_byte_intercept(unsigned char c)
00498 {
00499
00500 if(command_checkpoint[command_checkpoint_state] == c) {
00501 command_checkpoint_state++;
00502
00503 if(command_checkpoint_state == sizeof(command_checkpoint)) {
00504 serial_interrupt_checkpoint();
00505 command_checkpoint_state = 0;
00506 }
00507 } else {
00508 command_checkpoint_state = 0;
00509 }
00510
00511
00512 if(command_rollback[command_rollback_state] == c) {
00513 command_rollback_state++;
00514
00515 if(command_rollback_state == sizeof(command_rollback)) {
00516 serial_interrupt_rollback();
00517 command_rollback_state = 0;
00518 }
00519 } else {
00520 command_rollback_state = 0;
00521 }
00522
00523
00524 if(command_metrics[command_metrics_state] == c) {
00525 command_metrics_state++;
00526
00527 if(command_metrics_state == sizeof(command_metrics)) {
00528 serial_interrupt_metrics();
00529 command_metrics_state = 0;
00530 }
00531 } else {
00532 command_metrics_state = 0;
00533 }
00534
00535
00536 return serial_line_input_byte(c);
00537 }
00538
00539 static void
00540 handle_get_command(void)
00541 {
00542 int fd = 0;
00543 fd = cfs_open("cp", CFS_READ);
00544 if(fd < 0) {
00545 printf("ERROR: No file access (get)\n");
00546 } else {
00547 PRINTF_COMMAND("GET:START\n");
00548 char data[8];
00549 int offset=0, size=0, read=8;
00550 unsigned short crc = 0;
00551 cfs_seek(fd, offset, CFS_SEEK_SET);
00552
00553 while (read == 8) {
00554 int i;
00555
00556
00557
00558
00559
00560 read = cfs_read(fd, data, 8);
00561 size += read;
00562
00563 printf("%04i: ", offset);
00564 for (i=0; i < read; i++) {
00565 crc = crc16_add((uint8_t) data[i], crc);
00566 printf("%02x", (uint8_t) (0xff&data[i]));
00567 }
00568 printf("\n");
00569
00570 offset += 8;
00571 }
00572
00573 PRINTF_COMMAND("GET:DONE CRC=%u\n", crc);
00574 cfs_close(fd);
00575 }
00576 }
00577
00578 static int
00579 hex_decode_char(char c)
00580 {
00581 if(c >= 'A' && c <= 'F') {
00582 return c - 'A' + 10;
00583 } else if(c >= 'a' && c <= 'f') {
00584 return c - 'a' + 10;
00585 } else if(c >= '0' && c <= '9') {
00586 return c - '0';
00587 } else {
00588 printf("WARN: bad hex: %c\n", c);
00589 return 0;
00590 }
00591 }
00592
00593 PROCESS(checkpoint_serial_process, "Checkpoint via serial commands");
00594 PROCESS_THREAD(checkpoint_serial_process, ev, data)
00595 {
00596 static int set_fd = -1;
00597 static int set_count = -1;
00598
00599 PROCESS_BEGIN();
00600
00601
00602 PROCESS_PAUSE();
00603 uart1_set_input(serial_input_byte_intercept);
00604
00605
00606 PRINTF("Formatting Coffee\n");
00607 cfs_coffee_format();
00608 PRINTF("Formatting Coffee... done!\n");
00609
00610 while(1) {
00611 PROCESS_WAIT_EVENT_UNTIL(ev == serial_line_event_message && data != NULL);
00612
00613 if(strcmp("set", data) == 0) {
00614
00615
00616 cfs_remove("cp");
00617 cfs_coffee_reserve("cp", checkpoint_arch_size());
00618 set_fd = cfs_open("cp", CFS_WRITE);
00619 set_count = 0;
00620 if(set_fd < 0) {
00621 printf("SET:FSBUSY\n");
00622 } else {
00623 printf("SET:LINE\n");
00624 }
00625 } else if(set_fd >= 0 && strcmp("set:done", data) == 0) {
00626 cfs_close(set_fd);
00627 set_fd = -1;
00628 if(set_count == 9862) {
00629 printf("SET:DONE\n");
00630 } else {
00631 printf("SET:WRONGSIZE\n");
00632 }
00633 } else if(set_fd >= 0) {
00634
00635 printf("SET:LINE\n");
00636
00637 int len = strlen((char*)data);
00638 if(len > 16 || (len%2)!=0) {
00639 printf("WARN: bad set data: %s\n", (char*)data);
00640 } else {
00641 int i;
00642 for (i=0; i < len; i+=2) {
00643 uint8_t b =
00644 (hex_decode_char(((char*)data)[i]) << 4) +
00645 (hex_decode_char(((char*)data)[i+1]));
00646
00647 PRINTF("Parsing set command: writing to CFS: %02x\n", b);
00648 write_byte(set_fd, b);
00649 set_count++;
00650 }
00651 }
00652 } else if(strcmp("", data) == 0 ||
00653 strcmp("cp", data) == 0 ||
00654 strcmp("rb", data) == 0 ||
00655 strcmp("mt", data) == 0) {
00656
00657 } else if(strcmp("ping", data) == 0) {
00658 nr_pongs++;
00659 printf("pong %u\n", nr_pongs);
00660 } else if(strcmp("get", data) == 0) {
00661 handle_get_command();
00662 } else {
00663 printf("WARN: Unknown command: '%s'\n", (char*)data);
00664 }
00665 }
00666
00667 PROCESS_END();
00668 }
00669 #endif
00670
00671 #if CHECKPOINT_ROLLBACK_BUTTON
00672 PROCESS_THREAD(checkpoint_button_process, ev, data)
00673 {
00674 PROCESS_BEGIN();
00675
00676 button_sensor.configure(SENSORS_ACTIVE, 1);
00677
00678 while(1) {
00679 PROCESS_WAIT_EVENT();
00680
00681 if(ev == sensors_event && data == &button_sensor) {
00682 int fd = 0;
00683
00684
00685 fd = cfs_open("cp_wdt", CFS_READ);
00686 if(fd >= 0) {
00687 checkpoint_rollback(fd);
00688 cfs_close(fd);
00689 }
00690 }
00691 }
00692
00693 PROCESS_END();
00694 }
00695 #endif