mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
184 lines
2.9 KiB
C++
184 lines
2.9 KiB
C++
//
|
|
// FILE: DEVRANDOM.cpp
|
|
// AUTHOR: Rob Tillaart
|
|
// VERSION: 0.2.0
|
|
// PURPOSE: Arduino library for a /dev/random stream - useful for testing
|
|
// URL: https://github.com/RobTillaart/DEVRANDOM
|
|
//
|
|
// HISTORY:
|
|
// 0.1.0 2020-06-23 initial version
|
|
// 0.1.1 2020-12-18 add Arduino-CI + unit tests
|
|
// + getMode() + flush()
|
|
// 0.1.2 2021-01-15 add constructors with seed.
|
|
// 0.1.3 2021-12-15 update library.json, license, minor edits
|
|
//
|
|
// 0.2.0 2022-07-02 add Marsaglia PRNG, is portable over platforms
|
|
// becomes mode 3
|
|
// improved reseeding
|
|
// split off .cpp file
|
|
// add examples
|
|
|
|
|
|
#include "DEVRANDOM.h"
|
|
|
|
|
|
DEVRANDOM::DEVRANDOM()
|
|
{
|
|
_next = _rnd();
|
|
};
|
|
|
|
|
|
DEVRANDOM::DEVRANDOM(const char * str)
|
|
{
|
|
this->print(str);
|
|
_next = _rnd();
|
|
};
|
|
|
|
|
|
DEVRANDOM::DEVRANDOM(const uint32_t value)
|
|
{
|
|
this->print(value);
|
|
_next = _rnd();
|
|
};
|
|
|
|
|
|
DEVRANDOM::DEVRANDOM(const float value)
|
|
{
|
|
this->print(value, 6);
|
|
_next = _rnd();
|
|
};
|
|
|
|
|
|
int DEVRANDOM::available()
|
|
{
|
|
return 1;
|
|
};
|
|
|
|
|
|
int DEVRANDOM::peek()
|
|
{
|
|
return _next;
|
|
};
|
|
|
|
|
|
int DEVRANDOM::read()
|
|
{
|
|
uint8_t x = _next;
|
|
_next = _rnd();
|
|
return x;
|
|
};
|
|
|
|
|
|
// keep CI happy as parent class flush is virtual.
|
|
void DEVRANDOM::flush()
|
|
{
|
|
};
|
|
|
|
|
|
size_t DEVRANDOM::write(const uint8_t data)
|
|
{
|
|
return write(&data, 1);
|
|
};
|
|
|
|
|
|
size_t DEVRANDOM::write(const uint8_t * buffer, size_t size)
|
|
{
|
|
uint32_t tmp = _seed;
|
|
for (size_t i = 0; i < size; i++)
|
|
{
|
|
_seed = _seed * (_seed << 8) + buffer[i];
|
|
}
|
|
if (_mode == 0)
|
|
{
|
|
randomSeed(_seed);
|
|
}
|
|
if (_mode == 3)
|
|
{
|
|
_m_z = (_seed == 0) ? 1 : _seed;
|
|
_m_w = ( tmp == 0) ? 2 : tmp;
|
|
}
|
|
return size;
|
|
};
|
|
|
|
|
|
void DEVRANDOM::useMarsaglia()
|
|
{
|
|
_mode = 3;
|
|
};
|
|
|
|
|
|
void DEVRANDOM::useAnalogRead(uint8_t pin)
|
|
{
|
|
_mode = 2;
|
|
_pin = pin;
|
|
};
|
|
|
|
|
|
void DEVRANDOM::useDigitalRead(uint8_t pin)
|
|
{
|
|
_mode = 1;
|
|
_pin = pin;
|
|
pinMode(_pin, INPUT);
|
|
};
|
|
|
|
|
|
void DEVRANDOM::useRandom()
|
|
{
|
|
_mode = 0;
|
|
};
|
|
|
|
|
|
uint8_t DEVRANDOM::getMode()
|
|
{
|
|
return _mode;
|
|
};
|
|
|
|
|
|
int DEVRANDOM::_rnd()
|
|
{
|
|
if (_mode == 0 ) return random(256);
|
|
if (_mode == 1 ) return _digitalRead();
|
|
if (_mode == 2 ) return _analogRead();
|
|
if (_mode == 3 ) return _marsaglia();
|
|
return 0;
|
|
}
|
|
|
|
|
|
int DEVRANDOM::_digitalRead()
|
|
{
|
|
uint8_t value = 0;
|
|
for (uint8_t i = 0; i < 8; i++)
|
|
{
|
|
value <<= 1;
|
|
if (digitalRead(_pin)) value++;
|
|
}
|
|
return value ^ _seed;
|
|
}
|
|
|
|
|
|
int DEVRANDOM::_analogRead()
|
|
{
|
|
uint8_t value = 0;
|
|
for (uint8_t i = 0; i < 8; i++)
|
|
{
|
|
value <<= 1;
|
|
if (analogRead(_pin) & 1) value++;
|
|
}
|
|
return value ^ _seed;
|
|
}
|
|
|
|
|
|
// An example of a simple pseudo-random number generator is the
|
|
// Multiply-with-carry method invented by George Marsaglia.
|
|
// two initializers (not null)
|
|
uint32_t DEVRANDOM::_marsaglia()
|
|
{
|
|
_m_z = 36969L * (_m_z & 65535L) + (_m_z >> 16);
|
|
_m_w = 18000L * (_m_w & 65535L) + (_m_w >> 16);
|
|
return (_m_z << 16) + _m_w; /* 32-bit result */
|
|
}
|
|
|
|
|
|
// -- END OF FILE --
|
|
|