No Changes

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:26 2016 +0100
Revision:
47:69f452b1a5c9
Parent:
1:8aa5cdb4ab67
Child:
57:290a35cb9981
Synchronized with git rev deac0341
Author: James Devine
microbit-dal: panic now accepts codes in the range 0 - 999 [issue #129 ]

Issue #129 illustrated that panic is capable of accepting numbers in
the range 0-999 and should therefore not have an arbitrary range of
0-255.

Additionally, this commit introduces gaps between consecutive numbers
of the same value e.g. 999. As a result, the speed of panic has also
been reduced.

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 * Compatibility / portability funcitons and constants for the MicroBit DAL.
Jonathan Austin 1:8aa5cdb4ab67 28 */
Jonathan Austin 1:8aa5cdb4ab67 29 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 30 #include "MicroBitButton.h"
Jonathan Austin 1:8aa5cdb4ab67 31 #include "MicroBitDevice.h"
Jonathan Austin 1:8aa5cdb4ab67 32 #include "MicroBitFont.h"
Jonathan Austin 1:8aa5cdb4ab67 33 #include "mbed.h"
Jonathan Austin 1:8aa5cdb4ab67 34 #include "ErrorNo.h"
Jonathan Austin 1:8aa5cdb4ab67 35
Jonathan Austin 1:8aa5cdb4ab67 36 /*
Jonathan Austin 1:8aa5cdb4ab67 37 * The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ
Jonathan Austin 1:8aa5cdb4ab67 38 * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
Jonathan Austin 1:8aa5cdb4ab67 39 * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
Jonathan Austin 1:8aa5cdb4ab67 40 * as a compatability option, but does not support the options used...
Jonathan Austin 1:8aa5cdb4ab67 41 */
Jonathan Austin 1:8aa5cdb4ab67 42 #if !defined(__arm)
Jonathan Austin 1:8aa5cdb4ab67 43 #pragma GCC diagnostic ignored "-Wunused-function"
Jonathan Austin 1:8aa5cdb4ab67 44 #pragma GCC diagnostic push
Jonathan Austin 1:8aa5cdb4ab67 45 #pragma GCC diagnostic ignored "-Wunused-parameter"
Jonathan Austin 1:8aa5cdb4ab67 46 #endif
Jonathan Austin 1:8aa5cdb4ab67 47
Jonathan Austin 1:8aa5cdb4ab67 48 #include "nrf_soc.h"
Jonathan Austin 1:8aa5cdb4ab67 49 #include "nrf_sdm.h"
Jonathan Austin 1:8aa5cdb4ab67 50
Jonathan Austin 1:8aa5cdb4ab67 51 /*
Jonathan Austin 1:8aa5cdb4ab67 52 * Return to our predefined compiler settings.
Jonathan Austin 1:8aa5cdb4ab67 53 */
Jonathan Austin 1:8aa5cdb4ab67 54 #if !defined(__arm)
Jonathan Austin 1:8aa5cdb4ab67 55 #pragma GCC diagnostic pop
Jonathan Austin 1:8aa5cdb4ab67 56 #endif
Jonathan Austin 1:8aa5cdb4ab67 57
Jonathan Austin 1:8aa5cdb4ab67 58 static char friendly_name[MICROBIT_NAME_LENGTH+1];
Jonathan Austin 1:8aa5cdb4ab67 59 static const uint8_t panicFace[5] = {0x1B, 0x1B,0x0,0x0E,0x11};
Jonathan Austin 1:8aa5cdb4ab67 60 static int panic_timeout = 0;
Jonathan Austin 1:8aa5cdb4ab67 61 static uint32_t random_value = 0;
Jonathan Austin 1:8aa5cdb4ab67 62
Jonathan Austin 1:8aa5cdb4ab67 63 /**
Jonathan Austin 1:8aa5cdb4ab67 64 * Determines if a BLE stack is currently running.
Jonathan Austin 1:8aa5cdb4ab67 65 *
Jonathan Austin 1:8aa5cdb4ab67 66 * @return true is a bluetooth stack is operational, false otherwise.
Jonathan Austin 1:8aa5cdb4ab67 67 */
Jonathan Austin 1:8aa5cdb4ab67 68 bool ble_running()
Jonathan Austin 1:8aa5cdb4ab67 69 {
Jonathan Austin 1:8aa5cdb4ab67 70 uint8_t t;
Jonathan Austin 1:8aa5cdb4ab67 71 sd_softdevice_is_enabled(&t);
Jonathan Austin 1:8aa5cdb4ab67 72 return t==1;
Jonathan Austin 1:8aa5cdb4ab67 73 }
Jonathan Austin 1:8aa5cdb4ab67 74
Jonathan Austin 1:8aa5cdb4ab67 75 /**
Jonathan Austin 1:8aa5cdb4ab67 76 * Derived a unique, consistent serial number of this device from internal data.
Jonathan Austin 1:8aa5cdb4ab67 77 *
Jonathan Austin 1:8aa5cdb4ab67 78 * @return the serial number of this device.
Jonathan Austin 1:8aa5cdb4ab67 79 */
Jonathan Austin 1:8aa5cdb4ab67 80 uint32_t microbit_serial_number()
Jonathan Austin 1:8aa5cdb4ab67 81 {
Jonathan Austin 1:8aa5cdb4ab67 82 return NRF_FICR->DEVICEID[1];
Jonathan Austin 1:8aa5cdb4ab67 83 }
Jonathan Austin 1:8aa5cdb4ab67 84
Jonathan Austin 1:8aa5cdb4ab67 85 /**
Jonathan Austin 1:8aa5cdb4ab67 86 * Derive the friendly name for this device, based on its serial number.
Jonathan Austin 1:8aa5cdb4ab67 87 *
Jonathan Austin 1:8aa5cdb4ab67 88 * @return the serial number of this device.
Jonathan Austin 1:8aa5cdb4ab67 89 */
Jonathan Austin 1:8aa5cdb4ab67 90 char* microbit_friendly_name()
Jonathan Austin 1:8aa5cdb4ab67 91 {
Jonathan Austin 1:8aa5cdb4ab67 92 const uint8_t codebook[MICROBIT_NAME_LENGTH][MICROBIT_NAME_CODE_LETTERS] =
Jonathan Austin 1:8aa5cdb4ab67 93 {
Jonathan Austin 1:8aa5cdb4ab67 94 {'z', 'v', 'g', 'p', 't'},
Jonathan Austin 1:8aa5cdb4ab67 95 {'u', 'o', 'i', 'e', 'a'},
Jonathan Austin 1:8aa5cdb4ab67 96 {'z', 'v', 'g', 'p', 't'},
Jonathan Austin 1:8aa5cdb4ab67 97 {'u', 'o', 'i', 'e', 'a'},
Jonathan Austin 1:8aa5cdb4ab67 98 {'z', 'v', 'g', 'p', 't'}
Jonathan Austin 1:8aa5cdb4ab67 99 };
Jonathan Austin 1:8aa5cdb4ab67 100
Jonathan Austin 1:8aa5cdb4ab67 101 // We count right to left, so create a pointer to the end of the buffer.
Jonathan Austin 1:8aa5cdb4ab67 102 char *name = friendly_name;
Jonathan Austin 1:8aa5cdb4ab67 103 name += MICROBIT_NAME_LENGTH;
Jonathan Austin 1:8aa5cdb4ab67 104
Jonathan Austin 1:8aa5cdb4ab67 105 // Terminate the string.
Jonathan Austin 1:8aa5cdb4ab67 106 *name = 0;
Jonathan Austin 1:8aa5cdb4ab67 107
Jonathan Austin 1:8aa5cdb4ab67 108 // Derive our name from the nrf51822's unique ID.
Jonathan Austin 1:8aa5cdb4ab67 109 uint32_t n = microbit_serial_number();
Jonathan Austin 1:8aa5cdb4ab67 110 int ld = 1;
Jonathan Austin 1:8aa5cdb4ab67 111 int d = MICROBIT_NAME_CODE_LETTERS;
Jonathan Austin 1:8aa5cdb4ab67 112 int h;
Jonathan Austin 1:8aa5cdb4ab67 113
Jonathan Austin 1:8aa5cdb4ab67 114 for (int i=0; i<MICROBIT_NAME_LENGTH; i++)
Jonathan Austin 1:8aa5cdb4ab67 115 {
Jonathan Austin 1:8aa5cdb4ab67 116 h = (n % d) / ld;
Jonathan Austin 1:8aa5cdb4ab67 117 n -= h;
Jonathan Austin 1:8aa5cdb4ab67 118 d *= MICROBIT_NAME_CODE_LETTERS;
Jonathan Austin 1:8aa5cdb4ab67 119 ld *= MICROBIT_NAME_CODE_LETTERS;
Jonathan Austin 1:8aa5cdb4ab67 120 *--name = codebook[i][h];
Jonathan Austin 1:8aa5cdb4ab67 121 }
Jonathan Austin 1:8aa5cdb4ab67 122
Jonathan Austin 1:8aa5cdb4ab67 123 return friendly_name;
Jonathan Austin 1:8aa5cdb4ab67 124 }
Jonathan Austin 1:8aa5cdb4ab67 125
Jonathan Austin 1:8aa5cdb4ab67 126 /**
Jonathan Austin 1:8aa5cdb4ab67 127 * Perform a hard reset of the micro:bit.
Jonathan Austin 1:8aa5cdb4ab67 128 */
Jonathan Austin 1:8aa5cdb4ab67 129 void
Jonathan Austin 1:8aa5cdb4ab67 130 microbit_reset()
Jonathan Austin 1:8aa5cdb4ab67 131 {
Jonathan Austin 1:8aa5cdb4ab67 132 NVIC_SystemReset();
Jonathan Austin 1:8aa5cdb4ab67 133 }
Jonathan Austin 1:8aa5cdb4ab67 134
Jonathan Austin 1:8aa5cdb4ab67 135 /**
Jonathan Austin 1:8aa5cdb4ab67 136 * Determine the version of microbit-dal currently running.
Jonathan Austin 1:8aa5cdb4ab67 137 * @return a pointer to a character buffer containing a representation of the semantic version number.
Jonathan Austin 1:8aa5cdb4ab67 138 */
Jonathan Austin 1:8aa5cdb4ab67 139 const char *
Jonathan Austin 1:8aa5cdb4ab67 140 microbit_dal_version()
Jonathan Austin 1:8aa5cdb4ab67 141 {
Jonathan Austin 1:8aa5cdb4ab67 142 return MICROBIT_DAL_VERSION;
Jonathan Austin 1:8aa5cdb4ab67 143 }
Jonathan Austin 1:8aa5cdb4ab67 144
Jonathan Austin 1:8aa5cdb4ab67 145 /**
Jonathan Austin 1:8aa5cdb4ab67 146 * Defines the length of time that the device will remain in a error state before resetting.
Jonathan Austin 1:8aa5cdb4ab67 147 *
Jonathan Austin 1:8aa5cdb4ab67 148 * @param iteration The number of times the error code will be displayed before resetting. Set to zero to remain in error state forever.
Jonathan Austin 1:8aa5cdb4ab67 149 *
Jonathan Austin 1:8aa5cdb4ab67 150 * @code
Jonathan Austin 1:8aa5cdb4ab67 151 * microbit_panic_timeout(4);
Jonathan Austin 1:8aa5cdb4ab67 152 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 153 */
Jonathan Austin 1:8aa5cdb4ab67 154 void microbit_panic_timeout(int iterations)
Jonathan Austin 1:8aa5cdb4ab67 155 {
Jonathan Austin 1:8aa5cdb4ab67 156 panic_timeout = iterations;
Jonathan Austin 1:8aa5cdb4ab67 157 }
Jonathan Austin 1:8aa5cdb4ab67 158
Jonathan Austin 1:8aa5cdb4ab67 159 /**
Jonathan Austin 1:8aa5cdb4ab67 160 * Disables all interrupts and user processing.
Jonathan Austin 1:8aa5cdb4ab67 161 * Displays "=(" and an accompanying status code on the default display.
LancasterUniversity 47:69f452b1a5c9 162 * @param statusCode the appropriate status code, must be in the range 0-999.
Jonathan Austin 1:8aa5cdb4ab67 163 *
Jonathan Austin 1:8aa5cdb4ab67 164 * @code
Jonathan Austin 1:8aa5cdb4ab67 165 * microbit_panic(20);
Jonathan Austin 1:8aa5cdb4ab67 166 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 167 */
Jonathan Austin 1:8aa5cdb4ab67 168 void microbit_panic(int statusCode)
Jonathan Austin 1:8aa5cdb4ab67 169 {
Jonathan Austin 1:8aa5cdb4ab67 170 DigitalIn resetButton(MICROBIT_PIN_BUTTON_RESET);
Jonathan Austin 1:8aa5cdb4ab67 171 resetButton.mode(PullUp);
Jonathan Austin 1:8aa5cdb4ab67 172
Jonathan Austin 1:8aa5cdb4ab67 173 uint32_t row_mask = 0;
Jonathan Austin 1:8aa5cdb4ab67 174 uint32_t col_mask = 0;
Jonathan Austin 1:8aa5cdb4ab67 175 uint32_t row_reset = 0x01 << microbitMatrixMap.rowStart;
Jonathan Austin 1:8aa5cdb4ab67 176 uint32_t row_data = row_reset;
Jonathan Austin 1:8aa5cdb4ab67 177 uint8_t count = panic_timeout ? panic_timeout : 1;
Jonathan Austin 1:8aa5cdb4ab67 178 uint8_t strobeRow = 0;
Jonathan Austin 1:8aa5cdb4ab67 179
Jonathan Austin 1:8aa5cdb4ab67 180 row_mask = 0;
Jonathan Austin 1:8aa5cdb4ab67 181 for (int i = microbitMatrixMap.rowStart; i < microbitMatrixMap.rowStart + microbitMatrixMap.rows; i++)
Jonathan Austin 1:8aa5cdb4ab67 182 row_mask |= 0x01 << i;
Jonathan Austin 1:8aa5cdb4ab67 183
Jonathan Austin 1:8aa5cdb4ab67 184 for (int i = microbitMatrixMap.columnStart; i < microbitMatrixMap.columnStart + microbitMatrixMap.columns; i++)
Jonathan Austin 1:8aa5cdb4ab67 185 col_mask |= 0x01 << i;
Jonathan Austin 1:8aa5cdb4ab67 186
Jonathan Austin 1:8aa5cdb4ab67 187 PortOut LEDMatrix(Port0, row_mask | col_mask);
Jonathan Austin 1:8aa5cdb4ab67 188
LancasterUniversity 47:69f452b1a5c9 189 if(statusCode < 0 || statusCode > 999)
Jonathan Austin 1:8aa5cdb4ab67 190 statusCode = 0;
Jonathan Austin 1:8aa5cdb4ab67 191
Jonathan Austin 1:8aa5cdb4ab67 192 __disable_irq(); //stop ALL interrupts
Jonathan Austin 1:8aa5cdb4ab67 193
Jonathan Austin 1:8aa5cdb4ab67 194
Jonathan Austin 1:8aa5cdb4ab67 195 //point to the font stored in Flash
LancasterUniversity 47:69f452b1a5c9 196 const unsigned char* fontLocation = MicroBitFont::defaultFont;
Jonathan Austin 1:8aa5cdb4ab67 197
Jonathan Austin 1:8aa5cdb4ab67 198 //get individual digits of status code, and place it into a single array/
Jonathan Austin 1:8aa5cdb4ab67 199 const uint8_t* chars[MICROBIT_PANIC_ERROR_CHARS] = { panicFace, fontLocation+((((statusCode/100 % 10)+48)-MICROBIT_FONT_ASCII_START) * 5), fontLocation+((((statusCode/10 % 10)+48)-MICROBIT_FONT_ASCII_START) * 5), fontLocation+((((statusCode % 10)+48)-MICROBIT_FONT_ASCII_START) * 5)};
Jonathan Austin 1:8aa5cdb4ab67 200
Jonathan Austin 1:8aa5cdb4ab67 201 while(count)
Jonathan Austin 1:8aa5cdb4ab67 202 {
Jonathan Austin 1:8aa5cdb4ab67 203 //iterate through our chars :)
Jonathan Austin 1:8aa5cdb4ab67 204 for(int characterCount = 0; characterCount < MICROBIT_PANIC_ERROR_CHARS; characterCount++)
Jonathan Austin 1:8aa5cdb4ab67 205 {
Jonathan Austin 1:8aa5cdb4ab67 206 int outerCount = 0;
Jonathan Austin 1:8aa5cdb4ab67 207
Jonathan Austin 1:8aa5cdb4ab67 208 //display the current character
Jonathan Austin 1:8aa5cdb4ab67 209 while(outerCount < 500)
Jonathan Austin 1:8aa5cdb4ab67 210 {
Jonathan Austin 1:8aa5cdb4ab67 211 uint32_t col_data = 0;
Jonathan Austin 1:8aa5cdb4ab67 212
Jonathan Austin 1:8aa5cdb4ab67 213 int i = 0;
Jonathan Austin 1:8aa5cdb4ab67 214
Jonathan Austin 1:8aa5cdb4ab67 215 //if we have hit the row limit - reset both the bit mask and the row variable
Jonathan Austin 1:8aa5cdb4ab67 216 if(strobeRow == microbitMatrixMap.rows)
Jonathan Austin 1:8aa5cdb4ab67 217 {
Jonathan Austin 1:8aa5cdb4ab67 218 strobeRow = 0;
Jonathan Austin 1:8aa5cdb4ab67 219 row_data = row_reset;
Jonathan Austin 1:8aa5cdb4ab67 220 }
Jonathan Austin 1:8aa5cdb4ab67 221
Jonathan Austin 1:8aa5cdb4ab67 222 // Calculate the bitpattern to write.
Jonathan Austin 1:8aa5cdb4ab67 223 for (i = 0; i < microbitMatrixMap.columns; i++)
Jonathan Austin 1:8aa5cdb4ab67 224 {
Jonathan Austin 1:8aa5cdb4ab67 225 int index = (i * microbitMatrixMap.rows) + strobeRow;
Jonathan Austin 1:8aa5cdb4ab67 226
Jonathan Austin 1:8aa5cdb4ab67 227 int bitMsk = 0x10 >> microbitMatrixMap.map[index].x; //chars are right aligned but read left to right
Jonathan Austin 1:8aa5cdb4ab67 228 int y = microbitMatrixMap.map[index].y;
Jonathan Austin 1:8aa5cdb4ab67 229
Jonathan Austin 1:8aa5cdb4ab67 230 if(chars[characterCount][y] & bitMsk)
Jonathan Austin 1:8aa5cdb4ab67 231 col_data |= (1 << i);
Jonathan Austin 1:8aa5cdb4ab67 232 }
Jonathan Austin 1:8aa5cdb4ab67 233
Jonathan Austin 1:8aa5cdb4ab67 234 col_data = ~col_data << microbitMatrixMap.columnStart & col_mask;
Jonathan Austin 1:8aa5cdb4ab67 235
LancasterUniversity 47:69f452b1a5c9 236 if(chars[characterCount] == chars[(characterCount - 1) % MICROBIT_PANIC_ERROR_CHARS] && outerCount < 50)
LancasterUniversity 47:69f452b1a5c9 237 LEDMatrix = 0;
LancasterUniversity 47:69f452b1a5c9 238 else
LancasterUniversity 47:69f452b1a5c9 239 LEDMatrix = col_data | row_data;
Jonathan Austin 1:8aa5cdb4ab67 240
Jonathan Austin 1:8aa5cdb4ab67 241 //burn cycles
LancasterUniversity 47:69f452b1a5c9 242 i = 2000;
Jonathan Austin 1:8aa5cdb4ab67 243 while(i>0)
Jonathan Austin 1:8aa5cdb4ab67 244 {
Jonathan Austin 1:8aa5cdb4ab67 245 // Check if the reset button has been pressed. Interrupts are disabled, so the normal method can't be relied upon...
Jonathan Austin 1:8aa5cdb4ab67 246 if (resetButton == 0)
Jonathan Austin 1:8aa5cdb4ab67 247 microbit_reset();
Jonathan Austin 1:8aa5cdb4ab67 248
Jonathan Austin 1:8aa5cdb4ab67 249 i--;
Jonathan Austin 1:8aa5cdb4ab67 250 }
Jonathan Austin 1:8aa5cdb4ab67 251
Jonathan Austin 1:8aa5cdb4ab67 252 //update the bit mask and row count
Jonathan Austin 1:8aa5cdb4ab67 253 row_data <<= 1;
Jonathan Austin 1:8aa5cdb4ab67 254 strobeRow++;
Jonathan Austin 1:8aa5cdb4ab67 255 outerCount++;
Jonathan Austin 1:8aa5cdb4ab67 256 }
Jonathan Austin 1:8aa5cdb4ab67 257 }
Jonathan Austin 1:8aa5cdb4ab67 258
Jonathan Austin 1:8aa5cdb4ab67 259 if (panic_timeout)
Jonathan Austin 1:8aa5cdb4ab67 260 count--;
Jonathan Austin 1:8aa5cdb4ab67 261 }
Jonathan Austin 1:8aa5cdb4ab67 262
Jonathan Austin 1:8aa5cdb4ab67 263 microbit_reset();
Jonathan Austin 1:8aa5cdb4ab67 264 }
Jonathan Austin 1:8aa5cdb4ab67 265
Jonathan Austin 1:8aa5cdb4ab67 266 /**
Jonathan Austin 1:8aa5cdb4ab67 267 * Generate a random number in the given range.
Jonathan Austin 1:8aa5cdb4ab67 268 * We use a simple Galois LFSR random number generator here,
Jonathan Austin 1:8aa5cdb4ab67 269 * as a Galois LFSR is sufficient for our applications, and much more lightweight
Jonathan Austin 1:8aa5cdb4ab67 270 * than the hardware random number generator built int the processor, which takes
Jonathan Austin 1:8aa5cdb4ab67 271 * a long time and uses a lot of energy.
Jonathan Austin 1:8aa5cdb4ab67 272 *
Jonathan Austin 1:8aa5cdb4ab67 273 * KIDS: You shouldn't use this is the real world to generte cryptographic keys though...
Jonathan Austin 1:8aa5cdb4ab67 274 * have a think why not. :-)
Jonathan Austin 1:8aa5cdb4ab67 275 *
Jonathan Austin 1:8aa5cdb4ab67 276 * @param max the upper range to generate a number for. This number cannot be negative.
Jonathan Austin 1:8aa5cdb4ab67 277 *
Jonathan Austin 1:8aa5cdb4ab67 278 * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE if max is <= 0.
Jonathan Austin 1:8aa5cdb4ab67 279 *
Jonathan Austin 1:8aa5cdb4ab67 280 * @code
Jonathan Austin 1:8aa5cdb4ab67 281 * microbit_random(200); //a number between 0 and 199
Jonathan Austin 1:8aa5cdb4ab67 282 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 283 */
Jonathan Austin 1:8aa5cdb4ab67 284 int microbit_random(int max)
Jonathan Austin 1:8aa5cdb4ab67 285 {
Jonathan Austin 1:8aa5cdb4ab67 286 uint32_t m, result;
Jonathan Austin 1:8aa5cdb4ab67 287
Jonathan Austin 1:8aa5cdb4ab67 288 if(max <= 0)
Jonathan Austin 1:8aa5cdb4ab67 289 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 290
Jonathan Austin 1:8aa5cdb4ab67 291 // Our maximum return value is actually one less than passed
Jonathan Austin 1:8aa5cdb4ab67 292 max--;
Jonathan Austin 1:8aa5cdb4ab67 293
Jonathan Austin 1:8aa5cdb4ab67 294 do {
Jonathan Austin 1:8aa5cdb4ab67 295 m = (uint32_t)max;
Jonathan Austin 1:8aa5cdb4ab67 296 result = 0;
Jonathan Austin 1:8aa5cdb4ab67 297 do {
Jonathan Austin 1:8aa5cdb4ab67 298 // Cycle the LFSR (Linear Feedback Shift Register).
Jonathan Austin 1:8aa5cdb4ab67 299 // We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneier here (a true legend in the field!),
Jonathan Austin 1:8aa5cdb4ab67 300 // For those interested, it's documented in his paper:
Jonathan Austin 1:8aa5cdb4ab67 301 // "Pseudo-Random Sequence Generator for 32-Bit CPUs: A fast, machine-independent generator for 32-bit Microprocessors"
Jonathan Austin 1:8aa5cdb4ab67 302 // https://www.schneier.com/paper-pseudorandom-sequence.html
Jonathan Austin 1:8aa5cdb4ab67 303 uint32_t rnd = random_value;
Jonathan Austin 1:8aa5cdb4ab67 304
Jonathan Austin 1:8aa5cdb4ab67 305 rnd = ((((rnd >> 31)
Jonathan Austin 1:8aa5cdb4ab67 306 ^ (rnd >> 6)
Jonathan Austin 1:8aa5cdb4ab67 307 ^ (rnd >> 4)
Jonathan Austin 1:8aa5cdb4ab67 308 ^ (rnd >> 2)
Jonathan Austin 1:8aa5cdb4ab67 309 ^ (rnd >> 1)
Jonathan Austin 1:8aa5cdb4ab67 310 ^ rnd)
Jonathan Austin 1:8aa5cdb4ab67 311 & 0x0000001)
Jonathan Austin 1:8aa5cdb4ab67 312 << 31 )
Jonathan Austin 1:8aa5cdb4ab67 313 | (rnd >> 1);
Jonathan Austin 1:8aa5cdb4ab67 314
Jonathan Austin 1:8aa5cdb4ab67 315 random_value = rnd;
Jonathan Austin 1:8aa5cdb4ab67 316
Jonathan Austin 1:8aa5cdb4ab67 317 result = ((result << 1) | (rnd & 0x00000001));
Jonathan Austin 1:8aa5cdb4ab67 318 } while(m >>= 1);
Jonathan Austin 1:8aa5cdb4ab67 319 } while (result > (uint32_t)max);
Jonathan Austin 1:8aa5cdb4ab67 320
Jonathan Austin 1:8aa5cdb4ab67 321 return result;
Jonathan Austin 1:8aa5cdb4ab67 322 }
Jonathan Austin 1:8aa5cdb4ab67 323
Jonathan Austin 1:8aa5cdb4ab67 324 /**
Jonathan Austin 1:8aa5cdb4ab67 325 * Seed the random number generator (RNG).
Jonathan Austin 1:8aa5cdb4ab67 326 *
Jonathan Austin 1:8aa5cdb4ab67 327 * This function uses the NRF51822's in built cryptographic random number generator to seed a Galois LFSR.
Jonathan Austin 1:8aa5cdb4ab67 328 * We do this as the hardware RNG is relatively high power, and is locked out by the BLE stack internally,
Jonathan Austin 1:8aa5cdb4ab67 329 * with a less than optimal application interface. A Galois LFSR is sufficient for our
Jonathan Austin 1:8aa5cdb4ab67 330 * applications, and much more lightweight.
Jonathan Austin 1:8aa5cdb4ab67 331 */
Jonathan Austin 1:8aa5cdb4ab67 332 void microbit_seed_random()
Jonathan Austin 1:8aa5cdb4ab67 333 {
Jonathan Austin 1:8aa5cdb4ab67 334 random_value = 0;
Jonathan Austin 1:8aa5cdb4ab67 335
Jonathan Austin 1:8aa5cdb4ab67 336 if(ble_running())
Jonathan Austin 1:8aa5cdb4ab67 337 {
Jonathan Austin 1:8aa5cdb4ab67 338 // If Bluetooth is enabled, we need to go through the Nordic software to safely do this.
Jonathan Austin 1:8aa5cdb4ab67 339 uint32_t result = sd_rand_application_vector_get((uint8_t*)&random_value, sizeof(random_value));
Jonathan Austin 1:8aa5cdb4ab67 340
Jonathan Austin 1:8aa5cdb4ab67 341 // If we couldn't get the random bytes then at least make the seed non-zero.
Jonathan Austin 1:8aa5cdb4ab67 342 if (result != NRF_SUCCESS)
Jonathan Austin 1:8aa5cdb4ab67 343 random_value = 0xBBC5EED;
Jonathan Austin 1:8aa5cdb4ab67 344 }
Jonathan Austin 1:8aa5cdb4ab67 345 else
Jonathan Austin 1:8aa5cdb4ab67 346 {
Jonathan Austin 1:8aa5cdb4ab67 347 // Othwerwise we can access the hardware RNG directly.
Jonathan Austin 1:8aa5cdb4ab67 348
Jonathan Austin 1:8aa5cdb4ab67 349 // Start the Random number generator. No need to leave it running... I hope. :-)
Jonathan Austin 1:8aa5cdb4ab67 350 NRF_RNG->TASKS_START = 1;
Jonathan Austin 1:8aa5cdb4ab67 351
Jonathan Austin 1:8aa5cdb4ab67 352 for(int i = 0; i < 4; i++)
Jonathan Austin 1:8aa5cdb4ab67 353 {
Jonathan Austin 1:8aa5cdb4ab67 354 // Clear the VALRDY EVENT
Jonathan Austin 1:8aa5cdb4ab67 355 NRF_RNG->EVENTS_VALRDY = 0;
Jonathan Austin 1:8aa5cdb4ab67 356
Jonathan Austin 1:8aa5cdb4ab67 357 // Wait for a number ot be generated.
Jonathan Austin 1:8aa5cdb4ab67 358 while(NRF_RNG->EVENTS_VALRDY == 0);
Jonathan Austin 1:8aa5cdb4ab67 359
Jonathan Austin 1:8aa5cdb4ab67 360 random_value = (random_value << 8) | ((int) NRF_RNG->VALUE);
Jonathan Austin 1:8aa5cdb4ab67 361 }
Jonathan Austin 1:8aa5cdb4ab67 362
Jonathan Austin 1:8aa5cdb4ab67 363 // Disable the generator to save power.
Jonathan Austin 1:8aa5cdb4ab67 364 NRF_RNG->TASKS_STOP = 1;
Jonathan Austin 1:8aa5cdb4ab67 365 }
Jonathan Austin 1:8aa5cdb4ab67 366 }
Jonathan Austin 1:8aa5cdb4ab67 367
Jonathan Austin 1:8aa5cdb4ab67 368 /**
Jonathan Austin 1:8aa5cdb4ab67 369 * Seed the pseudo random number generator (RNG) using the given 32-bit value.
Jonathan Austin 1:8aa5cdb4ab67 370 * This function does not use the NRF51822's in built cryptographic random number generator.
Jonathan Austin 1:8aa5cdb4ab67 371 *
Jonathan Austin 1:8aa5cdb4ab67 372 * @param seed The value to use as a seed.
Jonathan Austin 1:8aa5cdb4ab67 373 */
Jonathan Austin 1:8aa5cdb4ab67 374 void microbit_seed_random(uint32_t seed)
Jonathan Austin 1:8aa5cdb4ab67 375 {
Jonathan Austin 1:8aa5cdb4ab67 376 random_value = seed;
LancasterUniversity 47:69f452b1a5c9 377 }