mbed.org local branch of microbit-dal. The real version lives in git at https://github.com/lancaster-university/microbit-dal

Dependencies:   BLE_API nRF51822 mbed-dev-bin

Dependents:   microbit Microbit IoTChallenge1 microbit ... more

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:14 2016 +0100
Revision:
35:8ce23bc1af38
Parent:
32:ece16b5987dd
Child:
37:b624ae5e94a5
Synchronized with git rev 732971e7
Author: James Devine
microbit-dal: Added events to MicroBitPin

Added rise, fall, pulse HI and LO events.

The pulse Hi and LO event timestamp given in the MicroBitEvent is the
duration for which the input was HI or LO for.

eventOn(int eventType) is used to configure the events generated
from the pin instance.

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 35:8ce23bc1af38 212 * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 213 */
LancasterUniversity 35:8ce23bc1af38 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 35:8ce23bc1af38 218 memcpy(pair.key, key, min(sizeof(pair.key), strlen(key)));
LancasterUniversity 35:8ce23bc1af38 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 35:8ce23bc1af38 293 * @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the storage page is full
Jonathan Austin 1:8aa5cdb4ab67 294 */
LancasterUniversity 35:8ce23bc1af38 295 int MicroBitStorage::put(ManagedString key, uint8_t* data)
Jonathan Austin 1:8aa5cdb4ab67 296 {
LancasterUniversity 35:8ce23bc1af38 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 }