settings.c
00001
00002 #include <stdbool.h>
00003
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)
00016 #endif
00017
00018 #ifndef SETTINGS_MAX_SIZE
00019 #define SETTINGS_MAX_SIZE (1024)
00020 #endif
00021
00022
00023
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
00040
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
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
00113
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
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
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
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
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
00175
00176 header.key = key;
00177
00178 if(value_size<0x80) {
00179
00180
00181
00182 header.size_low = value_size;
00183 } else if(value_size<=SETTINGS_MAX_VALUE_SIZE) {
00184
00185
00186
00187
00188
00189
00190 header.size_low = (value_size>>7) | 0x80;
00191 header.size_extra = value_size & ~0x80;
00192 } else {
00193
00194 goto bail;
00195 }
00196
00197 header.size_check = ~header.size_low;
00198
00199
00200 eeprom_write(
00201 current_item+1-sizeof(header),
00202 (unsigned char*)&header,
00203 sizeof(header)
00204 );
00205
00206
00207 if(settings_get_value_length_(current_item)!=value_size) {
00208 goto bail;
00209 }
00210
00211
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
00242 goto bail;
00243 }
00244
00245
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
00261
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