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

Dependencies:   BLE_API mbed-dev-bin nRF51822

Fork of microbit-dal by Lancaster University

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:08 2016 +0100
Revision:
30:db87179335d5
Parent:
1:8aa5cdb4ab67
Child:
31:87789e55bac7
Synchronized with git rev 3b435c0d
Author: James Devine
microbit-dal: BUGFIX in MicroBitStorage

There was an off by one error when storing the key of the key value
pair, where the null terminator was dropped. This would mean that if
the returned key of the KeyValuePair were used, it would cause a number
of issues.

Another issue raised was the copying a random 48 bytes from memory
regardless of the position of memory in the stack. If the memory was
smaller than 48 bytes, and existed at the top of the stack, this could
have dire consequences. As a result, MicroBitStorage now accepts a size
parameter which informs the number of bytes to be copied into flash.

#130

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 30:db87179335d5 212 * @param dataSize the size of the data to be persisted
LancasterUniversity 30:db87179335d5 213 *
LancasterUniversity 30:db87179335d5 214 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if the key or size is too large,
LancasterUniversity 30:db87179335d5 215 * MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 216 */
LancasterUniversity 30:db87179335d5 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 30:db87179335d5 221 int keySize = strlen(key) + 1;
LancasterUniversity 30:db87179335d5 222
LancasterUniversity 30:db87179335d5 223 if(keySize > (int)sizeof(pair.key) || dataSize > (int)sizeof(pair.value) || dataSize < 0)
LancasterUniversity 30:db87179335d5 224 return MICROBIT_INVALID_PARAMETER;
LancasterUniversity 30:db87179335d5 225
LancasterUniversity 30:db87179335d5 226 memcpy(pair.key, key, keySize);
LancasterUniversity 30:db87179335d5 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 30:db87179335d5 301 * @param dataSize the size of the data to be persisted
LancasterUniversity 30:db87179335d5 302 *
LancasterUniversity 30:db87179335d5 303 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if the key or size is too large,
LancasterUniversity 30:db87179335d5 304 * MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 305 */
LancasterUniversity 30:db87179335d5 306 int MicroBitStorage::put(ManagedString key, uint8_t* data, int dataSize)
Jonathan Austin 1:8aa5cdb4ab67 307 {
LancasterUniversity 30:db87179335d5 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 }