//
//
// hello.ftdi.44.echo.c
//
// 115200 baud FTDI character echo, with flash string
//
// set lfuse to 0x7E for 20 MHz xtal
//
// Neil Gershenfeld
// 12/8/10
//
// (c) Massachusetts Institute of Technology 2010
// Permission granted for experimental and personal use;
// license for commercial sale available from MIT.
//

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdio.h>

#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 8.5 // bit delay for 115200 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define char_delay() _delay_ms(10) // char delay

#define serial_port PORTA
#define serial_direction DDRA
#define serial_pins PINA
#define serial_pin_in (1 << PA0)
#define serial_pin_out (1 << PA1)

#define max_buffer 25

#define led_delay() _delay_ms(1) // LED delay

#define led_port PORTA
#define led_direction DDRA

#define A (1 << PA0) // row 1
#define B (1 << PA1) // row 2
#define C (1 << PA2) // row 3
#define D (1 << PA3) // row 4
#define E (1 << PA4) // row 5

void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) {
   //
   // read character into rxbyte on pins pin
   //    assumes line driver (inverts bits)
   //
   *rxbyte = 0;
   while (pin_test(*pins,pin))
      //
      // wait for start bit
      //
      ;
   //
   // delay to middle of first data bit
   //
   half_bit_delay();
   bit_delay();
   //
   // unrolled loop to read data bits
   //
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 0);
   else
      *rxbyte |= (0 << 0);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 1);
   else
      *rxbyte |= (0 << 1);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 2);
   else
      *rxbyte |= (0 << 2);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 3);
   else
      *rxbyte |= (0 << 3);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 4);
   else
      *rxbyte |= (0 << 4);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 5);
   else
      *rxbyte |= (0 << 5);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 6);
   else
      *rxbyte |= (0 << 6);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 7);
   else
      *rxbyte |= (0 << 7);
   //
   // wait for stop bit
   //
   bit_delay();
   half_bit_delay();
   }
//
   // code for led array
   //
   void flash(uint8_t from, uint8_t to, uint8_t delay) {
   //
   // source from, sink to, flash
   //
   static uint8_t i;
   set(led_port,from);
   clear(led_port,to);
   output(led_direction,from);
   output(led_direction,to);
   for (i = 0; i < delay; ++i)
       led_delay();
   input(led_direction,from);
   input(led_direction,to);
   }
   //
   // create array with corresponding LED array pattern for each character
   //
   int LEDarray[26];
   LEDarray[0] = void led_cycleA(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[1] = void led_cycleB(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[2] = void led_cycleC(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(A,C,delay);
                     flash(A,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[3] = void led_cycleD(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(C,E,delay);
                 }
                 }
   LEDarray[4] = void led_cycleE(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(A,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[5] = void led_cycleF(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(A,D,delay);
                     flash(A,E,delay);
                 }
                 }
   LEDarray[6] = void led_cycleG(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(A,C,delay);
                     flash(D,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[7] = void led_cycleH(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[8] = void led_cycleI(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(C,B,delay);
                     flash(D,B,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(B,D,delay);
                     flash(C,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[9] = void led_cycleJ(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(D,B,delay);
                     flash(D,C,delay);
                     flash(A,D,delay);
                     flash(C,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                 }
                 }
   LEDarray[10] = void led_cycleK(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(D,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(A,D,delay);
                     flash(C,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[11] = void led_cycleL(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(A,B,delay);
                     flash(A,C,delay);
                     flash(A,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[12] = void led_cycleM(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(C,B,delay);
                     flash(D,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[13] = void led_cycleN(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(C,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(D,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[14] = void led_cycleO(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[15] = void led_cycleP(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(A,E,delay);
                 }
                 }
   LEDarray[16] = void led_cycleQ(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(B,D,delay);
                     flash(C,D,delay);
                     flash(E,D,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[17] = void led_cycleR(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(A,B,delay);
                     flash(C,B,delay);
                     flash(A,C,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(A,D,delay);
                     flash(C,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[18] = void led_cycleS(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                 }
                 }
   LEDarray[19] = void led_cycleT(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(C,B,delay);
                     flash(D,B,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(B,D,delay);
                     flash(C,D,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                 }
                 }
   LEDarray[20] = void led_cycleU(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[21] = void led_cycleV(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(E,D,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                 }
                 }
   LEDarray[22] = void led_cycleW(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(A,C,delay);
                     flash(E,C,delay);
                     flash(A,D,delay);
                     flash(B,D,delay);
                     flash(C,D,delay);
                     flash(E,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[23] = void led_cycleX(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(C,B,delay);
                     flash(D,B,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(B,D,delay);
                     flash(C,D,delay);
                     flash(A,E,delay);
                     flash(D,E,delay);
                 }
                 }
   LEDarray[24] = void led_cycleY(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(E,A,delay);
                     flash(A,B,delay);
                     flash(E,B,delay);
                     flash(B,C,delay);
                     flash(D,C,delay);
                     flash(B,D,delay);
                     flash(C,D,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                 }
                 }
   LEDarray[25] = void led_cycleZ(uint8_t number, uint8_t delay) {
                 uint8_t i;
                 for (i = 0; i < number; ++i) {
                     flash(B,A,delay);
                     flash(C,A,delay);
                     flash(D,A,delay);
                     flash(E,A,delay);
                     flash(E,B,delay);
                     flash(D,C,delay);
                     flash(B,D,delay);
                     flash(A,E,delay);
                     flash(B,E,delay);
                     flash(C,E,delay);
                     flash(D,E,delay);
                 }
                 }
//
// main loop
int main(void) {
   //
   // main
   //
   static char chr;
   static char buffer[max_buffer] = {0};
   static int index;
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   //
   // initialize output pins
   //
   set(serial_port, serial_pin_out);
   output(serial_direction, serial_pin_out);
   
   //
   // main loop
   //
   index = 0;
   while (1) {
      get_char(&serial_pins, serial_pin_in, &chr);
      static char message[] PROGMEM = "hello.ftdi.44.echo.c: you typed \"";
      put_flash_string(&serial_port, serial_pin_out, (PGM_P) message);
      buffer[index++] = chr;
      if (index == (max_buffer-1))
         index = 0;
      put_ram_string(&serial_port, serial_pin_out, buffer);
      put_char(&serial_port, serial_pin_out, '\"');
      put_char(&serial_port, serial_pin_out, 10); // new line
      }
   }
