Merge pull request #144 from darconeous/pull-requests/settings-for-all-targets
core/lib/settings: Generalized settings manager to work on any platform
This commit is contained in:
commit
535e90343c
|
@ -60,7 +60,7 @@ SYSTEM = process.c procinit.c autostart.c elfloader.c profile.c \
|
||||||
timetable.c timetable-aggregate.c compower.c serial-line.c
|
timetable.c timetable-aggregate.c compower.c serial-line.c
|
||||||
THREADS = mt.c
|
THREADS = mt.c
|
||||||
LIBS = memb.c mmem.c timer.c list.c etimer.c ctimer.c energest.c rtimer.c stimer.c \
|
LIBS = memb.c mmem.c timer.c list.c etimer.c ctimer.c energest.c rtimer.c stimer.c \
|
||||||
print-stats.c ifft.c crc16.c random.c checkpoint.c ringbuf.c
|
print-stats.c ifft.c crc16.c random.c checkpoint.c ringbuf.c settings.c
|
||||||
DEV = nullradio.c
|
DEV = nullradio.c
|
||||||
|
|
||||||
include $(CONTIKI)/core/net/Makefile.uip
|
include $(CONTIKI)/core/net/Makefile.uip
|
||||||
|
|
479
core/lib/settings.c
Normal file
479
core/lib/settings.c
Normal file
|
@ -0,0 +1,479 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Robert Quattlebaum.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS
|
||||||
|
#undef SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS 1
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "dev/eeprom.h"
|
||||||
|
|
||||||
|
#if CONTIKI_CONF_SETTINGS_MANAGER
|
||||||
|
|
||||||
|
#if !EEPROM_CONF_SIZE
|
||||||
|
#error CONTIKI_CONF_SETTINGS_MANAGER has been set, but EEPROM_CONF_SIZE hasnt!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EEPROM_END_ADDR
|
||||||
|
#define EEPROM_END_ADDR (EEPROM_CONF_SIZE - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SETTINGS_MAX_SIZE
|
||||||
|
/** The maximum amount EEPROM dedicated to settings. */
|
||||||
|
#define SETTINGS_MAX_SIZE (127) /**< Defaults to 127 bytes */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SETTINGS_TOP_ADDR
|
||||||
|
/** The top address in EEPROM that settings should use. Inclusive. */
|
||||||
|
#define SETTINGS_TOP_ADDR (settings_iter_t)(EEPROM_END_ADDR)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SETTINGS_BOTTOM_ADDR
|
||||||
|
/** The lowest address in EEPROM that settings should use. Inclusive. */
|
||||||
|
#define SETTINGS_BOTTOM_ADDR (SETTINGS_TOP_ADDR + 1 - SETTINGS_MAX_SIZE)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a,b) ((a)<(b)?a:b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#if SETTINGS_CONF_SUPPORT_LARGE_VALUES
|
||||||
|
uint8_t size_extra;
|
||||||
|
#endif
|
||||||
|
uint8_t size_low;
|
||||||
|
uint8_t size_check;
|
||||||
|
settings_key_t key;
|
||||||
|
} item_header_t;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Public Travesal Functions
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_iter_t
|
||||||
|
settings_iter_begin()
|
||||||
|
{
|
||||||
|
return settings_iter_is_valid(SETTINGS_TOP_ADDR) ? SETTINGS_TOP_ADDR : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_iter_t
|
||||||
|
settings_iter_next(settings_iter_t ret)
|
||||||
|
{
|
||||||
|
if(ret) {
|
||||||
|
/* A settings iterator always points to the first byte
|
||||||
|
* after the actual key-value pair in memory. This means that
|
||||||
|
* the address of our value in EEPROM just happens
|
||||||
|
* to be the address of our next iterator.
|
||||||
|
*/
|
||||||
|
ret = settings_iter_get_value_addr(ret);
|
||||||
|
return settings_iter_is_valid(ret) ? ret : 0;
|
||||||
|
}
|
||||||
|
return SETTINGS_INVALID_ITER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
uint8_t
|
||||||
|
settings_iter_is_valid(settings_iter_t iter)
|
||||||
|
{
|
||||||
|
item_header_t header = { 0 };
|
||||||
|
|
||||||
|
if(iter == EEPROM_NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iter < SETTINGS_BOTTOM_ADDR + sizeof(header)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
eeprom_read(iter - sizeof(header), (uint8_t *)&header, sizeof(header));
|
||||||
|
|
||||||
|
if((uint8_t) header.size_check != (uint8_t) ~ header.size_low) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iter < SETTINGS_BOTTOM_ADDR + sizeof(header) + settings_iter_get_value_length(iter)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_key_t
|
||||||
|
settings_iter_get_key(settings_iter_t iter)
|
||||||
|
{
|
||||||
|
item_header_t header;
|
||||||
|
|
||||||
|
eeprom_read(iter - sizeof(header), (uint8_t *)&header, sizeof(header));
|
||||||
|
|
||||||
|
if((uint8_t) header.size_check != (uint8_t)~header.size_low) {
|
||||||
|
return SETTINGS_INVALID_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return header.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_length_t
|
||||||
|
settings_iter_get_value_length(settings_iter_t iter)
|
||||||
|
{
|
||||||
|
item_header_t header;
|
||||||
|
|
||||||
|
settings_length_t ret = 0;
|
||||||
|
|
||||||
|
eeprom_read(iter - sizeof(header), (uint8_t *)&header, sizeof(header) );
|
||||||
|
|
||||||
|
if((uint8_t)header.size_check == (uint8_t)~header.size_low) {
|
||||||
|
ret = header.size_low;
|
||||||
|
|
||||||
|
#if SETTINGS_CONF_SUPPORT_LARGE_VALUES
|
||||||
|
if(ret & (1 << 7)) {
|
||||||
|
ret = ((ret & ~(1 << 7)) << 7) | header.size_extra;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
eeprom_addr_t
|
||||||
|
settings_iter_get_value_addr(settings_iter_t iter)
|
||||||
|
{
|
||||||
|
settings_length_t len = settings_iter_get_value_length(iter);
|
||||||
|
#if SETTINGS_CONF_SUPPORT_LARGE_VALUES
|
||||||
|
len += (len >= 128);
|
||||||
|
#endif
|
||||||
|
return iter - sizeof(item_header_t) - len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_length_t
|
||||||
|
settings_iter_get_value_bytes(settings_iter_t iter, void *bytes,
|
||||||
|
settings_length_t max_length)
|
||||||
|
{
|
||||||
|
max_length = MIN(max_length, settings_iter_get_value_length(iter));
|
||||||
|
|
||||||
|
eeprom_read(settings_iter_get_value_addr(iter), bytes, max_length);
|
||||||
|
|
||||||
|
return max_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_status_t
|
||||||
|
settings_iter_delete(settings_iter_t iter)
|
||||||
|
{
|
||||||
|
settings_status_t ret = SETTINGS_STATUS_FAILURE;
|
||||||
|
|
||||||
|
settings_iter_t next = settings_iter_next(iter);
|
||||||
|
|
||||||
|
if(!next) {
|
||||||
|
/* Special case: we are the last item. we can get away with
|
||||||
|
* just wiping out our own header.
|
||||||
|
*/
|
||||||
|
item_header_t header;
|
||||||
|
|
||||||
|
memset(&header, 0xFF, sizeof(header));
|
||||||
|
|
||||||
|
eeprom_write(iter - sizeof(header), (uint8_t *)&header, sizeof(header));
|
||||||
|
|
||||||
|
ret = SETTINGS_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This case requires the settings store to be shifted.
|
||||||
|
* Currently unimplemented. TODO: Writeme!
|
||||||
|
*/
|
||||||
|
ret = SETTINGS_STATUS_UNIMPLEMENTED;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Public Functions
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
uint8_t
|
||||||
|
settings_check(settings_key_t key, uint8_t index)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
|
||||||
|
settings_iter_t iter;
|
||||||
|
|
||||||
|
for(iter = settings_iter_begin(); iter; iter = settings_iter_next(iter)) {
|
||||||
|
if(settings_iter_get_key(iter) == key) {
|
||||||
|
if(!index) {
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_status_t
|
||||||
|
settings_get(settings_key_t key, uint8_t index, uint8_t *value,
|
||||||
|
settings_length_t * value_size)
|
||||||
|
{
|
||||||
|
settings_status_t ret = SETTINGS_STATUS_NOT_FOUND;
|
||||||
|
|
||||||
|
settings_iter_t iter;
|
||||||
|
|
||||||
|
for(iter = settings_iter_begin(); iter; iter = settings_iter_next(iter)) {
|
||||||
|
if(settings_iter_get_key(iter) == key) {
|
||||||
|
if(!index) {
|
||||||
|
/* We found it! */
|
||||||
|
*value_size = settings_iter_get_value_bytes(iter,
|
||||||
|
(void *)value,
|
||||||
|
*value_size);
|
||||||
|
ret = SETTINGS_STATUS_OK;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* Nope, keep looking */
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_status_t
|
||||||
|
settings_add(settings_key_t key, const uint8_t *value,
|
||||||
|
settings_length_t value_size)
|
||||||
|
{
|
||||||
|
settings_status_t ret = SETTINGS_STATUS_FAILURE;
|
||||||
|
|
||||||
|
settings_iter_t iter;
|
||||||
|
|
||||||
|
item_header_t header;
|
||||||
|
|
||||||
|
/* Find the last item. */
|
||||||
|
for(iter = settings_iter_begin(); settings_iter_next(iter);
|
||||||
|
iter = settings_iter_next(iter)) {
|
||||||
|
/* This block intentionally left blank. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iter) {
|
||||||
|
/* Value address of item is the same as the iterator for next item. */
|
||||||
|
iter = settings_iter_get_value_addr(iter);
|
||||||
|
} else {
|
||||||
|
/* This will be the first setting! */
|
||||||
|
iter = SETTINGS_TOP_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iter < SETTINGS_BOTTOM_ADDR + value_size + sizeof(header)) {
|
||||||
|
/* This value is too big to store. */
|
||||||
|
ret = SETTINGS_STATUS_OUT_OF_SPACE;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.key = key;
|
||||||
|
|
||||||
|
if(value_size < 0x80) {
|
||||||
|
/* If the value size is less than 128, then
|
||||||
|
* we can get away with only using one byte
|
||||||
|
* to store the size.
|
||||||
|
*/
|
||||||
|
header.size_low = value_size;
|
||||||
|
}
|
||||||
|
#if SETTINGS_CONF_SUPPORT_LARGE_VALUES
|
||||||
|
else if(value_size <= SETTINGS_MAX_VALUE_SIZE) {
|
||||||
|
/* If the value size is larger than or equal to 128,
|
||||||
|
* then we need to use two bytes. Store
|
||||||
|
* the most significant 7 bits in the first
|
||||||
|
* size byte (with MSB set) and store the
|
||||||
|
* least significant bits in the second
|
||||||
|
* byte (with LSB clear)
|
||||||
|
*/
|
||||||
|
header.size_low = (value_size >> 7) | 0x80;
|
||||||
|
header.size_extra = value_size & ~0x80;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
/* Value size way too big! */
|
||||||
|
ret = SETTINGS_STATUS_VALUE_TOO_BIG;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
header.size_check = ~header.size_low;
|
||||||
|
|
||||||
|
/* Write the header first */
|
||||||
|
eeprom_write(iter - sizeof(header), (uint8_t *)&header, sizeof(header));
|
||||||
|
|
||||||
|
/* Sanity check, remove once confident */
|
||||||
|
if(settings_iter_get_value_length(iter) != value_size) {
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now write the data */
|
||||||
|
eeprom_write(settings_iter_get_value_addr(iter), (uint8_t *)value, value_size);
|
||||||
|
|
||||||
|
/* This should be the last item. If this is not the case,
|
||||||
|
* then we need to clear out the phantom setting.
|
||||||
|
*/
|
||||||
|
if((iter = settings_iter_next(iter))) {
|
||||||
|
memset(&header, 0xFF, sizeof(header));
|
||||||
|
|
||||||
|
eeprom_write(iter - sizeof(header),(uint8_t *)&header, sizeof(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SETTINGS_STATUS_OK;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_status_t
|
||||||
|
settings_set(settings_key_t key, const uint8_t *value,
|
||||||
|
settings_length_t value_size)
|
||||||
|
{
|
||||||
|
settings_status_t ret = SETTINGS_STATUS_FAILURE;
|
||||||
|
|
||||||
|
settings_iter_t iter;
|
||||||
|
|
||||||
|
for(iter = settings_iter_begin(); iter; iter = settings_iter_next(iter)) {
|
||||||
|
if(settings_iter_get_key(iter) == key) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((iter == EEPROM_NULL) || !settings_iter_is_valid(iter)) {
|
||||||
|
ret = settings_add(key, value, value_size);
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value_size != settings_iter_get_value_length(iter)) {
|
||||||
|
/* Requires the settings store to be shifted. Currently unimplemented. */
|
||||||
|
ret = SETTINGS_STATUS_UNIMPLEMENTED;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now write the data */
|
||||||
|
eeprom_write(settings_iter_get_value_addr(iter),
|
||||||
|
(uint8_t *)value, value_size);
|
||||||
|
|
||||||
|
ret = SETTINGS_STATUS_OK;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
settings_status_t
|
||||||
|
settings_delete(settings_key_t key, uint8_t index)
|
||||||
|
{
|
||||||
|
settings_status_t ret = SETTINGS_STATUS_NOT_FOUND;
|
||||||
|
|
||||||
|
settings_iter_t iter;
|
||||||
|
|
||||||
|
for(iter = settings_iter_begin(); iter; iter = settings_iter_next(iter)) {
|
||||||
|
if(settings_iter_get_key(iter) == key) {
|
||||||
|
if(!index) {
|
||||||
|
/* We found it! */
|
||||||
|
ret = settings_iter_delete(iter);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
/* Nope, keep looking */
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
settings_wipe(void)
|
||||||
|
{
|
||||||
|
/* Simply making the first item invalid will effectively
|
||||||
|
* clear the key-value store.
|
||||||
|
*/
|
||||||
|
const uint32_t x = 0xFFFFFF;
|
||||||
|
|
||||||
|
eeprom_write(SETTINGS_TOP_ADDR - sizeof(x), (uint8_t *)&x, sizeof(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Other Functions
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#include <stdio.h>
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
void
|
||||||
|
settings_debug_dump(void)
|
||||||
|
{
|
||||||
|
settings_iter_t iter;
|
||||||
|
|
||||||
|
printf("{\n");
|
||||||
|
for(iter = settings_iter_begin(); iter; iter = settings_iter_next(iter)) {
|
||||||
|
settings_length_t len = settings_iter_get_value_length(iter);
|
||||||
|
eeprom_addr_t addr = settings_iter_get_value_addr(iter);
|
||||||
|
uint8_t byte;
|
||||||
|
|
||||||
|
union {
|
||||||
|
settings_key_t key;
|
||||||
|
char bytes[0];
|
||||||
|
} u;
|
||||||
|
|
||||||
|
u.key = settings_iter_get_key(iter);
|
||||||
|
|
||||||
|
printf("\t\"%c%c\" = <", u.bytes[0], u.bytes[1]);
|
||||||
|
|
||||||
|
for(; len; len--, addr++) {
|
||||||
|
eeprom_read(addr, &byte, 1);
|
||||||
|
printf("%02X", byte);
|
||||||
|
if(len != 1) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(">;\n");
|
||||||
|
}
|
||||||
|
printf("}\n");
|
||||||
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
#endif /* CONTIKI_CONF_SETTINGS_MANAGER */
|
368
core/lib/settings.h
Normal file
368
core/lib/settings.h
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Robert Quattlebaum
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CONTIKI_SETTINGS_H__
|
||||||
|
#define __CONTIKI_SETTINGS_H__
|
||||||
|
|
||||||
|
/** @file settings.h
|
||||||
|
* @brief Settings Manager
|
||||||
|
* @author Robert Quattlebaum <darco@deepdarc.com>
|
||||||
|
*
|
||||||
|
* ## Overview ##
|
||||||
|
*
|
||||||
|
* The settings manager is a EEPROM-based key-value store. Keys
|
||||||
|
* are 16-bit integers and values may be up to 16,383 bytes long.
|
||||||
|
* It is intended to be used to store configuration-related information,
|
||||||
|
* like network settings, radio channels, etc.
|
||||||
|
*
|
||||||
|
* ## Features ##
|
||||||
|
*
|
||||||
|
* * Robust data format which requires no initialization.
|
||||||
|
* * Supports multiple values with the same key.
|
||||||
|
* * Data can be appended without erasing EEPROM.
|
||||||
|
* * Max size of settings data can be easily increased in the future,
|
||||||
|
* as long as it doesn't overlap with application data.
|
||||||
|
*
|
||||||
|
* ## Data Format ##
|
||||||
|
*
|
||||||
|
* The format was inspired by OLPC manufacturing data, as described here:
|
||||||
|
* <http://wiki.laptop.org/go/Manufacturing_data>
|
||||||
|
*
|
||||||
|
* Since the beginning of EEPROM often contains application-specific
|
||||||
|
* information, the best place to store settings is at the end of
|
||||||
|
* EEPROM. Because we are starting at the end of EEPROM, it makes sense
|
||||||
|
* to grow the list of key-value pairs downward, toward the start of
|
||||||
|
* EEPROM.
|
||||||
|
*
|
||||||
|
* Each key-value pair is stored in memory in the following format:
|
||||||
|
* <table>
|
||||||
|
* <thead>
|
||||||
|
* <td>Order</td>
|
||||||
|
* <td>Size<small> (in bytes)</small></td>
|
||||||
|
* <td>Name</td>
|
||||||
|
* <td>Description</td>
|
||||||
|
* </thead>
|
||||||
|
* <tr>
|
||||||
|
* <td>0</td>
|
||||||
|
* <td>2</td>
|
||||||
|
* <td>key</td>
|
||||||
|
* <td></td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>-2</td>
|
||||||
|
* <td>1</td>
|
||||||
|
* <td>size_check</td>
|
||||||
|
* <td>One's-complement of next byte</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>-3</td>
|
||||||
|
* <td>1 or 2</td>
|
||||||
|
* <td>size</td>
|
||||||
|
* <td>The size of the value, in bytes.</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>-4 or -5</td>
|
||||||
|
* <td>variable</td>
|
||||||
|
* <td>value</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
|
* The end of the key-value pairs is denoted by the first invalid entry.
|
||||||
|
* An invalid entry has any of the following attributes:
|
||||||
|
*
|
||||||
|
* * The size_check byte doesn't match the one's compliment
|
||||||
|
* of the size byte (or size_low byte).
|
||||||
|
* * The key has a value of 0x0000.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "dev/eeprom.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Types
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SETTINGS_STATUS_OK = 0,
|
||||||
|
SETTINGS_STATUS_FAILURE,
|
||||||
|
SETTINGS_STATUS_INVALID_ARGUMENT,
|
||||||
|
SETTINGS_STATUS_NOT_FOUND,
|
||||||
|
SETTINGS_STATUS_OUT_OF_SPACE,
|
||||||
|
SETTINGS_STATUS_VALUE_TOO_BIG,
|
||||||
|
SETTINGS_STATUS_UNIMPLEMENTED,
|
||||||
|
} settings_status_t;
|
||||||
|
|
||||||
|
typedef uint16_t settings_key_t;
|
||||||
|
|
||||||
|
typedef uint16_t settings_length_t;
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Settings Keys
|
||||||
|
|
||||||
|
/** Two-character constant macro */
|
||||||
|
#define TCC(a,b) ((a)+(b)*256)
|
||||||
|
|
||||||
|
/* All-capital-letter constants are always contiki-defined. */
|
||||||
|
#define SETTINGS_KEY_EUI64 TCC('E','8') /**< EUI64 Address, 8 bytes */
|
||||||
|
#define SETTINGS_KEY_EUI48 TCC('E','6') /*!< MAC Address, 6 bytes */
|
||||||
|
#define SETTINGS_KEY_CHANNEL TCC('C','H') /*!< Channel number, uint8_t */
|
||||||
|
#define SETTINGS_KEY_TXPOWER TCC('T','P') /*!< Transmit power, uint8_t */
|
||||||
|
#define SETTINGS_KEY_PAN_ID TCC('P','N') /*!< PAN ID, uint16_t */
|
||||||
|
#define SETTINGS_KEY_PAN_ADDR TCC('P','A') /*!< PAN address, uint16_t */
|
||||||
|
#define SETTINGS_KEY_AES128KEY TCC('S','K') /*!< AES128 key, 16 bytes */
|
||||||
|
#define SETTINGS_KEY_AES128ENABLED TCC('S','E') /*!< AES128 enabled, bool */
|
||||||
|
#define SETTINGS_KEY_HOSTNAME TCC('H','N') /*!< Hostname, C-String */
|
||||||
|
#define SETTINGS_KEY_DOMAINNAME TCC('D','N') /*!< Domainname, C-String */
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Experimental Settings Keys
|
||||||
|
|
||||||
|
#define SETTINGS_KEY_RDC_INDEX TCC('R','D') /*!< RDC index, uint8_t */
|
||||||
|
#define SETTINGS_KEY_CHANNEL_MASK TCC('C','M') /*!< Channel mask, uint16_t */
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Constants
|
||||||
|
|
||||||
|
/** Use this when you want to retrieve the last item */
|
||||||
|
#define SETTINGS_LAST_INDEX 0xFF
|
||||||
|
|
||||||
|
#define SETTINGS_INVALID_KEY 0xFFFF
|
||||||
|
|
||||||
|
#define SETTINGS_INVALID_ITER EEPROM_NULL
|
||||||
|
|
||||||
|
#ifndef SETTINGS_CONF_SUPPORT_LARGE_VALUES
|
||||||
|
#define SETTINGS_CONF_SUPPORT_LARGE_VALUES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SETTINGS_CONF_SUPPORT_LARGE_VALUES
|
||||||
|
#define SETTINGS_MAX_VALUE_SIZE 0x3FFF /* 16383 bytes */
|
||||||
|
#else
|
||||||
|
#define SETTINGS_MAX_VALUE_SIZE 0x7F /* 127 bytes */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Settings accessors
|
||||||
|
|
||||||
|
/** Fetches the value associated with the given key. */
|
||||||
|
extern settings_status_t settings_get(settings_key_t key, uint8_t index,
|
||||||
|
uint8_t *value,
|
||||||
|
settings_length_t * value_size);
|
||||||
|
|
||||||
|
/** Adds the given key-value pair to the end of the settings store. */
|
||||||
|
extern settings_status_t settings_add(settings_key_t key,
|
||||||
|
const uint8_t *value,
|
||||||
|
settings_length_t value_size);
|
||||||
|
|
||||||
|
/** Checks to see if the given key exists. */
|
||||||
|
extern uint8_t settings_check(settings_key_t key, uint8_t index);
|
||||||
|
|
||||||
|
/** Reinitializes all of the EEPROM used by settings. */
|
||||||
|
extern void settings_wipe(void);
|
||||||
|
|
||||||
|
/** Sets the value for the given key. If the key already exists in
|
||||||
|
* the settings store, then its value will be replaced.
|
||||||
|
*/
|
||||||
|
extern settings_status_t settings_set(settings_key_t key,
|
||||||
|
const uint8_t *value,
|
||||||
|
settings_length_t value_size);
|
||||||
|
|
||||||
|
/** Removes the given key (at the given index) from the settings store. */
|
||||||
|
extern settings_status_t settings_delete(settings_key_t key, uint8_t index);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - Settings traversal functions
|
||||||
|
|
||||||
|
typedef eeprom_addr_t settings_iter_t;
|
||||||
|
|
||||||
|
/** Will return extern SETTINGS_INVALID_ITER if the settings store is empty. */
|
||||||
|
extern settings_iter_t settings_iter_begin();
|
||||||
|
|
||||||
|
/** Will return extern SETTINGS_INVALID_ITER if at the end of settings list. */
|
||||||
|
extern settings_iter_t settings_iter_next(settings_iter_t iter);
|
||||||
|
|
||||||
|
extern uint8_t settings_iter_is_valid(settings_iter_t iter);
|
||||||
|
|
||||||
|
extern settings_key_t settings_iter_get_key(settings_iter_t iter);
|
||||||
|
|
||||||
|
extern settings_length_t settings_iter_get_value_length(settings_iter_t iter);
|
||||||
|
|
||||||
|
extern eeprom_addr_t settings_iter_get_value_addr(settings_iter_t iter);
|
||||||
|
|
||||||
|
extern settings_length_t settings_iter_get_value_bytes(settings_iter_t item,
|
||||||
|
void *bytes,
|
||||||
|
settings_length_t
|
||||||
|
max_length);
|
||||||
|
|
||||||
|
extern settings_status_t settings_iter_delete(settings_iter_t item);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
// MARK: - inline convenience functions
|
||||||
|
|
||||||
|
/* Unfortunately, some platforms don't properly drop unreferenced functions,
|
||||||
|
* so on these broken platforms we can save a significant amount
|
||||||
|
* of space by skipping the definition of the convenience functions.
|
||||||
|
*/
|
||||||
|
#if !SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS
|
||||||
|
|
||||||
|
static CC_INLINE const char *
|
||||||
|
settings_get_cstr(settings_key_t key, uint8_t index, char *c_str,
|
||||||
|
settings_length_t c_str_size)
|
||||||
|
{
|
||||||
|
/* Save room for the zero termination. */
|
||||||
|
c_str_size--;
|
||||||
|
|
||||||
|
if(settings_get(key, index, (uint8_t *)c_str, &c_str_size) == SETTINGS_STATUS_OK) {
|
||||||
|
/* Zero terminate. */
|
||||||
|
c_str[c_str_size] = 0;
|
||||||
|
} else {
|
||||||
|
c_str = NULL;
|
||||||
|
}
|
||||||
|
return c_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_set_cstr(settings_key_t key, const char* c_str)
|
||||||
|
{
|
||||||
|
return settings_set(key, (const uint8_t *)c_str, strlen(c_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_add_cstr(settings_key_t key, const char* c_str)
|
||||||
|
{
|
||||||
|
return settings_add(key, (const uint8_t *)c_str, strlen(c_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE uint8_t
|
||||||
|
settings_get_bool_with_default(settings_key_t key, uint8_t index,
|
||||||
|
uint8_t default_value)
|
||||||
|
{
|
||||||
|
uint8_t ret = default_value;
|
||||||
|
settings_length_t sizeof_uint8 = sizeof(uint8_t);
|
||||||
|
|
||||||
|
settings_get(key, index, (uint8_t *)&ret, &sizeof_uint8);
|
||||||
|
return !!ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE uint8_t
|
||||||
|
settings_get_uint8(settings_key_t key, uint8_t index)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
settings_length_t sizeof_uint8 = sizeof(uint8_t);
|
||||||
|
|
||||||
|
settings_get(key, index, (uint8_t *)&ret, &sizeof_uint8);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_add_uint8(settings_key_t key, uint8_t value)
|
||||||
|
{
|
||||||
|
return settings_add(key, (const uint8_t *)&value, sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_set_uint8(settings_key_t key, uint8_t value)
|
||||||
|
{
|
||||||
|
return settings_set(key, (const uint8_t *)&value, sizeof(uint8_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE uint16_t
|
||||||
|
settings_get_uint16(settings_key_t key, uint8_t index)
|
||||||
|
{
|
||||||
|
uint16_t ret = 0;
|
||||||
|
settings_length_t sizeof_uint16 = sizeof(uint16_t);
|
||||||
|
|
||||||
|
settings_get(key, index, (uint8_t *)&ret, &sizeof_uint16);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_add_uint16(settings_key_t key, uint16_t value)
|
||||||
|
{
|
||||||
|
return settings_add(key, (const uint8_t *)&value, sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_set_uint16(settings_key_t key, uint16_t value)
|
||||||
|
{
|
||||||
|
return settings_set(key, (const uint8_t *)&value, sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE uint32_t
|
||||||
|
settings_get_uint32(settings_key_t key, uint8_t index)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
settings_length_t sizeof_uint32 = sizeof(uint32_t);
|
||||||
|
|
||||||
|
settings_get(key, index, (uint8_t *)&ret, &sizeof_uint32);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_add_uint32(settings_key_t key, uint32_t value)
|
||||||
|
{
|
||||||
|
return settings_add(key, (const uint8_t *)&value, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_set_uint32(settings_key_t key, uint32_t value)
|
||||||
|
{
|
||||||
|
return settings_set(key, (const uint8_t *)&value, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __int64_t_defined
|
||||||
|
static CC_INLINE uint64_t
|
||||||
|
settings_get_uint64(settings_key_t key, uint8_t index)
|
||||||
|
{
|
||||||
|
uint64_t ret = 0;
|
||||||
|
settings_length_t sizeof_uint64 = sizeof(uint64_t);
|
||||||
|
|
||||||
|
settings_get(key, index, (uint8_t *)&ret, &sizeof_uint64);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_add_uint64(settings_key_t key, uint64_t value)
|
||||||
|
{
|
||||||
|
return settings_add(key, (const uint8_t *)&value, sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CC_INLINE settings_status_t
|
||||||
|
settings_set_uint64(settings_key_t key, uint64_t value)
|
||||||
|
{
|
||||||
|
return settings_set(key, (const uint8_t *)&value, sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
#endif /* __int64_t_defined */
|
||||||
|
|
||||||
|
#endif /* !SETTINGS_CONF_SKIP_CONVENIENCE_FUNCS */
|
||||||
|
|
||||||
|
#endif /* !defined(__CONTIKI_SETTINGS_H__) */
|
|
@ -13,7 +13,7 @@ CONTIKI_CPU=$(CONTIKI)/cpu/avr
|
||||||
### These directories will be searched for the specified source files
|
### These directories will be searched for the specified source files
|
||||||
### TARGETLIBS are platform-specific routines in the contiki library path
|
### TARGETLIBS are platform-specific routines in the contiki library path
|
||||||
CONTIKI_CPU_DIRS = . dev
|
CONTIKI_CPU_DIRS = . dev
|
||||||
AVR = clock.c mtarch.c eeprom.c flash.c rs232.c leds-arch.c watchdog.c rtimer-arch.c bootloader.c settings.c
|
AVR = clock.c mtarch.c eeprom.c flash.c rs232.c leds-arch.c watchdog.c rtimer-arch.c bootloader.c
|
||||||
ELFLOADER = elfloader.c elfloader-avr.c symtab-avr.c
|
ELFLOADER = elfloader.c elfloader-avr.c symtab-avr.c
|
||||||
TARGETLIBS = random.c leds.c
|
TARGETLIBS = random.c leds.c
|
||||||
|
|
||||||
|
|
|
@ -1,275 +0,0 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
//#include <sys/param.h>
|
|
||||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include "settings.h"
|
|
||||||
#include "dev/eeprom.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <avr/pgmspace.h>
|
|
||||||
#include <avr/eeprom.h>
|
|
||||||
#include <avr/wdt.h>
|
|
||||||
#include "contiki.h"
|
|
||||||
|
|
||||||
#ifndef SETTINGS_TOP_ADDR
|
|
||||||
#define SETTINGS_TOP_ADDR (E2END-4) //!< Defaults to end of EEPROM, minus 4 bytes for avrdude erase count
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SETTINGS_MAX_SIZE
|
|
||||||
#define SETTINGS_MAX_SIZE (1024) //!< Defaults to 1KB
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//#pragma mark -
|
|
||||||
//#pragma mark Private Functions
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t size_extra;
|
|
||||||
uint8_t size_low;
|
|
||||||
uint8_t size_check;
|
|
||||||
settings_key_t key;
|
|
||||||
} item_header_t;
|
|
||||||
|
|
||||||
inline static bool
|
|
||||||
settings_is_item_valid_(eeprom_addr_t item_addr) {
|
|
||||||
item_header_t header = {};
|
|
||||||
|
|
||||||
if(item_addr==EEPROM_NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// if((SETTINGS_TOP_ADDR-item_addr)>=SETTINGS_MAX_SIZE-3)
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
eeprom_read(
|
|
||||||
item_addr+1-sizeof(header),
|
|
||||||
(unsigned char*)&header,
|
|
||||||
sizeof(header)
|
|
||||||
);
|
|
||||||
|
|
||||||
if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// TODO: Check length as well
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static settings_key_t
|
|
||||||
settings_get_key_(eeprom_addr_t item_addr) {
|
|
||||||
item_header_t header;
|
|
||||||
|
|
||||||
eeprom_read(
|
|
||||||
item_addr+1-sizeof(header),
|
|
||||||
(unsigned char*)&header,
|
|
||||||
sizeof(header)
|
|
||||||
);
|
|
||||||
|
|
||||||
if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
|
|
||||||
return SETTINGS_INVALID_KEY;
|
|
||||||
|
|
||||||
return header.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static size_t
|
|
||||||
settings_get_value_length_(eeprom_addr_t item_addr) {
|
|
||||||
item_header_t header;
|
|
||||||
size_t ret = 0;
|
|
||||||
|
|
||||||
eeprom_read(
|
|
||||||
item_addr+1-sizeof(header),
|
|
||||||
(unsigned char*)&header,
|
|
||||||
sizeof(header)
|
|
||||||
);
|
|
||||||
|
|
||||||
if((uint8_t)header.size_check!=(uint8_t)~header.size_low)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
ret = header.size_low;
|
|
||||||
|
|
||||||
if(ret&(1<<7)) {
|
|
||||||
ret = ((ret&~(1<<7))<<8) | header.size_extra;
|
|
||||||
}
|
|
||||||
|
|
||||||
bail:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static eeprom_addr_t
|
|
||||||
settings_get_value_addr_(eeprom_addr_t item_addr) {
|
|
||||||
size_t len = settings_get_value_length_(item_addr);
|
|
||||||
|
|
||||||
if(len>128)
|
|
||||||
return item_addr+1-sizeof(item_header_t)-len;
|
|
||||||
|
|
||||||
return item_addr+1-sizeof(item_header_t)+1-len;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static eeprom_addr_t
|
|
||||||
settings_next_item_(eeprom_addr_t item_addr) {
|
|
||||||
return settings_get_value_addr_(item_addr)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//#pragma mark -
|
|
||||||
//#pragma mark Public Functions
|
|
||||||
|
|
||||||
bool
|
|
||||||
settings_check(settings_key_t key,uint8_t index) {
|
|
||||||
bool ret = false;
|
|
||||||
eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
|
|
||||||
|
|
||||||
for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
|
|
||||||
if(settings_get_key_(current_item)==key) {
|
|
||||||
if(!index) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// Nope, keep looking
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings_status_t
|
|
||||||
settings_get(settings_key_t key,uint8_t index,unsigned char* value,size_t* value_size) {
|
|
||||||
settings_status_t ret = SETTINGS_STATUS_NOT_FOUND;
|
|
||||||
eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
|
|
||||||
|
|
||||||
for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
|
|
||||||
if(settings_get_key_(current_item)==key) {
|
|
||||||
if(!index) {
|
|
||||||
// We found it!
|
|
||||||
*value_size = MIN(*value_size,settings_get_value_length_(current_item));
|
|
||||||
eeprom_read(
|
|
||||||
settings_get_value_addr_(current_item),
|
|
||||||
value,
|
|
||||||
*value_size
|
|
||||||
);
|
|
||||||
ret = SETTINGS_STATUS_OK;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// Nope, keep looking
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings_status_t
|
|
||||||
settings_add(settings_key_t key,const unsigned char* value,size_t value_size) {
|
|
||||||
settings_status_t ret = SETTINGS_STATUS_FAILURE;
|
|
||||||
eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
|
|
||||||
item_header_t header;
|
|
||||||
|
|
||||||
// Find end of list
|
|
||||||
for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item));
|
|
||||||
|
|
||||||
if(current_item==EEPROM_NULL)
|
|
||||||
goto bail;
|
|
||||||
|
|
||||||
// TODO: size check!
|
|
||||||
|
|
||||||
header.key = key;
|
|
||||||
|
|
||||||
if(value_size<0x80) {
|
|
||||||
// If the value size is less than 128, then
|
|
||||||
// we can get away with only using one byte
|
|
||||||
// as the size.
|
|
||||||
header.size_low = value_size;
|
|
||||||
} else if(value_size<=SETTINGS_MAX_VALUE_SIZE) {
|
|
||||||
// If the value size of larger than 128,
|
|
||||||
// then we need to use two bytes. Store
|
|
||||||
// the most significant 7 bits in the first
|
|
||||||
// size byte (with MSB set) and store the
|
|
||||||
// least significant bits in the second
|
|
||||||
// byte (with LSB clear)
|
|
||||||
header.size_low = (value_size>>7) | 0x80;
|
|
||||||
header.size_extra = value_size & ~0x80;
|
|
||||||
} else {
|
|
||||||
// Value size way too big!
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
header.size_check = ~header.size_low;
|
|
||||||
|
|
||||||
// Write the header first
|
|
||||||
eeprom_write(
|
|
||||||
current_item+1-sizeof(header),
|
|
||||||
(unsigned char*)&header,
|
|
||||||
sizeof(header)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Sanity check, remove once confident
|
|
||||||
if(settings_get_value_length_(current_item)!=value_size) {
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now write the data
|
|
||||||
eeprom_write(
|
|
||||||
settings_get_value_addr_(current_item),
|
|
||||||
(unsigned char*)value,
|
|
||||||
value_size
|
|
||||||
);
|
|
||||||
|
|
||||||
ret = SETTINGS_STATUS_OK;
|
|
||||||
|
|
||||||
bail:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings_status_t
|
|
||||||
settings_set(settings_key_t key,const unsigned char* value,size_t value_size) {
|
|
||||||
settings_status_t ret = SETTINGS_STATUS_FAILURE;
|
|
||||||
eeprom_addr_t current_item = SETTINGS_TOP_ADDR;
|
|
||||||
|
|
||||||
for(current_item=SETTINGS_TOP_ADDR;settings_is_item_valid_(current_item);current_item=settings_next_item_(current_item)) {
|
|
||||||
if(settings_get_key_(current_item)==key) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((current_item==EEPROM_NULL) || !settings_is_item_valid_(current_item)) {
|
|
||||||
ret = settings_add(key,value,value_size);
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(value_size!=settings_get_value_length_(current_item)) {
|
|
||||||
// Requires the settings store to be shifted. Currently unimplemented.
|
|
||||||
goto bail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now write the data
|
|
||||||
eeprom_write(
|
|
||||||
settings_get_value_addr_(current_item),
|
|
||||||
(unsigned char*)value,
|
|
||||||
value_size
|
|
||||||
);
|
|
||||||
|
|
||||||
ret = SETTINGS_STATUS_OK;
|
|
||||||
|
|
||||||
bail:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
settings_status_t
|
|
||||||
settings_delete(settings_key_t key,uint8_t index) {
|
|
||||||
// Requires the settings store to be shifted. Currently unimplemented.
|
|
||||||
// TODO: Writeme!
|
|
||||||
return SETTINGS_STATUS_UNIMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
settings_wipe(void) {
|
|
||||||
size_t i = SETTINGS_TOP_ADDR-SETTINGS_MAX_SIZE;
|
|
||||||
for(;i<=SETTINGS_TOP_ADDR;i++) {
|
|
||||||
eeprom_write_byte((uint8_t*)i,0xFF);
|
|
||||||
wdt_reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,118 +0,0 @@
|
||||||
#ifndef __AVR_SETTINGS_H__
|
|
||||||
#define __AVR_SETTINGS_H__
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
typedef uint16_t settings_key_t;
|
|
||||||
|
|
||||||
#define SETTINGS_KEY_EUI64 'E'*256+'8' //!< Value always 8 bytes long
|
|
||||||
#define SETTINGS_KEY_EUI48 'E'*256+'6' //!< Value always 8 bytes long
|
|
||||||
#define SETTINGS_KEY_CHANNEL 'C'*256+'H' //!< Value always 1 byte long
|
|
||||||
#define SETTINGS_KEY_TXPOWER 'T'*256+'P' //!< Value always 1 byte long
|
|
||||||
#define SETTINGS_KEY_PAN_ID 'P'*256+'N' //!< Value always 2 bytes long
|
|
||||||
#define SETTINGS_KEY_PAN_ADDR 'P'*256+'A' //!< Value always 2 bytes long
|
|
||||||
#define SETTINGS_KEY_AES128KEY 'S'*256+'K' //!< Value always 16 bytes long
|
|
||||||
#define SETTINGS_KEY_AES128ENABLED 'S'*256+'E' //!< Value always 16 bytes long
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SETTINGS_STATUS_OK=0,
|
|
||||||
SETTINGS_STATUS_INVALID_ARGUMENT,
|
|
||||||
SETTINGS_STATUS_NOT_FOUND,
|
|
||||||
SETTINGS_STATUS_OUT_OF_SPACE,
|
|
||||||
SETTINGS_STATUS_UNIMPLEMENTED,
|
|
||||||
SETTINGS_STATUS_FAILURE,
|
|
||||||
} settings_status_t;
|
|
||||||
|
|
||||||
// Use this when you want to retrieve the last item
|
|
||||||
#define SETTINGS_LAST_INDEX (0xFF)
|
|
||||||
|
|
||||||
#define SETTINGS_INVALID_KEY (0x00)
|
|
||||||
|
|
||||||
#define SETTINGS_MAX_VALUE_SIZE (0x3FFF) // 16383 bytes
|
|
||||||
|
|
||||||
extern settings_status_t settings_get(settings_key_t key,uint8_t index,unsigned char* value,size_t* value_size);
|
|
||||||
extern settings_status_t settings_add(settings_key_t key,const unsigned char* value,size_t value_size);
|
|
||||||
extern bool settings_check(settings_key_t key,uint8_t index);
|
|
||||||
extern void settings_wipe(void);
|
|
||||||
|
|
||||||
extern settings_status_t settings_set(settings_key_t key,const unsigned char* value,size_t value_size);
|
|
||||||
extern settings_status_t settings_delete(settings_key_t key,uint8_t index);
|
|
||||||
|
|
||||||
//#pragma mark -
|
|
||||||
//#pragma mark Inline convenience functions
|
|
||||||
|
|
||||||
static inline uint8_t
|
|
||||||
settings_get_uint8(settings_key_t key,uint8_t index) {
|
|
||||||
uint8_t ret = 0;
|
|
||||||
size_t sizeof_uint8 = sizeof(uint8_t);
|
|
||||||
settings_get(key,index,(unsigned char*)&ret,&sizeof_uint8);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_add_uint8(settings_key_t key,uint8_t value) {
|
|
||||||
return settings_add(key,(const unsigned char*)&value,sizeof(uint8_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_set_uint8(settings_key_t key,uint8_t value) {
|
|
||||||
return settings_set(key,(const unsigned char*)&value,sizeof(uint8_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint16_t
|
|
||||||
settings_get_uint16(settings_key_t key,uint8_t index) {
|
|
||||||
uint16_t ret = 0;
|
|
||||||
size_t sizeof_uint16 = sizeof(uint16_t);
|
|
||||||
settings_get(key,index,(unsigned char*)&ret,&sizeof_uint16);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_add_uint16(settings_key_t key,uint16_t value) {
|
|
||||||
return settings_add(key,(const unsigned char*)&value,sizeof(uint16_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_set_uint16(settings_key_t key,uint16_t value) {
|
|
||||||
return settings_set(key,(const unsigned char*)&value,sizeof(uint16_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t
|
|
||||||
settings_get_uint32(settings_key_t key,uint8_t index) {
|
|
||||||
uint32_t ret = 0;
|
|
||||||
size_t sizeof_uint32 = sizeof(uint32_t);
|
|
||||||
settings_get(key,index,(unsigned char*)&ret,&sizeof_uint32);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_add_uint32(settings_key_t key,uint32_t value) {
|
|
||||||
return settings_add(key,(const unsigned char*)&value,sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_set_uint32(settings_key_t key,uint32_t value) {
|
|
||||||
return settings_set(key,(const unsigned char*)&value,sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint64_t
|
|
||||||
settings_get_uint64(settings_key_t key,uint8_t index) {
|
|
||||||
uint64_t ret = 0;
|
|
||||||
size_t sizeof_uint64 = sizeof(uint64_t);
|
|
||||||
settings_get(key,index,(unsigned char*)&ret,&sizeof_uint64);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_add_uint64(settings_key_t key,uint64_t value) {
|
|
||||||
return settings_add(key,(const unsigned char*)&value,sizeof(uint64_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline settings_status_t
|
|
||||||
settings_set_uint64(settings_key_t key,uint64_t value) {
|
|
||||||
return settings_set(key,(const unsigned char*)&value,sizeof(uint64_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
5
examples/settings-example/Makefile
Normal file
5
examples/settings-example/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
CONTIKI_PROJECT = settings-example
|
||||||
|
all: $(CONTIKI_PROJECT)
|
||||||
|
CFLAGS += -DCONTIKI_CONF_SETTINGS_MANAGER=1
|
||||||
|
CONTIKI = ../..
|
||||||
|
include $(CONTIKI)/Makefile.include
|
151
examples/settings-example/settings-example.c
Normal file
151
examples/settings-example/settings-example.c
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013, Robert Quattlebaum.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Institute nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* This file is part of the Contiki operating system.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file settings-example.c
|
||||||
|
* @brief Contiki example showing how to use the settings manager.
|
||||||
|
* @author Robert Quattlebaum <darco@deepdarc.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "contiki.h"
|
||||||
|
#include "lib/settings.h"
|
||||||
|
|
||||||
|
#include <stdio.h> /* For printf() */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS(settings_example_process, "Settings Example Process");
|
||||||
|
AUTOSTART_PROCESSES(&settings_example_process);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
PROCESS_THREAD(settings_example_process, ev, data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
settings_status_t status;
|
||||||
|
settings_iter_t iter;
|
||||||
|
char hostname[30];
|
||||||
|
uint16_t panid;
|
||||||
|
uint16_t channel;
|
||||||
|
|
||||||
|
PROCESS_BEGIN();
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Basic setting of parameters */
|
||||||
|
|
||||||
|
status = settings_set_uint16(SETTINGS_KEY_PAN_ID, 0xABCD);
|
||||||
|
if(SETTINGS_STATUS_OK != status) {
|
||||||
|
printf("settings-example: `set` failed: %d\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = settings_set_uint8(SETTINGS_KEY_CHANNEL, 26);
|
||||||
|
if(SETTINGS_STATUS_OK != status) {
|
||||||
|
printf("settings-example: `set` failed: %d\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = settings_set_cstr(SETTINGS_KEY_HOSTNAME, "contiki.local");
|
||||||
|
if(SETTINGS_STATUS_OK != status) {
|
||||||
|
printf("settings-example: `set` failed: %d\n", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Basic getting of parameters */
|
||||||
|
|
||||||
|
panid = settings_get_uint16(SETTINGS_KEY_PAN_ID, 0);
|
||||||
|
if(0xABCD != panid) {
|
||||||
|
printf("settings-example: `get` failed: value mismatch.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
channel = settings_get_uint16(SETTINGS_KEY_CHANNEL, 0);
|
||||||
|
if(26 != channel) {
|
||||||
|
printf("settings-example: `get` failed: value mismatch.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!settings_get_cstr(SETTINGS_KEY_HOSTNAME, 0, hostname, sizeof(hostname))) {
|
||||||
|
printf("settings-example: `get` failed: settings_get_cstr returned NULL\n");
|
||||||
|
} else if(strcmp(hostname, "contiki.local") != 0) {
|
||||||
|
printf("settings-example: `get` failed: value mismatch.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Adding multiple values with the same key */
|
||||||
|
|
||||||
|
for(i = 0; i < 10; i++) {
|
||||||
|
settings_add_uint8(TCC('e','x'), i + 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Reading multiple values with the same key */
|
||||||
|
|
||||||
|
for(i = 0; i < 10; i++) {
|
||||||
|
if(settings_get_uint8(TCC('e', 'x'), i) != i + 20) {
|
||||||
|
printf("settings-example: `get` failed: value mismatch.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Iterating thru all settings */
|
||||||
|
|
||||||
|
for(iter = settings_iter_begin(); iter; iter = settings_iter_next(iter)) {
|
||||||
|
settings_length_t len = settings_iter_get_value_length(iter);
|
||||||
|
eeprom_addr_t addr = settings_iter_get_value_addr(iter);
|
||||||
|
uint8_t byte;
|
||||||
|
|
||||||
|
union {
|
||||||
|
settings_key_t key;
|
||||||
|
char bytes[0];
|
||||||
|
} u;
|
||||||
|
|
||||||
|
u.key = settings_iter_get_key(iter);
|
||||||
|
|
||||||
|
if(u.bytes[0] >= 32 && u.bytes[0] < 127
|
||||||
|
&& u.bytes[1] >= 32 && u.bytes[1] < 127
|
||||||
|
) {
|
||||||
|
printf("settings-example: [%c%c] = <",u.bytes[0],u.bytes[1]);
|
||||||
|
} else {
|
||||||
|
printf("settings-example: <0x%04X> = <",u.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; len; len--, addr++) {
|
||||||
|
eeprom_read(addr, &byte, 1);
|
||||||
|
printf("%02X", byte);
|
||||||
|
if(len != 1) {
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(">\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("settings-example: Done.\n");
|
||||||
|
|
||||||
|
PROCESS_END();
|
||||||
|
}
|
||||||
|
/*---------------------------------------------------------------------------*/
|
|
@ -50,6 +50,12 @@
|
||||||
#define F_CPU 8000000UL
|
#define F_CPU 8000000UL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
|
/* Skip the last four bytes of the EEPROM, to leave room for things
|
||||||
|
* like the avrdude erase count and bootloader signaling. */
|
||||||
|
#define EEPROM_CONF_SIZE ((E2END + 1) - 4)
|
||||||
|
|
||||||
/* MCU_CONF_LOW_WEAR will remove the signature and eeprom from the .elf file */
|
/* MCU_CONF_LOW_WEAR will remove the signature and eeprom from the .elf file */
|
||||||
/* This reduces reprogramming wear during development */
|
/* This reduces reprogramming wear during development */
|
||||||
//#define MCU_CONF_LOW_WEAR 1
|
//#define MCU_CONF_LOW_WEAR 1
|
||||||
|
|
|
@ -58,6 +58,12 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
|
/* Skip the last four bytes of the EEPROM, to leave room for things
|
||||||
|
* like the avrdude erase count and bootloader signaling. */
|
||||||
|
#define EEPROM_CONF_SIZE ((E2END + 1) - 4)
|
||||||
|
|
||||||
/* The AVR tick interrupt usually is done with an 8 bit counter around 128 Hz.
|
/* The AVR tick interrupt usually is done with an 8 bit counter around 128 Hz.
|
||||||
* 125 Hz needs slightly more overhead during the interrupt, as does a 32 bit
|
* 125 Hz needs slightly more overhead during the interrupt, as does a 32 bit
|
||||||
* clock_time_t.
|
* clock_time_t.
|
||||||
|
|
|
@ -50,6 +50,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
|
/* Skip the last four bytes of the EEPROM, to leave room for things
|
||||||
|
* like the avrdude erase count and bootloader signaling. */
|
||||||
|
#define EEPROM_CONF_SIZE ((E2END + 1) - 4)
|
||||||
|
|
||||||
/* The AVR tick interrupt usually is done with an 8 bit counter around 128 Hz.
|
/* The AVR tick interrupt usually is done with an 8 bit counter around 128 Hz.
|
||||||
* 125 Hz needs slightly more overhead during the interrupt, as does a 32 bit
|
* 125 Hz needs slightly more overhead during the interrupt, as does a 32 bit
|
||||||
|
|
|
@ -38,6 +38,7 @@ webserver-ipv6/sky \
|
||||||
webserver-ipv6/econotag \
|
webserver-ipv6/econotag \
|
||||||
wget/minimal-net \
|
wget/minimal-net \
|
||||||
z1/z1 \
|
z1/z1 \
|
||||||
|
settings-example/avr-raven \
|
||||||
sensinode/sensinode \
|
sensinode/sensinode \
|
||||||
sensinode/border-router/sensinode \
|
sensinode/border-router/sensinode \
|
||||||
sensinode/udp-ipv6/sensinode \
|
sensinode/udp-ipv6/sensinode \
|
||||||
|
|
Loading…
Reference in a new issue