// rgb_light
// Fab Academy Final Project
// Mio Kato
// 13/5/29

#include 
#include 
#include 

// I/O
#define output(directions, pin) (directions |= pin) // set DDRD for input
#define input(directions, pin) (directions &= (~pin)) // set DDRD to input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin

// Test
#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 102 // bit delay for 9600 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

// LED
#define led_port PORTA
#define led_direction DDRA
#define green (1 << PA0)
#define blue  (1 << PA1)
#define red   (1 << PA2)

// Serial Communication
#define serial_port PORTA
#define serial_direction DDRA
#define serial_pins PINA
#define serial_tx (1 << PA6) // TX(MOSI)
#define serial_rx (1 << PA5) // RX(MISO)

// get char
void get_char(volatile unsigned char *pins, unsigned char pin, unsigned 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
        ;
    half_bit_delay(); // 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();
}

// main
int main(void) {

  // set clock divider to /1
  CLKPR = (1 << CLKPCE);
  CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);

  // initialize LED pins (Turn off)
  set(led_port, red);
  output(led_direction, red);
  set(led_port, green);
  output(led_direction, green);
  set(led_port, blue);
  output(led_direction, blue);

  // set serial port                      Why doesn't this code use pull up resistor ?
  // set(serial_port, serial_rx);
  // input(serial_direction, serial_rx);

  int i; // using for loop
  unsigned char r, g, b;    // arugument put in receive data
  unsigned char pwm,count;

  // test working of this board
  clear(led_port,red);
  _delay_ms(500);
  set(led_port,red);

  clear(led_port,green);
  _delay_ms(500);
  set(led_port,green);

  clear(led_port,blue);
  _delay_ms(500);
  set(led_port,blue);

  // loop
  while (1) {
    //make charactor for inserted framing data
    unsigned char byte1, byte2, byte3, byte4;

    // check framing data
    while (1) {
      byte1 = byte2;
      byte2 = byte3;
      byte3 = byte4;
      get_char(&serial_pins, serial_rx, &byte4);

      // test receiveing data
      // clear(led_port,red);
      // _delay_ms(500);
      // set(led_port,red);
      // _delay_ms(500);

      if ((byte1 == 1) & (byte2 == 2) & (byte3 == 3) & (byte4 == 4)) {
        break;
      }
    }

    // If received data go through framing, receive r, g, b value
    get_char(&serial_pins, serial_rx, &r);
    get_char(&serial_pins, serial_rx, &g);
    get_char(&serial_pins, serial_rx, &b);

    // red led turn on or off
    if (r > 100)
    {
      clear(led_port, red);
      _delay_ms(100);
    } else if (r <= 100){
      set(led_port, red);
      _delay_ms(100);
    }

    // green led turn on or off
    if (g > 100)
    {
      clear(led_port, green);
      _delay_ms(100);
    } else if (g <= 100){
      set(led_port, green);
      _delay_ms(100);
    }

    // blue led turn on or off
    if (b > 100)
    {
      clear(led_port, blue);
      _delay_ms(100);
    } else if (b <= 100){
      set(led_port, blue);
      _delay_ms(100);
    }
  }
}