// ------- Preamble -------- //
#include <avr/io.h>
#include <util/delay.h>

#define DELAY     100                                            /* ms */

static inline uint8_t LFSR8_step(uint8_t random);

int main(void) {

  // -------- Inits --------- //

  DDRB = 0xff;                                   /* output on all LEDs */
  uint8_t random = 1;              /* can't init to 0, any other is ok */

  // ------ Event loop ------ //
  while (1) {

                                                 /* Display and output */
    random = LFSR8_step(random);
    PORTB = random;
    _delay_ms(DELAY);

  }                                                  /* End event loop */
  return 0;
}


// ----------------- LFSR Routines ---------------- //

inline uint8_t LFSR8_step(uint8_t random) {
  /*
     Takes an 8-bit number, takes one step in a () LFSR.
     [3, 4, 5, 7] is the set of taps for 8-bits that goes through
     the whole cycle before repeating.

     If you're really serious about randomness, you'll want a different
     algorithm.  In fact, this is a great demo of how "predictable"
     the "pseudo-random" sequence is.

     Note that this is not a very efficient way to code this up,
     but it's meant mostly for teaching and is plenty fast
     because the compiler does an OK job with it.
   */
  uint8_t tap1, tap2, tap3, tap4;
  uint8_t newBit;
  tap1 = 1 & (random >> 3);
  tap2 = 1 & (random >> 4);
  tap3 = 1 & (random >> 5);
  tap4 = 1 & (random >> 7);

  newBit = tap1 ^ tap2 ^ tap3 ^ tap4;
  random = ((random << 1) | newBit);
  return (random);
}


inline uint16_t LFSR16(uint16_t random) {
  // 3, 12, 14, 15 are the maximal taps for 16 bits.
  uint16_t tap1, tap2, tap3, tap4;
  uint16_t newBit;
  tap1 = 1 & (random >> 3);
  tap2 = 1 & (random >> 12);
  tap3 = 1 & (random >> 14);
  tap4 = 1 & (random >> 15);

  newBit = tap1 ^ tap2 ^ tap3 ^ tap4;
  random = ((random << 1) | newBit);
  return (random);
}
