Skip to content

Commit a11ce23

Browse files
markshannondpgeorge
authored andcommitted
Remove DAL dependency for random module.
1 parent 83f69b1 commit a11ce23

File tree

3 files changed

+150
-6
lines changed

3 files changed

+150
-6
lines changed

source/microbit/main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern "C" {
1414
void microbit_accelerometer_init(void);
1515
void microbit_button_tick(void);
1616
void pwm_init(void);
17+
void MicroBit_seedRandom(void);
1718
}
1819

1920
void app_main() {
@@ -83,6 +84,7 @@ void microbit_init(void) {
8384
ticker_init(microbit_ticker);
8485
ticker_start();
8586
pwm_start();
87+
MicroBit_seedRandom();
8688
}
8789

8890
}

source/microbit/modrandom.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@
2525
* THE SOFTWARE.
2626
*/
2727

28-
#include "MicroBit.h"
29-
30-
#define rand30() (uBit.random(0x40000000))
31-
#define randbelow(n) (uBit.random(n))
28+
#define rand30() (MicroBit_random(0x40000000))
29+
#define randbelow(n) (MicroBit_random(n))
3230

3331
extern "C" {
3432

@@ -38,6 +36,11 @@ extern "C" {
3836

3937
#include "py/runtime.h"
4038

39+
extern int MicroBit_random(int max);
40+
extern void MicroBit_seedRandom(void);
41+
extern void MicroBit_setSeed(uint32_t seed);
42+
43+
4144
STATIC mp_obj_t mod_random_getrandbits(mp_obj_t num_in) {
4245
int n = mp_obj_get_int(num_in);
4346
if (n > 30 || n == 0) {
@@ -52,10 +55,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_random_getrandbits_obj, mod_random_getrandb
5255

5356
STATIC mp_obj_t mod_random_seed(size_t n_args, const mp_obj_t *args) {
5457
if (n_args == 0 || args[0] == mp_const_none) {
55-
uBit.seedRandom();
58+
MicroBit_seedRandom();
5659
} else {
5760
mp_uint_t seed = mp_obj_get_int_truncated(args[0]);
58-
uBit.seedRandom(seed);
61+
MicroBit_setSeed(seed);
5962
}
6063
return mp_const_none;
6164
}

source/microbit/random.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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

Comments
 (0)