commit f3547bf7b883ac66303b20c3ab2e030efe763860 Author: ston1th Date: Sun Nov 5 18:30:54 2017 +0100 initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2bb060c --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (C) 2017 Marius Schellenberger +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * The names of the authors and/or contributors may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ston1th BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..434e940 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Arduino Projects diff --git a/enigma/enigma.ino b/enigma/enigma.ino new file mode 100644 index 0000000..56b5639 --- /dev/null +++ b/enigma/enigma.ino @@ -0,0 +1,442 @@ +// Copyright (C) 2017 Marius Schellenberger + +#include +#include +#include +#include +#include +#include + +/* Display +GND (Display) -> GND (Arduino UNO) +VCC (Display) -> 5V (Arduino UNO) +SDA (Display) -> A4 (Arduino UNO) +SCL (Display) -> A5 (Arduino UNO) +*/ + +// control +#define TRUE 1 +#define D8 8 +#define D9 9 +#define D10 10 +#define D11 11 +#define D12 12 +int b1, b2, b3, b4, b5; + +void read_b(void) { + b1 = digitalRead(D12); + b2 = digitalRead(D11); + b3 = digitalRead(D10); + b4 = digitalRead(D9); + b5 = digitalRead(D8); +} + +// data +#define ALPHA_MAX 36 +char _itoa[ALPHA_MAX]; +int _atoi[91]; + +void cont(void) { + while (digitalRead(D8) != HIGH); + delay(200); +} + +void init_itoa(void) { + for (int i = 0; i < 10; i++) + _itoa[i] = (char)48 + i; + for (int i = 10; i < ALPHA_MAX; i++) + _itoa[i] = (char)55 + i; +} + +void init_atoi(void) { + int c = 0; + for (int i = 48; i < 58; i++) + _atoi[i] = c++; + for (int i = 65; i < 91; i++) + _atoi[i] = c++; +} + +// random +#define CHAR_MAX 256 +const unsigned char _r_max = CHAR_MAX - (CHAR_MAX % ALPHA_MAX); +volatile unsigned char _r_sample = 0; +volatile char _r_new = 0; +unsigned char _r = 0; + +ISR(WDT_vect) { + _r_sample = TCNT1L; + _r_new = 1; +} + +void _r_init(void) { + cli(); + MCUSR = 0; + WDTCSR |= _BV(WDCE) | _BV(WDE); + WDTCSR = _BV(WDIE); + sei(); +} + +char _r_rotl_one(const char v) { + int shift = 1; + if ((shift &= sizeof(v) * 8 - 1) == 0) + return v; + return (v << shift) | (v >> (sizeof(v) * 8 - shift)); +} + +char _r_char(void) { + char i = 0; + while (TRUE) { + if (_r_new) { + _r_new = 0; + _r = _r_rotl_one(_r); + _r ^= _r_sample; + if (i++ > 7) { + if (_r < _r_max) + return _itoa[_r % ALPHA_MAX]; + else + i = 0; + } + } + } +} + +// LCD +#define COLS 20 +#define ROWS 4 +#define WS ' ' +#define NULL_CHAR '\0'; + +LiquidCrystal_I2C lcd(0x27, COLS, ROWS); + +void clr_all(void) { + for (int r = 0; r < ROWS; r++) + clr(r); +} + +void clr(const int row) { + for (int c = 0; c < COLS; c++) { + lcd.setCursor(c, row); + lcd.print(WS); + } +} + +void prntl(const int row, const char *str) { + int len = strlen(str); + for (int i = 0; i < len; i++) + prntc(row, i, str[i]); + while (len < COLS) + prntc(row, len++, WS); +} + +void prntlong(int row, const char *str) { + clr_all(); + int c = 0; + for (int i = 0; i < strlen(str); i++) { + prntc(row, c++, str[i]); + if (i == (COLS - 1) || i == ((COLS * 2) - 1) || i == ((COLS * 3) - 1)) { + row++; + c = 0; + } + } +} + +void prntstr(const int row, const int col, const int len, const char *str) { + for (int i = 0; i < len; i++) + prntc(row, col+i, str[i]); +} + +void prntc(const int row, const int col, const char c) { + lcd.setCursor(col, row); + lcd.print(c); +} + +void prnti(const int row, const int col, const int i) { + char buf[10]; + itoa(i, buf, 10); + prntstr(row, col, strlen(buf), buf); +} + +// char ops +char add_ten(char c) { + for (int i = 0; i < 10; i++) + c = add_one(c); + return c; +} + +char add_one(const char c) { + int n = (int)c + 1; + if (n == 91) + return '0'; + if (n == 64) + return '9'; + if (n == 58) + return 'A'; + if (n == 47) + return 'Z'; + return (char)n; +} + +char sub_ten(char c) { + for (int i = 0; i < 10; i++) + c = sub_one(c); + return c; +} + +char sub_one(const char c) { + int n = (int)c - 1; + if (n == 91) + return '0'; + if (n == 64) + return '9'; + if (n == 58) + return 'A'; + if (n == 47) + return 'Z'; + return (char)n; +} + +// crypto +char *keygen(const int len) { + char *key = (char*)malloc(sizeof(char) * (len + 1)); + for (int i = 0; i < len; i++) + key[i] = _r_char(); + key[len] = NULL_CHAR; + return key; +} + +char *encrypt(const char *txt, const char *key) { + int i = 0, c = 0; + int len = strlen(key); + char *enc = (char*)malloc(sizeof(char) * (len + 1)); + while (*txt) { + c = _atoi[(int)*txt++] + _atoi[(int)*key++]; + if (c > 36) { + c -= 36; + } + enc[i++] = _itoa[c]; + } + enc[len] = NULL_CHAR; + return enc; +} + +char *decrypt(const char *enc, const char *key) { + int i = 0, c = 0; + int len = strlen(key); + char *txt = (char*)malloc(sizeof(char) * (len + 1)); + while (*enc) { + c = _atoi[(int)*enc++] - _atoi[(int)*key++]; + if (c < 0) { + c += 36; + } + txt[i++] = _itoa[c]; + } + txt[len] = NULL_CHAR; + return txt; +} + +void enc_test(void) { + char txt[] = "0ZYX"; + char key[] = "EU16"; + char *enc = encrypt(txt, key); + clr_all(); + prntl(0, "Encrypt Test"); + prntl(2, enc); + prntl(3, "ETZ3"); + free(enc); + cont(); +} + +void dec_test(void) { + char enc[] = "KU69"; + char key[] = "AJU9"; + char *dec = decrypt(enc, key); + clr_all(); + prntl(0, "Decrypt Test"); + prntl(2, dec); + prntl(3, "ABC0"); + free(dec); + cont(); +} + +char *input(void) { + char p = 0, in = 'A'; + int row = 0, col = 0, c = 0; + int len = COLS; + char *buf = (char*)malloc(sizeof(char) * len); + prntc(row, col, in); + + while (TRUE) { + read_b(); + if (b1 == HIGH) { + delay(100); + if (b2 == HIGH) { + prntc(row, col--, WS); + if (c > 0) + c--; + if (row > 0 && col < 0) { + row--; + col = (COLS - 1); + } + in = 'A'; + delay(300); + } + } + if (b3 == HIGH) { + delay(100); + if (b4 == HIGH) { + prntc(row, col, WS); + buf = (char*)realloc(buf, sizeof(char) * c); + buf[c] = NULL_CHAR; + return buf; + } + } + if (b5 == HIGH) { + if (col == COLS || col == (COLS * 2) || col == (COLS * 3)) { + row++; + col = 0; + } + prntc(row, col++, in); + buf[c++] = in; + if (c == len) { + len += COLS; + buf = (char*)realloc(buf, sizeof(char) * len); + } + delay(300); + } + if (b1 == HIGH) { + in = sub_ten(in); + p = 1; + } + if (b2 == HIGH) { + in = sub_one(in); + p = 1; + } + if (b3 == HIGH) { + in = add_one(in); + p = 1; + } + if (b4 == HIGH) { + in = add_ten(in); + p = 1; + } + if (p) { + p = 0; + prntc(row, col, in); + delay(200); + } + } +} + +void enc_mode(void) { + clr_all(); + char *txt, *key, *enc; + txt = input(); + key = keygen(strlen(txt)); + enc = encrypt(txt, key); + prntlong(0, key); + cont(); + prntlong(0, enc); + free(txt); + free(key); + free(enc); + cont(); +} + +void dec_mode(void) { + clr_all(); + int len = 0; + char *enc, *key, *dec; + enc = input(); + clr_all(); + key = input(); + dec = decrypt(enc, key); + prntlong(0, dec); + free(enc); + free(key); + free(dec); + cont(); +} + +void key_mode(void) { + clr_all(); + char p = 0; + char *key; + int len = COLS * 2; + prnti(0, 0, len); + while (TRUE) { + read_b(); + if (b1 == HIGH && len > 10) { + len -= 10; + p = 1; + } + if (b2 == HIGH && len > 1) { + len--; + p = 1; + } + if (b3 == HIGH && len < (COLS * ROWS)) { + len++; + p = 1; + } + if (b4 == HIGH && len <= ((COLS * ROWS) - 10)) { + len += 10; + p = 1; + } + if (p) { + p = 0; + prntl(0, ""); + prnti(0, 0, len); + delay(150); + } + if (b5 == HIGH) + break; + } + key = keygen(len); + prntlong(0, key); + free(key); + cont(); +} + +void setup(void) { + pinMode(D8, INPUT); + pinMode(D9, INPUT); + pinMode(D10, INPUT); + pinMode(D11, INPUT); + pinMode(D12, INPUT); + _r_init(); + lcd.init(); + lcd.backlight(); + lcd.setCursor(0, 0); + init_atoi(); + init_itoa(); +} + +void loop(void) { + clr_all(); + prntl(0, "Encrypt: 1 KeyGen: 5"); + prntl(1, "Decrypt: 2"); + prntl(2, "Encrypt Test: 3"); + prntl(3, "Decrypt Test: 4"); + while (TRUE) { + read_b(); + if (b1 == HIGH) { + enc_mode(); + break; + } + if (b2 == HIGH) { + dec_mode(); + break; + } + if (b3 == HIGH) { + enc_test(); + break; + } + if (b4 == HIGH) { + dec_test(); + break; + } + if (b5 == HIGH) { + key_mode(); + break; + } + } +} diff --git a/libraries/Entropy/Entropy.cpp b/libraries/Entropy/Entropy.cpp new file mode 100644 index 0000000..f3a949d --- /dev/null +++ b/libraries/Entropy/Entropy.cpp @@ -0,0 +1,322 @@ +#include +#include + +const uint8_t WDT_MAX_8INT=0xFF; +const uint16_t WDT_MAX_16INT=0xFFFF; +const uint32_t WDT_MAX_32INT=0xFFFFFFFF; +// Since the Due TRNG is so fast we don't need a circular buffer for it +#ifndef ARDUINO_SAM_DUE + const uint8_t gWDT_buffer_SIZE=32; + const uint8_t WDT_POOL_SIZE=8; + uint8_t gWDT_buffer[gWDT_buffer_SIZE]; + uint8_t gWDT_buffer_position; + uint8_t gWDT_loop_counter; + volatile uint8_t gWDT_pool_start; + volatile uint8_t gWDT_pool_end; + volatile uint8_t gWDT_pool_count; + volatile uint32_t gWDT_entropy_pool[WDT_POOL_SIZE]; +#endif + +// This function initializes the global variables needed to implement the circular entropy pool and +// the buffer that holds the raw Timer 1 values that are used to create the entropy pool. It then +// Initializes the Watch Dog Timer (WDT) to perform an interrupt every 2048 clock cycles, (about +// 16 ms) which is as fast as it can be set. +void EntropyClass::initialize(void) +{ +#ifndef ARDUINO_SAM_DUE + gWDT_buffer_position=0; + gWDT_pool_start = 0; + gWDT_pool_end = 0; + gWDT_pool_count = 0; +#endif +#if defined(__AVR__) + cli(); // Temporarily turn off interrupts, until WDT configured + MCUSR = 0; // Use the MCU status register to reset flags for WDR, BOR, EXTR, and POWR + _WD_CONTROL_REG |= (1<<_WD_CHANGE_BIT) | (1<TRNG_IDR = 0xFFFFFFFF; + TRNG->TRNG_CR = TRNG_CR_KEY(0x524e47) | TRNG_CR_ENABLE; +#elif defined(__arm__) && defined(TEENSYDUINO) + SIM_SCGC5 |= SIM_SCGC5_LPTIMER; + LPTMR0_CSR = 0b10000100; + LPTMR0_PSR = 0b00000101; // PCS=01 : 1 kHz clock + LPTMR0_CMR = 0x0006; // smaller number = faster random numbers... + LPTMR0_CSR = 0b01000101; + NVIC_ENABLE_IRQ(IRQ_LPTMR); +#endif +} + +// This function returns a uniformly distributed random integer in the range +// of [0,0xFFFFFFFF] as long as some entropy exists in the pool and a 0 +// otherwise. To ensure a proper random return the available() function +// should be called first to ensure that entropy exists. +// +// The pool is implemented as an 8 value circular buffer +uint32_t EntropyClass::random(void) +{ +#ifdef ARDUINO_SAM_DUE + while (! (TRNG->TRNG_ISR & TRNG_ISR_DATRDY)) + ; + retVal = TRNG->TRNG_ODATA; +#else + uint8_t waiting; + while (gWDT_pool_count < 1) + waiting += 1; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + retVal = gWDT_entropy_pool[gWDT_pool_start]; + gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE; + --gWDT_pool_count; + } +#endif + return(retVal); +} + +// This function returns one byte of a single 32-bit entropy value, while preserving the remaining bytes to +// be returned upon successive calls to the method. This makes best use of the available entropy pool when +// only bytes size chunks of entropy are needed. Not available to public use since there is a method of using +// the default random method for the end-user to achieve the same results. This internal method is for providing +// that capability to the random method, shown below +uint8_t EntropyClass::random8(void) +{ + static uint8_t byte_position=0; + uint8_t retVal8; + + if (byte_position == 0) + share_entropy.int32 = random(); + retVal8 = share_entropy.int8[byte_position++]; + byte_position = byte_position % 4; + return(retVal8); +} + +// This function returns one word of a single 32-bit entropy value, while preserving the remaining word to +// be returned upon successive calls to the method. This makes best use of the available entropy pool when +// only word sized chunks of entropy are needed. Not available to public use since there is a method of using +// the default random method for the end-user to achieve the same results. This internal method is for providing +// that capability to the random method, shown below +uint16_t EntropyClass::random16(void) +{ + static uint8_t word_position=0; + uint16_t retVal16; + + if (word_position == 0) + share_entropy.int32 = random(); + retVal16 = share_entropy.int16[word_position++]; + word_position = word_position % 2; + return(retVal16); +} + +uint8_t EntropyClass::randomByte(void) +{ + return random8(); +} + +uint16_t EntropyClass::randomWord(void) +{ + return random16(); +} + +// This function returns a uniformly distributed integer in the range of +// of [0,max). The added complexity of this function is required to ensure +// a uniform distribution since the naive modulus max (% max) introduces +// bias for all values of max that are not powers of two. +// +// The loops below are needed, because there is a small and non-uniform chance +// That the division below will yield an answer = max, so we just get +// the next random value until answer < max. Which prevents the introduction +// of bias caused by the division process. This is why we can't use the +// simpler modulus operation which introduces significant bias for divisors +// that aren't a power of two +uint32_t EntropyClass::random(uint32_t max) +{ + uint32_t slice; + + if (max < 2) + retVal=0; + else + { + retVal = WDT_MAX_32INT; + if (max <= WDT_MAX_8INT) // If only byte values are needed, make best use of entropy + { // by diving the long into four bytes and using individually + slice = WDT_MAX_8INT / max; + while (retVal >= max) + retVal = random8() / slice; + } + else if (max <= WDT_MAX_16INT) // If only word values are need, make best use of entropy + { // by diving the long into two words and using individually + slice = WDT_MAX_16INT / max; + while (retVal >= max) + retVal = random16() / slice; + } + else + { + slice = WDT_MAX_32INT / max; + while (retVal >= max) + retVal = random() / slice; + } + } + return(retVal); +} + +// This function returns a uniformly distributed integer in the range of +// of [min,max). +uint32_t EntropyClass::random(uint32_t min, uint32_t max) +{ + uint32_t tmp_random, tmax; + + tmax = max - min; + if (tmax < 1) + retVal=min; + else + { + tmp_random = random(tmax); + retVal = min + tmp_random; + } + return(retVal); +} + +// This function returns a uniformly distributed single precision floating point +// in the range of [0.0,1.0) +float EntropyClass::randomf(void) +{ + float fRetVal; + + // Since c++ doesn't allow bit manipulations of floating point types, we are + // using integer type and arrange its bit pattern to follow the IEEE754 bit + // pattern for single precision floating point value in the range of 1.0 - 2.0 + uint32_t tmp_random = random(); + tmp_random = (tmp_random & 0x007FFFFF) | 0x3F800000; + // We then copy that binary representation from the temporary integer to the + // returned floating point value + memcpy((void *) &fRetVal, (void *) &tmp_random, sizeof(fRetVal)); + // Now translate the value back to its intended range by subtracting 1.0 + fRetVal = fRetVal - 1.0; + return (fRetVal); +} + +// This function returns a uniformly distributed single precision floating point +// in the range of [0.0, max) +float EntropyClass::randomf(float max) +{ + float fRetVal; + fRetVal = randomf() * max; + return(fRetVal); +} + +// This function returns a uniformly distributed single precision floating point +// in the range of [min, max) +float EntropyClass::randomf(float min,float max) +{ + float fRetVal; + float tmax; + tmax = max - min; + fRetVal = (randomf() * tmax) + min; + return(fRetVal); +} + +// This function implements the Marsaglia polar method of converting a uniformly +// distributed random numbers to a normaly distributed (bell curve) with the +// mean and standard deviation specified. This type of random number is useful +// for a variety of purposes, like Monte Carlo simulations. +float EntropyClass::rnorm(float mean, float stdDev) +{ + static float spare; + static float u1; + static float u2; + static float s; + static bool isSpareReady = false; + + if (isSpareReady) + { + isSpareReady = false; + return ((spare * stdDev) + mean); + } else { + do { + u1 = (randomf() * 2) - 1; + u2 = (randomf() * 2) - 1; + s = (u1 * u1) + (u2 * u2); + } while (s >= 1.0); + s = sqrt(-2.0 * log(s) / s); + spare = u2 * s; + isSpareReady = true; + return(mean + (stdDev * u1 * s)); + } +} + +// This function returns a unsigned char (8-bit) with the number of unsigned long values +// in the entropy pool +uint8_t EntropyClass::available(void) +{ +#ifdef ARDUINO_SAM_DUE + return(TRNG->TRNG_ISR & TRNG_ISR_DATRDY); +#else + return(gWDT_pool_count); +#endif +} + +// Circular buffer is not needed with the speed of the Arduino Due trng hardware generator +#ifndef ARDUINO_SAM_DUE +// This interrupt service routine is called every time the WDT interrupt is triggered. +// With the default configuration that is approximately once every 16ms, producing +// approximately two 32-bit integer values every second. +// +// The pool is implemented as an 8 value circular buffer +static void isr_hardware_neutral(uint8_t val) +{ + gWDT_buffer[gWDT_buffer_position] = val; + gWDT_buffer_position++; // every time the WDT interrupt is triggered + if (gWDT_buffer_position >= gWDT_buffer_SIZE) + { + gWDT_pool_end = (gWDT_pool_start + gWDT_pool_count) % WDT_POOL_SIZE; + // The following code is an implementation of Jenkin's one at a time hash + // This hash function has had preliminary testing to verify that it + // produces reasonably uniform random results when using WDT jitter + // on a variety of Arduino platforms + for(gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter) + { + gWDT_entropy_pool[gWDT_pool_end] += gWDT_buffer[gWDT_loop_counter]; + gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 10); + gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 6); + } + gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 3); + gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 11); + gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 15); + gWDT_entropy_pool[gWDT_pool_end] = gWDT_entropy_pool[gWDT_pool_end]; + gWDT_buffer_position = 0; // Start collecting the next 32 bytes of Timer 1 counts + if (gWDT_pool_count == WDT_POOL_SIZE) // The entropy pool is full + gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE; + else // Add another unsigned long (32 bits) to the entropy pool + ++gWDT_pool_count; + } +} +#endif + +#if defined( __AVR_ATtiny25__ ) || defined( __AVR_ATtiny45__ ) || defined( __AVR_ATtiny85__ ) +ISR(WDT_vect) +{ + isr_hardware_neutral(TCNT0); +} + +#elif defined(__AVR__) +ISR(WDT_vect) +{ + isr_hardware_neutral(TCNT1L); // Record the Timer 1 low byte (only one needed) +} + +#elif defined(__arm__) && defined(TEENSYDUINO) +void lptmr_isr(void) +{ + LPTMR0_CSR = 0b10000100; + LPTMR0_CSR = 0b01000101; + isr_hardware_neutral(SYST_CVR); +} +#endif + +// The library implements a single global instance. There is no need, nor will the library +// work properly if multiple instances are created. +EntropyClass Entropy; + diff --git a/libraries/Entropy/Entropy.h b/libraries/Entropy/Entropy.h new file mode 100644 index 0000000..0d790e2 --- /dev/null +++ b/libraries/Entropy/Entropy.h @@ -0,0 +1,55 @@ +#ifndef Entropy_h +#define Entropy_h + +#include + +// Separate the ARM Due headers we use +#ifdef ARDUINO_SAM_DUE +#include +#include +#endif + +// Teensy required headers +#ifdef TEENSYDUINO +#include +#endif + +// Separate AVR headers from ARM headers +#ifdef __AVR__ +#include +#include +#include +#endif + +const uint32_t WDT_RETURN_BYTE=256; +const uint32_t WDT_RETURN_WORD=65536; + +union ENTROPY_LONG_WORD +{ + uint32_t int32; + uint16_t int16[2]; + uint8_t int8[4]; +}; + +class EntropyClass +{ +public: + void initialize(void); + uint32_t random(void); + uint32_t random(uint32_t max); + uint32_t random(uint32_t min, uint32_t max); + uint8_t randomByte(void); + uint16_t randomWord(void); + float randomf(void); + float randomf(float max); + float randomf(float min, float max); + float rnorm(float mean, float stdDev); + uint8_t available(void); + private: + ENTROPY_LONG_WORD share_entropy; + uint32_t retVal; + uint8_t random8(void); + uint16_t random16(void); +}; +extern EntropyClass Entropy; +#endif diff --git a/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.cpp b/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.cpp new file mode 100644 index 0000000..4f1b787 --- /dev/null +++ b/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.cpp @@ -0,0 +1,322 @@ +//YWROBOT +//last updated on 21/12/2011 +//Tim Starling Fix the reset bug (Thanks Tim) +//wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063) +//Support Forum: http://www.dfrobot.com/forum/ +//Compatible with the Arduino IDE 1.0 +//Library version:1.1 + + +#include "LiquidCrystal_I2C.h" +#include +#if defined(ARDUINO) && ARDUINO >= 100 + +#include "Arduino.h" + +#define printIIC(args) Wire.write(args) +inline size_t LiquidCrystal_I2C::write(uint8_t value) { + send(value, Rs); + return 0; +} + +#else +#include "WProgram.h" + +#define printIIC(args) Wire.send(args) +inline void LiquidCrystal_I2C::write(uint8_t value) { + send(value, Rs); +} + +#endif +#include "Wire.h" + + + +// When the display powers up, it is configured as follows: +// +// 1. Display clear +// 2. Function set: +// DL = 1; 8-bit interface data +// N = 0; 1-line display +// F = 0; 5x8 dot character font +// 3. Display on/off control: +// D = 0; Display off +// C = 0; Cursor off +// B = 0; Blinking off +// 4. Entry mode set: +// I/D = 1; Increment by 1 +// S = 0; No shift +// +// Note, however, that resetting the Arduino doesn't reset the LCD, so we +// can't assume that its in that state when a sketch starts (and the +// LiquidCrystal constructor is called). + +LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows) +{ + _Addr = lcd_Addr; + _cols = lcd_cols; + _rows = lcd_rows; + _backlightval = LCD_NOBACKLIGHT; +} + +void LiquidCrystal_I2C::init(){ + init_priv(); +} + +void LiquidCrystal_I2C::init_priv() +{ + Wire.begin(); + _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; + begin(_cols, _rows); +} + +void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { + if (lines > 1) { + _displayfunction |= LCD_2LINE; + } + _numlines = lines; + + // for some 1 line displays you can select a 10 pixel high font + if ((dotsize != 0) && (lines == 1)) { + _displayfunction |= LCD_5x10DOTS; + } + + // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! + // according to datasheet, we need at least 40ms after power rises above 2.7V + // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 + delay(50); + + // Now we pull both RS and R/W low to begin commands + expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1) + delay(1000); + + //put the LCD into 4 bit mode + // this is according to the hitachi HD44780 datasheet + // figure 24, pg 46 + + // we start in 8bit mode, try to set 4 bit mode + write4bits(0x03 << 4); + delayMicroseconds(4500); // wait min 4.1ms + + // second try + write4bits(0x03 << 4); + delayMicroseconds(4500); // wait min 4.1ms + + // third go! + write4bits(0x03 << 4); + delayMicroseconds(150); + + // finally, set to 4-bit interface + write4bits(0x02 << 4); + + + // set # lines, font size, etc. + command(LCD_FUNCTIONSET | _displayfunction); + + // turn the display on with no cursor or blinking default + _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; + display(); + + // clear it off + clear(); + + // Initialize to default text direction (for roman languages) + _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; + + // set the entry mode + command(LCD_ENTRYMODESET | _displaymode); + + home(); + +} + +/********** high level commands, for the user! */ +void LiquidCrystal_I2C::clear(){ + command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero + delayMicroseconds(2000); // this command takes a long time! +} + +void LiquidCrystal_I2C::home(){ + command(LCD_RETURNHOME); // set cursor position to zero + delayMicroseconds(2000); // this command takes a long time! +} + +void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row){ + int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; + if ( row > _numlines ) { + row = _numlines-1; // we count rows starting w/0 + } + command(LCD_SETDDRAMADDR | (col + row_offsets[row])); +} + +// Turn the display on/off (quickly) +void LiquidCrystal_I2C::noDisplay() { + _displaycontrol &= ~LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal_I2C::display() { + _displaycontrol |= LCD_DISPLAYON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns the underline cursor on/off +void LiquidCrystal_I2C::noCursor() { + _displaycontrol &= ~LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal_I2C::cursor() { + _displaycontrol |= LCD_CURSORON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turn on and off the blinking cursor +void LiquidCrystal_I2C::noBlink() { + _displaycontrol &= ~LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void LiquidCrystal_I2C::blink() { + _displaycontrol |= LCD_BLINKON; + command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// These commands scroll the display without changing the RAM +void LiquidCrystal_I2C::scrollDisplayLeft(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); +} +void LiquidCrystal_I2C::scrollDisplayRight(void) { + command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); +} + +// This is for text that flows Left to Right +void LiquidCrystal_I2C::leftToRight(void) { + _displaymode |= LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This is for text that flows Right to Left +void LiquidCrystal_I2C::rightToLeft(void) { + _displaymode &= ~LCD_ENTRYLEFT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'right justify' text from the cursor +void LiquidCrystal_I2C::autoscroll(void) { + _displaymode |= LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'left justify' text from the cursor +void LiquidCrystal_I2C::noAutoscroll(void) { + _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; + command(LCD_ENTRYMODESET | _displaymode); +} + +// Allows us to fill the first 8 CGRAM locations +// with custom characters +void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) { + location &= 0x7; // we only have 8 locations 0-7 + command(LCD_SETCGRAMADDR | (location << 3)); + for (int i=0; i<8; i++) { + write(charmap[i]); + } +} + +// Turn the (optional) backlight off/on +void LiquidCrystal_I2C::noBacklight(void) { + _backlightval=LCD_NOBACKLIGHT; + expanderWrite(0); +} + +void LiquidCrystal_I2C::backlight(void) { + _backlightval=LCD_BACKLIGHT; + expanderWrite(0); +} + + + +/*********** mid level commands, for sending data/cmds */ + +inline void LiquidCrystal_I2C::command(uint8_t value) { + send(value, 0); +} + + +/************ low level data pushing commands **********/ + +// write either command or data +void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) { + uint8_t highnib=value&0xf0; + uint8_t lownib=(value<<4)&0xf0; + write4bits((highnib)|mode); + write4bits((lownib)|mode); +} + +void LiquidCrystal_I2C::write4bits(uint8_t value) { + expanderWrite(value); + pulseEnable(value); +} + +void LiquidCrystal_I2C::expanderWrite(uint8_t _data){ + Wire.beginTransmission(_Addr); + printIIC((int)(_data) | _backlightval); + Wire.endTransmission(); +} + +void LiquidCrystal_I2C::pulseEnable(uint8_t _data){ + expanderWrite(_data | En); // En high + delayMicroseconds(1); // enable pulse must be >450ns + + expanderWrite(_data & ~En); // En low + delayMicroseconds(50); // commands need > 37us to settle +} + + +// Alias functions + +void LiquidCrystal_I2C::cursor_on(){ + cursor(); +} + +void LiquidCrystal_I2C::cursor_off(){ + noCursor(); +} + +void LiquidCrystal_I2C::blink_on(){ + blink(); +} + +void LiquidCrystal_I2C::blink_off(){ + noBlink(); +} + +void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){ + createChar(char_num, rows); +} + +void LiquidCrystal_I2C::setBacklight(uint8_t new_val){ + if(new_val){ + backlight(); // turn backlight on + }else{ + noBacklight(); // turn backlight off + } +} + +void LiquidCrystal_I2C::printstr(const char c[]){ + //This function is not identical to the function used for "real" I2C displays + //it's here so the user sketch doesn't have to be changed + print(c); +} + + +// unsupported API functions +void LiquidCrystal_I2C::off(){} +void LiquidCrystal_I2C::on(){} +void LiquidCrystal_I2C::setDelay (int cmdDelay,int charDelay) {} +uint8_t LiquidCrystal_I2C::status(){return 0;} +uint8_t LiquidCrystal_I2C::keypad (){return 0;} +uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype){return 0;} +void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end){} +void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end){} +void LiquidCrystal_I2C::setContrast(uint8_t new_val){} + + \ No newline at end of file diff --git a/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.h b/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.h new file mode 100644 index 0000000..201be33 --- /dev/null +++ b/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.h @@ -0,0 +1,126 @@ +//YWROBOT +#ifndef LiquidCrystal_I2C_h +#define LiquidCrystal_I2C_h + +#include +#include "Print.h" +#include + +// commands +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_CURSORSHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +// flags for display entry mode +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 + +// flags for display/cursor shift +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +#define LCD_8BITMODE 0x10 +#define LCD_4BITMODE 0x00 +#define LCD_2LINE 0x08 +#define LCD_1LINE 0x00 +#define LCD_5x10DOTS 0x04 +#define LCD_5x8DOTS 0x00 + +// flags for backlight control +#define LCD_BACKLIGHT 0x08 +#define LCD_NOBACKLIGHT 0x00 + +#define En B00000100 // Enable bit +#define Rw B00000010 // Read/Write bit +#define Rs B00000001 // Register select bit + +class LiquidCrystal_I2C : public Print { +public: + LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows); + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS ); + void clear(); + void home(); + void noDisplay(); + void display(); + void noBlink(); + void blink(); + void noCursor(); + void cursor(); + void scrollDisplayLeft(); + void scrollDisplayRight(); + void printLeft(); + void printRight(); + void leftToRight(); + void rightToLeft(); + void shiftIncrement(); + void shiftDecrement(); + void noBacklight(); + void backlight(); + void autoscroll(); + void noAutoscroll(); + void createChar(uint8_t, uint8_t[]); + void setCursor(uint8_t, uint8_t); +#if defined(ARDUINO) && ARDUINO >= 100 + virtual size_t write(uint8_t); +#else + virtual void write(uint8_t); +#endif + void command(uint8_t); + void init(); + +////compatibility API function aliases +void blink_on(); // alias for blink() +void blink_off(); // alias for noBlink() +void cursor_on(); // alias for cursor() +void cursor_off(); // alias for noCursor() +void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight() +void load_custom_character(uint8_t char_num, uint8_t *rows); // alias for createChar() +void printstr(const char[]); + +////Unsupported API functions (not implemented in this library) +uint8_t status(); +void setContrast(uint8_t new_val); +uint8_t keypad(); +void setDelay(int,int); +void on(); +void off(); +uint8_t init_bargraph(uint8_t graphtype); +void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end); +void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end); + + +private: + void init_priv(); + void send(uint8_t, uint8_t); + void write4bits(uint8_t); + void expanderWrite(uint8_t); + void pulseEnable(uint8_t); + uint8_t _Addr; + uint8_t _displayfunction; + uint8_t _displaycontrol; + uint8_t _displaymode; + uint8_t _numlines; + uint8_t _cols; + uint8_t _rows; + uint8_t _backlightval; +}; + +#endif diff --git a/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.o b/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.o new file mode 100644 index 0000000..bca78e0 Binary files /dev/null and b/libraries/LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.o differ diff --git a/libraries/LiquidCrystal_I2C2004V1/diff.txt b/libraries/LiquidCrystal_I2C2004V1/diff.txt new file mode 100644 index 0000000..b477934 --- /dev/null +++ b/libraries/LiquidCrystal_I2C2004V1/diff.txt @@ -0,0 +1,69 @@ +1,6c1 +< //YWROBOT +< //last updated on 26/11/2010 +< //Tim Starling Fix the reset bug (Thanks Tim) +< //wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063) +< //Support Forum: http://www.dfrobot.com/forum/ +< +--- +> // LiquidCrystal_I2C V2.0 +10d4 +< #include "WProgram.h" +12c6 +< +--- +> #include "Arduino.h" +67c61 +< delay(50); +--- +> delayMicroseconds(50000); +77,90c71,84 +< // we start in 8bit mode, try to set 4 bit mode +< write4bits(0x03 << 4); +< delayMicroseconds(4500); // wait min 4.1ms +< +< // second try +< write4bits(0x03 << 4); +< delayMicroseconds(4500); // wait min 4.1ms +< +< // third go! +< write4bits(0x03 << 4); +< delayMicroseconds(150); +< +< // finally, set to 4-bit interface +< write4bits(0x02 << 4); +--- +> // we start in 8bit mode, try to set 4 bit mode +> write4bits(0x03); +> delayMicroseconds(4500); // wait min 4.1ms +> +> // second try +> write4bits(0x03); +> delayMicroseconds(4500); // wait min 4.1ms +> +> // third go! +> write4bits(0x03); +> delayMicroseconds(150); +> +> // finally, set to 4-bit interface +> write4bits(0x02); +225c219 +< inline void LiquidCrystal_I2C::write(uint8_t value) { +--- +> inline size_t LiquidCrystal_I2C::write(uint8_t value) { +226a221 +> return 0; +235,238c230,233 +< uint8_t highnib=value&0xf0; +< uint8_t lownib=(value<<4)&0xf0; +< write4bits((highnib)|mode); +< write4bits((lownib)|mode); +--- +> uint8_t highnib=value>>4; +> uint8_t lownib=value & 0x0F; +> write4bits((highnib)|mode); +> write4bits((lownib)|mode); +248c243 +< Wire.send((int)(_data) | _backlightval); +--- +> Wire.write((int)(_data) | _backlightval); diff --git a/libraries/LiquidCrystal_I2C2004V1/examples/CustomChars/CustomChars.pde b/libraries/LiquidCrystal_I2C2004V1/examples/CustomChars/CustomChars.pde new file mode 100644 index 0000000..beea6d6 --- /dev/null +++ b/libraries/LiquidCrystal_I2C2004V1/examples/CustomChars/CustomChars.pde @@ -0,0 +1,70 @@ +//YWROBOT +//Compatible with the Arduino IDE 1.0 +//Library version:1.1 +#include +#include + +#if defined(ARDUINO) && ARDUINO >= 100 +#define printByte(args) write(args); +#else +#define printByte(args) print(args,BYTE); +#endif + +uint8_t bell[8] = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4}; +uint8_t note[8] = {0x2,0x3,0x2,0xe,0x1e,0xc,0x0}; +uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0}; +uint8_t heart[8] = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0}; +uint8_t duck[8] = {0x0,0xc,0x1d,0xf,0xf,0x6,0x0}; +uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0}; +uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0}; +uint8_t retarrow[8] = { 0x1,0x1,0x5,0x9,0x1f,0x8,0x4}; + +LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display + +void setup() +{ + lcd.init(); // initialize the lcd + lcd.backlight(); + + lcd.createChar(0, bell); + lcd.createChar(1, note); + lcd.createChar(2, clock); + lcd.createChar(3, heart); + lcd.createChar(4, duck); + lcd.createChar(5, check); + lcd.createChar(6, cross); + lcd.createChar(7, retarrow); + lcd.home(); + + lcd.print("Hello world..."); + lcd.setCursor(0, 1); + lcd.print(" i "); + lcd.printByte(3); + lcd.print(" arduinos!"); + delay(5000); + displayKeyCodes(); + +} + +// display all keycodes +void displayKeyCodes(void) { + uint8_t i = 0; + while (1) { + lcd.clear(); + lcd.print("Codes 0x"); lcd.print(i, HEX); + lcd.print("-0x"); lcd.print(i+16, HEX); + lcd.setCursor(0, 1); + for (int j=0; j<16; j++) { + lcd.printByte(i+j); + } + i+=16; + + delay(4000); + } +} + +void loop() +{ + +} + diff --git a/libraries/LiquidCrystal_I2C2004V1/examples/HelloWorld/HelloWorld.pde b/libraries/LiquidCrystal_I2C2004V1/examples/HelloWorld/HelloWorld.pde new file mode 100644 index 0000000..458c6d8 --- /dev/null +++ b/libraries/LiquidCrystal_I2C2004V1/examples/HelloWorld/HelloWorld.pde @@ -0,0 +1,28 @@ +//YWROBOT +//Compatible with the Arduino IDE 1.0 +//Library version:1.1 +#include +#include + +LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display + +void setup() +{ + lcd.init(); // initialize the lcd + lcd.init(); + // Print a message to the LCD. + lcd.backlight(); + lcd.setCursor(3,0); + lcd.print("Hello, world!"); + lcd.setCursor(2,1); + lcd.print("Ywrobot Arduino!"); + lcd.setCursor(0,2); + lcd.print("Arduino LCM IIC 2004"); + lcd.setCursor(2,3); + lcd.print("Power By Ec-yuan!"); +} + + +void loop() +{ +} diff --git a/libraries/LiquidCrystal_I2C2004V1/examples/SerialDisplay/SerialDisplay.pde b/libraries/LiquidCrystal_I2C2004V1/examples/SerialDisplay/SerialDisplay.pde new file mode 100644 index 0000000..1fca4e1 --- /dev/null +++ b/libraries/LiquidCrystal_I2C2004V1/examples/SerialDisplay/SerialDisplay.pde @@ -0,0 +1,34 @@ +/* + * Displays text sent over the serial port (e.g. from the Serial Monitor) on + * an attached LCD. + * YWROBOT + *Compatible with the Arduino IDE 1.0 + *Library version:1.1 + */ +#include +#include + +LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display + +void setup() +{ + lcd.init(); // initialize the lcd + lcd.backlight(); + Serial.begin(9600); +} + +void loop() +{ + // when characters arrive over the serial port... + if (Serial.available()) { + // wait a bit for the entire message to arrive + delay(100); + // clear the screen + lcd.clear(); + // read all the available characters + while (Serial.available() > 0) { + // display each character to the LCD + lcd.write(Serial.read()); + } + } +} diff --git a/libraries/LiquidCrystal_I2C2004V1/keywords.txt b/libraries/LiquidCrystal_I2C2004V1/keywords.txt new file mode 100644 index 0000000..8c450a9 --- /dev/null +++ b/libraries/LiquidCrystal_I2C2004V1/keywords.txt @@ -0,0 +1,46 @@ +########################################### +# Syntax Coloring Map For LiquidCrystal_I2C +########################################### + +########################################### +# Datatypes (KEYWORD1) +########################################### + +LiquidCrystal_I2C KEYWORD1 + +########################################### +# Methods and Functions (KEYWORD2) +########################################### +init KEYWORD2 +begin KEYWORD2 +clear KEYWORD2 +home KEYWORD2 +noDisplay KEYWORD2 +display KEYWORD2 +noBlink KEYWORD2 +blink KEYWORD2 +noCursor KEYWORD2 +cursor KEYWORD2 +scrollDisplayLeft KEYWORD2 +scrollDisplayRight KEYWORD2 +leftToRight KEYWORD2 +rightToLeft KEYWORD2 +shiftIncrement KEYWORD2 +shiftDecrement KEYWORD2 +noBacklight KEYWORD2 +backlight KEYWORD2 +autoscroll KEYWORD2 +noAutoscroll KEYWORD2 +createChar KEYWORD2 +setCursor KEYWORD2 +print KEYWORD2 +blink_on KEYWORD2 +blink_off KEYWORD2 +cursor_on KEYWORD2 +cursor_off KEYWORD2 +setBacklight KEYWORD2 +load_custom_character KEYWORD2 +printstr KEYWORD2 +########################################### +# Constants (LITERAL1) +########################################### diff --git a/libraries/readme.txt b/libraries/readme.txt new file mode 100644 index 0000000..96ce674 --- /dev/null +++ b/libraries/readme.txt @@ -0,0 +1 @@ +For information on installing libraries, see: http://www.arduino.cc/en/Guide/Libraries diff --git a/random/random.ino b/random/random.ino new file mode 100644 index 0000000..a1a59f7 --- /dev/null +++ b/random/random.ino @@ -0,0 +1,70 @@ +// Copyright (C) 2017 Marius Schellenberger + +#include +#include +#include + +// data +#define ALPHA_MAX 36 +char _itoa[ALPHA_MAX]; + +void init_itoa(void) { + for (int i = 0; i < 10; i++) + _itoa[i] = (char)48 + i; + for (int i = 10; i < ALPHA_MAX; i++) + _itoa[i] = (char)55 + i; +} + +// random +#define CHAR_MAX 256 +volatile unsigned char _r_sample = 0; +volatile char _r_new = 0; +unsigned char _r = 0; +const unsigned char _r_max = CHAR_MAX - (CHAR_MAX % ALPHA_MAX); + +ISR(WDT_vect) { + _r_sample = TCNT1L; + _r_new = 1; +} + +void _r_init(void) { + cli(); + MCUSR = 0; + WDTCSR |= _BV(WDCE) | _BV(WDE); + WDTCSR = _BV(WDIE); + sei(); +} + +char _r_rotl_one(const char v) { + int shift = 1; + if ((shift &= sizeof(v) * 8 - 1) == 0) + return v; + return (v << shift) | (v >> (sizeof(v) * 8 - shift)); +} + +char _r_char(void) { + char i = 0; + while (1) { + if (_r_new) { + _r_new = 0; + _r = _r_rotl_one(_r); + _r ^= _r_sample; + if (i++ > 7) { + if (_r < _r_max) + return _itoa[_r % ALPHA_MAX]; + else + i = 0; + } + } + } +} + +void setup(void) { + Serial.begin(115200); + _r_init(); + init_itoa(); +} + +void loop(void) { + Serial.write(_r_char()); +}