//
//
// hello.RGB.45.c
//
// RGB LED software PWM hello-world
//
// Neil Gershenfeld
// 11/10/10
//
// (c) Massachusetts Institute of Technology 2010
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose. Copyright is
// retained and must be preserved. The work is provided
// as is; no warranty is provided, and users accept all 
// liability.
//

#include <avr/io.h>
#include <util/delay.h>
// My addition!!!!!!!!!!!!!!!!!
#include <inttypes.h>
#include <avr/interrupt.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include <string.h>
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
#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 PWM_delay() _delay_us(25) // PWM delay

//adition fron touchpad
#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
#define settle_delay() _delay_us(100) // settle delay
#define char_delay() _delay_ms(10) // char delay

////LED RGB
#define led_port PORTB
#define led_direction DDRB
#define red (1 << PB0)

/////touchpad
#define transmit_port PORTB
#define transmit_direction DDRB
#define transmit_pin (1 << PB1)
#define nloop 100 // loops to accumulate

/////bridge
#define serial_port PORTB
#define serial_direction DDRB
#define serial_pins PINB
#define serial_pin_in (1 << PB3)
#define serial_pin_out (1 << PB4)
#define node_id '0'
#define start_signal 's'
#define dumbbell_signal 'd'

// My Functions' Declarations!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
void turn_on_red_led(void);
void turn_off_led(void);
void semaforo(void);
uint16_t leer_value();
void put_char(volatile unsigned char *port, unsigned char pin, char txchar);
void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte);
void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str);
void send_info(int value);

/*// Variables
uint64_t _millis = 0;
uint16_t _1000us = 0;

// Interrupts routines 
// Every 0.256 ms
ISR(TIM0_OVF_vect) {
  _1000us += 256;
  while (_1000us > 1000) {
    _millis++;
    _1000us -= 1000;
  }
}

// safe access to millis counter
uint64_t millis(void) {
  uint64_t m;
  cli();
  m = _millis;
  sei();
  return m;
}*/
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

int main(void) {
	//
	// main
	//
	// Declaracion de variables
	static char chr;
	static uint64_t start_time;
	static uint16_t quantity, contador, cont_act;
	//
	// set clock divider to /1
	//
	CLKPR = (1 << CLKPCE);
	CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	/*// interrupt setup 
	// prescale timer0 to 1/8th the clock rate
	// overflow timer0 every 0.256 ms
	TCCR0B |= (1<<CS01);
	// enable timer overflow interrupt
	TIMSK  |= 1<<TOIE0;
	// Enable global interrupts
	sei();*/
	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//
	// initialize LED pins
	//   
	output(led_direction, red);
	clear(led_port, red);
	//
	// init touchpad
	//
	clear(transmit_port, transmit_pin);
	output(transmit_direction, transmit_pin);
	//
	// initialize output pins
	//
	set(serial_port, serial_pin_out);
	input(serial_direction, serial_pin_out);
	//
	// init A/D touchpad
	//
	ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) // Vcc ref
		| (0 << ADLAR) // right adjust
		| (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (1 << MUX0); // PB2
	ADCSRA = (1 << ADEN) // enable
		| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
	//
	// main loop
	//
	while (1) {
		get_char(&serial_pins, serial_pin_in, &chr);
		_delay_ms(100);
		if(chr == start_signal){	
			output(serial_direction, serial_pin_out);//
			put_char(&serial_port, serial_pin_out, chr);
			put_char(&serial_port, serial_pin_out, 10); // new line
			input(serial_direction, serial_pin_out);//
		}
		while(chr == start_signal){
			if(leer_value() > 12000){
				output(serial_direction, serial_pin_out);//
				static const char message_1[] PROGMEM = "Start";
         			put_string(&serial_port, serial_pin_out, (PGM_P) message_1);
				put_char(&serial_port, serial_pin_out, 10); // new line
				input(serial_direction, serial_pin_out);//
				semaforo();
				output(serial_direction, serial_pin_out); 
				static const char message_2[] PROGMEM = "Send a d";
         			put_string(&serial_port, serial_pin_out, (PGM_P) message_2);
				put_char(&serial_port, serial_pin_out, 10); // new line
				input(serial_direction, serial_pin_out);//
				//while(1);
				break;		
			}else{
				turn_off_led();
				break;
			}
		}
		/*if(leer_value() > 12000){
		//Si estas aqui es xq estas tocando
		contador++;
		if(contador == 1){
		quantity++;
		}
		}else{
		contador = 0;
		}
		// Verificar si pasó 1 segundo:
		if(millis() - start_time > 1000){
		cont_act++;
		if (quantity == 1){
		turn_on_red_led();
		//send_info(1);
		_delay_ms(1000);
		turn_off_led();
		_delay_ms(100);
		}
		//Inicia un nuevo juego, cada 5 seg:
		if (cont_act == 5){
		semaforo();
		cont_act = 0;
		}			
		// Reiniciar start_time y quantity:
		start_time = millis();	
		quantity = 0;					
		}*/
		//!!!!!!!!!!!!!!
	}
}

// My Functions' Definitions!
void turn_on_red_led(){
	set(PORTB, red);
}

void turn_off_led(){
	clear(PORTB, red);
}

void semaforo(){
	turn_on_red_led();
	_delay_ms(500);
	turn_off_led();
	_delay_ms(500);
	turn_on_red_led();
	_delay_ms(500);
	turn_off_led();
	_delay_ms(500);
	turn_on_red_led();
	_delay_ms(500);
	turn_off_led();
}

uint16_t leer_value(){
	//
	// accumulate touchpad magnetic value
	//
	unsigned char count;
	uint16_t up,down,value;
	up = 0;
	down = 0;
	for (count = 0; count < nloop; ++count) {
		// settle, charge
		settle_delay();
		set(transmit_port, transmit_pin);
		// initiate conversion
		ADCSRA |= (1 << ADSC);
		// wait for completion
		while (ADCSRA & (1 << ADSC))
		;
		// save result
		up += ADC;
		// settle, discharge
		settle_delay();
		clear(transmit_port, transmit_pin);
		// initiate conversion
		ADCSRA |= (1 << ADSC);
		// wait for completion
		while (ADCSRA & (1 << ADSC))
		;
		// save result
		down += ADC;
	}
	value = up-down;
	return value;
}

void send_info(int value){
	//
	// send framing
	//
	put_char(&serial_port, transmit_pin, 1);
	char_delay();
	put_char(&serial_port, transmit_pin, 2);
	char_delay();
	put_char(&serial_port, transmit_pin, 3);
	char_delay();
	put_char(&serial_port, transmit_pin, 4);
	//
	// send result
	//
	put_char(&serial_port, transmit_pin, value);
	char_delay();
}

void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   // start bit
   //
   clear(*port,pin);
   bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,1)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,2)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,3)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,4)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,5)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,6)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,7)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   //
   // stop bit
   //
   set(*port,pin);
   bit_delay();
   //
   // char delay
   //
   bit_delay();
}	
//!!!!!!!!!!!!!!!!!!
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();
}

void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   static char chr;
   static int index;
   index = 0;
   do {
      chr = pgm_read_byte(&(str[index]));
      put_char(&serial_port, serial_pin_out, chr);
      ++index;
      } while (chr != 0);
   }
