Solution for Bluetooth SIG hands-on training course

Dependencies:   BLE_API mbed-dev-bin nRF51822-bluetooth-mdw

Dependents:   microbit

Fork of microbit-dal-bluetooth-mdw_starter by Martin Woolley

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:10 2016 +0100
Revision:
31:87789e55bac7
Parent:
30:db87179335d5
Child:
32:ece16b5987dd
Synchronized with git rev 3923dfff
Author: James Devine
microbit-dal: increase granularity of the system wide timer

Added an mbed Timer instance to maintain a microsecond level timestamp.

Added a function system_timer_current_time_us() which now returns the
time since power on in microseconds.

MicroBitEvents now call system_timer_current_time_us() giving
microsecond level timestamps.

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