Contiki 3.x
settings.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, Robert Quattlebaum
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 #ifndef CONTIKI_SETTINGS_H_
34 #define CONTIKI_SETTINGS_H_
35 
36 /** @file settings.h
37  * @brief Settings Manager
38  * @author Robert Quattlebaum <darco@deepdarc.com>
39  */
40 
41 /** @addtogroup lib
42  * @{ */
43 
44 /** @defgroup settings_lib Settings Manager
45  *
46  * The settings manager is an EEPROM-based key-value store. Keys
47  * are 16-bit integers and values may be up to 16,383 bytes long.
48  * It is intended to be used to store configuration-related information,
49  * like network settings, radio channels, etc.
50  *
51  * ## Features ##
52  *
53  * * Robust data format which requires no initialization.
54  * * Supports multiple values with the same key.
55  * * Data can be appended without erasing EEPROM.
56  * * Max size of settings data can be easily increased in the future,
57  * as long as it doesn't overlap with application data.
58  *
59  * ## Data Format ##
60  *
61  * The format was inspired by OLPC manufacturing data, as described here:
62  * <http://wiki.laptop.org/go/Manufacturing_data>
63  *
64  * Since the beginning of EEPROM often contains application-specific
65  * information, the best place to store settings is at the end of
66  * EEPROM. Because we are starting at the end of EEPROM, it makes sense
67  * to grow the list of key-value pairs downward, toward the start of
68  * EEPROM.
69  *
70  * Each key-value pair is stored in memory in the following format:
71  *
72  * | Order | Size | Name | Description |
73  * | -------- | -------- | ---------- | ------------------------------- |
74  * | 0 | 2 | key | |
75  * | -2 | 1 | size_check | One's-complement of next byte |
76  * | -3 | 1 or 2 | size | The size of the value, in bytes |
77  * | -4 or -5 | variable | value | |
78  *
79  * The end of the key-value pairs is denoted by the first invalid entry.
80  * An invalid entry has any of the following attributes:
81  *
82  * * The size_check byte doesn't match the one's compliment
83  * of the size byte (or size_low byte).
84  * * The key has a value of 0x0000.
85  *
86  * @{ */
87 
88 #include <stdint.h>
89 #include <string.h>
90 #include "dev/eeprom.h"
91 #include "sys/cc.h"
92 
93 /*****************************************************************************/
94 // MARK: - Types
95 
96 typedef enum {
97  SETTINGS_STATUS_OK = 0,
98  SETTINGS_STATUS_FAILURE,
99  SETTINGS_STATUS_INVALID_ARGUMENT,
100  SETTINGS_STATUS_NOT_FOUND,
101  SETTINGS_STATUS_OUT_OF_SPACE,
102  SETTINGS_STATUS_VALUE_TOO_BIG,
103  SETTINGS_STATUS_UNIMPLEMENTED,
104 } settings_status_t;
105 
106 typedef uint16_t settings_key_t;
107 
108 typedef uint16_t settings_length_t;
109 
110 /*****************************************************************************/
111 // MARK: - Settings Keys
112 
113 /** Two-character constant macro */
114 #define TCC(a,b) ((a)+(b)*256)
115 
116 /* All-capital-letter constants are always contiki-defined. */
117 #define SETTINGS_KEY_EUI64 TCC('E','8') /**< EUI64 Address, 8 bytes */
118 #define SETTINGS_KEY_EUI48 TCC('E','6') /*!< MAC Address, 6 bytes */
119 #define SETTINGS_KEY_CHANNEL TCC('C','H') /*!< Channel number, uint8_t */
120 #define SETTINGS_KEY_TXPOWER TCC('T','P') /*!< Transmit power, uint8_t */
121 #define SETTINGS_KEY_PAN_ID TCC('P','N') /*!< PAN ID, uint16_t */
122 #define SETTINGS_KEY_PAN_ADDR TCC('P','A') /*!< PAN address, uint16_t */
123 #define SETTINGS_KEY_AES128KEY TCC('S','K') /*!< AES128 key, 16 bytes */
124 #define SETTINGS_KEY_AES128ENABLED TCC('S','E') /*!< AES128 enabled, bool */
125 #define SETTINGS_KEY_HOSTNAME TCC('H','N') /*!< Hostname, C-String */
126 #define SETTINGS_KEY_DOMAINNAME TCC('D','N') /*!< Domainname, C-String */
127 
128 /*****************************************************************************/
129 // MARK: - Experimental Settings Keys
130 
131 #define SETTINGS_KEY_RDC_INDEX TCC('R','D') /*!< RDC index, uint8_t */
132 #define SETTINGS_KEY_CHANNEL_MASK TCC('C','M') /*!< Channel mask, uint16_t */
133 
134 /*****************************************************************************/
135 // MARK: - Constants
136 
137 /** Use this when you want to retrieve the last item */
138 #define SETTINGS_LAST_INDEX 0xFF
139 /** Returned when key is invalid. */
140 #define SETTINGS_INVALID_KEY 0xFFFF
141 /** Returned if no (further) element was found. */
142 #define SETTINGS_INVALID_ITER EEPROM_NULL
143 
144 #ifndef SETTINGS_CONF_SUPPORT_LARGE_VALUES
145 #define SETTINGS_CONF_SUPPORT_LARGE_VALUES 0
146 #endif
147 
148 #if SETTINGS_CONF_SUPPORT_LARGE_VALUES
149 #define SETTINGS_MAX_VALUE_SIZE 0x3FFF /* 16383 bytes */
150 #else
151 #define SETTINGS_MAX_VALUE_SIZE 0x7F /* 127 bytes */
152 #endif
153 
154 /*****************************************************************************/
155 // MARK: - Settings accessors
156 
157 /** Fetches the value associated with the given key. */
158 extern settings_status_t settings_get(settings_key_t key, uint8_t index,
159  uint8_t *value,
160  settings_length_t * value_size);
161 
162 /** Adds the given key-value pair to the end of the settings store. */
163 extern settings_status_t settings_add(settings_key_t key,
164  const uint8_t *value,
165  settings_length_t value_size);
166 
167 /** Checks to see if the given key exists. */
168 extern uint8_t settings_check(settings_key_t key, uint8_t index);
169 
170 /** Reinitializes all of the EEPROM used by settings. */
171 extern void settings_wipe(void);
172 
173 /** Sets the value for the given key. If the key already exists in
174  * the settings store, then its value will be replaced.
175  */
176 extern settings_status_t settings_set(settings_key_t key,
177  const uint8_t *value,
178  settings_length_t value_size);
179 
180 /** Removes the given key (at the given index) from the settings store. */
181 extern settings_status_t settings_delete(settings_key_t key, uint8_t index);
182 
183 /*****************************************************************************/
184 // MARK: - Settings traversal functions
185 
186 typedef eeprom_addr_t settings_iter_t;
187 
188 /** Will return \ref SETTINGS_INVALID_ITER if the settings store is empty. */
189 extern settings_iter_t settings_iter_begin();
190 
191 /** Will return \ref SETTINGS_INVALID_ITER if at the end of settings list. */
192 extern settings_iter_t settings_iter_next(settings_iter_t iter);
193 
194 extern uint8_t settings_iter_is_valid(settings_iter_t iter);
195 
196 extern settings_key_t settings_iter_get_key(settings_iter_t iter);
197 
198 extern settings_length_t settings_iter_get_value_length(settings_iter_t iter);
199 
200 extern eeprom_addr_t settings_iter_get_value_addr(settings_iter_t iter);
201 
202 extern settings_length_t settings_iter_get_value_bytes(settings_iter_t item,
203  void *bytes,
204  settings_length_t
205  max_length);
206 
207 extern settings_status_t settings_iter_delete(settings_iter_t item);
208 
209 /*****************************************************************************/
210 // MARK: - inline convenience functions
211 
212 /* Unfortunately, some platforms don't properly drop unreferenced functions,
213  * so on these broken platforms we can save a significant amount
214  * of space by skipping the definition of the convenience functions.
215  */
216 #if !SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS
217 
218 static CC_INLINE const char *
219 settings_get_cstr(settings_key_t key, uint8_t index, char *c_str,
220  settings_length_t c_str_size)
221 {
222  /* Save room for the zero termination. */
223  c_str_size--;
224 
225  if(settings_get(key, index, (uint8_t *)c_str, &c_str_size) == SETTINGS_STATUS_OK) {
226  /* Zero terminate. */
227  c_str[c_str_size] = 0;
228  } else {
229  c_str = NULL;
230  }
231  return c_str;
232 }
233 
234 static CC_INLINE settings_status_t
235 settings_set_cstr(settings_key_t key, const char* c_str)
236 {
237  return settings_set(key, (const uint8_t *)c_str, strlen(c_str));
238 }
239 
240 static CC_INLINE settings_status_t
241 settings_add_cstr(settings_key_t key, const char* c_str)
242 {
243  return settings_add(key, (const uint8_t *)c_str, strlen(c_str));
244 }
245 
246 static CC_INLINE uint8_t
247 settings_get_bool_with_default(settings_key_t key, uint8_t index,
248  uint8_t default_value)
249 {
250  uint8_t ret = default_value;
251  settings_length_t sizeof_uint8 = sizeof(uint8_t);
252 
253  settings_get(key, index, (uint8_t *)&ret, &sizeof_uint8);
254  return !!ret;
255 }
256 
257 static CC_INLINE uint8_t
258 settings_get_uint8(settings_key_t key, uint8_t index)
259 {
260  uint8_t ret = 0;
261  settings_length_t sizeof_uint8 = sizeof(uint8_t);
262 
263  settings_get(key, index, (uint8_t *)&ret, &sizeof_uint8);
264  return ret;
265 }
266 
267 static CC_INLINE settings_status_t
268 settings_add_uint8(settings_key_t key, uint8_t value)
269 {
270  return settings_add(key, (const uint8_t *)&value, sizeof(uint8_t));
271 }
272 
273 static CC_INLINE settings_status_t
274 settings_set_uint8(settings_key_t key, uint8_t value)
275 {
276  return settings_set(key, (const uint8_t *)&value, sizeof(uint8_t));
277 }
278 
279 static CC_INLINE uint16_t
280 settings_get_uint16(settings_key_t key, uint8_t index)
281 {
282  uint16_t ret = 0;
283  settings_length_t sizeof_uint16 = sizeof(uint16_t);
284 
285  settings_get(key, index, (uint8_t *)&ret, &sizeof_uint16);
286  return ret;
287 }
288 
289 static CC_INLINE settings_status_t
290 settings_add_uint16(settings_key_t key, uint16_t value)
291 {
292  return settings_add(key, (const uint8_t *)&value, sizeof(uint16_t));
293 }
294 
295 static CC_INLINE settings_status_t
296 settings_set_uint16(settings_key_t key, uint16_t value)
297 {
298  return settings_set(key, (const uint8_t *)&value, sizeof(uint16_t));
299 }
300 
301 static CC_INLINE uint32_t
302 settings_get_uint32(settings_key_t key, uint8_t index)
303 {
304  uint32_t ret = 0;
305  settings_length_t sizeof_uint32 = sizeof(uint32_t);
306 
307  settings_get(key, index, (uint8_t *)&ret, &sizeof_uint32);
308  return ret;
309 }
310 
311 static CC_INLINE settings_status_t
312 settings_add_uint32(settings_key_t key, uint32_t value)
313 {
314  return settings_add(key, (const uint8_t *)&value, sizeof(uint32_t));
315 }
316 
317 static CC_INLINE settings_status_t
318 settings_set_uint32(settings_key_t key, uint32_t value)
319 {
320  return settings_set(key, (const uint8_t *)&value, sizeof(uint32_t));
321 }
322 
323 #if __int64_t_defined
324 static CC_INLINE uint64_t
325 settings_get_uint64(settings_key_t key, uint8_t index)
326 {
327  uint64_t ret = 0;
328  settings_length_t sizeof_uint64 = sizeof(uint64_t);
329 
330  settings_get(key, index, (uint8_t *)&ret, &sizeof_uint64);
331  return ret;
332 }
333 
334 static CC_INLINE settings_status_t
335 settings_add_uint64(settings_key_t key, uint64_t value)
336 {
337  return settings_add(key, (const uint8_t *)&value, sizeof(uint64_t));
338 }
339 
340 static CC_INLINE settings_status_t
341 settings_set_uint64(settings_key_t key, uint64_t value)
342 {
343  return settings_set(key, (const uint8_t *)&value, sizeof(uint64_t));
344 }
345 #endif /* __int64_t_defined */
346 
347 #endif /* !SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS */
348 
349 #endif /* !defined(CONTIKI_SETTINGS_H_) */
350 
351 /** @} */
352 /** @} */
settings_status_t settings_get(settings_key_t key, uint8_t index, uint8_t *value, settings_length_t *value_size)
Fetches the value associated with the given key.
settings_status_t settings_delete(settings_key_t key, uint8_t index)
Removes the given key (at the given index) from the settings store.
settings_status_t settings_set(settings_key_t key, const uint8_t *value, settings_length_t value_size)
Sets the value for the given key.
uint8_t settings_check(settings_key_t key, uint8_t index)
Checks to see if the given key exists.
#define NULL
The null pointer.
Default definitions of C compiler quirk work-arounds.
settings_iter_t settings_iter_next(settings_iter_t iter)
Will return SETTINGS_INVALID_ITER if at the end of settings list.
EEPROM functions.
void settings_wipe(void)
Reinitializes all of the EEPROM used by settings.
settings_status_t settings_add(settings_key_t key, const uint8_t *value, settings_length_t value_size)
Adds the given key-value pair to the end of the settings store.
settings_iter_t settings_iter_begin()
Will return SETTINGS_INVALID_ITER if the settings store is empty.