Contiki 2.5
settings.c
1 
2 #include <stdbool.h>
3 //#include <sys/param.h>
4 #define MIN(a,b) ((a) < (b) ? (a) : (b))
5 #include <avr/io.h>
6 #include "settings.h"
7 #include "dev/eeprom.h"
8 #include <stdio.h>
9 #include <avr/pgmspace.h>
10 #include <avr/eeprom.h>
11 #include <avr/wdt.h>
12 #include "contiki.h"
13 
14 #ifndef SETTINGS_TOP_ADDR
15 #define SETTINGS_TOP_ADDR (E2END-4) //!< Defaults to end of EEPROM, minus 4 bytes for avrdude erase count
16 #endif
17 
18 #ifndef SETTINGS_MAX_SIZE
19 #define SETTINGS_MAX_SIZE (1024) //!< Defaults to 1KB
20 #endif
21 
22 //#pragma mark -
23 //#pragma mark Private Functions
24 
25 typedef struct {
26  uint8_t size_extra;
27  uint8_t size_low;
28  uint8_t size_check;
29  settings_key_t key;
30 } item_header_t;
31 
32 inline static bool
33 settings_is_item_valid_(eeprom_addr_t item_addr) {
34  item_header_t header = {};
35 
36  if(item_addr==EEPROM_NULL)
37  return false;
38 
39 // if((SETTINGS_TOP_ADDR-item_addr)>=SETTINGS_MAX_SIZE-3)
40 // return false;
41 
43  item_addr+1-sizeof(header),
44  (unsigned char*)&header,
45  sizeof(header)
46  );
47 
48  if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
49  return false;
50 
51  // TODO: Check length as well
52 
53  return true;
54 }
55 
56 inline static settings_key_t
57 settings_get_key_(eeprom_addr_t item_addr) {
58  item_header_t header;
59 
61  item_addr+1-sizeof(header),
62  (unsigned char*)&header,
63  sizeof(header)
64  );
65 
66  if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
67  return SETTINGS_INVALID_KEY;
68 
69  return header.key;
70 }
71 
72 inline static size_t
73 settings_get_value_length_(eeprom_addr_t item_addr) {
74  item_header_t header;
75  size_t ret = 0;
76 
78  item_addr+1-sizeof(header),
79  (unsigned char*)&header,
80  sizeof(header)
81  );
82 
83  if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
84  goto bail;
85 
86  ret = header.size_low;
87 
88  if(ret&(1<<7)) {
89  ret = ((ret&~(1<<7))<<8) | header.size_extra;
90  }
91 
92 bail:
93  return ret;
94 }
95 
96 inline static eeprom_addr_t
97 settings_get_value_addr_(eeprom_addr_t item_addr) {
98  size_t len = settings_get_value_length_(item_addr);
99 
100  if(len>128)
101  return item_addr+1-sizeof(item_header_t)-len;
102 
103  return item_addr+1-sizeof(item_header_t)+1-len;
104 }
105 
106 inline static eeprom_addr_t
107 settings_next_item_(eeprom_addr_t item_addr) {
108  return settings_get_value_addr_(item_addr)-1;
109 }
110 
111 
112 //#pragma mark -
113 //#pragma mark Public Functions
114 
115 bool
116 settings_check(settings_key_t key,uint8_t index) {
117  bool ret = false;
118  eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
119 
120  for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
121  if(settings_get_key_(current_item)==key) {
122  if(!index) {
123  ret = true;
124  break;
125  } else {
126  // Nope, keep looking
127  index--;
128  }
129  }
130  }
131 
132  return ret;
133 }
134 
135 settings_status_t
136 settings_get(settings_key_t key,uint8_t index,unsigned char* value,size_t* value_size) {
137  settings_status_t ret = SETTINGS_STATUS_NOT_FOUND;
138  eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
139 
140  for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
141  if(settings_get_key_(current_item)==key) {
142  if(!index) {
143  // We found it!
144  *value_size = MIN(*value_size,settings_get_value_length_(current_item));
145  eeprom_read(
146  settings_get_value_addr_(current_item),
147  value,
148  *value_size
149  );
150  ret = SETTINGS_STATUS_OK;
151  break;
152  } else {
153  // Nope, keep looking
154  index--;
155  }
156  }
157  }
158 
159  return ret;
160 }
161 
162 settings_status_t
163 settings_add(settings_key_t key,const unsigned char* value,size_t value_size) {
164  settings_status_t ret = SETTINGS_STATUS_FAILURE;
165  eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
166  item_header_t header;
167 
168  // Find end of list
169  for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item));
170 
171  if(current_item==EEPROM_NULL)
172  goto bail;
173 
174  // TODO: size check!
175 
176  header.key = key;
177 
178  if(value_size<0x80) {
179  // If the value size is less than 128, then
180  // we can get away with only using one byte
181  // as the size.
182  header.size_low = value_size;
183  } else if(value_size<=SETTINGS_MAX_VALUE_SIZE) {
184  // If the value size of larger than 128,
185  // then we need to use two bytes. Store
186  // the most significant 7 bits in the first
187  // size byte (with MSB set) and store the
188  // least significant bits in the second
189  // byte (with LSB clear)
190  header.size_low = (value_size>>7) | 0x80;
191  header.size_extra = value_size & ~0x80;
192  } else {
193  // Value size way too big!
194  goto bail;
195  }
196 
197  header.size_check = ~header.size_low;
198 
199  // Write the header first
200  eeprom_write(
201  current_item+1-sizeof(header),
202  (unsigned char*)&header,
203  sizeof(header)
204  );
205 
206  // Sanity check, remove once confident
207  if(settings_get_value_length_(current_item)!=value_size) {
208  goto bail;
209  }
210 
211  // Now write the data
212  eeprom_write(
213  settings_get_value_addr_(current_item),
214  (unsigned char*)value,
215  value_size
216  );
217 
218  ret = SETTINGS_STATUS_OK;
219 
220 bail:
221  return ret;
222 }
223 
224 settings_status_t
225 settings_set(settings_key_t key,const unsigned char* value,size_t value_size) {
226  settings_status_t ret = SETTINGS_STATUS_FAILURE;
227  eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
228 
229  for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
230  if(settings_get_key_(current_item)==key) {
231  break;
232  }
233  }
234 
235  if((current_item==EEPROM_NULL) || !settings_is_item_valid_(current_item)) {
236  ret = settings_add(key,value,value_size);
237  goto bail;
238  }
239 
240  if(value_size!=settings_get_value_length_(current_item)) {
241  // Requires the settings store to be shifted. Currently unimplemented.
242  goto bail;
243  }
244 
245  // Now write the data
246  eeprom_write(
247  settings_get_value_addr_(current_item),
248  (unsigned char*)value,
249  value_size
250  );
251 
252  ret = SETTINGS_STATUS_OK;
253 
254 bail:
255  return ret;
256 }
257 
258 settings_status_t
259 settings_delete(settings_key_t key,uint8_t index) {
260  // Requires the settings store to be shifted. Currently unimplemented.
261  // TODO: Writeme!
262  return SETTINGS_STATUS_UNIMPLEMENTED;
263 }
264 
265 
266 void
267 settings_wipe(void) {
268  size_t i = SETTINGS_TOP_ADDR-SETTINGS_MAX_SIZE;
269  for(;i<=SETTINGS_TOP_ADDR;i++) {
270  eeprom_write_byte((uint8_t*)i,0xFF);
271  wdt_reset();
272  }
273 }
274 
275