Contiki-Inga 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  * ## Overview ##
41  *
42  * The settings manager is a EEPROM-based key-value store. Keys
43  * are 16-bit integers and values may be up to 16,383 bytes long.
44  * It is intended to be used to store configuration-related information,
45  * like network settings, radio channels, etc.
46  *
47  * ## Features ##
48  *
49  * * Robust data format which requires no initialization.
50  * * Supports multiple values with the same key.
51  * * Data can be appended without erasing EEPROM.
52  * * Max size of settings data can be easily increased in the future,
53  * as long as it doesn't overlap with application data.
54  *
55  * ## Data Format ##
56  *
57  * The format was inspired by OLPC manufacturing data, as described here:
58  * <http://wiki.laptop.org/go/Manufacturing_data>
59  *
60  * Since the beginning of EEPROM often contains application-specific
61  * information, the best place to store settings is at the end of
62  * EEPROM. Because we are starting at the end of EEPROM, it makes sense
63  * to grow the list of key-value pairs downward, toward the start of
64  * EEPROM.
65  *
66  * Each key-value pair is stored in memory in the following format:
67  *
68  * | Order | Size | Name | Description |
69  * | ----- | ---- | ---- | ------------------------------- |
70  * | 0 | 2 | key | |
71  * | -2 | 1 | size_check | One's-complement of next byte |
72  * | -3 | 1 or 2 | size | The size of the value, in bytes |
73  * | -4 or 5 | variable | value | |
74  *
75  *
76  * The end of the key-value pairs is denoted by the first invalid entry.
77  * An invalid entry has any of the following attributes:
78  *
79  * * The size_check byte doesn't match the one's compliment
80  * of the size byte (or size_low byte).
81  * * The key has a value of 0x0000.
82  *
83  */
84 
85 #include <stdint.h>
86 #include <string.h>
87 #include "dev/eeprom.h"
88 #include "sys/cc.h"
89 
90 /*****************************************************************************/
91 // MARK: - Types
92 
93 typedef enum {
94  SETTINGS_STATUS_OK = 0,
95  SETTINGS_STATUS_FAILURE,
96  SETTINGS_STATUS_INVALID_ARGUMENT,
97  SETTINGS_STATUS_NOT_FOUND,
98  SETTINGS_STATUS_OUT_OF_SPACE,
99  SETTINGS_STATUS_VALUE_TOO_BIG,
100  SETTINGS_STATUS_UNIMPLEMENTED,
101 } settings_status_t;
102 
103 typedef uint16_t settings_key_t;
104 
105 typedef uint16_t settings_length_t;
106 
107 /*****************************************************************************/
108 // MARK: - Settings Keys
109 
110 /** Two-character constant macro */
111 #define TCC(a,b) ((a)+(b)*256)
112 
113 /* All-capital-letter constants are always contiki-defined. */
114 #define SETTINGS_KEY_EUI64 TCC('E','8') /**< EUI64 Address, 8 bytes */
115 #define SETTINGS_KEY_EUI48 TCC('E','6') /*!< MAC Address, 6 bytes */
116 #define SETTINGS_KEY_CHANNEL TCC('C','H') /*!< Channel number, uint8_t */
117 #define SETTINGS_KEY_TXPOWER TCC('T','P') /*!< Transmit power, uint8_t */
118 #define SETTINGS_KEY_PAN_ID TCC('P','N') /*!< PAN ID, uint16_t */
119 #define SETTINGS_KEY_PAN_ADDR TCC('P','A') /*!< PAN address, uint16_t */
120 #define SETTINGS_KEY_AES128KEY TCC('S','K') /*!< AES128 key, 16 bytes */
121 #define SETTINGS_KEY_AES128ENABLED TCC('S','E') /*!< AES128 enabled, bool */
122 #define SETTINGS_KEY_HOSTNAME TCC('H','N') /*!< Hostname, C-String */
123 #define SETTINGS_KEY_DOMAINNAME TCC('D','N') /*!< Domainname, C-String */
124 
125 /*****************************************************************************/
126 // MARK: - Experimental Settings Keys
127 
128 #define SETTINGS_KEY_RDC_INDEX TCC('R','D') /*!< RDC index, uint8_t */
129 #define SETTINGS_KEY_CHANNEL_MASK TCC('C','M') /*!< Channel mask, uint16_t */
130 
131 /*****************************************************************************/
132 // MARK: - Constants
133 
134 /** Use this when you want to retrieve the last item */
135 #define SETTINGS_LAST_INDEX 0xFF
136 
137 #define SETTINGS_INVALID_KEY 0xFFFF
138 
139 #define SETTINGS_INVALID_ITER EEPROM_NULL
140 
141 #ifndef SETTINGS_CONF_SUPPORT_LARGE_VALUES
142 #define SETTINGS_CONF_SUPPORT_LARGE_VALUES 0
143 #endif
144 
145 #if SETTINGS_CONF_SUPPORT_LARGE_VALUES
146 #define SETTINGS_MAX_VALUE_SIZE 0x3FFF /* 16383 bytes */
147 #else
148 #define SETTINGS_MAX_VALUE_SIZE 0x7F /* 127 bytes */
149 #endif
150 
151 /*****************************************************************************/
152 // MARK: - Settings accessors
153 
154 /** Fetches the value associated with the given key. */
155 extern settings_status_t settings_get(settings_key_t key, uint8_t index,
156  uint8_t *value,
157  settings_length_t value_size);
158 
159 /** Adds the given key-value pair to the end of the settings store. */
160 extern settings_status_t settings_add(settings_key_t key,
161  const uint8_t *value,
162  settings_length_t value_size);
163 
164 /** Checks to see if the given key exists.
165  *
166  * @retval 0 not found
167  * @retval 1 found
168  */
169 extern uint8_t settings_check(settings_key_t key, uint8_t index);
170 
171 /** Reinitializes all of the EEPROM used by settings. */
172 extern void settings_wipe(void);
173 
174 /** Sets the value for the given key. If the key already exists in
175  * the settings store, then its value will be replaced.
176  */
177 extern settings_status_t settings_set(settings_key_t key,
178  const uint8_t *value,
179  settings_length_t value_size);
180 
181 /** Removes the given key (at the given index) from the settings store. */
182 extern settings_status_t settings_delete(settings_key_t key, uint8_t index);
183 
184 /*****************************************************************************/
185 // MARK: - Settings traversal functions
186 
187 typedef eeprom_addr_t settings_iter_t;
188 
189 /** Will return extern SETTINGS_INVALID_ITER if the settings store is empty. */
190 extern settings_iter_t settings_iter_begin();
191 
192 /** Will return extern SETTINGS_INVALID_ITER if at the end of settings list. */
193 extern settings_iter_t settings_iter_next(settings_iter_t iter);
194 
195 extern uint8_t settings_iter_is_valid(settings_iter_t iter);
196 
197 extern settings_key_t settings_iter_get_key(settings_iter_t iter);
198 
199 extern settings_length_t settings_iter_get_value_length(settings_iter_t iter);
200 
201 extern eeprom_addr_t settings_iter_get_value_addr(settings_iter_t iter);
202 
203 extern settings_length_t settings_iter_get_value_bytes(settings_iter_t item,
204  void *bytes,
205  settings_length_t
206  max_length);
207 
208 extern settings_status_t settings_iter_delete(settings_iter_t item);
209 
210 /*****************************************************************************/
211 // MARK: - inline convenience functions
212 
213 /* Unfortunately, some platforms don't properly drop unreferenced functions,
214  * so on these broken platforms we can save a significant amount
215  * of space by skipping the definition of the convenience functions.
216  */
217 #if !SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS
218 
219 static CC_INLINE const char *
220 settings_get_cstr(settings_key_t key, uint8_t index, char *c_str,
221  settings_length_t c_str_size)
222 {
223  /* Save room for the zero termination. */
224  c_str_size--;
225 
226  if(settings_get(key, index, (uint8_t *)c_str, c_str_size) == SETTINGS_STATUS_OK) {
227  /* Zero terminate. */
228  c_str[c_str_size] = 0;
229  } else {
230  c_str = NULL;
231  }
232  return c_str;
233 }
234 
235 static CC_INLINE settings_status_t
236 settings_set_cstr(settings_key_t key, const char* c_str)
237 {
238  return settings_set(key, (const uint8_t *)c_str, strlen(c_str));
239 }
240 
241 static CC_INLINE settings_status_t
242 settings_add_cstr(settings_key_t key, const char* c_str)
243 {
244  return settings_add(key, (const uint8_t *)c_str, strlen(c_str));
245 }
246 
247 static CC_INLINE uint8_t
248 settings_get_bool_with_default(settings_key_t key, uint8_t index,
249  uint8_t default_value)
250 {
251  uint8_t ret = default_value;
252 
253  settings_get(key, index, (uint8_t *)&ret, sizeof(uint8_t));
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 
262  settings_get(key, index, (uint8_t *)&ret, sizeof(uint8_t));
263  return ret;
264 }
265 
266 static CC_INLINE settings_status_t
267 settings_add_uint8(settings_key_t key, uint8_t value)
268 {
269  return settings_add(key, (const uint8_t *)&value, sizeof(uint8_t));
270 }
271 
272 static CC_INLINE settings_status_t
273 settings_set_uint8(settings_key_t key, uint8_t value)
274 {
275  return settings_set(key, (const uint8_t *)&value, sizeof(uint8_t));
276 }
277 
278 static CC_INLINE uint16_t
279 settings_get_uint16(settings_key_t key, uint8_t index)
280 {
281  uint16_t ret = 0;
282 
283  settings_get(key, index, (uint8_t *)&ret, sizeof(uint16_t));
284  return ret;
285 }
286 
287 static CC_INLINE settings_status_t
288 settings_add_uint16(settings_key_t key, uint16_t value)
289 {
290  return settings_add(key, (const uint8_t *)&value, sizeof(uint16_t));
291 }
292 
293 static CC_INLINE settings_status_t
294 settings_set_uint16(settings_key_t key, uint16_t value)
295 {
296  return settings_set(key, (const uint8_t *)&value, sizeof(uint16_t));
297 }
298 
299 static CC_INLINE uint32_t
300 settings_get_uint32(settings_key_t key, uint8_t index)
301 {
302  uint32_t ret = 0;
303  settings_length_t sizeof_uint32 = sizeof(uint32_t);
304 
305  settings_get(key, index, (uint8_t *)&ret, sizeof_uint32);
306  return ret;
307 }
308 
309 static CC_INLINE settings_status_t
310 settings_add_uint32(settings_key_t key, uint32_t value)
311 {
312  return settings_add(key, (const uint8_t *)&value, sizeof(uint32_t));
313 }
314 
315 static CC_INLINE settings_status_t
316 settings_set_uint32(settings_key_t key, uint32_t value)
317 {
318  return settings_set(key, (const uint8_t *)&value, sizeof(uint32_t));
319 }
320 
321 #if __int64_t_defined
322 static CC_INLINE uint64_t
323 settings_get_uint64(settings_key_t key, uint8_t index)
324 {
325  uint64_t ret = 0;
326  settings_length_t sizeof_uint64 = sizeof(uint64_t);
327 
328  settings_get(key, index, (uint8_t *)&ret, sizeof_uint64);
329  return ret;
330 }
331 
332 static CC_INLINE settings_status_t
333 settings_add_uint64(settings_key_t key, uint64_t value)
334 {
335  return settings_add(key, (const uint8_t *)&value, sizeof(uint64_t));
336 }
337 
338 static CC_INLINE settings_status_t
339 settings_set_uint64(settings_key_t key, uint64_t value)
340 {
341  return settings_set(key, (const uint8_t *)&value, sizeof(uint64_t));
342 }
343 #endif /* __int64_t_defined */
344 
345 #endif /* !SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS */
346 
347 #endif /* !defined(CONTIKI_SETTINGS_H_) */