Random number generation on the ESP8266

Soooo random!


For an ESP8266 project that sends randomised tweets, I need to use a random number generator.  In such a deterministic system such as a digital computer however, true randomness is hard (impossible) to come by, so we must settle for a pseudo-random number - that is a number that is part of a seemingly random sequence and is generated algorithmically from the previous number(s) in the sequence.  It is good enough for our purposes.  The simplest implementation of a pseudo-random number generator (PRNG) is a Linear Congruential Generator, i.e.

Xn+1 = (aXn + c) mod m

We don't need to guess at suitable values of a, c and m as common values have been tabulated for various implementations (Wikipedia).  From the first entry of the Parameters in Common Use table, I chose a = 1664525, c = 1013904223, m = 2^16 (rather than 32).  Therefore we can define a data structure to hold the previous value in (in this example I also have "tweet_id" as I want to save this but it is of course not required for the PRNG.
struct { 
    uint8_t tweet_id;
    uint32_t seed;
  }random_data;

uint32_t nextrandom()
{
  random_data.seed = (random_data.seed*1664525 + 1013904223) % 65536;
  return random_data.seed;
}

If we ran this code and called the nextrandom function in a loop, we would get a sequence of random numbers... but the SAME sequence of random numbers every time we rebooted the ESP8266! In my case, I need a DIFFERENT random number every time I start as I want to randomly choose a tweet (and not the same tweet as the previous time).  So what do we do?  One answer is to save the last random number (random_data.seed) into EEPROM, then read it back in when we boot up and so continue the sequence.

Briefly EEPROM access is easy in the Arduino GUI:
// Setup and read from EEPROM
EEPROM.begin(sizeof(random_data)); // Set aside some memory
EEPROM.get(0, random_data); // Gets data from address 0

uint8_t prev_id = random_data.tweet_id;
while(random_data.tweet_id==prev_id)
{
    random_data.tweet_id = nextrandom() % NUM_TWEETS; // 0,1,2... NUM_TWEETS-1
} 
// Do things
. . .
// Save to EEPROM
EEPROM.put(0,random_data);  // This just writes to an array
EEPROM.commit();   // This does the actual writing to EEPROM

Now every time we boot up, we get the next random number!  Note a 32-bit number (well, truncated 16-bit ) is returned by nextrandom, so it is modulus-ed with NUM_TWEETS to return a number between zero and NUM_TWEETS-1.  A bit of logic is used to make sure a different tweet_id to the previous id is selected.

Enjoy the randomness!

Comments

Popular posts from this blog

Arduino and Raspberry Pi serial communciation

Getting started with the Pro Micro Arduino Board