Contiki 2.6
|
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