1+ /*
2+ The MIT License (MIT)
3+
4+ Copyright (c) 2016 British Broadcasting Corporation.
5+ This software is provided by Lancaster University by arrangement with the BBC.
6+
7+ Permission is hereby granted, free of charge, to any person obtaining a
8+ copy of this software and associated documentation files (the "Software"),
9+ to deal in the Software without restriction, including without limitation
10+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
11+ and/or sell copies of the Software, and to permit persons to whom the
12+ Software is furnished to do so, subject to the following conditions:
13+
14+ The above copyright notice and this permission notice shall be included in
15+ all copies or substantial portions of the Software.
16+
17+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+ DEALINGS IN THE SOFTWARE.
24+ */
25+
26+ /* The following code has been copied from the DAL (https://github.com/lancaster-university/microbit-dal)
27+ * and modified slightly to:
28+ * Have a C api
29+ * Not use the BLE softdevice code.
30+ * Make sure that seed is not set to zero accidentally.
31+ * (Mark Shannon 2017)
32+ */
33+
34+ extern " C" {
35+
36+ #include " device.h"
37+ #include " nrf51_bitfields.h"
38+
39+
40+ static uint32_t randomValue;
41+
42+ /* *
43+ * Generate a random number in the given range.
44+ * We use a simple Galois LFSR random number generator here,
45+ * as a Galois LFSR is sufficient for our applications, and much more lightweight
46+ * than the hardware random number generator built int the processor, which takes
47+ * a long time and uses a lot of energy.
48+ *
49+ * KIDS: You shouldn't use this is the real world to generte cryptographic keys though...
50+ * have a think why not. :-)
51+ *
52+ * @param max the upper range to generate a number for. This number cannot be negative
53+ * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE (defined in ErrorNo.h) if max is <= 0.
54+ *
55+ * Example:
56+ * @code
57+ * uBit.random(200); //a number between 0 and 199
58+ * @endcode
59+ */
60+ int MicroBit_random (int max)
61+ {
62+ uint32_t m, result;
63+
64+ // Our maximum return value is actually one less than passed
65+ max--;
66+
67+ do {
68+ m = (uint32_t )max;
69+ result = 0 ;
70+ do {
71+ // Cycle the LFSR (Linear Feedback Shift Register).
72+ // We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneier here (a true legend in the field!),
73+ // For those interested, it's documented in his paper:
74+ // "Pseudo-Random Sequence Generator for 32-Bit CPUs: A fast, machine-independent generator for 32-bit Microprocessors"
75+ // https://www.schneier.com/paper-pseudorandom-sequence.html
76+ uint32_t rnd = randomValue;
77+
78+ rnd = ((((rnd >> 31 )
79+ ^ (rnd >> 6 )
80+ ^ (rnd >> 4 )
81+ ^ (rnd >> 2 )
82+ ^ (rnd >> 1 )
83+ ^ rnd)
84+ & 0x0000001 )
85+ << 31 )
86+ | (rnd >> 1 );
87+
88+ randomValue = rnd;
89+
90+ result = ((result << 1 ) | (rnd & 0x00000001 ));
91+ } while (m >>= 1 );
92+ } while (result > (uint32_t )max);
93+
94+
95+ return result;
96+ }
97+
98+
99+ /* *
100+ * Seed our a random number generator (RNG).
101+ * We use the NRF51822 in built cryptographic random number generator to seed a Galois LFSR.
102+ * We do this as the hardware RNG is relatively high power, and use the the BLE stack internally,
103+ * with a less than optimal application interface. A Galois LFSR is sufficient for our
104+ * applications, and much more lightweight.
105+ */
106+ void MicroBit_seedRandom (void )
107+ {
108+ randomValue = 0 ;
109+
110+ // Start the Random number generator. No need to leave it running... I hope. :-)
111+ NRF_RNG->TASKS_START = 1 ;
112+ do {
113+ for (int i = 0 ; i < 4 ; i++)
114+ {
115+ // Clear the VALRDY EVENT
116+ NRF_RNG->EVENTS_VALRDY = 0 ;
117+
118+ // Wait for a number ot be generated.
119+ while (NRF_RNG->EVENTS_VALRDY == 0 );
120+
121+ randomValue = (randomValue << 8 ) | ((int ) NRF_RNG->VALUE );
122+ }
123+ // PRNG won't work if seed is zero.
124+ } while (randomValue == 0 );
125+
126+ // Disable the generator to save power.
127+ NRF_RNG->TASKS_STOP = 1 ;
128+ }
129+
130+
131+ /* *
132+ * Seed our pseudo random number generator (PRNG) using the given 32-bit value.
133+ */
134+ void MicroBit_setSeed (uint32_t seed)
135+ {
136+ randomValue = seed;
137+ }
138+
139+ }
0 commit comments