settings.c

00001 
00002 #include <stdbool.h>
00003 //#include <sys/param.h>
00004 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00005 #include <avr/io.h>
00006 #include "settings.h"
00007 #include "dev/eeprom.h"
00008 #include <stdio.h>
00009 #include <avr/pgmspace.h>
00010 #include <avr/eeprom.h>
00011 #include <avr/wdt.h>
00012 #include "contiki.h"
00013 
00014 #ifndef SETTINGS_TOP_ADDR
00015 #define SETTINGS_TOP_ADDR       (E2END-4)       //!< Defaults to end of EEPROM, minus 4 bytes for avrdude erase count
00016 #endif
00017 
00018 #ifndef SETTINGS_MAX_SIZE
00019 #define SETTINGS_MAX_SIZE       (1024)  //!< Defaults to 1KB
00020 #endif
00021 
00022 //#pragma mark -
00023 //#pragma mark Private Functions
00024 
00025 typedef struct {
00026         uint8_t size_extra;
00027         uint8_t size_low;
00028         uint8_t size_check;
00029         settings_key_t key;
00030 } item_header_t;
00031 
00032 inline static bool
00033 settings_is_item_valid_(eeprom_addr_t item_addr) {
00034         item_header_t header = {};
00035 
00036         if(item_addr==EEPROM_NULL)
00037                 return false;
00038 
00039 //      if((SETTINGS_TOP_ADDR-item_addr)>=SETTINGS_MAX_SIZE-3)
00040 //              return false;
00041         
00042         eeprom_read(
00043                 item_addr+1-sizeof(header),
00044                 (unsigned char*)&header,
00045                 sizeof(header)
00046         );
00047         
00048         if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
00049                 return false;
00050 
00051         // TODO: Check length as well
00052 
00053         return true;
00054 }
00055 
00056 inline static settings_key_t
00057 settings_get_key_(eeprom_addr_t item_addr) {
00058         item_header_t header;
00059         
00060         eeprom_read(
00061                 item_addr+1-sizeof(header),
00062                 (unsigned char*)&header,
00063                 sizeof(header)
00064         );
00065         
00066         if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
00067                 return SETTINGS_INVALID_KEY;
00068 
00069         return header.key;
00070 }
00071 
00072 inline static size_t
00073 settings_get_value_length_(eeprom_addr_t item_addr) {
00074         item_header_t header;
00075         size_t ret = 0;
00076         
00077         eeprom_read(
00078                 item_addr+1-sizeof(header),
00079                 (unsigned char*)&header,
00080                 sizeof(header)
00081         );
00082         
00083         if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
00084                 goto bail;
00085         
00086         ret = header.size_low;
00087         
00088         if(ret&(1<<7)) {
00089                 ret = ((ret&~(1<<7))<<8) | header.size_extra;
00090         }
00091 
00092 bail:
00093         return ret;
00094 }
00095 
00096 inline static eeprom_addr_t
00097 settings_get_value_addr_(eeprom_addr_t item_addr) {
00098         size_t len = settings_get_value_length_(item_addr);
00099         
00100         if(len>128)
00101                 return item_addr+1-sizeof(item_header_t)-len;
00102 
00103         return item_addr+1-sizeof(item_header_t)+1-len;
00104 }
00105 
00106 inline static eeprom_addr_t
00107 settings_next_item_(eeprom_addr_t item_addr) {
00108         return settings_get_value_addr_(item_addr)-1;
00109 }
00110 
00111 
00112 //#pragma mark -
00113 //#pragma mark Public Functions
00114 
00115 bool
00116 settings_check(settings_key_t key,uint8_t index) {
00117         bool ret = false;
00118         eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
00119 
00120         for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
00121                 if(settings_get_key_(current_item)==key) {
00122                         if(!index) {
00123                                 ret = true;
00124                                 break;
00125                         } else {
00126                                 // Nope, keep looking
00127                                 index--;
00128                         }
00129                 }
00130         }
00131 
00132         return ret;
00133 }
00134 
00135 settings_status_t
00136 settings_get(settings_key_t key,uint8_t index,unsigned char* value,size_t* value_size) {
00137         settings_status_t ret = SETTINGS_STATUS_NOT_FOUND;
00138         eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
00139         
00140         for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
00141                 if(settings_get_key_(current_item)==key) {
00142                         if(!index) {
00143                                 // We found it!
00144                                 *value_size = MIN(*value_size,settings_get_value_length_(current_item));
00145                                 eeprom_read(
00146                                         settings_get_value_addr_(current_item),
00147                                         value,
00148                                         *value_size
00149                                 );
00150                                 ret = SETTINGS_STATUS_OK;
00151                                 break;
00152                         } else {
00153                                 // Nope, keep looking
00154                                 index--;
00155                         }
00156                 }
00157         }
00158 
00159         return ret;
00160 }
00161 
00162 settings_status_t
00163 settings_add(settings_key_t key,const unsigned char* value,size_t value_size) {
00164         settings_status_t ret = SETTINGS_STATUS_FAILURE;
00165         eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
00166         item_header_t header;
00167         
00168         // Find end of list
00169         for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item));
00170         
00171         if(current_item==EEPROM_NULL)
00172                 goto bail;
00173 
00174         // TODO: size check!
00175 
00176         header.key = key;
00177 
00178         if(value_size<0x80) {
00179                 // If the value size is less than 128, then
00180                 // we can get away with only using one byte
00181                 // as the size.
00182                 header.size_low = value_size;
00183         } else if(value_size<=SETTINGS_MAX_VALUE_SIZE) {
00184                 // If the value size of larger than 128,
00185                 // then we need to use two bytes. Store
00186                 // the most significant 7 bits in the first
00187                 // size byte (with MSB set) and store the
00188                 // least significant bits in the second
00189                 // byte (with LSB clear)
00190                 header.size_low = (value_size>>7) | 0x80;               
00191                 header.size_extra = value_size & ~0x80;
00192         } else {
00193                 // Value size way too big!
00194                 goto bail;
00195         }
00196 
00197         header.size_check = ~header.size_low;
00198 
00199         // Write the header first
00200         eeprom_write(
00201                 current_item+1-sizeof(header),
00202                 (unsigned char*)&header,
00203                 sizeof(header)
00204         );
00205         
00206         // Sanity check, remove once confident
00207         if(settings_get_value_length_(current_item)!=value_size) {
00208                 goto bail;
00209         }
00210         
00211         // Now write the data
00212         eeprom_write(
00213                 settings_get_value_addr_(current_item),
00214                 (unsigned char*)value,
00215                 value_size
00216         );
00217         
00218         ret = SETTINGS_STATUS_OK;
00219         
00220 bail:
00221         return ret;
00222 }
00223 
00224 settings_status_t
00225 settings_set(settings_key_t key,const unsigned char* value,size_t value_size) {
00226         settings_status_t ret = SETTINGS_STATUS_FAILURE;
00227         eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
00228 
00229         for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
00230                 if(settings_get_key_(current_item)==key) {
00231                         break;
00232                 }
00233         }
00234 
00235         if((current_item==EEPROM_NULL) || !settings_is_item_valid_(current_item)) {
00236                 ret = settings_add(key,value,value_size);
00237                 goto bail;
00238         }
00239         
00240         if(value_size!=settings_get_value_length_(current_item)) {
00241                 // Requires the settings store to be shifted. Currently unimplemented.
00242                 goto bail;
00243         }
00244         
00245         // Now write the data
00246         eeprom_write(
00247                 settings_get_value_addr_(current_item),
00248                 (unsigned char*)value,
00249                 value_size
00250         );
00251 
00252         ret = SETTINGS_STATUS_OK;
00253         
00254 bail:
00255         return ret;
00256 }
00257 
00258 settings_status_t
00259 settings_delete(settings_key_t key,uint8_t index) {
00260         // Requires the settings store to be shifted. Currently unimplemented.
00261         // TODO: Writeme!
00262         return SETTINGS_STATUS_UNIMPLEMENTED;
00263 }
00264 
00265 
00266 void
00267 settings_wipe(void) {
00268         size_t i = SETTINGS_TOP_ADDR-SETTINGS_MAX_SIZE;
00269         for(;i<=SETTINGS_TOP_ADDR;i++) {
00270                 eeprom_write_byte((uint8_t*)i,0xFF);
00271                 wdt_reset();
00272         }
00273 }
00274 
00275 

Generated on Mon Apr 11 14:23:37 2011 for Contiki 2.5 by  doxygen 1.6.1