BA / SerialCom

Fork of OmniWheels by Gustav Atmel

Committer:
gustavatmel
Date:
Tue May 01 15:47:08 2018 +0000
Revision:
1:9c5af431a1f1
sdf

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gustavatmel 1:9c5af431a1f1 1 /*
gustavatmel 1:9c5af431a1f1 2 * Copyright (c) 2018 ARM Limited. All rights reserved.
gustavatmel 1:9c5af431a1f1 3 * SPDX-License-Identifier: Apache-2.0
gustavatmel 1:9c5af431a1f1 4 * Licensed under the Apache License, Version 2.0 (the License); you may
gustavatmel 1:9c5af431a1f1 5 * not use this file except in compliance with the License.
gustavatmel 1:9c5af431a1f1 6 * You may obtain a copy of the License at
gustavatmel 1:9c5af431a1f1 7 *
gustavatmel 1:9c5af431a1f1 8 * http://www.apache.org/licenses/LICENSE-2.0
gustavatmel 1:9c5af431a1f1 9 *
gustavatmel 1:9c5af431a1f1 10 * Unless required by applicable law or agreed to in writing, software
gustavatmel 1:9c5af431a1f1 11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
gustavatmel 1:9c5af431a1f1 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
gustavatmel 1:9c5af431a1f1 13 * See the License for the specific language governing permissions and
gustavatmel 1:9c5af431a1f1 14 * limitations under the License.
gustavatmel 1:9c5af431a1f1 15 */
gustavatmel 1:9c5af431a1f1 16
gustavatmel 1:9c5af431a1f1 17 // ----------------------------------------------------------- Includes -----------------------------------------------------------
gustavatmel 1:9c5af431a1f1 18
gustavatmel 1:9c5af431a1f1 19 #include "nvstore.h"
gustavatmel 1:9c5af431a1f1 20
gustavatmel 1:9c5af431a1f1 21 #if NVSTORE_ENABLED
gustavatmel 1:9c5af431a1f1 22
gustavatmel 1:9c5af431a1f1 23 #include "FlashIAP.h"
gustavatmel 1:9c5af431a1f1 24 #include "mbed_critical.h"
gustavatmel 1:9c5af431a1f1 25 #include "mbed_assert.h"
gustavatmel 1:9c5af431a1f1 26 #include "Thread.h"
gustavatmel 1:9c5af431a1f1 27 #include "mbed_wait_api.h"
gustavatmel 1:9c5af431a1f1 28 #include <algorithm>
gustavatmel 1:9c5af431a1f1 29 #include <string.h>
gustavatmel 1:9c5af431a1f1 30 #include <stdio.h>
gustavatmel 1:9c5af431a1f1 31
gustavatmel 1:9c5af431a1f1 32 // --------------------------------------------------------- Definitions ----------------------------------------------------------
gustavatmel 1:9c5af431a1f1 33
gustavatmel 1:9c5af431a1f1 34 static const uint16_t delete_item_flag = 0x8000;
gustavatmel 1:9c5af431a1f1 35 static const uint16_t set_once_flag = 0x4000;
gustavatmel 1:9c5af431a1f1 36 static const uint16_t header_flag_mask = 0xF000;
gustavatmel 1:9c5af431a1f1 37
gustavatmel 1:9c5af431a1f1 38 static const uint16_t master_record_key = 0xFFE;
gustavatmel 1:9c5af431a1f1 39 static const uint16_t no_key = 0xFFF;
gustavatmel 1:9c5af431a1f1 40 static const uint16_t last_reserved_key = master_record_key;
gustavatmel 1:9c5af431a1f1 41
gustavatmel 1:9c5af431a1f1 42 typedef struct
gustavatmel 1:9c5af431a1f1 43 {
gustavatmel 1:9c5af431a1f1 44 uint16_t key_and_flags;
gustavatmel 1:9c5af431a1f1 45 uint16_t size;
gustavatmel 1:9c5af431a1f1 46 uint32_t crc;
gustavatmel 1:9c5af431a1f1 47 } nvstore_record_header_t;
gustavatmel 1:9c5af431a1f1 48
gustavatmel 1:9c5af431a1f1 49 static const uint32_t offs_by_key_area_mask = 0x80000000UL;
gustavatmel 1:9c5af431a1f1 50 static const uint32_t offs_by_key_set_once_mask = 0x40000000UL;
gustavatmel 1:9c5af431a1f1 51 static const uint32_t offs_by_key_flag_mask = 0xC0000000UL;
gustavatmel 1:9c5af431a1f1 52 static const unsigned int offs_by_key_area_bit_pos = 31;
gustavatmel 1:9c5af431a1f1 53 static const unsigned int offs_by_key_set_once_bit_pos = 30;
gustavatmel 1:9c5af431a1f1 54
gustavatmel 1:9c5af431a1f1 55 typedef struct {
gustavatmel 1:9c5af431a1f1 56 uint16_t version;
gustavatmel 1:9c5af431a1f1 57 uint16_t reserved1;
gustavatmel 1:9c5af431a1f1 58 uint32_t reserved2;
gustavatmel 1:9c5af431a1f1 59 } master_record_data_t;
gustavatmel 1:9c5af431a1f1 60
gustavatmel 1:9c5af431a1f1 61 static const uint32_t min_area_size = 4096;
gustavatmel 1:9c5af431a1f1 62
gustavatmel 1:9c5af431a1f1 63 static const int num_write_retries = 16;
gustavatmel 1:9c5af431a1f1 64
gustavatmel 1:9c5af431a1f1 65 static const uint8_t blank_flash_val = 0xFF;
gustavatmel 1:9c5af431a1f1 66
gustavatmel 1:9c5af431a1f1 67 // See whether any of these defines are given (by config files)
gustavatmel 1:9c5af431a1f1 68 // If so, this means that that area configuration is given by the user
gustavatmel 1:9c5af431a1f1 69 #if defined(NVSTORE_AREA_1_ADDRESS) || defined(NVSTORE_AREA_1_SIZE) ||\
gustavatmel 1:9c5af431a1f1 70 defined(NVSTORE_AREA_2_ADDRESS) || defined(NVSTORE_AREA_2_SIZE)
gustavatmel 1:9c5af431a1f1 71
gustavatmel 1:9c5af431a1f1 72 // Require all area configuration parameters if any one of them is present
gustavatmel 1:9c5af431a1f1 73 #if !defined(NVSTORE_AREA_1_ADDRESS) || !defined(NVSTORE_AREA_1_SIZE) ||\
gustavatmel 1:9c5af431a1f1 74 !defined(NVSTORE_AREA_2_ADDRESS) || !defined(NVSTORE_AREA_2_SIZE)
gustavatmel 1:9c5af431a1f1 75 #error Incomplete NVStore area configuration
gustavatmel 1:9c5af431a1f1 76 #endif
gustavatmel 1:9c5af431a1f1 77 #if (NVSTORE_AREA_1_SIZE == 0) || (NVSTORE_AREA_2_SIZE == 0)
gustavatmel 1:9c5af431a1f1 78 #error NVStore area size cannot be 0
gustavatmel 1:9c5af431a1f1 79 #endif
gustavatmel 1:9c5af431a1f1 80
gustavatmel 1:9c5af431a1f1 81 NVStore::nvstore_area_data_t NVStore::initial_area_params[] = {{NVSTORE_AREA_1_ADDRESS, NVSTORE_AREA_1_SIZE},
gustavatmel 1:9c5af431a1f1 82 {NVSTORE_AREA_2_ADDRESS, NVSTORE_AREA_2_SIZE}};
gustavatmel 1:9c5af431a1f1 83 #else
gustavatmel 1:9c5af431a1f1 84 NVStore::nvstore_area_data_t NVStore::initial_area_params[] = {{0, 0},
gustavatmel 1:9c5af431a1f1 85 {0, 0}};
gustavatmel 1:9c5af431a1f1 86 #endif
gustavatmel 1:9c5af431a1f1 87
gustavatmel 1:9c5af431a1f1 88 typedef enum {
gustavatmel 1:9c5af431a1f1 89 NVSTORE_AREA_STATE_NONE = 0,
gustavatmel 1:9c5af431a1f1 90 NVSTORE_AREA_STATE_EMPTY,
gustavatmel 1:9c5af431a1f1 91 NVSTORE_AREA_STATE_VALID,
gustavatmel 1:9c5af431a1f1 92 } area_state_e;
gustavatmel 1:9c5af431a1f1 93
gustavatmel 1:9c5af431a1f1 94 static const uint32_t initial_crc = 0xFFFFFFFF;
gustavatmel 1:9c5af431a1f1 95
gustavatmel 1:9c5af431a1f1 96
gustavatmel 1:9c5af431a1f1 97 // -------------------------------------------------- Local Functions Declaration ----------------------------------------------------
gustavatmel 1:9c5af431a1f1 98
gustavatmel 1:9c5af431a1f1 99 // -------------------------------------------------- Functions Implementation ----------------------------------------------------
gustavatmel 1:9c5af431a1f1 100
gustavatmel 1:9c5af431a1f1 101 // Align a value to a specified size.
gustavatmel 1:9c5af431a1f1 102 // Parameters :
gustavatmel 1:9c5af431a1f1 103 // val - [IN] Value.
gustavatmel 1:9c5af431a1f1 104 // size - [IN] Size.
gustavatmel 1:9c5af431a1f1 105 // Return : Aligned value.
gustavatmel 1:9c5af431a1f1 106 static inline uint32_t align_up(uint32_t val, uint32_t size)
gustavatmel 1:9c5af431a1f1 107 {
gustavatmel 1:9c5af431a1f1 108 return (((val - 1) / size) + 1) * size;
gustavatmel 1:9c5af431a1f1 109 }
gustavatmel 1:9c5af431a1f1 110
gustavatmel 1:9c5af431a1f1 111 // CRC32 calculation. Supports "rolling" calculation (using the initial value).
gustavatmel 1:9c5af431a1f1 112 // Parameters :
gustavatmel 1:9c5af431a1f1 113 // init_crc - [IN] Initial CRC.
gustavatmel 1:9c5af431a1f1 114 // data_size - [IN] Buffer's data size.
gustavatmel 1:9c5af431a1f1 115 // data_buf - [IN] Data buffer.
gustavatmel 1:9c5af431a1f1 116 // Return : CRC.
gustavatmel 1:9c5af431a1f1 117 static uint32_t crc32(uint32_t init_crc, uint32_t data_size, uint8_t *data_buf)
gustavatmel 1:9c5af431a1f1 118 {
gustavatmel 1:9c5af431a1f1 119 uint32_t i, j;
gustavatmel 1:9c5af431a1f1 120 uint32_t crc, mask;
gustavatmel 1:9c5af431a1f1 121
gustavatmel 1:9c5af431a1f1 122 crc = init_crc;
gustavatmel 1:9c5af431a1f1 123 for (i = 0; i < data_size; i++) {
gustavatmel 1:9c5af431a1f1 124 crc = crc ^ (uint32_t) (data_buf[i]);
gustavatmel 1:9c5af431a1f1 125 for (j = 0; j < 8; j++) {
gustavatmel 1:9c5af431a1f1 126 mask = -(crc & 1);
gustavatmel 1:9c5af431a1f1 127 crc = (crc >> 1) ^ (0xEDB88320 & mask);
gustavatmel 1:9c5af431a1f1 128 }
gustavatmel 1:9c5af431a1f1 129 }
gustavatmel 1:9c5af431a1f1 130 return crc;
gustavatmel 1:9c5af431a1f1 131 }
gustavatmel 1:9c5af431a1f1 132
gustavatmel 1:9c5af431a1f1 133 NVStore::NVStore() : _init_done(0), _init_attempts(0), _active_area(0), _max_keys(NVSTORE_MAX_KEYS),
gustavatmel 1:9c5af431a1f1 134 _active_area_version(0), _free_space_offset(0), _size(0), _mutex(0), _offset_by_key(0), _flash(0),
gustavatmel 1:9c5af431a1f1 135 _min_prog_size(0), _page_buf(0)
gustavatmel 1:9c5af431a1f1 136 {
gustavatmel 1:9c5af431a1f1 137 memcpy(_flash_area_params, 0, sizeof(_flash_area_params));
gustavatmel 1:9c5af431a1f1 138 }
gustavatmel 1:9c5af431a1f1 139
gustavatmel 1:9c5af431a1f1 140 NVStore::~NVStore()
gustavatmel 1:9c5af431a1f1 141 {
gustavatmel 1:9c5af431a1f1 142 if (_init_done) {
gustavatmel 1:9c5af431a1f1 143 deinit();
gustavatmel 1:9c5af431a1f1 144 }
gustavatmel 1:9c5af431a1f1 145 }
gustavatmel 1:9c5af431a1f1 146
gustavatmel 1:9c5af431a1f1 147 uint16_t NVStore::get_max_keys() const
gustavatmel 1:9c5af431a1f1 148 {
gustavatmel 1:9c5af431a1f1 149 return _max_keys;
gustavatmel 1:9c5af431a1f1 150 }
gustavatmel 1:9c5af431a1f1 151
gustavatmel 1:9c5af431a1f1 152 uint16_t NVStore::get_max_possible_keys()
gustavatmel 1:9c5af431a1f1 153 {
gustavatmel 1:9c5af431a1f1 154 if (!_init_done) {
gustavatmel 1:9c5af431a1f1 155 init();
gustavatmel 1:9c5af431a1f1 156 }
gustavatmel 1:9c5af431a1f1 157
gustavatmel 1:9c5af431a1f1 158 size_t max_possible_keys = _size / align_up(sizeof(nvstore_record_header_t) * 2, _min_prog_size) - 1;
gustavatmel 1:9c5af431a1f1 159
gustavatmel 1:9c5af431a1f1 160 return (uint16_t)std::min(max_possible_keys, (size_t) last_reserved_key);
gustavatmel 1:9c5af431a1f1 161 }
gustavatmel 1:9c5af431a1f1 162
gustavatmel 1:9c5af431a1f1 163 void NVStore::set_max_keys(uint16_t num_keys)
gustavatmel 1:9c5af431a1f1 164 {
gustavatmel 1:9c5af431a1f1 165 MBED_ASSERT(num_keys < get_max_possible_keys());
gustavatmel 1:9c5af431a1f1 166 _max_keys = num_keys;
gustavatmel 1:9c5af431a1f1 167 // User is allowed to change number of keys. As this affects init, need to deinitialize now.
gustavatmel 1:9c5af431a1f1 168 // Don't call init right away - it is lazily called by get/set functions if needed.
gustavatmel 1:9c5af431a1f1 169 deinit();
gustavatmel 1:9c5af431a1f1 170 }
gustavatmel 1:9c5af431a1f1 171
gustavatmel 1:9c5af431a1f1 172 int NVStore::flash_read_area(uint8_t area, uint32_t offset, uint32_t size, void *buf)
gustavatmel 1:9c5af431a1f1 173 {
gustavatmel 1:9c5af431a1f1 174 return _flash->read(buf, _flash_area_params[area].address + offset, size);
gustavatmel 1:9c5af431a1f1 175 }
gustavatmel 1:9c5af431a1f1 176
gustavatmel 1:9c5af431a1f1 177 int NVStore::flash_write_area(uint8_t area, uint32_t offset, uint32_t size, const void *buf)
gustavatmel 1:9c5af431a1f1 178 {
gustavatmel 1:9c5af431a1f1 179 int ret;
gustavatmel 1:9c5af431a1f1 180 // On some boards, write action can fail due to HW limitations (like critical drivers
gustavatmel 1:9c5af431a1f1 181 // that disable all other actions). Just retry a few times until success.
gustavatmel 1:9c5af431a1f1 182 for (int i = 0; i < num_write_retries; i++) {
gustavatmel 1:9c5af431a1f1 183 ret = _flash->program(buf, _flash_area_params[area].address + offset, size);
gustavatmel 1:9c5af431a1f1 184 if (!ret) {
gustavatmel 1:9c5af431a1f1 185 return ret;
gustavatmel 1:9c5af431a1f1 186 }
gustavatmel 1:9c5af431a1f1 187 wait_ms(1);
gustavatmel 1:9c5af431a1f1 188 }
gustavatmel 1:9c5af431a1f1 189 return ret;
gustavatmel 1:9c5af431a1f1 190 }
gustavatmel 1:9c5af431a1f1 191
gustavatmel 1:9c5af431a1f1 192 int NVStore::flash_erase_area(uint8_t area)
gustavatmel 1:9c5af431a1f1 193 {
gustavatmel 1:9c5af431a1f1 194 int ret;
gustavatmel 1:9c5af431a1f1 195 // On some boards, write action can fail due to HW limitations (like critical drivers
gustavatmel 1:9c5af431a1f1 196 // that disable all other actions). Just retry a few times until success.
gustavatmel 1:9c5af431a1f1 197 for (int i = 0; i < num_write_retries; i++) {
gustavatmel 1:9c5af431a1f1 198 ret = _flash->erase(_flash_area_params[area].address, _flash_area_params[area].size);
gustavatmel 1:9c5af431a1f1 199 if (!ret) {
gustavatmel 1:9c5af431a1f1 200 return ret;
gustavatmel 1:9c5af431a1f1 201 }
gustavatmel 1:9c5af431a1f1 202 wait_ms(1);
gustavatmel 1:9c5af431a1f1 203 }
gustavatmel 1:9c5af431a1f1 204 return ret;
gustavatmel 1:9c5af431a1f1 205 }
gustavatmel 1:9c5af431a1f1 206
gustavatmel 1:9c5af431a1f1 207 void NVStore::calc_validate_area_params()
gustavatmel 1:9c5af431a1f1 208 {
gustavatmel 1:9c5af431a1f1 209 int num_sectors = 0;
gustavatmel 1:9c5af431a1f1 210
gustavatmel 1:9c5af431a1f1 211 size_t flash_addr = _flash->get_flash_start();
gustavatmel 1:9c5af431a1f1 212 size_t flash_size = _flash->get_flash_size();
gustavatmel 1:9c5af431a1f1 213 size_t sector_size;
gustavatmel 1:9c5af431a1f1 214 int max_sectors = flash_size / _flash->get_sector_size(flash_addr) + 1;
gustavatmel 1:9c5af431a1f1 215 size_t *sector_map = new size_t[max_sectors];
gustavatmel 1:9c5af431a1f1 216
gustavatmel 1:9c5af431a1f1 217 int area = 0;
gustavatmel 1:9c5af431a1f1 218 size_t left_size = flash_size;
gustavatmel 1:9c5af431a1f1 219
gustavatmel 1:9c5af431a1f1 220 memcpy(_flash_area_params, initial_area_params, sizeof(_flash_area_params));
gustavatmel 1:9c5af431a1f1 221 int user_config = (_flash_area_params[0].size != 0);
gustavatmel 1:9c5af431a1f1 222 int in_area = 0;
gustavatmel 1:9c5af431a1f1 223 size_t area_size = 0;
gustavatmel 1:9c5af431a1f1 224
gustavatmel 1:9c5af431a1f1 225 while (left_size) {
gustavatmel 1:9c5af431a1f1 226 sector_size = _flash->get_sector_size(flash_addr);
gustavatmel 1:9c5af431a1f1 227 sector_map[num_sectors++] = flash_addr;
gustavatmel 1:9c5af431a1f1 228
gustavatmel 1:9c5af431a1f1 229 if (user_config) {
gustavatmel 1:9c5af431a1f1 230 // User configuration - here we validate it
gustavatmel 1:9c5af431a1f1 231 // Check that address is on a sector boundary, that size covers complete sector sizes,
gustavatmel 1:9c5af431a1f1 232 // and that areas don't overlap.
gustavatmel 1:9c5af431a1f1 233 if (_flash_area_params[area].address == flash_addr) {
gustavatmel 1:9c5af431a1f1 234 in_area = 1;
gustavatmel 1:9c5af431a1f1 235 }
gustavatmel 1:9c5af431a1f1 236 if (in_area) {
gustavatmel 1:9c5af431a1f1 237 area_size += sector_size;
gustavatmel 1:9c5af431a1f1 238 if (area_size == _flash_area_params[area].size) {
gustavatmel 1:9c5af431a1f1 239 area++;
gustavatmel 1:9c5af431a1f1 240 if (area == NVSTORE_NUM_AREAS) {
gustavatmel 1:9c5af431a1f1 241 break;
gustavatmel 1:9c5af431a1f1 242 }
gustavatmel 1:9c5af431a1f1 243 in_area = 0;
gustavatmel 1:9c5af431a1f1 244 area_size = 0;
gustavatmel 1:9c5af431a1f1 245 }
gustavatmel 1:9c5af431a1f1 246 }
gustavatmel 1:9c5af431a1f1 247 }
gustavatmel 1:9c5af431a1f1 248
gustavatmel 1:9c5af431a1f1 249 flash_addr += sector_size;
gustavatmel 1:9c5af431a1f1 250 left_size -= sector_size;
gustavatmel 1:9c5af431a1f1 251 }
gustavatmel 1:9c5af431a1f1 252 sector_map[num_sectors] = flash_addr;
gustavatmel 1:9c5af431a1f1 253
gustavatmel 1:9c5af431a1f1 254 if (user_config) {
gustavatmel 1:9c5af431a1f1 255 // Valid areas were counted. Assert if not the expected number.
gustavatmel 1:9c5af431a1f1 256 MBED_ASSERT(area == NVSTORE_NUM_AREAS);
gustavatmel 1:9c5af431a1f1 257 } else {
gustavatmel 1:9c5af431a1f1 258 // Not user configuration - calculate area parameters.
gustavatmel 1:9c5af431a1f1 259 // Take last two sectors by default. If their sizes aren't big enough, take
gustavatmel 1:9c5af431a1f1 260 // a few consecutive ones.
gustavatmel 1:9c5af431a1f1 261 area = 1;
gustavatmel 1:9c5af431a1f1 262 _flash_area_params[area].size = 0;
gustavatmel 1:9c5af431a1f1 263 int i;
gustavatmel 1:9c5af431a1f1 264 for (i = num_sectors - 1; i >= 0; i--) {
gustavatmel 1:9c5af431a1f1 265 sector_size = sector_map[i+1] - sector_map[i];
gustavatmel 1:9c5af431a1f1 266 _flash_area_params[area].size += sector_size;
gustavatmel 1:9c5af431a1f1 267 if (_flash_area_params[area].size >= min_area_size) {
gustavatmel 1:9c5af431a1f1 268 _flash_area_params[area].address = sector_map[i];
gustavatmel 1:9c5af431a1f1 269 area--;
gustavatmel 1:9c5af431a1f1 270 if (area < 0) {
gustavatmel 1:9c5af431a1f1 271 break;
gustavatmel 1:9c5af431a1f1 272 }
gustavatmel 1:9c5af431a1f1 273 _flash_area_params[area].size = 0;
gustavatmel 1:9c5af431a1f1 274 }
gustavatmel 1:9c5af431a1f1 275 }
gustavatmel 1:9c5af431a1f1 276 }
gustavatmel 1:9c5af431a1f1 277
gustavatmel 1:9c5af431a1f1 278 delete[] sector_map;
gustavatmel 1:9c5af431a1f1 279 }
gustavatmel 1:9c5af431a1f1 280
gustavatmel 1:9c5af431a1f1 281
gustavatmel 1:9c5af431a1f1 282 int NVStore::calc_empty_space(uint8_t area, uint32_t &offset)
gustavatmel 1:9c5af431a1f1 283 {
gustavatmel 1:9c5af431a1f1 284 uint32_t buf[32];
gustavatmel 1:9c5af431a1f1 285 uint8_t *chbuf;
gustavatmel 1:9c5af431a1f1 286 uint32_t i, j;
gustavatmel 1:9c5af431a1f1 287 int ret;
gustavatmel 1:9c5af431a1f1 288
gustavatmel 1:9c5af431a1f1 289 offset = _size;
gustavatmel 1:9c5af431a1f1 290 for (i = 0; i < _size / sizeof(buf); i++) {
gustavatmel 1:9c5af431a1f1 291 offset -= sizeof(buf);
gustavatmel 1:9c5af431a1f1 292 ret = flash_read_area(area, offset, sizeof(buf), buf);
gustavatmel 1:9c5af431a1f1 293 if (ret) {
gustavatmel 1:9c5af431a1f1 294 return ret;
gustavatmel 1:9c5af431a1f1 295 }
gustavatmel 1:9c5af431a1f1 296 chbuf = (uint8_t *) buf;
gustavatmel 1:9c5af431a1f1 297 for (j = sizeof(buf); j > 0; j--) {
gustavatmel 1:9c5af431a1f1 298 if (chbuf[j - 1] != blank_flash_val) {
gustavatmel 1:9c5af431a1f1 299 offset += j;
gustavatmel 1:9c5af431a1f1 300 return 0;
gustavatmel 1:9c5af431a1f1 301 }
gustavatmel 1:9c5af431a1f1 302 }
gustavatmel 1:9c5af431a1f1 303 }
gustavatmel 1:9c5af431a1f1 304 return 0;
gustavatmel 1:9c5af431a1f1 305 }
gustavatmel 1:9c5af431a1f1 306
gustavatmel 1:9c5af431a1f1 307 int NVStore::read_record(uint8_t area, uint32_t offset, uint16_t buf_size, void *buf,
gustavatmel 1:9c5af431a1f1 308 uint16_t &actual_size, int validate_only, int &valid,
gustavatmel 1:9c5af431a1f1 309 uint16_t &key, uint16_t &flags, uint32_t &next_offset)
gustavatmel 1:9c5af431a1f1 310 {
gustavatmel 1:9c5af431a1f1 311 uint8_t int_buf[128];
gustavatmel 1:9c5af431a1f1 312 void *buf_ptr;
gustavatmel 1:9c5af431a1f1 313 uint16_t data_size, chunk_size;
gustavatmel 1:9c5af431a1f1 314 int os_ret;
gustavatmel 1:9c5af431a1f1 315 nvstore_record_header_t header;
gustavatmel 1:9c5af431a1f1 316 uint32_t crc = initial_crc;
gustavatmel 1:9c5af431a1f1 317
gustavatmel 1:9c5af431a1f1 318 valid = 1;
gustavatmel 1:9c5af431a1f1 319
gustavatmel 1:9c5af431a1f1 320 os_ret = flash_read_area(area, offset, sizeof(header), &header);
gustavatmel 1:9c5af431a1f1 321 if (os_ret) {
gustavatmel 1:9c5af431a1f1 322 return NVSTORE_READ_ERROR;
gustavatmel 1:9c5af431a1f1 323 }
gustavatmel 1:9c5af431a1f1 324
gustavatmel 1:9c5af431a1f1 325 crc = crc32(crc, sizeof(header) - sizeof(header.crc), (uint8_t *) &header);
gustavatmel 1:9c5af431a1f1 326
gustavatmel 1:9c5af431a1f1 327 actual_size = 0;
gustavatmel 1:9c5af431a1f1 328 key = header.key_and_flags & ~header_flag_mask;
gustavatmel 1:9c5af431a1f1 329 flags = header.key_and_flags & header_flag_mask;
gustavatmel 1:9c5af431a1f1 330
gustavatmel 1:9c5af431a1f1 331 if ((key >= _max_keys) && (key != master_record_key)) {
gustavatmel 1:9c5af431a1f1 332 valid = 0;
gustavatmel 1:9c5af431a1f1 333 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 334 }
gustavatmel 1:9c5af431a1f1 335
gustavatmel 1:9c5af431a1f1 336 data_size = header.size;
gustavatmel 1:9c5af431a1f1 337 offset += sizeof(header);
gustavatmel 1:9c5af431a1f1 338
gustavatmel 1:9c5af431a1f1 339 // In case of validate only enabled, we use our internal buffer for data reading,
gustavatmel 1:9c5af431a1f1 340 // instead of the user one. This allows us to use a smaller buffer, on which CRC
gustavatmel 1:9c5af431a1f1 341 // is continuously calculated.
gustavatmel 1:9c5af431a1f1 342 if (validate_only) {
gustavatmel 1:9c5af431a1f1 343 buf_ptr = int_buf;
gustavatmel 1:9c5af431a1f1 344 buf_size = sizeof(int_buf);
gustavatmel 1:9c5af431a1f1 345 } else {
gustavatmel 1:9c5af431a1f1 346 if (data_size > buf_size) {
gustavatmel 1:9c5af431a1f1 347 offset += data_size;
gustavatmel 1:9c5af431a1f1 348 actual_size = data_size;
gustavatmel 1:9c5af431a1f1 349 next_offset = align_up(offset, _min_prog_size);
gustavatmel 1:9c5af431a1f1 350 return NVSTORE_BUFF_TOO_SMALL;
gustavatmel 1:9c5af431a1f1 351 }
gustavatmel 1:9c5af431a1f1 352 buf_ptr = buf;
gustavatmel 1:9c5af431a1f1 353 }
gustavatmel 1:9c5af431a1f1 354
gustavatmel 1:9c5af431a1f1 355 while (data_size) {
gustavatmel 1:9c5af431a1f1 356 chunk_size = std::min(data_size, buf_size);
gustavatmel 1:9c5af431a1f1 357 os_ret = flash_read_area(area, offset, chunk_size, buf_ptr);
gustavatmel 1:9c5af431a1f1 358 if (os_ret) {
gustavatmel 1:9c5af431a1f1 359 return NVSTORE_READ_ERROR;
gustavatmel 1:9c5af431a1f1 360 }
gustavatmel 1:9c5af431a1f1 361 crc = crc32(crc, chunk_size, (uint8_t *) buf_ptr);
gustavatmel 1:9c5af431a1f1 362 data_size -= chunk_size;
gustavatmel 1:9c5af431a1f1 363 offset += chunk_size;
gustavatmel 1:9c5af431a1f1 364 }
gustavatmel 1:9c5af431a1f1 365
gustavatmel 1:9c5af431a1f1 366 if (header.crc != crc) {
gustavatmel 1:9c5af431a1f1 367 valid = 0;
gustavatmel 1:9c5af431a1f1 368 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 369 }
gustavatmel 1:9c5af431a1f1 370
gustavatmel 1:9c5af431a1f1 371 actual_size = header.size;
gustavatmel 1:9c5af431a1f1 372 next_offset = align_up(offset, _min_prog_size);
gustavatmel 1:9c5af431a1f1 373
gustavatmel 1:9c5af431a1f1 374 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 375 }
gustavatmel 1:9c5af431a1f1 376
gustavatmel 1:9c5af431a1f1 377 int NVStore::write_record(uint8_t area, uint32_t offset, uint16_t key, uint16_t flags,
gustavatmel 1:9c5af431a1f1 378 uint32_t data_size, const void *data_buf, uint32_t &next_offset)
gustavatmel 1:9c5af431a1f1 379 {
gustavatmel 1:9c5af431a1f1 380 nvstore_record_header_t header;
gustavatmel 1:9c5af431a1f1 381 uint32_t crc = initial_crc;
gustavatmel 1:9c5af431a1f1 382 int os_ret;
gustavatmel 1:9c5af431a1f1 383 uint8_t *prog_buf;
gustavatmel 1:9c5af431a1f1 384
gustavatmel 1:9c5af431a1f1 385 header.key_and_flags = key | flags;
gustavatmel 1:9c5af431a1f1 386 header.size = data_size;
gustavatmel 1:9c5af431a1f1 387 header.crc = 0; // Satisfy compiler
gustavatmel 1:9c5af431a1f1 388 crc = crc32(crc, sizeof(header) - sizeof(header.crc), (uint8_t *) &header);
gustavatmel 1:9c5af431a1f1 389 if (data_size) {
gustavatmel 1:9c5af431a1f1 390 crc = crc32(crc, data_size, (uint8_t *) data_buf);
gustavatmel 1:9c5af431a1f1 391 }
gustavatmel 1:9c5af431a1f1 392 header.crc = crc;
gustavatmel 1:9c5af431a1f1 393
gustavatmel 1:9c5af431a1f1 394 // In case page size is greater than header size, we can't write header and data
gustavatmel 1:9c5af431a1f1 395 // separately. Instead, we need to copy header and start of data to our page buffer
gustavatmel 1:9c5af431a1f1 396 // and write them together. Otherwise, simply write header and data separately.
gustavatmel 1:9c5af431a1f1 397 uint32_t prog_size = sizeof(header);
gustavatmel 1:9c5af431a1f1 398 uint32_t copy_size = 0;
gustavatmel 1:9c5af431a1f1 399 if (_min_prog_size > sizeof(header)) {
gustavatmel 1:9c5af431a1f1 400 prog_buf = _page_buf;
gustavatmel 1:9c5af431a1f1 401 memcpy(prog_buf, &header, sizeof(header));
gustavatmel 1:9c5af431a1f1 402 if (data_size) {
gustavatmel 1:9c5af431a1f1 403 memcpy(prog_buf, &header, sizeof(header));
gustavatmel 1:9c5af431a1f1 404 copy_size = std::min(data_size, _min_prog_size - sizeof(header));
gustavatmel 1:9c5af431a1f1 405 memcpy(prog_buf + sizeof(header), data_buf, copy_size);
gustavatmel 1:9c5af431a1f1 406 data_size -= copy_size;
gustavatmel 1:9c5af431a1f1 407 prog_size += copy_size;
gustavatmel 1:9c5af431a1f1 408 }
gustavatmel 1:9c5af431a1f1 409 } else {
gustavatmel 1:9c5af431a1f1 410 prog_buf = (uint8_t *) &header;
gustavatmel 1:9c5af431a1f1 411 }
gustavatmel 1:9c5af431a1f1 412
gustavatmel 1:9c5af431a1f1 413 os_ret = flash_write_area(area, offset, prog_size, prog_buf);
gustavatmel 1:9c5af431a1f1 414 if (os_ret) {
gustavatmel 1:9c5af431a1f1 415 return NVSTORE_WRITE_ERROR;
gustavatmel 1:9c5af431a1f1 416 }
gustavatmel 1:9c5af431a1f1 417 offset += prog_size;
gustavatmel 1:9c5af431a1f1 418
gustavatmel 1:9c5af431a1f1 419 if (data_size) {
gustavatmel 1:9c5af431a1f1 420 prog_buf = (uint8_t *) data_buf + copy_size;
gustavatmel 1:9c5af431a1f1 421 os_ret = flash_write_area(area, offset, data_size, prog_buf);
gustavatmel 1:9c5af431a1f1 422 if (os_ret) {
gustavatmel 1:9c5af431a1f1 423 return NVSTORE_WRITE_ERROR;
gustavatmel 1:9c5af431a1f1 424 }
gustavatmel 1:9c5af431a1f1 425 offset += data_size;
gustavatmel 1:9c5af431a1f1 426 }
gustavatmel 1:9c5af431a1f1 427
gustavatmel 1:9c5af431a1f1 428 next_offset = align_up(offset, _min_prog_size);
gustavatmel 1:9c5af431a1f1 429 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 430 }
gustavatmel 1:9c5af431a1f1 431
gustavatmel 1:9c5af431a1f1 432 int NVStore::write_master_record(uint8_t area, uint16_t version, uint32_t &next_offset)
gustavatmel 1:9c5af431a1f1 433 {
gustavatmel 1:9c5af431a1f1 434 master_record_data_t master_rec;
gustavatmel 1:9c5af431a1f1 435
gustavatmel 1:9c5af431a1f1 436 master_rec.version = version;
gustavatmel 1:9c5af431a1f1 437 master_rec.reserved1 = 0;
gustavatmel 1:9c5af431a1f1 438 master_rec.reserved2 = 0;
gustavatmel 1:9c5af431a1f1 439 return write_record(area, 0, master_record_key, 0, sizeof(master_rec),
gustavatmel 1:9c5af431a1f1 440 &master_rec, next_offset);
gustavatmel 1:9c5af431a1f1 441 }
gustavatmel 1:9c5af431a1f1 442
gustavatmel 1:9c5af431a1f1 443 int NVStore::copy_record(uint8_t from_area, uint32_t from_offset, uint32_t to_offset,
gustavatmel 1:9c5af431a1f1 444 uint32_t &next_offset)
gustavatmel 1:9c5af431a1f1 445 {
gustavatmel 1:9c5af431a1f1 446 uint8_t local_buf[128];
gustavatmel 1:9c5af431a1f1 447 uint16_t record_size, chunk_size, prog_buf_size;
gustavatmel 1:9c5af431a1f1 448 int os_ret;
gustavatmel 1:9c5af431a1f1 449 nvstore_record_header_t *header;
gustavatmel 1:9c5af431a1f1 450 uint8_t *read_buf, *prog_buf;
gustavatmel 1:9c5af431a1f1 451
gustavatmel 1:9c5af431a1f1 452 // This function assumes that the source record is valid, so no need to recalculate CRC.
gustavatmel 1:9c5af431a1f1 453
gustavatmel 1:9c5af431a1f1 454 if (_min_prog_size > sizeof(nvstore_record_header_t)) {
gustavatmel 1:9c5af431a1f1 455 prog_buf = _page_buf;
gustavatmel 1:9c5af431a1f1 456 prog_buf_size = _min_prog_size;
gustavatmel 1:9c5af431a1f1 457 } else {
gustavatmel 1:9c5af431a1f1 458 prog_buf = local_buf;
gustavatmel 1:9c5af431a1f1 459 prog_buf_size = sizeof(local_buf);
gustavatmel 1:9c5af431a1f1 460 }
gustavatmel 1:9c5af431a1f1 461 read_buf = prog_buf;
gustavatmel 1:9c5af431a1f1 462
gustavatmel 1:9c5af431a1f1 463 os_ret = flash_read_area(from_area, from_offset, sizeof(nvstore_record_header_t), read_buf);
gustavatmel 1:9c5af431a1f1 464 if (os_ret) {
gustavatmel 1:9c5af431a1f1 465 return NVSTORE_READ_ERROR;
gustavatmel 1:9c5af431a1f1 466 }
gustavatmel 1:9c5af431a1f1 467
gustavatmel 1:9c5af431a1f1 468 header = (nvstore_record_header_t *) read_buf;
gustavatmel 1:9c5af431a1f1 469 record_size = sizeof(nvstore_record_header_t) + header->size;
gustavatmel 1:9c5af431a1f1 470
gustavatmel 1:9c5af431a1f1 471 // No need to copy records whose flags indicate deletion
gustavatmel 1:9c5af431a1f1 472 if (header->key_and_flags & delete_item_flag) {
gustavatmel 1:9c5af431a1f1 473 next_offset = align_up(to_offset, _min_prog_size);
gustavatmel 1:9c5af431a1f1 474 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 475 }
gustavatmel 1:9c5af431a1f1 476
gustavatmel 1:9c5af431a1f1 477 // no need to align record size here, as it won't change the outcome of this condition
gustavatmel 1:9c5af431a1f1 478 if (to_offset + record_size >= _size) {
gustavatmel 1:9c5af431a1f1 479 return NVSTORE_FLASH_AREA_TOO_SMALL;
gustavatmel 1:9c5af431a1f1 480 }
gustavatmel 1:9c5af431a1f1 481
gustavatmel 1:9c5af431a1f1 482 uint16_t start_size = sizeof(nvstore_record_header_t);
gustavatmel 1:9c5af431a1f1 483 from_offset += start_size;
gustavatmel 1:9c5af431a1f1 484 read_buf += start_size;
gustavatmel 1:9c5af431a1f1 485 record_size -= start_size;
gustavatmel 1:9c5af431a1f1 486
gustavatmel 1:9c5af431a1f1 487 do {
gustavatmel 1:9c5af431a1f1 488 chunk_size = std::min(record_size, (uint16_t)(prog_buf_size - start_size));
gustavatmel 1:9c5af431a1f1 489 if (chunk_size) {
gustavatmel 1:9c5af431a1f1 490 os_ret = flash_read_area(from_area, from_offset, chunk_size, read_buf);
gustavatmel 1:9c5af431a1f1 491 if (os_ret) {
gustavatmel 1:9c5af431a1f1 492 return NVSTORE_READ_ERROR;
gustavatmel 1:9c5af431a1f1 493 }
gustavatmel 1:9c5af431a1f1 494 }
gustavatmel 1:9c5af431a1f1 495 os_ret = flash_write_area(1 - from_area, to_offset, chunk_size + start_size, prog_buf);
gustavatmel 1:9c5af431a1f1 496 if (os_ret) {
gustavatmel 1:9c5af431a1f1 497 return NVSTORE_WRITE_ERROR;
gustavatmel 1:9c5af431a1f1 498 }
gustavatmel 1:9c5af431a1f1 499
gustavatmel 1:9c5af431a1f1 500 read_buf = prog_buf;
gustavatmel 1:9c5af431a1f1 501 record_size -= chunk_size;
gustavatmel 1:9c5af431a1f1 502 from_offset += chunk_size;
gustavatmel 1:9c5af431a1f1 503 to_offset += chunk_size + start_size;
gustavatmel 1:9c5af431a1f1 504 start_size = 0;
gustavatmel 1:9c5af431a1f1 505 } while (record_size);
gustavatmel 1:9c5af431a1f1 506
gustavatmel 1:9c5af431a1f1 507 next_offset = align_up(to_offset, _min_prog_size);
gustavatmel 1:9c5af431a1f1 508 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 509 }
gustavatmel 1:9c5af431a1f1 510
gustavatmel 1:9c5af431a1f1 511 int NVStore::garbage_collection(uint16_t key, uint16_t flags, uint16_t buf_size, const void *buf)
gustavatmel 1:9c5af431a1f1 512 {
gustavatmel 1:9c5af431a1f1 513 uint32_t curr_offset, new_area_offset, next_offset;
gustavatmel 1:9c5af431a1f1 514 int ret;
gustavatmel 1:9c5af431a1f1 515 uint8_t curr_area;
gustavatmel 1:9c5af431a1f1 516
gustavatmel 1:9c5af431a1f1 517 new_area_offset = align_up(sizeof(nvstore_record_header_t) + sizeof(master_record_data_t), _min_prog_size);
gustavatmel 1:9c5af431a1f1 518
gustavatmel 1:9c5af431a1f1 519 // If GC is triggered by a set item request, we need to first write that item in the new location,
gustavatmel 1:9c5af431a1f1 520 // otherwise we may either write it twice (if already included), or lose it in case we decide
gustavatmel 1:9c5af431a1f1 521 // to skip it at garbage collection phase (and the system crashes).
gustavatmel 1:9c5af431a1f1 522 if ((key != no_key) && !(flags & delete_item_flag)) {
gustavatmel 1:9c5af431a1f1 523 ret = write_record(1 - _active_area, new_area_offset, key, 0, buf_size, buf, next_offset);
gustavatmel 1:9c5af431a1f1 524 if (ret != NVSTORE_SUCCESS) {
gustavatmel 1:9c5af431a1f1 525 return ret;
gustavatmel 1:9c5af431a1f1 526 }
gustavatmel 1:9c5af431a1f1 527 _offset_by_key[key] = new_area_offset | (1 - _active_area) << offs_by_key_area_bit_pos |
gustavatmel 1:9c5af431a1f1 528 (((flags & set_once_flag) != 0) << offs_by_key_set_once_bit_pos);
gustavatmel 1:9c5af431a1f1 529 new_area_offset = next_offset;
gustavatmel 1:9c5af431a1f1 530 }
gustavatmel 1:9c5af431a1f1 531
gustavatmel 1:9c5af431a1f1 532 // Now iterate on all types, and copy the ones who have valid offsets (meaning that they exist)
gustavatmel 1:9c5af431a1f1 533 // to the other area.
gustavatmel 1:9c5af431a1f1 534 for (key = 0; key < _max_keys; key++) {
gustavatmel 1:9c5af431a1f1 535 curr_offset = _offset_by_key[key];
gustavatmel 1:9c5af431a1f1 536 uint16_t save_flags = curr_offset & offs_by_key_area_mask;
gustavatmel 1:9c5af431a1f1 537 curr_area = (uint8_t)(curr_offset >> offs_by_key_area_bit_pos) & 1;
gustavatmel 1:9c5af431a1f1 538 curr_offset &= ~offs_by_key_flag_mask;
gustavatmel 1:9c5af431a1f1 539 if ((!curr_offset) || (curr_area != _active_area)) {
gustavatmel 1:9c5af431a1f1 540 continue;
gustavatmel 1:9c5af431a1f1 541 }
gustavatmel 1:9c5af431a1f1 542 ret = copy_record(curr_area, curr_offset, new_area_offset, next_offset);
gustavatmel 1:9c5af431a1f1 543 if (ret != NVSTORE_SUCCESS) {
gustavatmel 1:9c5af431a1f1 544 return ret;
gustavatmel 1:9c5af431a1f1 545 }
gustavatmel 1:9c5af431a1f1 546 _offset_by_key[key] = new_area_offset | (1 - curr_area) << offs_by_key_area_bit_pos | save_flags;
gustavatmel 1:9c5af431a1f1 547 new_area_offset = next_offset;
gustavatmel 1:9c5af431a1f1 548 }
gustavatmel 1:9c5af431a1f1 549
gustavatmel 1:9c5af431a1f1 550 // Now write master record, with version incremented by 1.
gustavatmel 1:9c5af431a1f1 551 _active_area_version++;
gustavatmel 1:9c5af431a1f1 552 ret = write_master_record(1 - _active_area, _active_area_version, next_offset);
gustavatmel 1:9c5af431a1f1 553 if (ret != NVSTORE_SUCCESS) {
gustavatmel 1:9c5af431a1f1 554 return ret;
gustavatmel 1:9c5af431a1f1 555 }
gustavatmel 1:9c5af431a1f1 556
gustavatmel 1:9c5af431a1f1 557 _free_space_offset = new_area_offset;
gustavatmel 1:9c5af431a1f1 558
gustavatmel 1:9c5af431a1f1 559 // Only now we can switch to the new active area
gustavatmel 1:9c5af431a1f1 560 _active_area = 1 - _active_area;
gustavatmel 1:9c5af431a1f1 561
gustavatmel 1:9c5af431a1f1 562 // The older area doesn't concern us now. Erase it now.
gustavatmel 1:9c5af431a1f1 563 if (flash_erase_area(1 - _active_area)) {
gustavatmel 1:9c5af431a1f1 564 return NVSTORE_WRITE_ERROR;
gustavatmel 1:9c5af431a1f1 565 }
gustavatmel 1:9c5af431a1f1 566
gustavatmel 1:9c5af431a1f1 567 return ret;
gustavatmel 1:9c5af431a1f1 568 }
gustavatmel 1:9c5af431a1f1 569
gustavatmel 1:9c5af431a1f1 570
gustavatmel 1:9c5af431a1f1 571 int NVStore::do_get(uint16_t key, uint16_t buf_size, void *buf, uint16_t &actual_size,
gustavatmel 1:9c5af431a1f1 572 int validate_only)
gustavatmel 1:9c5af431a1f1 573 {
gustavatmel 1:9c5af431a1f1 574 int ret = NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 575 int valid;
gustavatmel 1:9c5af431a1f1 576 uint32_t record_offset, next_offset;
gustavatmel 1:9c5af431a1f1 577 uint16_t read_type, flags;
gustavatmel 1:9c5af431a1f1 578 uint8_t area;
gustavatmel 1:9c5af431a1f1 579
gustavatmel 1:9c5af431a1f1 580 if (!_init_done) {
gustavatmel 1:9c5af431a1f1 581 ret = init();
gustavatmel 1:9c5af431a1f1 582 if (ret != NVSTORE_SUCCESS) {
gustavatmel 1:9c5af431a1f1 583 return ret;
gustavatmel 1:9c5af431a1f1 584 }
gustavatmel 1:9c5af431a1f1 585 }
gustavatmel 1:9c5af431a1f1 586
gustavatmel 1:9c5af431a1f1 587 if (key >= _max_keys) {
gustavatmel 1:9c5af431a1f1 588 return NVSTORE_BAD_VALUE;
gustavatmel 1:9c5af431a1f1 589 }
gustavatmel 1:9c5af431a1f1 590
gustavatmel 1:9c5af431a1f1 591 if (!buf) {
gustavatmel 1:9c5af431a1f1 592 buf_size = 0;
gustavatmel 1:9c5af431a1f1 593 // This is only required in order to satisfy static code analysis tools, fearing
gustavatmel 1:9c5af431a1f1 594 // that a null buff is dereferenced inside read_record function. However, this won't happen
gustavatmel 1:9c5af431a1f1 595 // when buf_size is 0, so just have buf point to a dummy location.
gustavatmel 1:9c5af431a1f1 596 buf = &flags;
gustavatmel 1:9c5af431a1f1 597 }
gustavatmel 1:9c5af431a1f1 598
gustavatmel 1:9c5af431a1f1 599 _mutex->lock();
gustavatmel 1:9c5af431a1f1 600 record_offset = _offset_by_key[key];
gustavatmel 1:9c5af431a1f1 601
gustavatmel 1:9c5af431a1f1 602 if (!record_offset) {
gustavatmel 1:9c5af431a1f1 603 _mutex->unlock();
gustavatmel 1:9c5af431a1f1 604 return NVSTORE_NOT_FOUND;
gustavatmel 1:9c5af431a1f1 605 }
gustavatmel 1:9c5af431a1f1 606
gustavatmel 1:9c5af431a1f1 607 area = (uint8_t)(record_offset >> offs_by_key_area_bit_pos) & 1;
gustavatmel 1:9c5af431a1f1 608 record_offset &= ~offs_by_key_flag_mask;
gustavatmel 1:9c5af431a1f1 609
gustavatmel 1:9c5af431a1f1 610 ret = read_record(area, record_offset, buf_size, buf,
gustavatmel 1:9c5af431a1f1 611 actual_size, validate_only, valid,
gustavatmel 1:9c5af431a1f1 612 read_type, flags, next_offset);
gustavatmel 1:9c5af431a1f1 613 if ((ret == NVSTORE_SUCCESS) && !valid) {
gustavatmel 1:9c5af431a1f1 614 ret = NVSTORE_DATA_CORRUPT;
gustavatmel 1:9c5af431a1f1 615 }
gustavatmel 1:9c5af431a1f1 616
gustavatmel 1:9c5af431a1f1 617 _mutex->unlock();
gustavatmel 1:9c5af431a1f1 618 return ret;
gustavatmel 1:9c5af431a1f1 619 }
gustavatmel 1:9c5af431a1f1 620
gustavatmel 1:9c5af431a1f1 621 int NVStore::get(uint16_t key, uint16_t buf_size, void *buf, uint16_t &actual_size)
gustavatmel 1:9c5af431a1f1 622 {
gustavatmel 1:9c5af431a1f1 623 return do_get(key, buf_size, buf, actual_size, 0);
gustavatmel 1:9c5af431a1f1 624 }
gustavatmel 1:9c5af431a1f1 625
gustavatmel 1:9c5af431a1f1 626 int NVStore::get_item_size(uint16_t key, uint16_t &actual_size)
gustavatmel 1:9c5af431a1f1 627 {
gustavatmel 1:9c5af431a1f1 628 return do_get(key, 0, NULL, actual_size, 1);
gustavatmel 1:9c5af431a1f1 629 }
gustavatmel 1:9c5af431a1f1 630
gustavatmel 1:9c5af431a1f1 631 int NVStore::do_set(uint16_t &key, uint16_t buf_size, const void *buf, uint16_t flags)
gustavatmel 1:9c5af431a1f1 632 {
gustavatmel 1:9c5af431a1f1 633 int ret = NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 634 uint32_t record_offset, record_size, new_free_space;
gustavatmel 1:9c5af431a1f1 635 uint32_t next_offset;
gustavatmel 1:9c5af431a1f1 636
gustavatmel 1:9c5af431a1f1 637 if (!_init_done) {
gustavatmel 1:9c5af431a1f1 638 ret = init();
gustavatmel 1:9c5af431a1f1 639 if (ret != NVSTORE_SUCCESS) {
gustavatmel 1:9c5af431a1f1 640 return ret;
gustavatmel 1:9c5af431a1f1 641 }
gustavatmel 1:9c5af431a1f1 642 }
gustavatmel 1:9c5af431a1f1 643
gustavatmel 1:9c5af431a1f1 644 if ((key != no_key) && (key >= _max_keys)) {
gustavatmel 1:9c5af431a1f1 645 return NVSTORE_BAD_VALUE;
gustavatmel 1:9c5af431a1f1 646 }
gustavatmel 1:9c5af431a1f1 647
gustavatmel 1:9c5af431a1f1 648 if ((key == no_key) && (flags & delete_item_flag)) {
gustavatmel 1:9c5af431a1f1 649 return NVSTORE_BAD_VALUE;
gustavatmel 1:9c5af431a1f1 650 }
gustavatmel 1:9c5af431a1f1 651
gustavatmel 1:9c5af431a1f1 652 if (!buf) {
gustavatmel 1:9c5af431a1f1 653 buf_size = 0;
gustavatmel 1:9c5af431a1f1 654 }
gustavatmel 1:9c5af431a1f1 655
gustavatmel 1:9c5af431a1f1 656 if ((flags & delete_item_flag) && !_offset_by_key[key]) {
gustavatmel 1:9c5af431a1f1 657 return NVSTORE_NOT_FOUND;
gustavatmel 1:9c5af431a1f1 658 }
gustavatmel 1:9c5af431a1f1 659
gustavatmel 1:9c5af431a1f1 660 if ((key != no_key) && (_offset_by_key[key] & offs_by_key_set_once_mask)) {
gustavatmel 1:9c5af431a1f1 661 return NVSTORE_ALREADY_EXISTS;
gustavatmel 1:9c5af431a1f1 662 }
gustavatmel 1:9c5af431a1f1 663
gustavatmel 1:9c5af431a1f1 664 record_size = align_up(sizeof(nvstore_record_header_t) + buf_size, _min_prog_size);
gustavatmel 1:9c5af431a1f1 665
gustavatmel 1:9c5af431a1f1 666 _mutex->lock();
gustavatmel 1:9c5af431a1f1 667
gustavatmel 1:9c5af431a1f1 668 if (key == no_key) {
gustavatmel 1:9c5af431a1f1 669 for (key = NVSTORE_NUM_PREDEFINED_KEYS; key < _max_keys; key++) {
gustavatmel 1:9c5af431a1f1 670 if (!_offset_by_key[key]) {
gustavatmel 1:9c5af431a1f1 671 break;
gustavatmel 1:9c5af431a1f1 672 }
gustavatmel 1:9c5af431a1f1 673 }
gustavatmel 1:9c5af431a1f1 674 if (key == _max_keys) {
gustavatmel 1:9c5af431a1f1 675 return NVSTORE_NO_FREE_KEY;
gustavatmel 1:9c5af431a1f1 676 }
gustavatmel 1:9c5af431a1f1 677 }
gustavatmel 1:9c5af431a1f1 678
gustavatmel 1:9c5af431a1f1 679 new_free_space = core_util_atomic_incr_u32(&_free_space_offset, record_size);
gustavatmel 1:9c5af431a1f1 680 record_offset = new_free_space - record_size;
gustavatmel 1:9c5af431a1f1 681
gustavatmel 1:9c5af431a1f1 682 // If we cross the area limit, we need to invoke GC.
gustavatmel 1:9c5af431a1f1 683 if (new_free_space >= _size) {
gustavatmel 1:9c5af431a1f1 684 ret = garbage_collection(key, flags, buf_size, buf);
gustavatmel 1:9c5af431a1f1 685 _mutex->unlock();
gustavatmel 1:9c5af431a1f1 686 return ret;
gustavatmel 1:9c5af431a1f1 687 }
gustavatmel 1:9c5af431a1f1 688
gustavatmel 1:9c5af431a1f1 689 // Now write the record
gustavatmel 1:9c5af431a1f1 690 ret = write_record(_active_area, record_offset, key, flags, buf_size, buf, next_offset);
gustavatmel 1:9c5af431a1f1 691 if (ret != NVSTORE_SUCCESS) {
gustavatmel 1:9c5af431a1f1 692 _mutex->unlock();
gustavatmel 1:9c5af431a1f1 693 return ret;
gustavatmel 1:9c5af431a1f1 694 }
gustavatmel 1:9c5af431a1f1 695
gustavatmel 1:9c5af431a1f1 696 // Update _offset_by_key. High bit indicates area.
gustavatmel 1:9c5af431a1f1 697 if (flags & delete_item_flag) {
gustavatmel 1:9c5af431a1f1 698 _offset_by_key[key] = 0;
gustavatmel 1:9c5af431a1f1 699 } else {
gustavatmel 1:9c5af431a1f1 700 _offset_by_key[key] = record_offset | (_active_area << offs_by_key_area_bit_pos) |
gustavatmel 1:9c5af431a1f1 701 (((flags & set_once_flag) != 0) << offs_by_key_set_once_bit_pos);
gustavatmel 1:9c5af431a1f1 702 }
gustavatmel 1:9c5af431a1f1 703
gustavatmel 1:9c5af431a1f1 704 _mutex->unlock();
gustavatmel 1:9c5af431a1f1 705
gustavatmel 1:9c5af431a1f1 706 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 707 }
gustavatmel 1:9c5af431a1f1 708
gustavatmel 1:9c5af431a1f1 709 int NVStore::set(uint16_t key, uint16_t buf_size, const void *buf)
gustavatmel 1:9c5af431a1f1 710 {
gustavatmel 1:9c5af431a1f1 711 return do_set(key, buf_size, buf, 0);
gustavatmel 1:9c5af431a1f1 712 }
gustavatmel 1:9c5af431a1f1 713
gustavatmel 1:9c5af431a1f1 714 int NVStore::set_once(uint16_t key, uint16_t buf_size, const void *buf)
gustavatmel 1:9c5af431a1f1 715 {
gustavatmel 1:9c5af431a1f1 716 return do_set(key, buf_size, buf, set_once_flag);
gustavatmel 1:9c5af431a1f1 717 }
gustavatmel 1:9c5af431a1f1 718
gustavatmel 1:9c5af431a1f1 719 int NVStore::set_alloc_key(uint16_t &key, uint16_t buf_size, const void *buf)
gustavatmel 1:9c5af431a1f1 720 {
gustavatmel 1:9c5af431a1f1 721 key = no_key;
gustavatmel 1:9c5af431a1f1 722 return do_set(key, buf_size, buf, 0);
gustavatmel 1:9c5af431a1f1 723 }
gustavatmel 1:9c5af431a1f1 724
gustavatmel 1:9c5af431a1f1 725 int NVStore::remove(uint16_t key)
gustavatmel 1:9c5af431a1f1 726 {
gustavatmel 1:9c5af431a1f1 727 return do_set(key, 0, NULL, delete_item_flag);
gustavatmel 1:9c5af431a1f1 728 }
gustavatmel 1:9c5af431a1f1 729
gustavatmel 1:9c5af431a1f1 730 int NVStore::init()
gustavatmel 1:9c5af431a1f1 731 {
gustavatmel 1:9c5af431a1f1 732 area_state_e area_state[NVSTORE_NUM_AREAS];
gustavatmel 1:9c5af431a1f1 733 uint32_t free_space_offset_of_area[NVSTORE_NUM_AREAS];
gustavatmel 1:9c5af431a1f1 734 uint32_t init_attempts_val;
gustavatmel 1:9c5af431a1f1 735 uint32_t next_offset;
gustavatmel 1:9c5af431a1f1 736 int os_ret;
gustavatmel 1:9c5af431a1f1 737 int ret = NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 738 int valid;
gustavatmel 1:9c5af431a1f1 739 uint16_t key;
gustavatmel 1:9c5af431a1f1 740 uint16_t flags;
gustavatmel 1:9c5af431a1f1 741 uint16_t versions[NVSTORE_NUM_AREAS];
gustavatmel 1:9c5af431a1f1 742 uint16_t actual_size;
gustavatmel 1:9c5af431a1f1 743
gustavatmel 1:9c5af431a1f1 744 if (_init_done) {
gustavatmel 1:9c5af431a1f1 745 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 746 }
gustavatmel 1:9c5af431a1f1 747
gustavatmel 1:9c5af431a1f1 748 // This handles the case that init function is called by more than one thread concurrently.
gustavatmel 1:9c5af431a1f1 749 // Only the one who gets the value of 1 in _init_attempts_val will proceed, while others will
gustavatmel 1:9c5af431a1f1 750 // wait until init is finished.
gustavatmel 1:9c5af431a1f1 751 init_attempts_val = core_util_atomic_incr_u32(&_init_attempts, 1);
gustavatmel 1:9c5af431a1f1 752 if (init_attempts_val != 1) {
gustavatmel 1:9c5af431a1f1 753 while (!_init_done) {
gustavatmel 1:9c5af431a1f1 754 wait_ms(1);
gustavatmel 1:9c5af431a1f1 755 }
gustavatmel 1:9c5af431a1f1 756 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 757 }
gustavatmel 1:9c5af431a1f1 758
gustavatmel 1:9c5af431a1f1 759 _offset_by_key = new uint32_t[_max_keys];
gustavatmel 1:9c5af431a1f1 760 MBED_ASSERT(_offset_by_key);
gustavatmel 1:9c5af431a1f1 761
gustavatmel 1:9c5af431a1f1 762 for (key = 0; key < _max_keys; key++) {
gustavatmel 1:9c5af431a1f1 763 _offset_by_key[key] = 0;
gustavatmel 1:9c5af431a1f1 764 }
gustavatmel 1:9c5af431a1f1 765
gustavatmel 1:9c5af431a1f1 766 _mutex = new PlatformMutex;
gustavatmel 1:9c5af431a1f1 767 MBED_ASSERT(_mutex);
gustavatmel 1:9c5af431a1f1 768
gustavatmel 1:9c5af431a1f1 769 _size = (uint32_t) -1;
gustavatmel 1:9c5af431a1f1 770 _flash = new mbed::FlashIAP;
gustavatmel 1:9c5af431a1f1 771 MBED_ASSERT(_flash);
gustavatmel 1:9c5af431a1f1 772 _flash->init();
gustavatmel 1:9c5af431a1f1 773
gustavatmel 1:9c5af431a1f1 774 _min_prog_size = std::max(_flash->get_page_size(), (uint32_t)sizeof(nvstore_record_header_t));
gustavatmel 1:9c5af431a1f1 775 if (_min_prog_size > sizeof(nvstore_record_header_t)) {
gustavatmel 1:9c5af431a1f1 776 _page_buf = new uint8_t[_min_prog_size];
gustavatmel 1:9c5af431a1f1 777 MBED_ASSERT(_page_buf);
gustavatmel 1:9c5af431a1f1 778 }
gustavatmel 1:9c5af431a1f1 779
gustavatmel 1:9c5af431a1f1 780 calc_validate_area_params();
gustavatmel 1:9c5af431a1f1 781
gustavatmel 1:9c5af431a1f1 782 for (uint8_t area = 0; area < NVSTORE_NUM_AREAS; area++) {
gustavatmel 1:9c5af431a1f1 783 area_state[area] = NVSTORE_AREA_STATE_NONE;
gustavatmel 1:9c5af431a1f1 784 free_space_offset_of_area[area] = 0;
gustavatmel 1:9c5af431a1f1 785 versions[area] = 0;
gustavatmel 1:9c5af431a1f1 786
gustavatmel 1:9c5af431a1f1 787 _size = std::min(_size, _flash_area_params[area].size);
gustavatmel 1:9c5af431a1f1 788
gustavatmel 1:9c5af431a1f1 789 // Find start of empty space at the end of the area. This serves for both
gustavatmel 1:9c5af431a1f1 790 // knowing whether the area is empty and for the record traversal at the end.
gustavatmel 1:9c5af431a1f1 791 os_ret = calc_empty_space(area, free_space_offset_of_area[area]);
gustavatmel 1:9c5af431a1f1 792 MBED_ASSERT(!os_ret);
gustavatmel 1:9c5af431a1f1 793
gustavatmel 1:9c5af431a1f1 794 if (!free_space_offset_of_area[area]) {
gustavatmel 1:9c5af431a1f1 795 area_state[area] = NVSTORE_AREA_STATE_EMPTY;
gustavatmel 1:9c5af431a1f1 796 continue;
gustavatmel 1:9c5af431a1f1 797 }
gustavatmel 1:9c5af431a1f1 798
gustavatmel 1:9c5af431a1f1 799 // Check validity of master record
gustavatmel 1:9c5af431a1f1 800 master_record_data_t master_rec;
gustavatmel 1:9c5af431a1f1 801 ret = read_record(area, 0, sizeof(master_rec), &master_rec,
gustavatmel 1:9c5af431a1f1 802 actual_size, 0, valid,
gustavatmel 1:9c5af431a1f1 803 key, flags, next_offset);
gustavatmel 1:9c5af431a1f1 804 MBED_ASSERT((ret == NVSTORE_SUCCESS) || (ret == NVSTORE_BUFF_TOO_SMALL));
gustavatmel 1:9c5af431a1f1 805 if (ret == NVSTORE_BUFF_TOO_SMALL) {
gustavatmel 1:9c5af431a1f1 806 // Buf too small error means that we have a corrupt master record -
gustavatmel 1:9c5af431a1f1 807 // treat it as such
gustavatmel 1:9c5af431a1f1 808 valid = 0;
gustavatmel 1:9c5af431a1f1 809 }
gustavatmel 1:9c5af431a1f1 810
gustavatmel 1:9c5af431a1f1 811 // We have a non valid master record, in a non-empty area. Just erase the area.
gustavatmel 1:9c5af431a1f1 812 if ((!valid) || (key != master_record_key)) {
gustavatmel 1:9c5af431a1f1 813 os_ret = flash_erase_area(area);
gustavatmel 1:9c5af431a1f1 814 MBED_ASSERT(!os_ret);
gustavatmel 1:9c5af431a1f1 815 area_state[area] = NVSTORE_AREA_STATE_EMPTY;
gustavatmel 1:9c5af431a1f1 816 continue;
gustavatmel 1:9c5af431a1f1 817 }
gustavatmel 1:9c5af431a1f1 818 versions[area] = master_rec.version;
gustavatmel 1:9c5af431a1f1 819
gustavatmel 1:9c5af431a1f1 820 // Place _free_space_offset after the master record (for the traversal,
gustavatmel 1:9c5af431a1f1 821 // which takes place after this loop).
gustavatmel 1:9c5af431a1f1 822 _free_space_offset = next_offset;
gustavatmel 1:9c5af431a1f1 823 area_state[area] = NVSTORE_AREA_STATE_VALID;
gustavatmel 1:9c5af431a1f1 824
gustavatmel 1:9c5af431a1f1 825 // Unless both areas are valid (a case handled later), getting here means
gustavatmel 1:9c5af431a1f1 826 // that we found our active area.
gustavatmel 1:9c5af431a1f1 827 _active_area = area;
gustavatmel 1:9c5af431a1f1 828 _active_area_version = versions[area];
gustavatmel 1:9c5af431a1f1 829 }
gustavatmel 1:9c5af431a1f1 830
gustavatmel 1:9c5af431a1f1 831 // In case we have two empty areas, arbitrarily assign 0 to the active one.
gustavatmel 1:9c5af431a1f1 832 if ((area_state[0] == NVSTORE_AREA_STATE_EMPTY) && (area_state[1] == NVSTORE_AREA_STATE_EMPTY)) {
gustavatmel 1:9c5af431a1f1 833 _active_area = 0;
gustavatmel 1:9c5af431a1f1 834 ret = write_master_record(_active_area, 1, _free_space_offset);
gustavatmel 1:9c5af431a1f1 835 MBED_ASSERT(ret == NVSTORE_SUCCESS);
gustavatmel 1:9c5af431a1f1 836 _init_done = 1;
gustavatmel 1:9c5af431a1f1 837 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 838 }
gustavatmel 1:9c5af431a1f1 839
gustavatmel 1:9c5af431a1f1 840 // In case we have two valid areas, choose the one having the higher version (or 0
gustavatmel 1:9c5af431a1f1 841 // in case of wrap around). Erase the other one.
gustavatmel 1:9c5af431a1f1 842 if ((area_state[0] == NVSTORE_AREA_STATE_VALID) && (area_state[1] == NVSTORE_AREA_STATE_VALID)) {
gustavatmel 1:9c5af431a1f1 843 if ((versions[0] > versions[1]) || (!versions[0])) {
gustavatmel 1:9c5af431a1f1 844 _active_area = 0;
gustavatmel 1:9c5af431a1f1 845 } else {
gustavatmel 1:9c5af431a1f1 846 _active_area = 1;
gustavatmel 1:9c5af431a1f1 847 }
gustavatmel 1:9c5af431a1f1 848 _active_area_version = versions[_active_area];
gustavatmel 1:9c5af431a1f1 849 os_ret = flash_erase_area(1 - _active_area);
gustavatmel 1:9c5af431a1f1 850 MBED_ASSERT(!os_ret);
gustavatmel 1:9c5af431a1f1 851 }
gustavatmel 1:9c5af431a1f1 852
gustavatmel 1:9c5af431a1f1 853 // Traverse area until reaching the empty space at the end or until reaching a faulty record
gustavatmel 1:9c5af431a1f1 854 while (_free_space_offset < free_space_offset_of_area[_active_area]) {
gustavatmel 1:9c5af431a1f1 855 ret = read_record(_active_area, _free_space_offset, 0, NULL,
gustavatmel 1:9c5af431a1f1 856 actual_size, 1, valid,
gustavatmel 1:9c5af431a1f1 857 key, flags, next_offset);
gustavatmel 1:9c5af431a1f1 858 MBED_ASSERT(ret == NVSTORE_SUCCESS);
gustavatmel 1:9c5af431a1f1 859
gustavatmel 1:9c5af431a1f1 860 // In case we have a faulty record, this probably means that the system crashed when written.
gustavatmel 1:9c5af431a1f1 861 // Perform a garbage collection, to make the the other area valid.
gustavatmel 1:9c5af431a1f1 862 if (!valid) {
gustavatmel 1:9c5af431a1f1 863 ret = garbage_collection(no_key, 0, 0, NULL);
gustavatmel 1:9c5af431a1f1 864 break;
gustavatmel 1:9c5af431a1f1 865 }
gustavatmel 1:9c5af431a1f1 866 if (flags & delete_item_flag) {
gustavatmel 1:9c5af431a1f1 867 _offset_by_key[key] = 0;
gustavatmel 1:9c5af431a1f1 868 } else {
gustavatmel 1:9c5af431a1f1 869 _offset_by_key[key] = _free_space_offset | (_active_area << offs_by_key_area_bit_pos) |
gustavatmel 1:9c5af431a1f1 870 (((flags & set_once_flag) != 0) << offs_by_key_set_once_bit_pos);
gustavatmel 1:9c5af431a1f1 871 }
gustavatmel 1:9c5af431a1f1 872 _free_space_offset = next_offset;
gustavatmel 1:9c5af431a1f1 873 }
gustavatmel 1:9c5af431a1f1 874
gustavatmel 1:9c5af431a1f1 875 _init_done = 1;
gustavatmel 1:9c5af431a1f1 876 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 877 }
gustavatmel 1:9c5af431a1f1 878
gustavatmel 1:9c5af431a1f1 879 int NVStore::deinit()
gustavatmel 1:9c5af431a1f1 880 {
gustavatmel 1:9c5af431a1f1 881 if (_init_done) {
gustavatmel 1:9c5af431a1f1 882 _flash->deinit();
gustavatmel 1:9c5af431a1f1 883 delete _flash;
gustavatmel 1:9c5af431a1f1 884 delete _mutex;
gustavatmel 1:9c5af431a1f1 885 delete[] _offset_by_key;
gustavatmel 1:9c5af431a1f1 886 if (_page_buf) {
gustavatmel 1:9c5af431a1f1 887 delete[] _page_buf;
gustavatmel 1:9c5af431a1f1 888 _page_buf = 0;
gustavatmel 1:9c5af431a1f1 889 }
gustavatmel 1:9c5af431a1f1 890 }
gustavatmel 1:9c5af431a1f1 891
gustavatmel 1:9c5af431a1f1 892 _init_attempts = 0;
gustavatmel 1:9c5af431a1f1 893 _init_done = 0;
gustavatmel 1:9c5af431a1f1 894
gustavatmel 1:9c5af431a1f1 895 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 896 }
gustavatmel 1:9c5af431a1f1 897
gustavatmel 1:9c5af431a1f1 898 int NVStore::reset()
gustavatmel 1:9c5af431a1f1 899 {
gustavatmel 1:9c5af431a1f1 900 uint8_t area;
gustavatmel 1:9c5af431a1f1 901 int os_ret;
gustavatmel 1:9c5af431a1f1 902
gustavatmel 1:9c5af431a1f1 903 if (!_init_done) {
gustavatmel 1:9c5af431a1f1 904 init();
gustavatmel 1:9c5af431a1f1 905 }
gustavatmel 1:9c5af431a1f1 906
gustavatmel 1:9c5af431a1f1 907 // Erase both areas, and reinitialize the module. This is totally not thread safe,
gustavatmel 1:9c5af431a1f1 908 // as init doesn't take the case of re-initialization into account. It's OK, as this function
gustavatmel 1:9c5af431a1f1 909 // should only be called in pre-production cases.
gustavatmel 1:9c5af431a1f1 910 for (area = 0; area < NVSTORE_NUM_AREAS; area++) {
gustavatmel 1:9c5af431a1f1 911 os_ret = flash_erase_area(area);
gustavatmel 1:9c5af431a1f1 912 if (os_ret) {
gustavatmel 1:9c5af431a1f1 913 return NVSTORE_WRITE_ERROR;
gustavatmel 1:9c5af431a1f1 914 }
gustavatmel 1:9c5af431a1f1 915 }
gustavatmel 1:9c5af431a1f1 916
gustavatmel 1:9c5af431a1f1 917 deinit();
gustavatmel 1:9c5af431a1f1 918 return init();
gustavatmel 1:9c5af431a1f1 919 }
gustavatmel 1:9c5af431a1f1 920
gustavatmel 1:9c5af431a1f1 921 int NVStore::get_area_params(uint8_t area, uint32_t &address, size_t &size)
gustavatmel 1:9c5af431a1f1 922 {
gustavatmel 1:9c5af431a1f1 923 if (area >= NVSTORE_NUM_AREAS) {
gustavatmel 1:9c5af431a1f1 924 return NVSTORE_BAD_VALUE;
gustavatmel 1:9c5af431a1f1 925 }
gustavatmel 1:9c5af431a1f1 926
gustavatmel 1:9c5af431a1f1 927 if (!_init_done) {
gustavatmel 1:9c5af431a1f1 928 init();
gustavatmel 1:9c5af431a1f1 929 }
gustavatmel 1:9c5af431a1f1 930
gustavatmel 1:9c5af431a1f1 931 address = _flash_area_params[area].address;
gustavatmel 1:9c5af431a1f1 932 size = _flash_area_params[area].size;
gustavatmel 1:9c5af431a1f1 933
gustavatmel 1:9c5af431a1f1 934 return NVSTORE_SUCCESS;
gustavatmel 1:9c5af431a1f1 935 }
gustavatmel 1:9c5af431a1f1 936
gustavatmel 1:9c5af431a1f1 937 size_t NVStore::size()
gustavatmel 1:9c5af431a1f1 938 {
gustavatmel 1:9c5af431a1f1 939 if (!_init_done) {
gustavatmel 1:9c5af431a1f1 940 init();
gustavatmel 1:9c5af431a1f1 941 }
gustavatmel 1:9c5af431a1f1 942
gustavatmel 1:9c5af431a1f1 943 return _size;
gustavatmel 1:9c5af431a1f1 944 }
gustavatmel 1:9c5af431a1f1 945
gustavatmel 1:9c5af431a1f1 946 #endif // NVSTORE_ENABLED