mirror of https://github.com/ARMmbed/mbed-os.git
NVStore: add the allocate_key API (instead of set_alloc_key)
Add the allocate_key API. This replaces the previously added set_alloc_key API (which allocates a key and sets the value at the same time). Reason for the change: Key allocation will typically be used by other storage features (like StorageLite), keeping the allocated keys in another location. Previous API created problems in the case key allocation and value setting couldn't be done at the same time (for instance, if the set value was derived from the allocated key, such as hash or CMAC).pull/6480/head
parent
9fd04c4a37
commit
c90182a02c
|
@ -133,9 +133,17 @@ static void nvstore_basic_functionality_test()
|
||||||
result = nvstore.set(19, 10, &(nvstore_testing_buf_set[3]));
|
result = nvstore.set(19, 10, &(nvstore_testing_buf_set[3]));
|
||||||
TEST_ASSERT_EQUAL(NVSTORE_ALREADY_EXISTS, result);
|
TEST_ASSERT_EQUAL(NVSTORE_ALREADY_EXISTS, result);
|
||||||
|
|
||||||
result = nvstore.set_alloc_key(key, 17, &(nvstore_testing_buf_set[3]));
|
result = nvstore.allocate_key(key, 3);
|
||||||
TEST_ASSERT_EQUAL(NVSTORE_NUM_PREDEFINED_KEYS, key);
|
TEST_ASSERT_EQUAL(NVSTORE_NUM_PREDEFINED_KEYS, key);
|
||||||
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
||||||
|
result = nvstore.set(NVSTORE_NUM_PREDEFINED_KEYS, 17, &(nvstore_testing_buf_set[3]));
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
||||||
|
|
||||||
|
result = nvstore.allocate_key(key, 3);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_NUM_PREDEFINED_KEYS + 1, key);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
||||||
|
result = nvstore.set(NVSTORE_NUM_PREDEFINED_KEYS + 1, 17, &(nvstore_testing_buf_set[3]));
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
||||||
|
|
||||||
// Make sure set items are also gotten OK after reset
|
// Make sure set items are also gotten OK after reset
|
||||||
result = nvstore.deinit();
|
result = nvstore.deinit();
|
||||||
|
@ -168,6 +176,20 @@ static void nvstore_basic_functionality_test()
|
||||||
TEST_ASSERT_EQUAL(17, actual_len_bytes);
|
TEST_ASSERT_EQUAL(17, actual_len_bytes);
|
||||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(&nvstore_testing_buf_set[3], nvstore_testing_buf_get, 17);
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(&nvstore_testing_buf_set[3], nvstore_testing_buf_get, 17);
|
||||||
|
|
||||||
|
result = nvstore.get(NVSTORE_NUM_PREDEFINED_KEYS + 1, 64, nvstore_testing_buf_get, actual_len_bytes);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
||||||
|
TEST_ASSERT_EQUAL(17, actual_len_bytes);
|
||||||
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(&nvstore_testing_buf_set[3], nvstore_testing_buf_get, 17);
|
||||||
|
|
||||||
|
result = nvstore.free_all_keys_by_owner(3);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
||||||
|
|
||||||
|
result = nvstore.get(NVSTORE_NUM_PREDEFINED_KEYS, 64, nvstore_testing_buf_get, actual_len_bytes);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_NOT_FOUND, result);
|
||||||
|
|
||||||
|
result = nvstore.get(NVSTORE_NUM_PREDEFINED_KEYS + 1, 64, nvstore_testing_buf_get, actual_len_bytes);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_NOT_FOUND, result);
|
||||||
|
|
||||||
result = nvstore.get(10, 65, nvstore_testing_buf_get, actual_len_bytes);
|
result = nvstore.get(10, 65, nvstore_testing_buf_get, actual_len_bytes);
|
||||||
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, result);
|
||||||
TEST_ASSERT_EQUAL(64, actual_len_bytes);
|
TEST_ASSERT_EQUAL(64, actual_len_bytes);
|
||||||
|
@ -346,6 +368,12 @@ static void nvstore_basic_functionality_test()
|
||||||
TEST_ASSERT_EQUAL(53, actual_len_bytes);
|
TEST_ASSERT_EQUAL(53, actual_len_bytes);
|
||||||
TEST_ASSERT_EQUAL_UINT8_ARRAY(&(nvstore_testing_buf_set[10]), nvstore_testing_buf_get, 53);
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(&(nvstore_testing_buf_set[10]), nvstore_testing_buf_get, 53);
|
||||||
|
|
||||||
|
result = nvstore.get(NVSTORE_NUM_PREDEFINED_KEYS, 64, nvstore_testing_buf_get, actual_len_bytes);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_NOT_FOUND, result);
|
||||||
|
|
||||||
|
result = nvstore.get(NVSTORE_NUM_PREDEFINED_KEYS + 1, 64, nvstore_testing_buf_get, actual_len_bytes);
|
||||||
|
TEST_ASSERT_EQUAL(NVSTORE_NOT_FOUND, result);
|
||||||
|
|
||||||
delete[] nvstore_testing_buf_set;
|
delete[] nvstore_testing_buf_set;
|
||||||
delete[] nvstore_testing_buf_get;
|
delete[] nvstore_testing_buf_get;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,15 +42,24 @@ static const uint16_t last_reserved_key = master_record_key;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint16_t key_and_flags;
|
uint16_t key_and_flags;
|
||||||
uint16_t size;
|
uint16_t size_and_owner;
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
} nvstore_record_header_t;
|
} nvstore_record_header_t;
|
||||||
|
|
||||||
static const uint32_t offs_by_key_area_mask = 0x80000000UL;
|
static const uint32_t offs_by_key_area_mask = 0x00000001UL;
|
||||||
static const uint32_t offs_by_key_set_once_mask = 0x40000000UL;
|
static const uint32_t offs_by_key_set_once_mask = 0x00000002UL;
|
||||||
static const uint32_t offs_by_key_flag_mask = 0xC0000000UL;
|
static const uint32_t offs_by_key_allocated_mask = 0x00000004UL;
|
||||||
static const unsigned int offs_by_key_area_bit_pos = 31;
|
static const uint32_t offs_by_key_flag_mask = 0x00000007UL;
|
||||||
static const unsigned int offs_by_key_set_once_bit_pos = 30;
|
static const uint32_t offs_by_key_offset_mask = 0x0FFFFFF8UL;
|
||||||
|
static const uint32_t offs_by_key_owner_mask = 0xF0000000UL;
|
||||||
|
|
||||||
|
static const unsigned int offs_by_key_area_bit_pos = 0;
|
||||||
|
static const unsigned int offs_by_key_set_once_bit_pos = 1;
|
||||||
|
static const unsigned int offs_by_key_owner_bit_pos = 28;
|
||||||
|
|
||||||
|
static const uint16_t size_mask = 0x0FFF;
|
||||||
|
static const uint16_t owner_mask = 0xF000;
|
||||||
|
static const unsigned int owner_bit_pos = 12;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
|
@ -59,6 +68,7 @@ typedef struct {
|
||||||
} master_record_data_t;
|
} master_record_data_t;
|
||||||
|
|
||||||
static const uint32_t min_area_size = 4096;
|
static const uint32_t min_area_size = 4096;
|
||||||
|
static const uint32_t max_data_size = 4096;
|
||||||
|
|
||||||
static const int num_write_retries = 16;
|
static const int num_write_retries = 16;
|
||||||
|
|
||||||
|
@ -134,7 +144,6 @@ NVStore::NVStore() : _init_done(0), _init_attempts(0), _active_area(0), _max_key
|
||||||
_active_area_version(0), _free_space_offset(0), _size(0), _mutex(0), _offset_by_key(0), _flash(0),
|
_active_area_version(0), _free_space_offset(0), _size(0), _mutex(0), _offset_by_key(0), _flash(0),
|
||||||
_min_prog_size(0), _page_buf(0)
|
_min_prog_size(0), _page_buf(0)
|
||||||
{
|
{
|
||||||
memset(_flash_area_params, 0, sizeof(_flash_area_params));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NVStore::~NVStore()
|
NVStore::~NVStore()
|
||||||
|
@ -306,7 +315,7 @@ int NVStore::calc_empty_space(uint8_t area, uint32_t &offset)
|
||||||
|
|
||||||
int NVStore::read_record(uint8_t area, uint32_t offset, uint16_t buf_size, void *buf,
|
int NVStore::read_record(uint8_t area, uint32_t offset, uint16_t buf_size, void *buf,
|
||||||
uint16_t &actual_size, int validate_only, int &valid,
|
uint16_t &actual_size, int validate_only, int &valid,
|
||||||
uint16_t &key, uint16_t &flags, uint32_t &next_offset)
|
uint16_t &key, uint16_t &flags, uint8_t &owner, uint32_t &next_offset)
|
||||||
{
|
{
|
||||||
uint8_t int_buf[128];
|
uint8_t int_buf[128];
|
||||||
void *buf_ptr;
|
void *buf_ptr;
|
||||||
|
@ -327,13 +336,14 @@ int NVStore::read_record(uint8_t area, uint32_t offset, uint16_t buf_size, void
|
||||||
actual_size = 0;
|
actual_size = 0;
|
||||||
key = header.key_and_flags & ~header_flag_mask;
|
key = header.key_and_flags & ~header_flag_mask;
|
||||||
flags = header.key_and_flags & header_flag_mask;
|
flags = header.key_and_flags & header_flag_mask;
|
||||||
|
owner = (header.size_and_owner & owner_mask) >> owner_bit_pos;
|
||||||
|
|
||||||
if ((key >= _max_keys) && (key != master_record_key)) {
|
if ((key >= _max_keys) && (key != master_record_key)) {
|
||||||
valid = 0;
|
valid = 0;
|
||||||
return NVSTORE_SUCCESS;
|
return NVSTORE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_size = header.size;
|
data_size = header.size_and_owner & size_mask;
|
||||||
offset += sizeof(header);
|
offset += sizeof(header);
|
||||||
|
|
||||||
// In case of validate only enabled, we use our internal buffer for data reading,
|
// In case of validate only enabled, we use our internal buffer for data reading,
|
||||||
|
@ -368,13 +378,13 @@ int NVStore::read_record(uint8_t area, uint32_t offset, uint16_t buf_size, void
|
||||||
return NVSTORE_SUCCESS;
|
return NVSTORE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
actual_size = header.size;
|
actual_size = header.size_and_owner & size_mask;
|
||||||
next_offset = align_up(offset, _min_prog_size);
|
next_offset = align_up(offset, _min_prog_size);
|
||||||
|
|
||||||
return NVSTORE_SUCCESS;
|
return NVSTORE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NVStore::write_record(uint8_t area, uint32_t offset, uint16_t key, uint16_t flags,
|
int NVStore::write_record(uint8_t area, uint32_t offset, uint16_t key, uint16_t flags, uint8_t owner,
|
||||||
uint32_t data_size, const void *data_buf, uint32_t &next_offset)
|
uint32_t data_size, const void *data_buf, uint32_t &next_offset)
|
||||||
{
|
{
|
||||||
nvstore_record_header_t header;
|
nvstore_record_header_t header;
|
||||||
|
@ -383,7 +393,7 @@ int NVStore::write_record(uint8_t area, uint32_t offset, uint16_t key, uint16_t
|
||||||
uint8_t *prog_buf;
|
uint8_t *prog_buf;
|
||||||
|
|
||||||
header.key_and_flags = key | flags;
|
header.key_and_flags = key | flags;
|
||||||
header.size = data_size;
|
header.size_and_owner = data_size | (owner << owner_bit_pos);
|
||||||
header.crc = 0; // Satisfy compiler
|
header.crc = 0; // Satisfy compiler
|
||||||
crc = crc32(crc, sizeof(header) - sizeof(header.crc), (uint8_t *) &header);
|
crc = crc32(crc, sizeof(header) - sizeof(header.crc), (uint8_t *) &header);
|
||||||
if (data_size) {
|
if (data_size) {
|
||||||
|
@ -436,7 +446,7 @@ int NVStore::write_master_record(uint8_t area, uint16_t version, uint32_t &next_
|
||||||
master_rec.version = version;
|
master_rec.version = version;
|
||||||
master_rec.reserved1 = 0;
|
master_rec.reserved1 = 0;
|
||||||
master_rec.reserved2 = 0;
|
master_rec.reserved2 = 0;
|
||||||
return write_record(area, 0, master_record_key, 0, sizeof(master_rec),
|
return write_record(area, 0, master_record_key, 0, 0, sizeof(master_rec),
|
||||||
&master_rec, next_offset);
|
&master_rec, next_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +476,7 @@ int NVStore::copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_of
|
||||||
}
|
}
|
||||||
|
|
||||||
header = (nvstore_record_header_t *) read_buf;
|
header = (nvstore_record_header_t *) read_buf;
|
||||||
record_size = sizeof(nvstore_record_header_t) + header->size;
|
record_size = sizeof(nvstore_record_header_t) + (header->size_and_owner & size_mask);
|
||||||
|
|
||||||
// No need to copy records whose flags indicate deletion
|
// No need to copy records whose flags indicate deletion
|
||||||
if (header->key_and_flags & delete_item_flag) {
|
if (header->key_and_flags & delete_item_flag) {
|
||||||
|
@ -508,7 +518,7 @@ int NVStore::copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_of
|
||||||
return NVSTORE_SUCCESS;
|
return NVSTORE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NVStore::garbage_collection(uint16_t key, uint16_t flags, uint16_t buf_size, const void *buf)
|
int NVStore::garbage_collection(uint16_t key, uint16_t flags, uint8_t owner, uint16_t buf_size, const void *buf)
|
||||||
{
|
{
|
||||||
uint32_t curr_offset, new_area_offset, next_offset;
|
uint32_t curr_offset, new_area_offset, next_offset;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -520,7 +530,7 @@ int NVStore::garbage_collection(uint16_t key, uint16_t flags, uint16_t buf_size,
|
||||||
// otherwise we may either write it twice (if already included), or lose it in case we decide
|
// otherwise we may either write it twice (if already included), or lose it in case we decide
|
||||||
// to skip it at garbage collection phase (and the system crashes).
|
// to skip it at garbage collection phase (and the system crashes).
|
||||||
if ((key != no_key) && !(flags & delete_item_flag)) {
|
if ((key != no_key) && !(flags & delete_item_flag)) {
|
||||||
ret = write_record(1 - _active_area, new_area_offset, key, 0, buf_size, buf, next_offset);
|
ret = write_record(1 - _active_area, new_area_offset, key, 0, owner, buf_size, buf, next_offset);
|
||||||
if (ret != NVSTORE_SUCCESS) {
|
if (ret != NVSTORE_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -533,7 +543,7 @@ int NVStore::garbage_collection(uint16_t key, uint16_t flags, uint16_t buf_size,
|
||||||
// to the other area.
|
// to the other area.
|
||||||
for (key = 0; key < _max_keys; key++) {
|
for (key = 0; key < _max_keys; key++) {
|
||||||
curr_offset = _offset_by_key[key];
|
curr_offset = _offset_by_key[key];
|
||||||
uint16_t save_flags = curr_offset & offs_by_key_area_mask;
|
uint16_t save_flags = curr_offset & offs_by_key_flag_mask & ~offs_by_key_area_mask;
|
||||||
curr_area = (uint8_t)(curr_offset >> offs_by_key_area_bit_pos) & 1;
|
curr_area = (uint8_t)(curr_offset >> offs_by_key_area_bit_pos) & 1;
|
||||||
curr_offset &= ~offs_by_key_flag_mask;
|
curr_offset &= ~offs_by_key_flag_mask;
|
||||||
if ((!curr_offset) || (curr_area != _active_area)) {
|
if ((!curr_offset) || (curr_area != _active_area)) {
|
||||||
|
@ -575,7 +585,7 @@ int NVStore::do_get(uint16_t key, uint16_t buf_size, void *buf, uint16_t &actual
|
||||||
int valid;
|
int valid;
|
||||||
uint32_t record_offset, next_offset;
|
uint32_t record_offset, next_offset;
|
||||||
uint16_t read_type, flags;
|
uint16_t read_type, flags;
|
||||||
uint8_t area;
|
uint8_t area, owner;
|
||||||
|
|
||||||
if (!_init_done) {
|
if (!_init_done) {
|
||||||
ret = init();
|
ret = init();
|
||||||
|
@ -597,19 +607,19 @@ int NVStore::do_get(uint16_t key, uint16_t buf_size, void *buf, uint16_t &actual
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex->lock();
|
_mutex->lock();
|
||||||
|
|
||||||
record_offset = _offset_by_key[key];
|
record_offset = _offset_by_key[key];
|
||||||
|
area = (uint8_t)(record_offset >> offs_by_key_area_bit_pos) & 1;
|
||||||
|
record_offset &= offs_by_key_offset_mask;
|
||||||
|
|
||||||
if (!record_offset) {
|
if (!record_offset) {
|
||||||
_mutex->unlock();
|
_mutex->unlock();
|
||||||
return NVSTORE_NOT_FOUND;
|
return NVSTORE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
area = (uint8_t)(record_offset >> offs_by_key_area_bit_pos) & 1;
|
|
||||||
record_offset &= ~offs_by_key_flag_mask;
|
|
||||||
|
|
||||||
ret = read_record(area, record_offset, buf_size, buf,
|
ret = read_record(area, record_offset, buf_size, buf,
|
||||||
actual_size, validate_only, valid,
|
actual_size, validate_only, valid,
|
||||||
read_type, flags, next_offset);
|
read_type, flags, owner, next_offset);
|
||||||
if ((ret == NVSTORE_SUCCESS) && !valid) {
|
if ((ret == NVSTORE_SUCCESS) && !valid) {
|
||||||
ret = NVSTORE_DATA_CORRUPT;
|
ret = NVSTORE_DATA_CORRUPT;
|
||||||
}
|
}
|
||||||
|
@ -628,11 +638,12 @@ int NVStore::get_item_size(uint16_t key, uint16_t &actual_size)
|
||||||
return do_get(key, 0, NULL, actual_size, 1);
|
return do_get(key, 0, NULL, actual_size, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int NVStore::do_set(uint16_t &key, uint16_t buf_size, const void *buf, uint16_t flags)
|
int NVStore::do_set(uint16_t key, uint16_t buf_size, const void *buf, uint16_t flags)
|
||||||
{
|
{
|
||||||
int ret = NVSTORE_SUCCESS;
|
int ret = NVSTORE_SUCCESS;
|
||||||
uint32_t record_offset, record_size, new_free_space;
|
uint32_t record_offset, record_size, new_free_space;
|
||||||
uint32_t next_offset;
|
uint32_t next_offset;
|
||||||
|
uint8_t owner;
|
||||||
|
|
||||||
if (!_init_done) {
|
if (!_init_done) {
|
||||||
ret = init();
|
ret = init();
|
||||||
|
@ -641,11 +652,11 @@ int NVStore::do_set(uint16_t &key, uint16_t buf_size, const void *buf, uint16_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((key != no_key) && (key >= _max_keys)) {
|
if (key >= _max_keys) {
|
||||||
return NVSTORE_BAD_VALUE;
|
return NVSTORE_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((key == no_key) && (flags & delete_item_flag)) {
|
if (buf_size >= max_data_size) {
|
||||||
return NVSTORE_BAD_VALUE;
|
return NVSTORE_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,11 +664,11 @@ int NVStore::do_set(uint16_t &key, uint16_t buf_size, const void *buf, uint16_t
|
||||||
buf_size = 0;
|
buf_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & delete_item_flag) && !_offset_by_key[key]) {
|
if ((flags & delete_item_flag) && !(_offset_by_key[key] & offs_by_key_offset_mask)) {
|
||||||
return NVSTORE_NOT_FOUND;
|
return NVSTORE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((key != no_key) && (_offset_by_key[key] & offs_by_key_set_once_mask)) {
|
if (_offset_by_key[key] & offs_by_key_set_once_mask) {
|
||||||
return NVSTORE_ALREADY_EXISTS;
|
return NVSTORE_ALREADY_EXISTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,40 +676,31 @@ int NVStore::do_set(uint16_t &key, uint16_t buf_size, const void *buf, uint16_t
|
||||||
|
|
||||||
_mutex->lock();
|
_mutex->lock();
|
||||||
|
|
||||||
if (key == no_key) {
|
owner = (_offset_by_key[key] & offs_by_key_owner_mask) >> offs_by_key_owner_bit_pos;
|
||||||
for (key = NVSTORE_NUM_PREDEFINED_KEYS; key < _max_keys; key++) {
|
|
||||||
if (!_offset_by_key[key]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (key == _max_keys) {
|
|
||||||
return NVSTORE_NO_FREE_KEY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new_free_space = core_util_atomic_incr_u32(&_free_space_offset, record_size);
|
new_free_space = core_util_atomic_incr_u32(&_free_space_offset, record_size);
|
||||||
record_offset = new_free_space - record_size;
|
record_offset = new_free_space - record_size;
|
||||||
|
|
||||||
// If we cross the area limit, we need to invoke GC.
|
// If we cross the area limit, we need to invoke GC.
|
||||||
if (new_free_space >= _size) {
|
if (new_free_space >= _size) {
|
||||||
ret = garbage_collection(key, flags, buf_size, buf);
|
ret = garbage_collection(key, flags, owner, buf_size, buf);
|
||||||
_mutex->unlock();
|
_mutex->unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now write the record
|
// Now write the record
|
||||||
ret = write_record(_active_area, record_offset, key, flags, buf_size, buf, next_offset);
|
ret = write_record(_active_area, record_offset, key, flags, owner, buf_size, buf, next_offset);
|
||||||
if (ret != NVSTORE_SUCCESS) {
|
if (ret != NVSTORE_SUCCESS) {
|
||||||
_mutex->unlock();
|
_mutex->unlock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update _offset_by_key. High bit indicates area.
|
// Update _offset_by_key
|
||||||
if (flags & delete_item_flag) {
|
if (flags & delete_item_flag) {
|
||||||
_offset_by_key[key] = 0;
|
_offset_by_key[key] = 0;
|
||||||
} else {
|
} else {
|
||||||
_offset_by_key[key] = record_offset | (_active_area << offs_by_key_area_bit_pos) |
|
_offset_by_key[key] = record_offset | (_active_area << offs_by_key_area_bit_pos) |
|
||||||
(((flags & set_once_flag) != 0) << offs_by_key_set_once_bit_pos);
|
(((flags & set_once_flag) != 0) << offs_by_key_set_once_bit_pos) |
|
||||||
|
(owner << offs_by_key_owner_bit_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex->unlock();
|
_mutex->unlock();
|
||||||
|
@ -716,10 +718,67 @@ int NVStore::set_once(uint16_t key, uint16_t buf_size, const void *buf)
|
||||||
return do_set(key, buf_size, buf, set_once_flag);
|
return do_set(key, buf_size, buf, set_once_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
int NVStore::set_alloc_key(uint16_t &key, uint16_t buf_size, const void *buf)
|
int NVStore::allocate_key(uint16_t &key, uint8_t owner)
|
||||||
{
|
{
|
||||||
key = no_key;
|
int ret = NVSTORE_SUCCESS;
|
||||||
return do_set(key, buf_size, buf, 0);
|
|
||||||
|
if ((owner == NVSTORE_UNSPECIFIED_OWNER) || (owner >= NVSTORE_MAX_OWNERS)) {
|
||||||
|
return NVSTORE_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_init_done) {
|
||||||
|
ret = init();
|
||||||
|
if (ret != NVSTORE_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mutex->lock();
|
||||||
|
|
||||||
|
for (key = NVSTORE_NUM_PREDEFINED_KEYS; key < _max_keys; key++) {
|
||||||
|
if (!_offset_by_key[key]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key == _max_keys) {
|
||||||
|
ret = NVSTORE_NO_FREE_KEY;
|
||||||
|
} else {
|
||||||
|
_offset_by_key[key] |= offs_by_key_allocated_mask | (owner << offs_by_key_owner_bit_pos);
|
||||||
|
}
|
||||||
|
_mutex->unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NVStore::free_all_keys_by_owner(uint8_t owner)
|
||||||
|
{
|
||||||
|
int ret = NVSTORE_SUCCESS;
|
||||||
|
|
||||||
|
if ((owner == NVSTORE_UNSPECIFIED_OWNER) || (owner >= NVSTORE_MAX_OWNERS)) {
|
||||||
|
return NVSTORE_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_init_done) {
|
||||||
|
ret = init();
|
||||||
|
if (ret != NVSTORE_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mutex->lock();
|
||||||
|
|
||||||
|
for (uint16_t key = 0; key < _max_keys; key++) {
|
||||||
|
uint8_t curr_owner = (_offset_by_key[key] & offs_by_key_owner_mask) >> offs_by_key_owner_bit_pos;
|
||||||
|
if (curr_owner != owner) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret = remove(key);
|
||||||
|
if (ret) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mutex->unlock();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NVStore::remove(uint16_t key)
|
int NVStore::remove(uint16_t key)
|
||||||
|
@ -740,6 +799,7 @@ int NVStore::init()
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
uint16_t versions[NVSTORE_NUM_AREAS];
|
uint16_t versions[NVSTORE_NUM_AREAS];
|
||||||
uint16_t actual_size;
|
uint16_t actual_size;
|
||||||
|
uint8_t owner;
|
||||||
|
|
||||||
if (_init_done) {
|
if (_init_done) {
|
||||||
return NVSTORE_SUCCESS;
|
return NVSTORE_SUCCESS;
|
||||||
|
@ -800,7 +860,7 @@ int NVStore::init()
|
||||||
master_record_data_t master_rec;
|
master_record_data_t master_rec;
|
||||||
ret = read_record(area, 0, sizeof(master_rec), &master_rec,
|
ret = read_record(area, 0, sizeof(master_rec), &master_rec,
|
||||||
actual_size, 0, valid,
|
actual_size, 0, valid,
|
||||||
key, flags, next_offset);
|
key, flags, owner, next_offset);
|
||||||
MBED_ASSERT((ret == NVSTORE_SUCCESS) || (ret == NVSTORE_BUFF_TOO_SMALL));
|
MBED_ASSERT((ret == NVSTORE_SUCCESS) || (ret == NVSTORE_BUFF_TOO_SMALL));
|
||||||
if (ret == NVSTORE_BUFF_TOO_SMALL) {
|
if (ret == NVSTORE_BUFF_TOO_SMALL) {
|
||||||
// Buf too small error means that we have a corrupt master record -
|
// Buf too small error means that we have a corrupt master record -
|
||||||
|
@ -854,20 +914,21 @@ int NVStore::init()
|
||||||
while (_free_space_offset < free_space_offset_of_area[_active_area]) {
|
while (_free_space_offset < free_space_offset_of_area[_active_area]) {
|
||||||
ret = read_record(_active_area, _free_space_offset, 0, NULL,
|
ret = read_record(_active_area, _free_space_offset, 0, NULL,
|
||||||
actual_size, 1, valid,
|
actual_size, 1, valid,
|
||||||
key, flags, next_offset);
|
key, flags, owner, next_offset);
|
||||||
MBED_ASSERT(ret == NVSTORE_SUCCESS);
|
MBED_ASSERT(ret == NVSTORE_SUCCESS);
|
||||||
|
|
||||||
// In case we have a faulty record, this probably means that the system crashed when written.
|
// In case we have a faulty record, this probably means that the system crashed when written.
|
||||||
// Perform a garbage collection, to make the the other area valid.
|
// Perform a garbage collection, to make the the other area valid.
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
ret = garbage_collection(no_key, 0, 0, NULL);
|
ret = garbage_collection(no_key, 0, 0, 0, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (flags & delete_item_flag) {
|
if (flags & delete_item_flag) {
|
||||||
_offset_by_key[key] = 0;
|
_offset_by_key[key] = 0;
|
||||||
} else {
|
} else {
|
||||||
_offset_by_key[key] = _free_space_offset | (_active_area << offs_by_key_area_bit_pos) |
|
_offset_by_key[key] = _free_space_offset | (_active_area << offs_by_key_area_bit_pos) |
|
||||||
(((flags & set_once_flag) != 0) << offs_by_key_set_once_bit_pos);
|
(((flags & set_once_flag) != 0) << offs_by_key_set_once_bit_pos) |
|
||||||
|
(owner << offs_by_key_owner_bit_pos);
|
||||||
}
|
}
|
||||||
_free_space_offset = next_offset;
|
_free_space_offset = next_offset;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,12 @@ typedef enum {
|
||||||
NVSTORE_NUM_PREDEFINED_KEYS
|
NVSTORE_NUM_PREDEFINED_KEYS
|
||||||
} nvstore_predefined_keys_e;
|
} nvstore_predefined_keys_e;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
NVSTORE_UNSPECIFIED_OWNER = 0,
|
||||||
|
// All owners (by features) should be specified here.
|
||||||
|
NVSTORE_MAX_OWNERS = 16
|
||||||
|
} nvstore_owner_e;
|
||||||
|
|
||||||
#ifndef NVSTORE_MAX_KEYS
|
#ifndef NVSTORE_MAX_KEYS
|
||||||
#define NVSTORE_MAX_KEYS ((uint16_t)NVSTORE_NUM_PREDEFINED_KEYS)
|
#define NVSTORE_MAX_KEYS ((uint16_t)NVSTORE_NUM_PREDEFINED_KEYS)
|
||||||
#endif
|
#endif
|
||||||
|
@ -159,22 +165,28 @@ public:
|
||||||
int set(uint16_t key, uint16_t buf_size, const void *buf);
|
int set(uint16_t key, uint16_t buf_size, const void *buf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Programs one item of data on Flash, allocating a key.
|
* @brief Allocate a free key (to be used later in a set operation).
|
||||||
*
|
*
|
||||||
* @param[out] key Returned key of stored item.
|
* @param[out] key Returned key of stored item.
|
||||||
* @param[in] buf_size Item size in bytes.
|
* @param[in] owner Owner of allocated key.
|
||||||
* @param[in] buf Buffer containing data.
|
*
|
||||||
|
* @returns NVSTORE_SUCCESS Key was successfully allocated.
|
||||||
|
* NVSTORE_NO_FREE_KEY Couldn't allocate a key for this call.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int allocate_key(uint16_t &key, uint8_t owner = NVSTORE_UNSPECIFIED_OWNER);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free all allocated keys that belong to a specific owner.
|
||||||
|
*
|
||||||
|
* @param[in] owner Owner.
|
||||||
*
|
*
|
||||||
* @returns NVSTORE_SUCCESS Value was successfully written on Flash.
|
* @returns NVSTORE_SUCCESS Value was successfully written on Flash.
|
||||||
* NVSTORE_WRITE_ERROR Physical error writing data.
|
* NVSTORE_WRITE_ERROR Physical error writing data.
|
||||||
* NVSTORE_BAD_VALUE Bad value in any of the parameters.
|
* NVSTORE_BAD_VALUE Bad value in any of the parameters.
|
||||||
* NVSTORE_FLASH_AREA_TOO_SMALL
|
|
||||||
* Not enough space in Flash area.
|
|
||||||
* NVSTORE_ALREADY_EXISTS Item set with write once API already exists.
|
|
||||||
* NVSTORE_NO_FREE_KEY Couldn't allocate a key for this call.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int set_alloc_key(uint16_t &key, uint16_t buf_size, const void *buf);
|
int free_all_keys_by_owner(uint8_t owner);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Programs one item of data on Flash, given key, allowing no consequent sets to this key.
|
* @brief Programs one item of data on Flash, given key, allowing no consequent sets to this key.
|
||||||
|
@ -344,13 +356,14 @@ private:
|
||||||
* @param[out] valid Is the record valid.
|
* @param[out] valid Is the record valid.
|
||||||
* @param[out] key Record key.
|
* @param[out] key Record key.
|
||||||
* @param[out] flags Record flags.
|
* @param[out] flags Record flags.
|
||||||
|
* @param[out] owner Owner.
|
||||||
* @param[out] next_offset Offset of next record.
|
* @param[out] next_offset Offset of next record.
|
||||||
*
|
*
|
||||||
* @returns 0 for success, nonzero for failure.
|
* @returns 0 for success, nonzero for failure.
|
||||||
*/
|
*/
|
||||||
int read_record(uint8_t area, uint32_t offset, uint16_t buf_size, void *buf,
|
int read_record(uint8_t area, uint32_t offset, uint16_t buf_size, void *buf,
|
||||||
uint16_t &actual_size, int validate_only, int &valid,
|
uint16_t &actual_size, int validate_only, int &valid,
|
||||||
uint16_t &key, uint16_t &flags, uint32_t &next_offset);
|
uint16_t &key, uint16_t &flags, uint8_t &owner, uint32_t &next_offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write an NVStore record from a given location.
|
* @brief Write an NVStore record from a given location.
|
||||||
|
@ -359,13 +372,14 @@ private:
|
||||||
* @param[in] offset Offset of record in area.
|
* @param[in] offset Offset of record in area.
|
||||||
* @param[in] key Record key.
|
* @param[in] key Record key.
|
||||||
* @param[in] flags Record flags.
|
* @param[in] flags Record flags.
|
||||||
|
* @param[in] owner Owner.
|
||||||
* @param[in] data_size Data size (bytes).
|
* @param[in] data_size Data size (bytes).
|
||||||
* @param[in] data_buf Data buffer.
|
* @param[in] data_buf Data buffer.
|
||||||
* @param[out] next_offset Offset of next record.
|
* @param[out] next_offset Offset of next record.
|
||||||
*
|
*
|
||||||
* @returns 0 for success, nonzero for failure.
|
* @returns 0 for success, nonzero for failure.
|
||||||
*/
|
*/
|
||||||
int write_record(uint8_t area, uint32_t offset, uint16_t key, uint16_t flags,
|
int write_record(uint8_t area, uint32_t offset, uint16_t key, uint16_t flags, uint8_t owner,
|
||||||
uint32_t data_size, const void *data_buf, uint32_t &next_offset);
|
uint32_t data_size, const void *data_buf, uint32_t &next_offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -398,12 +412,13 @@ private:
|
||||||
*
|
*
|
||||||
* @param[in] key Record key.
|
* @param[in] key Record key.
|
||||||
* @param[in] flags Record flags.
|
* @param[in] flags Record flags.
|
||||||
|
* @param[in] owner Owner.
|
||||||
* @param[in] buf_size Data size (bytes).
|
* @param[in] buf_size Data size (bytes).
|
||||||
* @param[in] buf Data buffer.
|
* @param[in] buf Data buffer.
|
||||||
*
|
*
|
||||||
* @returns 0 for success, nonzero for failure.
|
* @returns 0 for success, nonzero for failure.
|
||||||
*/
|
*/
|
||||||
int garbage_collection(uint16_t key, uint16_t flags, uint16_t buf_size, const void *buf);
|
int garbage_collection(uint16_t key, uint16_t flags, uint8_t owner, uint16_t buf_size, const void *buf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Actual logics of get API (covers also get size API).
|
* @brief Actual logics of get API (covers also get size API).
|
||||||
|
@ -422,14 +437,14 @@ private:
|
||||||
/**
|
/**
|
||||||
* @brief Actual logics of set API (covers also set_once and remove APIs).
|
* @brief Actual logics of set API (covers also set_once and remove APIs).
|
||||||
*
|
*
|
||||||
* @param[out] key key (both input and output).
|
* @param[in] key key.
|
||||||
* @param[in] buf_size Buffer size (bytes).
|
* @param[in] buf_size Buffer size (bytes).
|
||||||
* @param[in] buf Input Buffer.
|
* @param[in] buf Input Buffer.
|
||||||
* @param[in] flags Record flags.
|
* @param[in] flags Record flags.
|
||||||
*
|
*
|
||||||
* @returns 0 for success, nonzero for failure.
|
* @returns 0 for success, nonzero for failure.
|
||||||
*/
|
*/
|
||||||
int do_set(uint16_t &key, uint16_t buf_size, const void *buf, uint16_t flags);
|
int do_set(uint16_t key, uint16_t buf_size, const void *buf, uint16_t flags);
|
||||||
|
|
||||||
};
|
};
|
||||||
/** @}*/
|
/** @}*/
|
||||||
|
|
Loading…
Reference in New Issue