https://github.com/WebBluetoothCG/demos/pull/42

Dependencies:   BLE_API mbed-dev-bin nRF51822

Fork of microbit-dal by Lancaster University

Committer:
fbeaufort
Date:
Thu Jul 21 07:19:19 2016 +0000
Revision:
74:04376b21995b
Parent:
48:34d1adb6771c
First commit

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 37:b624ae5e94a5 212 * @param dataSize the size of the data to be persisted
LancasterUniversity 37:b624ae5e94a5 213 *
LancasterUniversity 37:b624ae5e94a5 214 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if the key or size is too large,
LancasterUniversity 37:b624ae5e94a5 215 * MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 216 */
LancasterUniversity 37:b624ae5e94a5 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 37:b624ae5e94a5 221 int keySize = strlen(key) + 1;
LancasterUniversity 37:b624ae5e94a5 222
LancasterUniversity 37:b624ae5e94a5 223 if(keySize > (int)sizeof(pair.key) || dataSize > (int)sizeof(pair.value) || dataSize < 0)
LancasterUniversity 37:b624ae5e94a5 224 return MICROBIT_INVALID_PARAMETER;
LancasterUniversity 37:b624ae5e94a5 225
LancasterUniversity 48:34d1adb6771c 226 KeyValuePair *currentValue = get(key);
LancasterUniversity 48:34d1adb6771c 227
LancasterUniversity 48:34d1adb6771c 228 int upToDate = currentValue && (memcmp(currentValue->value, data, dataSize) == 0);
LancasterUniversity 48:34d1adb6771c 229
LancasterUniversity 48:34d1adb6771c 230 if(currentValue)
LancasterUniversity 48:34d1adb6771c 231 delete currentValue;
LancasterUniversity 48:34d1adb6771c 232
LancasterUniversity 48:34d1adb6771c 233 if(upToDate)
LancasterUniversity 48:34d1adb6771c 234 return MICROBIT_OK;
LancasterUniversity 48:34d1adb6771c 235
LancasterUniversity 37:b624ae5e94a5 236 memcpy(pair.key, key, keySize);
LancasterUniversity 37:b624ae5e94a5 237 memcpy(pair.value, data, dataSize);
Jonathan Austin 1:8aa5cdb4ab67 238
Jonathan Austin 1:8aa5cdb4ab67 239 //calculate our various offsets.
Jonathan Austin 1:8aa5cdb4ab67 240 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 241 uint32_t *flashPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 242 uint32_t *flashBlockPointer = flashPointer;
Jonathan Austin 1:8aa5cdb4ab67 243 uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 244
Jonathan Austin 1:8aa5cdb4ab67 245 uint32_t kvStoreSize = sizeof(KeyValueStore) / 4;
Jonathan Austin 1:8aa5cdb4ab67 246 uint32_t kvPairSize = sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 247
Jonathan Austin 1:8aa5cdb4ab67 248 int storeSize = size();
Jonathan Austin 1:8aa5cdb4ab67 249
Jonathan Austin 1:8aa5cdb4ab67 250 //our KeyValueStore struct is always at 0
Jonathan Austin 1:8aa5cdb4ab67 251 flashPointer += kvStoreSize;
Jonathan Austin 1:8aa5cdb4ab67 252
Jonathan Austin 1:8aa5cdb4ab67 253 KeyValuePair storedPair = KeyValuePair();
Jonathan Austin 1:8aa5cdb4ab67 254
Jonathan Austin 1:8aa5cdb4ab67 255 int found = 0;
Jonathan Austin 1:8aa5cdb4ab67 256
Jonathan Austin 1:8aa5cdb4ab67 257 //erase our scratch page
Jonathan Austin 1:8aa5cdb4ab67 258 flashPageErase(scratchPointer);
Jonathan Austin 1:8aa5cdb4ab67 259
Jonathan Austin 1:8aa5cdb4ab67 260 //iterate through key value pairs in flash, writing them to the scratch page.
Jonathan Austin 1:8aa5cdb4ab67 261 for(int i = 0; i < storeSize; i++)
Jonathan Austin 1:8aa5cdb4ab67 262 {
Jonathan Austin 1:8aa5cdb4ab67 263 memcpy(&storedPair, flashPointer, sizeof(KeyValuePair));
Jonathan Austin 1:8aa5cdb4ab67 264
Jonathan Austin 1:8aa5cdb4ab67 265 //check if the keys match...
Jonathan Austin 1:8aa5cdb4ab67 266 if(strcmp((char *)storedPair.key, (char *)pair.key) == 0)
Jonathan Austin 1:8aa5cdb4ab67 267 {
Jonathan Austin 1:8aa5cdb4ab67 268 found = 1;
Jonathan Austin 1:8aa5cdb4ab67 269 //scratch our KeyValueStore struct so that it is preserved.
Jonathan Austin 1:8aa5cdb4ab67 270 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
Jonathan Austin 1:8aa5cdb4ab67 271 scratchKeyValuePair(pair, flashPointer);
Jonathan Austin 1:8aa5cdb4ab67 272 }
Jonathan Austin 1:8aa5cdb4ab67 273 else
Jonathan Austin 1:8aa5cdb4ab67 274 {
Jonathan Austin 1:8aa5cdb4ab67 275 scratchKeyValuePair(storedPair, flashPointer);
Jonathan Austin 1:8aa5cdb4ab67 276 }
Jonathan Austin 1:8aa5cdb4ab67 277
Jonathan Austin 1:8aa5cdb4ab67 278 flashPointer += kvPairSize;
Jonathan Austin 1:8aa5cdb4ab67 279 }
Jonathan Austin 1:8aa5cdb4ab67 280
Jonathan Austin 1:8aa5cdb4ab67 281 if(!found)
Jonathan Austin 1:8aa5cdb4ab67 282 {
Jonathan Austin 1:8aa5cdb4ab67 283 //if we haven't got a match for the key, check we can add a new KeyValuePair
Jonathan Austin 1:8aa5cdb4ab67 284 if(storeSize == (int)((pg_size - kvStoreSize) / MICROBIT_STORAGE_BLOCK_SIZE))
Jonathan Austin 1:8aa5cdb4ab67 285 return MICROBIT_NO_RESOURCES;
Jonathan Austin 1:8aa5cdb4ab67 286
Jonathan Austin 1:8aa5cdb4ab67 287 storeSize += 1;
Jonathan Austin 1:8aa5cdb4ab67 288
Jonathan Austin 1:8aa5cdb4ab67 289 //scratch our updated values.
Jonathan Austin 1:8aa5cdb4ab67 290 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
Jonathan Austin 1:8aa5cdb4ab67 291 scratchKeyValuePair(pair, flashPointer);
Jonathan Austin 1:8aa5cdb4ab67 292 }
Jonathan Austin 1:8aa5cdb4ab67 293
Jonathan Austin 1:8aa5cdb4ab67 294 //erase our storage page
Jonathan Austin 1:8aa5cdb4ab67 295 flashPageErase((uint32_t *)flashBlockPointer);
Jonathan Austin 1:8aa5cdb4ab67 296
Jonathan Austin 1:8aa5cdb4ab67 297 //copy from scratch to storage.
Jonathan Austin 1:8aa5cdb4ab67 298 flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, kvStoreSize + (storeSize * kvPairSize));
Jonathan Austin 1:8aa5cdb4ab67 299
Jonathan Austin 1:8aa5cdb4ab67 300 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 301 }
Jonathan Austin 1:8aa5cdb4ab67 302
Jonathan Austin 1:8aa5cdb4ab67 303 /**
Jonathan Austin 1:8aa5cdb4ab67 304 * Places a given key, and it's corresponding value into flash at the earliest
Jonathan Austin 1:8aa5cdb4ab67 305 * available point.
Jonathan Austin 1:8aa5cdb4ab67 306 *
Jonathan Austin 1:8aa5cdb4ab67 307 * @param key the unique name that should be used as an identifier for the given data.
Jonathan Austin 1:8aa5cdb4ab67 308 *
Jonathan Austin 1:8aa5cdb4ab67 309 * @param data a pointer to the beginning of the data to be persisted.
Jonathan Austin 1:8aa5cdb4ab67 310 *
LancasterUniversity 37:b624ae5e94a5 311 * @param dataSize the size of the data to be persisted
LancasterUniversity 37:b624ae5e94a5 312 *
LancasterUniversity 37:b624ae5e94a5 313 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if the key or size is too large,
LancasterUniversity 37:b624ae5e94a5 314 * MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 315 */
LancasterUniversity 37:b624ae5e94a5 316 int MicroBitStorage::put(ManagedString key, uint8_t* data, int dataSize)
Jonathan Austin 1:8aa5cdb4ab67 317 {
LancasterUniversity 37:b624ae5e94a5 318 return put((char *)key.toCharArray(), data, dataSize);
Jonathan Austin 1:8aa5cdb4ab67 319 }
Jonathan Austin 1:8aa5cdb4ab67 320
Jonathan Austin 1:8aa5cdb4ab67 321 /**
Jonathan Austin 1:8aa5cdb4ab67 322 * Retreives a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 323 *
Jonathan Austin 1:8aa5cdb4ab67 324 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 325 *
Jonathan Austin 1:8aa5cdb4ab67 326 * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
Jonathan Austin 1:8aa5cdb4ab67 327 * NULL if the key was not found in storage.
Jonathan Austin 1:8aa5cdb4ab67 328 *
Jonathan Austin 1:8aa5cdb4ab67 329 * @note it is up to the user to free memory after use.
Jonathan Austin 1:8aa5cdb4ab67 330 */
Jonathan Austin 1:8aa5cdb4ab67 331 KeyValuePair* MicroBitStorage::get(const char* key)
Jonathan Austin 1:8aa5cdb4ab67 332 {
Jonathan Austin 1:8aa5cdb4ab67 333 //calculate our offsets for our storage page
Jonathan Austin 1:8aa5cdb4ab67 334 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 335 uint32_t pg_num = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
Jonathan Austin 1:8aa5cdb4ab67 336
Jonathan Austin 1:8aa5cdb4ab67 337 uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
Jonathan Austin 1:8aa5cdb4ab67 338
Jonathan Austin 1:8aa5cdb4ab67 339 int storeSize = size();
Jonathan Austin 1:8aa5cdb4ab67 340
Jonathan Austin 1:8aa5cdb4ab67 341 //we haven't got anything stored, so return...
Jonathan Austin 1:8aa5cdb4ab67 342 if(storeSize == 0)
Jonathan Austin 1:8aa5cdb4ab67 343 return NULL;
Jonathan Austin 1:8aa5cdb4ab67 344
Jonathan Austin 1:8aa5cdb4ab67 345 //our KeyValueStore struct is always at 0
Jonathan Austin 1:8aa5cdb4ab67 346 flashBlockPointer += sizeof(KeyValueStore) / 4;
Jonathan Austin 1:8aa5cdb4ab67 347
Jonathan Austin 1:8aa5cdb4ab67 348 KeyValuePair *pair = new KeyValuePair();
Jonathan Austin 1:8aa5cdb4ab67 349
Jonathan Austin 1:8aa5cdb4ab67 350 int i;
Jonathan Austin 1:8aa5cdb4ab67 351
Jonathan Austin 1:8aa5cdb4ab67 352 //iterate through flash until we have a match, or drop out.
Jonathan Austin 1:8aa5cdb4ab67 353 for(i = 0; i < storeSize; i++)
Jonathan Austin 1:8aa5cdb4ab67 354 {
Jonathan Austin 1:8aa5cdb4ab67 355 memcpy(pair, flashBlockPointer, sizeof(KeyValuePair));
Jonathan Austin 1:8aa5cdb4ab67 356
Jonathan Austin 1:8aa5cdb4ab67 357 if(strcmp(key,(char *)pair->key) == 0)
Jonathan Austin 1:8aa5cdb4ab67 358 break;
Jonathan Austin 1:8aa5cdb4ab67 359
Jonathan Austin 1:8aa5cdb4ab67 360 flashBlockPointer += sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 361 }
Jonathan Austin 1:8aa5cdb4ab67 362
Jonathan Austin 1:8aa5cdb4ab67 363 //clean up
Jonathan Austin 1:8aa5cdb4ab67 364 if(i == storeSize)
Jonathan Austin 1:8aa5cdb4ab67 365 {
Jonathan Austin 1:8aa5cdb4ab67 366 delete pair;
Jonathan Austin 1:8aa5cdb4ab67 367 return NULL;
Jonathan Austin 1:8aa5cdb4ab67 368 }
Jonathan Austin 1:8aa5cdb4ab67 369
Jonathan Austin 1:8aa5cdb4ab67 370 return pair;
Jonathan Austin 1:8aa5cdb4ab67 371 }
Jonathan Austin 1:8aa5cdb4ab67 372
Jonathan Austin 1:8aa5cdb4ab67 373 /**
Jonathan Austin 1:8aa5cdb4ab67 374 * Retreives a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 375 *
Jonathan Austin 1:8aa5cdb4ab67 376 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 377 *
Jonathan Austin 1:8aa5cdb4ab67 378 * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be
Jonathan Austin 1:8aa5cdb4ab67 379 * NULL if the key was not found in storage.
Jonathan Austin 1:8aa5cdb4ab67 380 *
Jonathan Austin 1:8aa5cdb4ab67 381 * @note it is up to the user to free memory after use.
Jonathan Austin 1:8aa5cdb4ab67 382 */
Jonathan Austin 1:8aa5cdb4ab67 383 KeyValuePair* MicroBitStorage::get(ManagedString key)
Jonathan Austin 1:8aa5cdb4ab67 384 {
Jonathan Austin 1:8aa5cdb4ab67 385 return get((char *)key.toCharArray());
Jonathan Austin 1:8aa5cdb4ab67 386 }
Jonathan Austin 1:8aa5cdb4ab67 387
Jonathan Austin 1:8aa5cdb4ab67 388 /**
Jonathan Austin 1:8aa5cdb4ab67 389 * Removes a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 390 *
Jonathan Austin 1:8aa5cdb4ab67 391 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 392 *
Jonathan Austin 1:8aa5cdb4ab67 393 * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
Jonathan Austin 1:8aa5cdb4ab67 394 * was not found in flash.
Jonathan Austin 1:8aa5cdb4ab67 395 */
Jonathan Austin 1:8aa5cdb4ab67 396 int MicroBitStorage::remove(const char* key)
Jonathan Austin 1:8aa5cdb4ab67 397 {
Jonathan Austin 1:8aa5cdb4ab67 398 //calculate our various offsets
Jonathan Austin 1:8aa5cdb4ab67 399 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 400 uint32_t *flashPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 401 uint32_t *flashBlockPointer = flashPointer;
Jonathan Austin 1:8aa5cdb4ab67 402 uint32_t *scratchPointer = (uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET));
Jonathan Austin 1:8aa5cdb4ab67 403
Jonathan Austin 1:8aa5cdb4ab67 404 uint32_t kvStoreSize = sizeof(KeyValueStore) / 4;
Jonathan Austin 1:8aa5cdb4ab67 405 uint32_t kvPairSize = sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 406
Jonathan Austin 1:8aa5cdb4ab67 407 int storeSize = size();
Jonathan Austin 1:8aa5cdb4ab67 408
Jonathan Austin 1:8aa5cdb4ab67 409 //if we have no data, we have nothing to do.
Jonathan Austin 1:8aa5cdb4ab67 410 if(storeSize == 0)
Jonathan Austin 1:8aa5cdb4ab67 411 return MICROBIT_NO_DATA;
Jonathan Austin 1:8aa5cdb4ab67 412
Jonathan Austin 1:8aa5cdb4ab67 413 //our KeyValueStore struct is always at 0
Jonathan Austin 1:8aa5cdb4ab67 414 flashPointer += kvStoreSize;
Jonathan Austin 1:8aa5cdb4ab67 415 scratchPointer += kvStoreSize;
Jonathan Austin 1:8aa5cdb4ab67 416
Jonathan Austin 1:8aa5cdb4ab67 417 KeyValuePair storedPair = KeyValuePair();
Jonathan Austin 1:8aa5cdb4ab67 418
Jonathan Austin 1:8aa5cdb4ab67 419 int found = 0;
Jonathan Austin 1:8aa5cdb4ab67 420
Jonathan Austin 1:8aa5cdb4ab67 421 //set up our scratch area
Jonathan Austin 1:8aa5cdb4ab67 422 flashPageErase(scratchPointer);
Jonathan Austin 1:8aa5cdb4ab67 423
Jonathan Austin 1:8aa5cdb4ab67 424 //iterate through our flash copy pairs to scratch, unless there is a key patch
Jonathan Austin 1:8aa5cdb4ab67 425 for(int i = 0; i < storeSize; i++)
Jonathan Austin 1:8aa5cdb4ab67 426 {
Jonathan Austin 1:8aa5cdb4ab67 427 memcpy(&storedPair, flashPointer, sizeof(KeyValuePair));
Jonathan Austin 1:8aa5cdb4ab67 428
Jonathan Austin 1:8aa5cdb4ab67 429 //if we have a match, don't increment our scratchPointer
Jonathan Austin 1:8aa5cdb4ab67 430 if(strcmp((char *)storedPair.key, (char *)key) == 0)
Jonathan Austin 1:8aa5cdb4ab67 431 {
Jonathan Austin 1:8aa5cdb4ab67 432 found = 1;
Jonathan Austin 1:8aa5cdb4ab67 433 //write our new KeyValueStore data
Jonathan Austin 1:8aa5cdb4ab67 434 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize - 1));
Jonathan Austin 1:8aa5cdb4ab67 435 }
Jonathan Austin 1:8aa5cdb4ab67 436 else
Jonathan Austin 1:8aa5cdb4ab67 437 {
Jonathan Austin 1:8aa5cdb4ab67 438 //otherwise copy the KeyValuePair from our storage page.
Jonathan Austin 1:8aa5cdb4ab67 439 flashCopy(flashPointer, scratchPointer, sizeof(KeyValuePair) / 4);
Jonathan Austin 1:8aa5cdb4ab67 440 scratchPointer += sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 441 }
Jonathan Austin 1:8aa5cdb4ab67 442
Jonathan Austin 1:8aa5cdb4ab67 443 flashPointer += sizeof(KeyValuePair) / 4;
Jonathan Austin 1:8aa5cdb4ab67 444 }
Jonathan Austin 1:8aa5cdb4ab67 445
Jonathan Austin 1:8aa5cdb4ab67 446 //if we haven't got a match, write our old KeyValueStore struct
Jonathan Austin 1:8aa5cdb4ab67 447 if(!found)
Jonathan Austin 1:8aa5cdb4ab67 448 {
Jonathan Austin 1:8aa5cdb4ab67 449 scratchKeyValueStore(KeyValueStore(MICROBIT_STORAGE_MAGIC, storeSize));
Jonathan Austin 1:8aa5cdb4ab67 450 return MICROBIT_NO_DATA;
Jonathan Austin 1:8aa5cdb4ab67 451 }
Jonathan Austin 1:8aa5cdb4ab67 452
Jonathan Austin 1:8aa5cdb4ab67 453 //copy scratch to our storage page
Jonathan Austin 1:8aa5cdb4ab67 454 flashPageErase((uint32_t *)flashBlockPointer);
Jonathan Austin 1:8aa5cdb4ab67 455 flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, kvStoreSize + (storeSize * kvPairSize));
Jonathan Austin 1:8aa5cdb4ab67 456
Jonathan Austin 1:8aa5cdb4ab67 457 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 458 }
Jonathan Austin 1:8aa5cdb4ab67 459
Jonathan Austin 1:8aa5cdb4ab67 460 /**
Jonathan Austin 1:8aa5cdb4ab67 461 * Removes a KeyValuePair identified by a given key.
Jonathan Austin 1:8aa5cdb4ab67 462 *
Jonathan Austin 1:8aa5cdb4ab67 463 * @param key the unique name used to identify a KeyValuePair in flash.
Jonathan Austin 1:8aa5cdb4ab67 464 *
Jonathan Austin 1:8aa5cdb4ab67 465 * @return MICROBIT_OK on success, or MICROBIT_NO_DATA if the given key
Jonathan Austin 1:8aa5cdb4ab67 466 * was not found in flash.
Jonathan Austin 1:8aa5cdb4ab67 467 */
Jonathan Austin 1:8aa5cdb4ab67 468 int MicroBitStorage::remove(ManagedString key)
Jonathan Austin 1:8aa5cdb4ab67 469 {
Jonathan Austin 1:8aa5cdb4ab67 470 return remove((char *)key.toCharArray());
Jonathan Austin 1:8aa5cdb4ab67 471 }
Jonathan Austin 1:8aa5cdb4ab67 472
Jonathan Austin 1:8aa5cdb4ab67 473 /**
Jonathan Austin 1:8aa5cdb4ab67 474 * The size of the flash based KeyValueStore.
Jonathan Austin 1:8aa5cdb4ab67 475 *
Jonathan Austin 1:8aa5cdb4ab67 476 * @return the number of entries in the key value store
Jonathan Austin 1:8aa5cdb4ab67 477 */
Jonathan Austin 1:8aa5cdb4ab67 478 int MicroBitStorage::size()
Jonathan Austin 1:8aa5cdb4ab67 479 {
Jonathan Austin 1:8aa5cdb4ab67 480 uint32_t pg_size = NRF_FICR->CODEPAGESIZE;
Jonathan Austin 1:8aa5cdb4ab67 481 uint32_t pg_num = NRF_FICR->CODESIZE - MICROBIT_STORAGE_STORE_PAGE_OFFSET;
Jonathan Austin 1:8aa5cdb4ab67 482
Jonathan Austin 1:8aa5cdb4ab67 483 uint32_t *flashBlockPointer = (uint32_t *)(pg_size * pg_num);
Jonathan Austin 1:8aa5cdb4ab67 484
Jonathan Austin 1:8aa5cdb4ab67 485 KeyValueStore store = KeyValueStore();
Jonathan Austin 1:8aa5cdb4ab67 486
Jonathan Austin 1:8aa5cdb4ab67 487 //read our data!
Jonathan Austin 1:8aa5cdb4ab67 488 memcpy(&store, flashBlockPointer, sizeof(KeyValueStore));
Jonathan Austin 1:8aa5cdb4ab67 489
Jonathan Austin 1:8aa5cdb4ab67 490 //if we haven't used flash before, we need to configure it
Jonathan Austin 1:8aa5cdb4ab67 491 if(store.magic != MICROBIT_STORAGE_MAGIC)
Jonathan Austin 1:8aa5cdb4ab67 492 {
Jonathan Austin 1:8aa5cdb4ab67 493 store.magic = MICROBIT_STORAGE_MAGIC;
Jonathan Austin 1:8aa5cdb4ab67 494 store.size = 0;
Jonathan Austin 1:8aa5cdb4ab67 495
Jonathan Austin 1:8aa5cdb4ab67 496 //erase the scratch page and write our new KeyValueStore
Jonathan Austin 1:8aa5cdb4ab67 497 flashPageErase((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)));
Jonathan Austin 1:8aa5cdb4ab67 498 scratchKeyValueStore(store);
Jonathan Austin 1:8aa5cdb4ab67 499
Jonathan Austin 1:8aa5cdb4ab67 500 //erase flash, and copy the scratch page over
Jonathan Austin 1:8aa5cdb4ab67 501 flashPageErase((uint32_t *)flashBlockPointer);
Jonathan Austin 1:8aa5cdb4ab67 502 flashCopy((uint32_t *)(pg_size * (NRF_FICR->CODESIZE - MICROBIT_STORAGE_SCRATCH_PAGE_OFFSET)), flashBlockPointer, pg_size/4);
Jonathan Austin 1:8aa5cdb4ab67 503 }
Jonathan Austin 1:8aa5cdb4ab67 504
Jonathan Austin 1:8aa5cdb4ab67 505 return store.size;
LancasterUniversity 30:db87179335d5 506 }