No Changes

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:11 2016 +0100
Revision:
32:ece16b5987dd
Parent:
31:87789e55bac7
Child:
35:8ce23bc1af38
Synchronized with git rev 36d9130b

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jonathan Austin 1:8aa5cdb4ab67 1 /*
Jonathan Austin 1:8aa5cdb4ab67 2 The MIT License (MIT)
Jonathan Austin 1:8aa5cdb4ab67 3
Jonathan Austin 1:8aa5cdb4ab67 4 Copyright (c) 2016 British Broadcasting Corporation.
Jonathan Austin 1:8aa5cdb4ab67 5 This software is provided by Lancaster University by arrangement with the BBC.
Jonathan Austin 1:8aa5cdb4ab67 6
Jonathan Austin 1:8aa5cdb4ab67 7 Permission is hereby granted, free of charge, to any person obtaining a
Jonathan Austin 1:8aa5cdb4ab67 8 copy of this software and associated documentation files (the "Software"),
Jonathan Austin 1:8aa5cdb4ab67 9 to deal in the Software without restriction, including without limitation
Jonathan Austin 1:8aa5cdb4ab67 10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
Jonathan Austin 1:8aa5cdb4ab67 11 and/or sell copies of the Software, and to permit persons to whom the
Jonathan Austin 1:8aa5cdb4ab67 12 Software is furnished to do so, subject to the following conditions:
Jonathan Austin 1:8aa5cdb4ab67 13
Jonathan Austin 1:8aa5cdb4ab67 14 The above copyright notice and this permission notice shall be included in
Jonathan Austin 1:8aa5cdb4ab67 15 all copies or substantial portions of the Software.
Jonathan Austin 1:8aa5cdb4ab67 16
Jonathan Austin 1:8aa5cdb4ab67 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Jonathan Austin 1:8aa5cdb4ab67 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Jonathan Austin 1:8aa5cdb4ab67 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Jonathan Austin 1:8aa5cdb4ab67 20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Jonathan Austin 1:8aa5cdb4ab67 22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 23 DEALINGS IN THE SOFTWARE.
Jonathan Austin 1:8aa5cdb4ab67 24 */
Jonathan Austin 1:8aa5cdb4ab67 25
Jonathan Austin 1:8aa5cdb4ab67 26 /**
Jonathan Austin 1:8aa5cdb4ab67 27 * Class definition for the MicroBitStorage class.
Jonathan Austin 1:8aa5cdb4ab67 28 * This allows reading and writing of FLASH memory.
Jonathan Austin 1:8aa5cdb4ab67 29 */
Jonathan Austin 1:8aa5cdb4ab67 30
Jonathan Austin 1:8aa5cdb4ab67 31 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 32 #include "MicroBitStorage.h"
Jonathan Austin 1:8aa5cdb4ab67 33 #include "MicroBitCompat.h"
Jonathan Austin 1:8aa5cdb4ab67 34
Jonathan Austin 1:8aa5cdb4ab67 35 /**
Jonathan Austin 1:8aa5cdb4ab67 36 * Default constructor.
Jonathan Austin 1:8aa5cdb4ab67 37 *
Jonathan Austin 1:8aa5cdb4ab67 38 * Creates an instance of MicroBitStorage which acts like a KeyValueStore
Jonathan Austin 1:8aa5cdb4ab67 39 * that allows the retrieval, addition and deletion of KeyValuePairs.
Jonathan Austin 1:8aa5cdb4ab67 40 */
Jonathan Austin 1:8aa5cdb4ab67 41 MicroBitStorage::MicroBitStorage()
Jonathan Austin 1:8aa5cdb4ab67 42 {
Jonathan Austin 1:8aa5cdb4ab67 43 //initialise our magic block, if required.
Jonathan Austin 1:8aa5cdb4ab67 44 size();
Jonathan Austin 1:8aa5cdb4ab67 45 }
Jonathan Austin 1:8aa5cdb4ab67 46
Jonathan Austin 1:8aa5cdb4ab67 47 /**
Jonathan Austin 1:8aa5cdb4ab67 48 * Writes the given number of bytes to the address specified.
Jonathan Austin 1:8aa5cdb4ab67 49 *
Jonathan Austin 1:8aa5cdb4ab67 50 * @param buffer the data to write.
Jonathan Austin 1:8aa5cdb4ab67 51 *
Jonathan Austin 1:8aa5cdb4ab67 52 * @param address the location in memory to write to.
Jonathan Austin 1:8aa5cdb4ab67 53 *
Jonathan Austin 1:8aa5cdb4ab67 54 * @param length the number of bytes to write.
Jonathan Austin 1:8aa5cdb4ab67 55 *
Jonathan Austin 1:8aa5cdb4ab67 56 * @note currently not implemented.
Jonathan Austin 1:8aa5cdb4ab67 57 */
Jonathan Austin 1:8aa5cdb4ab67 58 int MicroBitStorage::writeBytes(uint8_t *buffer, uint32_t address, int length)
Jonathan Austin 1:8aa5cdb4ab67 59 {
Jonathan Austin 1:8aa5cdb4ab67 60 (void) buffer;
Jonathan Austin 1:8aa5cdb4ab67 61 (void) address;
Jonathan Austin 1:8aa5cdb4ab67 62 (void) length;
Jonathan Austin 1:8aa5cdb4ab67 63
Jonathan Austin 1:8aa5cdb4ab67 64 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 65 }
Jonathan Austin 1:8aa5cdb4ab67 66
Jonathan Austin 1:8aa5cdb4ab67 67 /**
Jonathan Austin 1:8aa5cdb4ab67 68 * Method for erasing a page in flash.
Jonathan Austin 1:8aa5cdb4ab67 69 *
Jonathan Austin 1:8aa5cdb4ab67 70 * @param page_address Address of the first word in the page to be erased.
Jonathan Austin 1:8aa5cdb4ab67 71 */
Jonathan Austin 1:8aa5cdb4ab67 72 void MicroBitStorage::flashPageErase(uint32_t * page_address)
Jonathan Austin 1:8aa5cdb4ab67 73 {
Jonathan Austin 1:8aa5cdb4ab67 74 // Turn on flash erase enable and wait until the NVMC is ready:
Jonathan Austin 1:8aa5cdb4ab67 75 NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);
Jonathan Austin 1:8aa5cdb4ab67 76
Jonathan Austin 1:8aa5cdb4ab67 77 while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
Jonathan Austin 1:8aa5cdb4ab67 78
Jonathan Austin 1:8aa5cdb4ab67 79 // Erase page:
Jonathan Austin 1:8aa5cdb4ab67 80 NRF_NVMC->ERASEPAGE = (uint32_t)page_address;
Jonathan Austin 1:8aa5cdb4ab67 81
Jonathan Austin 1:8aa5cdb4ab67 82 while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
Jonathan Austin 1:8aa5cdb4ab67 83
Jonathan Austin 1:8aa5cdb4ab67 84 // Turn off flash erase enable and wait until the NVMC is ready:
Jonathan Austin 1:8aa5cdb4ab67 85 NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
Jonathan Austin 1:8aa5cdb4ab67 86
Jonathan Austin 1:8aa5cdb4ab67 87 while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
Jonathan Austin 1:8aa5cdb4ab67 88 }
Jonathan Austin 1:8aa5cdb4ab67 89
Jonathan Austin 1:8aa5cdb4ab67 90 /**
Jonathan Austin 1:8aa5cdb4ab67 91 * Function for copying words from one location to another.
Jonathan Austin 1:8aa5cdb4ab67 92 *
Jonathan Austin 1:8aa5cdb4ab67 93 * @param from the address to copy data from.
Jonathan Austin 1:8aa5cdb4ab67 94 *
Jonathan Austin 1:8aa5cdb4ab67 95 * @param to the address to copy the data to.
Jonathan Austin 1:8aa5cdb4ab67 96 *
Jonathan Austin 1:8aa5cdb4ab67 97 * @param sizeInWords the number of words to copy
Jonathan Austin 1:8aa5cdb4ab67 98 */
Jonathan Austin 1:8aa5cdb4ab67 99 void MicroBitStorage::flashCopy(uint32_t* from, uint32_t* to, int sizeInWords)
Jonathan Austin 1:8aa5cdb4ab67 100 {
Jonathan Austin 1:8aa5cdb4ab67 101 // Turn on flash write enable and wait until the NVMC is ready:
Jonathan Austin 1:8aa5cdb4ab67 102 NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
Jonathan Austin 1:8aa5cdb4ab67 103
Jonathan Austin 1:8aa5cdb4ab67 104 while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {};
Jonathan Austin 1:8aa5cdb4ab67 105
Jonathan Austin 1:8aa5cdb4ab67 106 for(int i = 0; i < sizeInWords; i++)
Jonathan Austin 1:8aa5cdb4ab67 107 {
Jonathan Austin 1:8aa5cdb4ab67 108 *(to + i) = *(from + i);
Jonathan Austin 1:8aa5cdb4ab67 109 while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {};
Jonathan Austin 1:8aa5cdb4ab67 110 }
Jonathan Austin 1:8aa5cdb4ab67 111
Jonathan Austin 1:8aa5cdb4ab67 112 // Turn off flash write enable and wait until the NVMC is ready:
Jonathan Austin 1:8aa5cdb4ab67 113 NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
Jonathan Austin 1:8aa5cdb4ab67 114 while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {};
Jonathan Austin 1:8aa5cdb4ab67 115 }
Jonathan Austin 1:8aa5cdb4ab67 116
Jonathan Austin 1:8aa5cdb4ab67 117 /**
Jonathan Austin 1:8aa5cdb4ab67 118 * Method for writing a word of data in flash with a value.
Jonathan Austin 1:8aa5cdb4ab67 119 *
Jonathan Austin 1:8aa5cdb4ab67 120 * @param address Address of the word to change.
Jonathan Austin 1:8aa5cdb4ab67 121 *
Jonathan Austin 1:8aa5cdb4ab67 122 * @param value Value to be written to flash.
Jonathan Austin 1:8aa5cdb4ab67 123 */
Jonathan Austin 1:8aa5cdb4ab67 124 void MicroBitStorage::flashWordWrite(uint32_t * address, uint32_t value)
Jonathan Austin 1:8aa5cdb4ab67 125 {
Jonathan Austin 1:8aa5cdb4ab67 126 // Turn on flash write enable and wait until the NVMC is ready:
Jonathan Austin 1:8aa5cdb4ab67 127 NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);
Jonathan Austin 1:8aa5cdb4ab67 128
Jonathan Austin 1:8aa5cdb4ab67 129 while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
Jonathan Austin 1:8aa5cdb4ab67 130
Jonathan Austin 1:8aa5cdb4ab67 131 *address = value;
Jonathan Austin 1:8aa5cdb4ab67 132
Jonathan Austin 1:8aa5cdb4ab67 133 while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
Jonathan Austin 1:8aa5cdb4ab67 134
Jonathan Austin 1:8aa5cdb4ab67 135 // Turn off flash write enable and wait until the NVMC is ready:
Jonathan Austin 1:8aa5cdb4ab67 136 NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);
Jonathan Austin 1:8aa5cdb4ab67 137
Jonathan Austin 1:8aa5cdb4ab67 138 while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
Jonathan Austin 1:8aa5cdb4ab67 139 }
Jonathan Austin 1:8aa5cdb4ab67 140
Jonathan Austin 1:8aa5cdb4ab67 141 /**
Jonathan Austin 1:8aa5cdb4ab67 142 * Function for populating the scratch page with a KeyValueStore.
Jonathan Austin 1:8aa5cdb4ab67 143 *
Jonathan Austin 1:8aa5cdb4ab67 144 * @param store the KeyValueStore struct to write to the scratch page.
Jonathan Austin 1:8aa5cdb4ab67 145 */
Jonathan Austin 1:8aa5cdb4ab67 146 void MicroBitStorage::scratchKeyValueStore(KeyValueStore store)
Jonathan Austin 1:8aa5cdb4ab67 147 {
Jonathan Austin 1:8aa5cdb4ab67 148 //calculate our various offsets
Jonathan Austin 1:8aa5cdb4ab67 149 uint32_t *s = (uint32_t *) &store;
Jonathan Austin 1:8aa5cdb4ab67 150 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 151
Jonathan Austin 1:8aa5cdb4ab67 152 uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 153
Jonathan Austin 1:8aa5cdb4ab67 154 //KeyValueStore is word aligned.
Jonathan Austin 1:8aa5cdb4ab67 155 int wordsToWrite = sizeof(KeyValueStore) / 4;
Jonathan Austin 1:8aa5cdb4ab67 156
Jonathan Austin 1:8aa5cdb4ab67 157 //write the given KeyValueStore
Jonathan Austin 1:8aa5cdb4ab67 158 for (int i = 0; i < wordsToWrite; i++)
Jonathan Austin 1:8aa5cdb4ab67 159 {
Jonathan Austin 1:8aa5cdb4ab67 160 flashWordWrite(scratchPointer, *s);
Jonathan Austin 1:8aa5cdb4ab67 161 scratchPointer++;
Jonathan Austin 1:8aa5cdb4ab67 162 s++;
Jonathan Austin 1:8aa5cdb4ab67 163 }
Jonathan Austin 1:8aa5cdb4ab67 164 }
Jonathan Austin 1:8aa5cdb4ab67 165
Jonathan Austin 1:8aa5cdb4ab67 166 /**
Jonathan Austin 1:8aa5cdb4ab67 167 * Function for populating the scratch page with a KeyValuePair.
Jonathan Austin 1:8aa5cdb4ab67 168 *
Jonathan Austin 1:8aa5cdb4ab67 169 * @param pair the KeyValuePair struct to write to the scratch page.
Jonathan Austin 1:8aa5cdb4ab67 170 *
Jonathan Austin 1:8aa5cdb4ab67 171 * @param flashPointer the pointer in flash where this KeyValuePair resides. This pointer
Jonathan Austin 1:8aa5cdb4ab67 172 * is used to determine the offset into the scratch page, where the KeyValuePair should
Jonathan Austin 1:8aa5cdb4ab67 173 * be written.
Jonathan Austin 1:8aa5cdb4ab67 174 */
Jonathan Austin 1:8aa5cdb4ab67 175 void MicroBitStorage::scratchKeyValuePair(KeyValuePair pair, uint32_t* flashPointer)
Jonathan Austin 1:8aa5cdb4ab67 176 {
Jonathan Austin 1:8aa5cdb4ab67 177 //we can only write using words
Jonathan Austin 1:8aa5cdb4ab67 178 uint32_t *p = (uint32_t *) &pair;
Jonathan Austin 1:8aa5cdb4ab67 179
Jonathan Austin 1:8aa5cdb4ab67 180 //calculate our various offsets
Jonathan Austin 1:8aa5cdb4ab67 181 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 182 uint32_t pg_num = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
Jonathan Austin 1:8aa5cdb4ab67 183
Jonathan Austin 1:8aa5cdb4ab67 184 uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 185 uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
Jonathan Austin 1:8aa5cdb4ab67 186
Jonathan Austin 1:8aa5cdb4ab67 187 uint32_t flashPointerOffset = flashPointer - flashBlockPointer;
Jonathan Austin 1:8aa5cdb4ab67 188
Jonathan Austin 1:8aa5cdb4ab67 189 scratchPointer += flashPointerOffset;
Jonathan Austin 1:8aa5cdb4ab67 190
Jonathan Austin 1:8aa5cdb4ab67 191 //KeyValuePair is word aligned...
Jonathan Austin 1:8aa5cdb4ab67 192 int wordsToWrite = sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 193
Jonathan Austin 1:8aa5cdb4ab67 194 //write
Jonathan Austin 1:8aa5cdb4ab67 195 for (int i = 0; i < wordsToWrite; i++)
Jonathan Austin 1:8aa5cdb4ab67 196 {
Jonathan Austin 1:8aa5cdb4ab67 197 flashWordWrite(scratchPointer, *p);
Jonathan Austin 1:8aa5cdb4ab67 198 scratchPointer++;
Jonathan Austin 1:8aa5cdb4ab67 199 p++;
Jonathan Austin 1:8aa5cdb4ab67 200 }
Jonathan Austin 1:8aa5cdb4ab67 201 }
Jonathan Austin 1:8aa5cdb4ab67 202
Jonathan Austin 1:8aa5cdb4ab67 203 /**
Jonathan Austin 1:8aa5cdb4ab67 204 * Places a given key, and it's corresponding value into flash at the earliest
Jonathan Austin 1:8aa5cdb4ab67 205 * available point.
Jonathan Austin 1:8aa5cdb4ab67 206 *
Jonathan Austin 1:8aa5cdb4ab67 207 * @param key the unique name that should be used as an identifier for the given data.
Jonathan Austin 1:8aa5cdb4ab67 208 * The key is presumed to be null terminated.
Jonathan Austin 1:8aa5cdb4ab67 209 *
Jonathan Austin 1:8aa5cdb4ab67 210 * @param data a pointer to the beginning of the data to be persisted.
Jonathan Austin 1:8aa5cdb4ab67 211 *
LancasterUniversity 32:ece16b5987dd 212 * @param dataSize the size of the data to be persisted
LancasterUniversity 32:ece16b5987dd 213 *
LancasterUniversity 32:ece16b5987dd 214 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if the key or size is too large,
LancasterUniversity 32:ece16b5987dd 215 * MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 216 */
LancasterUniversity 32:ece16b5987dd 217 int MicroBitStorage::put(const char *key, uint8_t *data, int dataSize)
Jonathan Austin 1:8aa5cdb4ab67 218 {
Jonathan Austin 1:8aa5cdb4ab67 219 KeyValuePair pair = KeyValuePair();
Jonathan Austin 1:8aa5cdb4ab67 220
LancasterUniversity 32:ece16b5987dd 221 int keySize = strlen(key) + 1;
LancasterUniversity 32:ece16b5987dd 222
LancasterUniversity 32:ece16b5987dd 223 if(keySize > (int)sizeof(pair.key) || dataSize > (int)sizeof(pair.value) || dataSize < 0)
LancasterUniversity 32:ece16b5987dd 224 return MICROBIT_INVALID_PARAMETER;
LancasterUniversity 32:ece16b5987dd 225
LancasterUniversity 32:ece16b5987dd 226 memcpy(pair.key, key, keySize);
LancasterUniversity 32:ece16b5987dd 227 memcpy(pair.value, data, dataSize);
Jonathan Austin 1:8aa5cdb4ab67 228
Jonathan Austin 1:8aa5cdb4ab67 229 //calculate our various offsets.
Jonathan Austin 1:8aa5cdb4ab67 230 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 231 uint32_t *flashPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 232 uint32_t *flashBlockPointer = flashPointer;
Jonathan Austin 1:8aa5cdb4ab67 233 uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 234
Jonathan Austin 1:8aa5cdb4ab67 235 uint32_t kvStoreSize = sizeof(KeyValueStore) / 4;
Jonathan Austin 1:8aa5cdb4ab67 236 uint32_t kvPairSize = sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 237
Jonathan Austin 1:8aa5cdb4ab67 238 int storeSize = size();
Jonathan Austin 1:8aa5cdb4ab67 239
Jonathan Austin 1:8aa5cdb4ab67 240 //our KeyValueStore struct is always at 0
Jonathan Austin 1:8aa5cdb4ab67 241 flashPointer += kvStoreSize;
Jonathan Austin 1:8aa5cdb4ab67 242
Jonathan Austin 1:8aa5cdb4ab67 243 KeyValuePair storedPair = KeyValuePair();
Jonathan Austin 1:8aa5cdb4ab67 244
Jonathan Austin 1:8aa5cdb4ab67 245 int found = 0;
Jonathan Austin 1:8aa5cdb4ab67 246
Jonathan Austin 1:8aa5cdb4ab67 247 //erase our scratch page
Jonathan Austin 1:8aa5cdb4ab67 248 flashPageErase(scratchPointer);
Jonathan Austin 1:8aa5cdb4ab67 249
Jonathan Austin 1:8aa5cdb4ab67 250 //iterate through key value pairs in flash, writing them to the scratch page.
Jonathan Austin 1:8aa5cdb4ab67 251 for(int i = 0; i < storeSize; i++)
Jonathan Austin 1:8aa5cdb4ab67 252 {
Jonathan Austin 1:8aa5cdb4ab67 253 memcpy(&storedPair, flashPointer, sizeof(KeyValuePair));
Jonathan Austin 1:8aa5cdb4ab67 254
Jonathan Austin 1:8aa5cdb4ab67 255 //check if the keys match...
Jonathan Austin 1:8aa5cdb4ab67 256 if(strcmp((char *)storedPair.key, (char *)pair.key) == 0)
Jonathan Austin 1:8aa5cdb4ab67 257 {
Jonathan Austin 1:8aa5cdb4ab67 258 found = 1;
Jonathan Austin 1:8aa5cdb4ab67 259 //scratch our KeyValueStore struct so that it is preserved.
Jonathan Austin 1:8aa5cdb4ab67 260 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
Jonathan Austin 1:8aa5cdb4ab67 261 scratchKeyValuePair(pair, flashPointer);
Jonathan Austin 1:8aa5cdb4ab67 262 }
Jonathan Austin 1:8aa5cdb4ab67 263 else
Jonathan Austin 1:8aa5cdb4ab67 264 {
Jonathan Austin 1:8aa5cdb4ab67 265 scratchKeyValuePair(storedPair, flashPointer);
Jonathan Austin 1:8aa5cdb4ab67 266 }
Jonathan Austin 1:8aa5cdb4ab67 267
Jonathan Austin 1:8aa5cdb4ab67 268 flashPointer += kvPairSize;
Jonathan Austin 1:8aa5cdb4ab67 269 }
Jonathan Austin 1:8aa5cdb4ab67 270
Jonathan Austin 1:8aa5cdb4ab67 271 if(!found)
Jonathan Austin 1:8aa5cdb4ab67 272 {
Jonathan Austin 1:8aa5cdb4ab67 273 //if we haven't got a match for the key, check we can add a new KeyValuePair
Jonathan Austin 1:8aa5cdb4ab67 274 if(storeSize == (int)((pg_size - kvStoreSize) / MICROBIT_STORAGE_BLOCK_SIZE))
Jonathan Austin 1:8aa5cdb4ab67 275 return MICROBIT_NO_RESOURCES;
Jonathan Austin 1:8aa5cdb4ab67 276
Jonathan Austin 1:8aa5cdb4ab67 277 storeSize += 1;
Jonathan Austin 1:8aa5cdb4ab67 278
Jonathan Austin 1:8aa5cdb4ab67 279 //scratch our updated values.
Jonathan Austin 1:8aa5cdb4ab67 280 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
Jonathan Austin 1:8aa5cdb4ab67 281 scratchKeyValuePair(pair, flashPointer);
Jonathan Austin 1:8aa5cdb4ab67 282 }
Jonathan Austin 1:8aa5cdb4ab67 283
Jonathan Austin 1:8aa5cdb4ab67 284 //erase our storage page
Jonathan Austin 1:8aa5cdb4ab67 285 flashPageErase((uint32_t *)flashBlockPointer);
Jonathan Austin 1:8aa5cdb4ab67 286
Jonathan Austin 1:8aa5cdb4ab67 287 //copy from scratch to storage.
Jonathan Austin 1:8aa5cdb4ab67 288 flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, kvStoreSize + (storeSize * kvPairSize));
Jonathan Austin 1:8aa5cdb4ab67 289
Jonathan Austin 1:8aa5cdb4ab67 290 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 291 }
Jonathan Austin 1:8aa5cdb4ab67 292
Jonathan Austin 1:8aa5cdb4ab67 293 /**
Jonathan Austin 1:8aa5cdb4ab67 294 * Places a given key, and it's corresponding value into flash at the earliest
Jonathan Austin 1:8aa5cdb4ab67 295 * available point.
Jonathan Austin 1:8aa5cdb4ab67 296 *
Jonathan Austin 1:8aa5cdb4ab67 297 * @param key the unique name that should be used as an identifier for the given data.
Jonathan Austin 1:8aa5cdb4ab67 298 *
Jonathan Austin 1:8aa5cdb4ab67 299 * @param data a pointer to the beginning of the data to be persisted.
Jonathan Austin 1:8aa5cdb4ab67 300 *
LancasterUniversity 32:ece16b5987dd 301 * @param dataSize the size of the data to be persisted
LancasterUniversity 32:ece16b5987dd 302 *
LancasterUniversity 32:ece16b5987dd 303 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if the key or size is too large,
LancasterUniversity 32:ece16b5987dd 304 * MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 305 */
LancasterUniversity 32:ece16b5987dd 306 int MicroBitStorage::put(ManagedString key, uint8_t* data, int dataSize)
Jonathan Austin 1:8aa5cdb4ab67 307 {
LancasterUniversity 32:ece16b5987dd 308 return put((char *)key.toCharArray(), data, dataSize);
Jonathan Austin 1:8aa5cdb4ab67 309 }
Jonathan Austin 1:8aa5cdb4ab67 310
Jonathan Austin 1:8aa5cdb4ab67 311 /**
Jonathan Austin 1:8aa5cdb4ab67 312 * Retreives a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 313 *
Jonathan Austin 1:8aa5cdb4ab67 314 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 315 *
Jonathan Austin 1:8aa5cdb4ab67 316 * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
Jonathan Austin 1:8aa5cdb4ab67 317 * NULL if the key was not found in storage.
Jonathan Austin 1:8aa5cdb4ab67 318 *
Jonathan Austin 1:8aa5cdb4ab67 319 * @note it is up to the user to free memory after use.
Jonathan Austin 1:8aa5cdb4ab67 320 */
Jonathan Austin 1:8aa5cdb4ab67 321 KeyValuePair* MicroBitStorage::get(const char* key)
Jonathan Austin 1:8aa5cdb4ab67 322 {
Jonathan Austin 1:8aa5cdb4ab67 323 //calculate our offsets for our storage page
Jonathan Austin 1:8aa5cdb4ab67 324 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 325 uint32_t pg_num = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
Jonathan Austin 1:8aa5cdb4ab67 326
Jonathan Austin 1:8aa5cdb4ab67 327 uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
Jonathan Austin 1:8aa5cdb4ab67 328
Jonathan Austin 1:8aa5cdb4ab67 329 int storeSize = size();
Jonathan Austin 1:8aa5cdb4ab67 330
Jonathan Austin 1:8aa5cdb4ab67 331 //we haven't got anything stored, so return...
Jonathan Austin 1:8aa5cdb4ab67 332 if(storeSize == 0)
Jonathan Austin 1:8aa5cdb4ab67 333 return NULL;
Jonathan Austin 1:8aa5cdb4ab67 334
Jonathan Austin 1:8aa5cdb4ab67 335 //our KeyValueStore struct is always at 0
Jonathan Austin 1:8aa5cdb4ab67 336 flashBlockPointer += sizeof(KeyValueStore) / 4;
Jonathan Austin 1:8aa5cdb4ab67 337
Jonathan Austin 1:8aa5cdb4ab67 338 KeyValuePair *pair = new KeyValuePair();
Jonathan Austin 1:8aa5cdb4ab67 339
Jonathan Austin 1:8aa5cdb4ab67 340 int i;
Jonathan Austin 1:8aa5cdb4ab67 341
Jonathan Austin 1:8aa5cdb4ab67 342 //iterate through flash until we have a match, or drop out.
Jonathan Austin 1:8aa5cdb4ab67 343 for(i = 0; i < storeSize; i++)
Jonathan Austin 1:8aa5cdb4ab67 344 {
Jonathan Austin 1:8aa5cdb4ab67 345 memcpy(pair, flashBlockPointer, sizeof(KeyValuePair));
Jonathan Austin 1:8aa5cdb4ab67 346
Jonathan Austin 1:8aa5cdb4ab67 347 if(strcmp(key,(char *)pair->key) == 0)
Jonathan Austin 1:8aa5cdb4ab67 348 break;
Jonathan Austin 1:8aa5cdb4ab67 349
Jonathan Austin 1:8aa5cdb4ab67 350 flashBlockPointer += sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 351 }
Jonathan Austin 1:8aa5cdb4ab67 352
Jonathan Austin 1:8aa5cdb4ab67 353 //clean up
Jonathan Austin 1:8aa5cdb4ab67 354 if(i == storeSize)
Jonathan Austin 1:8aa5cdb4ab67 355 {
Jonathan Austin 1:8aa5cdb4ab67 356 delete pair;
Jonathan Austin 1:8aa5cdb4ab67 357 return NULL;
Jonathan Austin 1:8aa5cdb4ab67 358 }
Jonathan Austin 1:8aa5cdb4ab67 359
Jonathan Austin 1:8aa5cdb4ab67 360 return pair;
Jonathan Austin 1:8aa5cdb4ab67 361 }
Jonathan Austin 1:8aa5cdb4ab67 362
Jonathan Austin 1:8aa5cdb4ab67 363 /**
Jonathan Austin 1:8aa5cdb4ab67 364 * Retreives a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 365 *
Jonathan Austin 1:8aa5cdb4ab67 366 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 367 *
Jonathan Austin 1:8aa5cdb4ab67 368 * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
Jonathan Austin 1:8aa5cdb4ab67 369 * NULL if the key was not found in storage.
Jonathan Austin 1:8aa5cdb4ab67 370 *
Jonathan Austin 1:8aa5cdb4ab67 371 * @note it is up to the user to free memory after use.
Jonathan Austin 1:8aa5cdb4ab67 372 */
Jonathan Austin 1:8aa5cdb4ab67 373 KeyValuePair* MicroBitStorage::get(ManagedString key)
Jonathan Austin 1:8aa5cdb4ab67 374 {
Jonathan Austin 1:8aa5cdb4ab67 375 return get((char *)key.toCharArray());
Jonathan Austin 1:8aa5cdb4ab67 376 }
Jonathan Austin 1:8aa5cdb4ab67 377
Jonathan Austin 1:8aa5cdb4ab67 378 /**
Jonathan Austin 1:8aa5cdb4ab67 379 * Removes a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 380 *
Jonathan Austin 1:8aa5cdb4ab67 381 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 382 *
Jonathan Austin 1:8aa5cdb4ab67 383 * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
Jonathan Austin 1:8aa5cdb4ab67 384 * was not found in flash.
Jonathan Austin 1:8aa5cdb4ab67 385 */
Jonathan Austin 1:8aa5cdb4ab67 386 int MicroBitStorage::remove(const char* key)
Jonathan Austin 1:8aa5cdb4ab67 387 {
Jonathan Austin 1:8aa5cdb4ab67 388 //calculate our various offsets
Jonathan Austin 1:8aa5cdb4ab67 389 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 390 uint32_t *flashPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 391 uint32_t *flashBlockPointer = flashPointer;
Jonathan Austin 1:8aa5cdb4ab67 392 uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 393
Jonathan Austin 1:8aa5cdb4ab67 394 uint32_t kvStoreSize = sizeof(KeyValueStore) / 4;
Jonathan Austin 1:8aa5cdb4ab67 395 uint32_t kvPairSize = sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 396
Jonathan Austin 1:8aa5cdb4ab67 397 int storeSize = size();
Jonathan Austin 1:8aa5cdb4ab67 398
Jonathan Austin 1:8aa5cdb4ab67 399 //if we have no data, we have nothing to do.
Jonathan Austin 1:8aa5cdb4ab67 400 if(storeSize == 0)
Jonathan Austin 1:8aa5cdb4ab67 401 return MICROBIT_NO_DATA;
Jonathan Austin 1:8aa5cdb4ab67 402
Jonathan Austin 1:8aa5cdb4ab67 403 //our KeyValueStore struct is always at 0
Jonathan Austin 1:8aa5cdb4ab67 404 flashPointer += kvStoreSize;
Jonathan Austin 1:8aa5cdb4ab67 405 scratchPointer += kvStoreSize;
Jonathan Austin 1:8aa5cdb4ab67 406
Jonathan Austin 1:8aa5cdb4ab67 407 KeyValuePair storedPair = KeyValuePair();
Jonathan Austin 1:8aa5cdb4ab67 408
Jonathan Austin 1:8aa5cdb4ab67 409 int found = 0;
Jonathan Austin 1:8aa5cdb4ab67 410
Jonathan Austin 1:8aa5cdb4ab67 411 //set up our scratch area
Jonathan Austin 1:8aa5cdb4ab67 412 flashPageErase(scratchPointer);
Jonathan Austin 1:8aa5cdb4ab67 413
Jonathan Austin 1:8aa5cdb4ab67 414 //iterate through our flash copy pairs to scratch, unless there is a key patch
Jonathan Austin 1:8aa5cdb4ab67 415 for(int i = 0; i < storeSize; i++)
Jonathan Austin 1:8aa5cdb4ab67 416 {
Jonathan Austin 1:8aa5cdb4ab67 417 memcpy(&storedPair, flashPointer, sizeof(KeyValuePair));
Jonathan Austin 1:8aa5cdb4ab67 418
Jonathan Austin 1:8aa5cdb4ab67 419 //if we have a match, don't increment our scratchPointer
Jonathan Austin 1:8aa5cdb4ab67 420 if(strcmp((char *)storedPair.key, (char *)key) == 0)
Jonathan Austin 1:8aa5cdb4ab67 421 {
Jonathan Austin 1:8aa5cdb4ab67 422 found = 1;
Jonathan Austin 1:8aa5cdb4ab67 423 //write our new KeyValueStore data
Jonathan Austin 1:8aa5cdb4ab67 424 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize - 1));
Jonathan Austin 1:8aa5cdb4ab67 425 }
Jonathan Austin 1:8aa5cdb4ab67 426 else
Jonathan Austin 1:8aa5cdb4ab67 427 {
Jonathan Austin 1:8aa5cdb4ab67 428 //otherwise copy the KeyValuePair from our storage page.
Jonathan Austin 1:8aa5cdb4ab67 429 flashCopy(flashPointer, scratchPointer, sizeof(KeyValuePair) / 4);
Jonathan Austin 1:8aa5cdb4ab67 430 scratchPointer += sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 431 }
Jonathan Austin 1:8aa5cdb4ab67 432
Jonathan Austin 1:8aa5cdb4ab67 433 flashPointer += sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 434 }
Jonathan Austin 1:8aa5cdb4ab67 435
Jonathan Austin 1:8aa5cdb4ab67 436 //if we haven't got a match, write our old KeyValueStore struct
Jonathan Austin 1:8aa5cdb4ab67 437 if(!found)
Jonathan Austin 1:8aa5cdb4ab67 438 {
Jonathan Austin 1:8aa5cdb4ab67 439 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
Jonathan Austin 1:8aa5cdb4ab67 440 return MICROBIT_NO_DATA;
Jonathan Austin 1:8aa5cdb4ab67 441 }
Jonathan Austin 1:8aa5cdb4ab67 442
Jonathan Austin 1:8aa5cdb4ab67 443 //copy scratch to our storage page
Jonathan Austin 1:8aa5cdb4ab67 444 flashPageErase((uint32_t *)flashBlockPointer);
Jonathan Austin 1:8aa5cdb4ab67 445 flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, kvStoreSize + (storeSize * kvPairSize));
Jonathan Austin 1:8aa5cdb4ab67 446
Jonathan Austin 1:8aa5cdb4ab67 447 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 448 }
Jonathan Austin 1:8aa5cdb4ab67 449
Jonathan Austin 1:8aa5cdb4ab67 450 /**
Jonathan Austin 1:8aa5cdb4ab67 451 * Removes a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 452 *
Jonathan Austin 1:8aa5cdb4ab67 453 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 454 *
Jonathan Austin 1:8aa5cdb4ab67 455 * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
Jonathan Austin 1:8aa5cdb4ab67 456 * was not found in flash.
Jonathan Austin 1:8aa5cdb4ab67 457 */
Jonathan Austin 1:8aa5cdb4ab67 458 int MicroBitStorage::remove(ManagedString key)
Jonathan Austin 1:8aa5cdb4ab67 459 {
Jonathan Austin 1:8aa5cdb4ab67 460 return remove((char *)key.toCharArray());
Jonathan Austin 1:8aa5cdb4ab67 461 }
Jonathan Austin 1:8aa5cdb4ab67 462
Jonathan Austin 1:8aa5cdb4ab67 463 /**
Jonathan Austin 1:8aa5cdb4ab67 464 * The size of the flash based KeyValueStore.
Jonathan Austin 1:8aa5cdb4ab67 465 *
Jonathan Austin 1:8aa5cdb4ab67 466 * @return the number of entries in the key value store
Jonathan Austin 1:8aa5cdb4ab67 467 */
Jonathan Austin 1:8aa5cdb4ab67 468 int MicroBitStorage::size()
Jonathan Austin 1:8aa5cdb4ab67 469 {
Jonathan Austin 1:8aa5cdb4ab67 470 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 471 uint32_t pg_num = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
Jonathan Austin 1:8aa5cdb4ab67 472
Jonathan Austin 1:8aa5cdb4ab67 473 uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
Jonathan Austin 1:8aa5cdb4ab67 474
Jonathan Austin 1:8aa5cdb4ab67 475 KeyValueStore store = KeyValueStore();
Jonathan Austin 1:8aa5cdb4ab67 476
Jonathan Austin 1:8aa5cdb4ab67 477 //read our data!
Jonathan Austin 1:8aa5cdb4ab67 478 memcpy(&store, flashBlockPointer, sizeof(KeyValueStore));
Jonathan Austin 1:8aa5cdb4ab67 479
Jonathan Austin 1:8aa5cdb4ab67 480 //if we haven't used flash before, we need to configure it
Jonathan Austin 1:8aa5cdb4ab67 481 if(store.magic != MICROBIT_STORAGE_MAGIC)
Jonathan Austin 1:8aa5cdb4ab67 482 {
Jonathan Austin 1:8aa5cdb4ab67 483 store.magic = MICROBIT_STORAGE_MAGIC;
Jonathan Austin 1:8aa5cdb4ab67 484 store.size = 0;
Jonathan Austin 1:8aa5cdb4ab67 485
Jonathan Austin 1:8aa5cdb4ab67 486 //erase the scratch page and write our new KeyValueStore
Jonathan Austin 1:8aa5cdb4ab67 487 flashPageErase((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)));
Jonathan Austin 1:8aa5cdb4ab67 488 scratchKeyValueStore(store);
Jonathan Austin 1:8aa5cdb4ab67 489
Jonathan Austin 1:8aa5cdb4ab67 490 //erase flash, and copy the scratch page over
Jonathan Austin 1:8aa5cdb4ab67 491 flashPageErase((uint32_t *)flashBlockPointer);
Jonathan Austin 1:8aa5cdb4ab67 492 flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, pg_size/4);
Jonathan Austin 1:8aa5cdb4ab67 493 }
Jonathan Austin 1:8aa5cdb4ab67 494
Jonathan Austin 1:8aa5cdb4ab67 495 return store.size;
LancasterUniversity 30:db87179335d5 496 }