Revert "Cchange random() to use libc srand()/rand()"
This reverts commit db5227872a
.
return to using our own random implementation.
master
parent
db5227872a
commit
5333729644
|
@ -90,6 +90,7 @@ class MicroBit
|
|||
private:
|
||||
|
||||
void seedRandom();
|
||||
uint32_t randomValue;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -213,9 +214,8 @@ class MicroBit
|
|||
|
||||
/**
|
||||
* Generate a random number in the given range.
|
||||
* We use libc's rand() which is sufficient for our applications and much
|
||||
* more lightweight than the hardware random number generator built into
|
||||
* the processor, which takes a long time and uses a lot of energy.
|
||||
* We use the NRF51822 in built random number generator here
|
||||
* TODO: Determine if we want to, given its relatively high power consumption!
|
||||
*
|
||||
* @param max the upper range to generate a number for. This number cannot be negative
|
||||
* @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_PARAMETER if max is <= 0.
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "MicroBit.h"
|
||||
#include <stdlib.h> /* rand(),srand() */
|
||||
|
||||
char MICROBIT_BLE_DEVICE_NAME[] = "BBC micro:bit [xxxxx]";
|
||||
|
||||
|
@ -284,11 +283,13 @@ int MicroBit::sleep(int milliseconds)
|
|||
|
||||
/**
|
||||
* Generate a random number in the given range.
|
||||
* We use libc's rand() which is sufficient for our applications and much
|
||||
* more lightweight than the hardware random number generator built into
|
||||
* the processor, which takes a long time and uses a lot of energy.
|
||||
* We use a simple Galois LFSR random number generator here,
|
||||
* as a Galois LFSR is sufficient for our applications, and much more lightweight
|
||||
* than the hardware random number generator built int the processor, which takes
|
||||
* a long time and uses a lot of energy.
|
||||
*
|
||||
* KIDS: You shouldn't use this is the real world to generate cryptographic keys though...
|
||||
* KIDS: You shouldn't use this is the real world to generte cryptographic keys though...
|
||||
* have a think why not. :-)
|
||||
*
|
||||
* @param max the upper range to generate a number for. This number cannot be negative
|
||||
* @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE (defined in ErrorNo.h) if max is <= 0.
|
||||
|
@ -300,38 +301,60 @@ int MicroBit::sleep(int milliseconds)
|
|||
*/
|
||||
int MicroBit::random(int max)
|
||||
{
|
||||
unsigned long num_bins, num_rand, bin_size, defect;
|
||||
int result;
|
||||
uint32_t m, result;
|
||||
|
||||
//return MICROBIT_INVALID_VALUE if max is <= 0...
|
||||
if(max <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
num_bins = (unsigned long) max;
|
||||
num_rand = (unsigned long) RAND_MAX + 1;
|
||||
bin_size = num_rand / num_bins;
|
||||
defect = num_rand % num_bins;
|
||||
// Our maximum return value is actually one less than passed
|
||||
max--;
|
||||
|
||||
do {
|
||||
result = rand();
|
||||
} while ((num_rand - defect) <= (unsigned long)result); // CARE: avoid overflow
|
||||
m = (uint32_t)max;
|
||||
result = 0;
|
||||
while(m >>= 1) {
|
||||
// Cycle the LFSR (Linear Feedback Shift Register).
|
||||
// We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneider here (a true legend in the field!),
|
||||
// For those interested, it's documented in his paper:
|
||||
// "Pseudo-Random Sequence Generator for 32-Bit CPUs: A fast, machine-independent generator for 32-bit Microprocessors"
|
||||
// https://www.schneier.com/paper-pseudorandom-sequence.html
|
||||
// Avoid interupts (and hence fibre context switch) while we are doing this
|
||||
|
||||
__disable_irq();
|
||||
|
||||
randomValue = ((((randomValue >> 31)
|
||||
^ (randomValue >> 6)
|
||||
^ (randomValue >> 4)
|
||||
^ (randomValue >> 2)
|
||||
^ (randomValue >> 1)
|
||||
^ randomValue)
|
||||
& 0x0000001)
|
||||
<< 31 )
|
||||
| (randomValue >> 1);
|
||||
|
||||
__enable_irq();
|
||||
|
||||
result = ((result << 1) | (randomValue & 0x00000001));
|
||||
}
|
||||
} while (result > (uint32_t)max);
|
||||
|
||||
|
||||
return result/bin_size;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Seed our a random number generator (RNG).
|
||||
* We use the NRF51822 in built cryptographic random number generator to seed rand().
|
||||
* We use the NRF51822 in built cryptographic random number generator to seed a Galois LFSR.
|
||||
* We do this as the hardware RNG is relatively high power, and use the the BLE stack internally,
|
||||
* with a less than optimal application interface. rand() is sufficient for our
|
||||
* with a less than optimal application interface. A Galois LFSR is sufficient for our
|
||||
* applications, and much more lightweight.
|
||||
*/
|
||||
void MicroBit::seedRandom()
|
||||
{
|
||||
unsigned int seed = 0;
|
||||
|
||||
randomValue = 0;
|
||||
|
||||
// Start the Random number generator. No need to leave it running... I hope. :-)
|
||||
NRF_RNG->TASKS_START = 1;
|
||||
|
||||
|
@ -343,13 +366,11 @@ void MicroBit::seedRandom()
|
|||
// Wait for a number ot be generated.
|
||||
while ( NRF_RNG->EVENTS_VALRDY == 0);
|
||||
|
||||
seed = (seed << 8) | ((int) NRF_RNG->VALUE);
|
||||
randomValue = (randomValue << 8) | ((int) NRF_RNG->VALUE);
|
||||
}
|
||||
|
||||
// Disable the generator to save power.
|
||||
NRF_RNG->TASKS_STOP = 1;
|
||||
|
||||
srand(seed);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue