Contiki 2.6

checkpoint-arch.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009, 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  */
00032 
00033 /**
00034  * \file
00035  *  Checkpoint library implementation for the Tmote Sky platform.
00036  * \author
00037  *  Fredrik Osterlind <fros@sics.se>
00038  */
00039 
00040 #include "contiki.h"
00041 #include "lib/checkpoint.h"
00042 
00043 #include "sys/rtimer.h"
00044 #include "sys/mt.h"
00045 #include "cfs/cfs.h"
00046 #include "cfs/cfs-coffee.h"
00047 #include "dev/leds.h"
00048 #include "dev/watchdog.h"
00049 #include <stdio.h>
00050 
00051 #define DEBUG 1
00052 #if DEBUG
00053 #define PRINTF(...) printf(__VA_ARGS__)
00054 #else
00055 #define PRINTF(...)
00056 #endif
00057 
00058 #define COMMAND_ROLLBACK 1
00059 #define COMMAND_CHECKPOINT 2
00060 #define COMMAND_TBR 3
00061 
00062 #define DATA_AS_HEX 0 /* If false, store binary data */
00063 
00064 #define INCLUDE_RAM 1 /* Less then 10240 bytes */
00065 #define INCLUDE_TIMERS 1 /* 16 bytes */
00066 #define INCLUDE_LEDS 1 /* 1 bytes */
00067 
00068 // 8kB memory 
00069 #define RAM_START 0x1100
00070 #define RAM_END 0x30FF
00071 
00072 #define STOP_TIMERS() TACTL &= ~(MC1); TBCTL &= ~(MC1); watchdog_stop();
00073 #define START_TIMERS() watchdog_start(); TACTL |= MC1; TBCTL |= MC1;
00074 
00075 static struct mt_thread checkpoint_thread;
00076 static uint8_t preset_cmd;
00077 static int preset_fd;
00078 
00079 typedef union {
00080   unsigned char u8[2];
00081   unsigned short u16;
00082 } word_union_t;
00083 
00084 /*---------------------------------------------------------------------------*/
00085 static void
00086 write_byte(int fd, uint8_t c)
00087 {
00088 #if DATA_AS_HEX
00089   uint8_t hex[2];
00090   sprintf(hex, "%02x", c);
00091   if(cfs_write(fd, hex, 2) != 2) {
00092     printf("err #1\n");
00093   }
00094 #else /* DATA_AS_HEX */
00095   if(cfs_write(fd, &c, 1) != 1) {
00096     printf("err #2\n");
00097   }
00098 #endif /* DATA_AS_HEX */
00099 }/*---------------------------------------------------------------------------*/
00100 #if 0
00101 static void
00102 write_array(int fd, unsigned char *mem, uint16_t len)
00103 {
00104 #if DATA_AS_HEX
00105   int i;
00106   for(i = 0; i < len; i++) {
00107     write_byte(fd, mem[i]);
00108   }
00109 #else /* DATA_AS_HEX */
00110   cfs_write(fd, mem, len);
00111 #endif /* DATA_AS_HEX */
00112 }
00113 #endif /* 0 */
00114 /*---------------------------------------------------------------------------*/
00115 static void
00116 write_word(int fd, uint16_t w)
00117 {
00118   word_union_t tmp;
00119   tmp.u16 = w;
00120   write_byte(fd, tmp.u8[0]);
00121   write_byte(fd, tmp.u8[1]);
00122 }
00123 /*---------------------------------------------------------------------------*/
00124 static uint8_t
00125 read_byte(int fd)
00126 {
00127 #if DATA_AS_HEX
00128   uint8_t hex[2];
00129 
00130   cfs_read(fd, hex, 2);
00131 
00132   if(hex[0] >= 'A' && hex[0] <= 'F') {
00133     hex[0] = (hex[0] - 'A' + 0xa);
00134   } else if(hex[0] >= 'a' && hex[0] <= 'f') {
00135     hex[0] = (hex[0] - 'a' + 0xa);
00136   } else {
00137     hex[0] = (hex[0] - '0');
00138   }
00139   if(hex[1] >= 'A' && hex[1] <= 'F') {
00140     hex[1] = (hex[1] - 'A' + 0xa);
00141   } else if(hex[1] >= 'a' && hex[1] <= 'f') {
00142     hex[1] = (hex[1] - 'a' + 0xa);
00143   } else {
00144     hex[1] = (hex[1] - '0');
00145   }
00146   return (uint8_t)((hex[0]<<4)&0xf0) | (hex[1]&0x0f);
00147 #else /* DATA_AS_HEX */
00148   uint8_t c;
00149   cfs_read(fd, &c, 1);
00150   return c;
00151 #endif /* DATA_AS_HEX */
00152 }
00153 /*---------------------------------------------------------------------------*/
00154 static uint16_t
00155 read_word(int fd)
00156 {
00157   word_union_t tmp;
00158   tmp.u8[0] = read_byte(fd);
00159   tmp.u8[1] = read_byte(fd);
00160   return tmp.u16;
00161 }
00162 /*---------------------------------------------------------------------------*/
00163 static void
00164 thread_checkpoint(int fd)
00165 {
00166 #if INCLUDE_RAM
00167   unsigned char *addr;
00168   uint16_t size = 0;
00169   unsigned char *thread_mem_start = (unsigned char *)&checkpoint_thread.thread.stack;
00170   unsigned char *thread_mem_end = thread_mem_start + sizeof(checkpoint_thread.thread.stack) - 1;
00171   unsigned char *coffee_mem_start = cfs_coffee_get_protected_mem(&size);
00172   unsigned char *coffee_mem_end = coffee_mem_start + size - 1;
00173 #endif /* INCLUDE_RAM */
00174 
00175   /*printf("protected thread memory: %u, size=%u\n", (uint16_t) thread_mem_start, sizeof(checkpoint_thread.thread.stack));*/
00176   /*printf("protected coffee memory: %u, size=%u\n", (uint16_t) coffee_mem_start, size);*/
00177 
00178   /* RAM */
00179 #if INCLUDE_RAM
00180   for(addr = (unsigned char *)RAM_START;
00181       addr < (unsigned char *)RAM_END;
00182       addr++) {
00183 
00184     if((addr >= thread_mem_start && addr <= thread_mem_end)) {
00185       /* Writing dummy memory */
00186       /*write_byte(fd, 1);*/
00187       continue;
00188     }
00189 
00190     if((addr >= coffee_mem_start && addr <= coffee_mem_end)) {
00191       /* Writing dummy memory */
00192       /*write_byte(fd, 2);*/
00193       continue;
00194     }
00195 
00196     /* TODO Use write_array() */
00197     write_byte(fd, *addr);
00198 
00199     if(((int)addr % 512) == 0) {
00200       PRINTF(".");
00201     }
00202   }
00203 
00204 #endif /* INCLUDE_RAM */
00205 
00206   /* Timers */
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 /* INCLUDE_TIMERS */
00218 
00219   /* LEDs */
00220 #if INCLUDE_LEDS
00221   write_byte(fd, leds_arch_get());
00222 #endif /* INCLUDE_LEDS */
00223 
00224   /* Radio */
00225   /* ADC */
00226   /* ... */
00227 
00228   write_byte(fd, -1); /* Coffee padding byte */
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 /* INCLUDE_RAM */
00242 
00243   /*printf("protected thread memory: %u, size=%u\n", (uint16_t) thread_mem_start, sizeof(checkpoint_thread.thread.stack));*/
00244   /*printf("protected coffee memory: %u, size=%u\n", (uint16_t) coffee_mem_start, size);*/
00245 
00246   /* RAM */
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       /* Ignoring incoming memory */
00253       /*read_byte(fd);*/
00254       continue;
00255     }
00256 
00257     if((addr >= coffee_mem_start && addr <= coffee_mem_end)) {
00258       /* Ignoring incoming memory */
00259       /*read_byte(fd);*/
00260       continue;
00261     }
00262 
00263     *addr = read_byte(fd);
00264 
00265     if(((int)addr % 512) == 0) {
00266       PRINTF(".");
00267     }
00268   }
00269 
00270 #endif /* INCLUDE_RAM */
00271 
00272   /* Timers */
00273 #if INCLUDE_TIMERS
00274   TACTL = read_word(fd);
00275   TACCTL1 = read_word(fd);
00276   TACCR1 = read_word(fd);
00277   TAR = read_word(fd);
00278 
00279   TBCTL = read_word(fd);
00280   TBCCTL1 = read_word(fd);
00281   TBCCR1 = read_word(fd);
00282   TBR = read_word(fd);
00283 #endif /* INCLUDE_TIMERS */
00284 
00285   /* LEDs */
00286 #if INCLUDE_LEDS
00287   leds_arch_set(read_byte(fd));
00288 #endif /* INCLUDE_LEDS */
00289 
00290   /* Radio */
00291   /* ADC */
00292   /* ... */
00293 
00294   read_byte(fd); /* Coffee padding byte */
00295 }
00296 /*---------------------------------------------------------------------------*/
00297 static void
00298 thread_loop(void *data)
00299 {
00300   uint8_t cmd;
00301   int fd;
00302 
00303   while(1) {
00304     /* Store command and file descriptor on stack */
00305     cmd = preset_cmd;
00306     fd = preset_fd;
00307 
00308     /* Handle command */
00309     if(cmd == COMMAND_ROLLBACK) {
00310       PRINTF("Rolling back");
00311       thread_rollback(fd);
00312       PRINTF(" done!\n");
00313     } else if(cmd == COMMAND_CHECKPOINT) {
00314       PRINTF("Checkpointing");
00315       thread_checkpoint(fd);
00316       PRINTF(" done!\n");
00317     } else if(cmd == COMMAND_TBR) {
00318       PRINTF("Writing TBR");
00319       write_word(fd, TBR);
00320       PRINTF(" done!\n");
00321     } else {
00322       printf("Error: unknown command: %u\n", cmd);
00323     }
00324 
00325     /* Return to main Contiki thread */
00326     mt_yield();
00327   }
00328 }
00329 /*---------------------------------------------------------------------------*/
00330 int
00331 checkpoint_arch_size()
00332 {
00333   return 10258;
00334 }
00335 /*---------------------------------------------------------------------------*/
00336 void
00337 checkpoint_arch_checkpoint(int fd)
00338 {
00339   STOP_TIMERS();
00340 
00341   preset_cmd = COMMAND_CHECKPOINT;
00342   preset_fd = fd;
00343   mt_exec(&checkpoint_thread);
00344 
00345   START_TIMERS();
00346 }
00347 /*---------------------------------------------------------------------------*/
00348 void
00349 checkpoint_arch_rollback(int fd)
00350 {
00351   STOP_TIMERS();
00352 
00353   preset_cmd = COMMAND_ROLLBACK;
00354   preset_fd = fd;
00355   mt_exec(&checkpoint_thread);
00356 
00357   START_TIMERS();
00358 }
00359 /*---------------------------------------------------------------------------*/
00360 void
00361 checkpoint_arch_init(void)
00362 {
00363   mt_init();
00364   mt_start(&checkpoint_thread, thread_loop, NULL);
00365 
00366   /*mt_stop(&checkpoint_thread);*/
00367   /*mt_remove();*/
00368 }
00369 /*---------------------------------------------------------------------------*/