#include <avr/io.h>

#define F_CPU 16000000UL

#include <util/delay.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>

void inicializar_puertos(void);
void reset(void);
void i2c_MT(unsigned char direccion, unsigned char dato);
unsigned char i2c_MR(unsigned char direccion);
void i2c_error(void);

volatile unsigned char r_estado=0x02;
volatile unsigned char comunicaciones=0;

volatile unsigned int encoder0;
volatile unsigned int encoder1;
volatile unsigned char baterial;
volatile unsigned char bateriah;
volatile unsigned char direccionl;
volatile unsigned char direccionh;
volatile unsigned char sensoresd;
volatile unsigned char sensoresi;
volatile unsigned char posicion;
volatile unsigned char velocidad;


int main(void)
{
    inicializar_puertos();
    reset();

    while(1)
    {
        if(comunicaciones != 0)
        {
            comunicaciones=0;
//***//
            posicion=i2c_MR(0xE2);
            _delay_us(20);


            velocidad=i2c_MR(0xE2);
            _delay_us(20);


//***//
            r_estado=i2c_MR(0xE2);
            _delay_us(20);

            i2c_MT(0xE2, baterial);
            _delay_us(20);
            i2c_MT(0xE2, bateriah);
            _delay_us(20);
            i2c_MT(0xE2, direccionl);
            _delay_us(20);
            i2c_MT(0xE2, direccionh);
            _delay_us(20);
            i2c_MT(0xE2, sensoresd);
            _delay_us(20);
            i2c_MT(0xE2, sensoresi);
            _delay_us(20);
            i2c_MT(0xE2, (char)encoder0);
            _delay_us(20);
            i2c_MT(0xE2, (char)encoder1);
            _delay_us(20);
            i2c_MT(0xE2, r_estado);
        }

        if((r_estado&0x01)!=0)
            PORTD |= (1<<PORTD5);
        else
            PORTD &= ~(1<<PORTD5);
        if((r_estado&0x02)!=0)
               PORTD |= (1<<PORTD4);
        else
            PORTD &= ~(1<<PORTD4);
        if((r_estado&0x04)!=0)
               PORTD |= (1<<PORTD3);
        else
            PORTD &= ~(1<<PORTD3);
    }
}

void reset(void)
{
    cli();
    PORTD |= ((1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5));
    _delay_ms(250);
    PORTD &= ~((1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5));
    _delay_ms(250);

    PORTD |= ((1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5));
    _delay_ms(250);
    PORTD &= ~((1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5));
    _delay_ms(250);

    PORTD |= ((1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5));
    _delay_ms(250);
    PORTD &= ~((1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5));
    _delay_ms(250);
    sei();
}


void inicializar_puertos(void)
{
    DDRD |= ((1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5));  //Salidas

    //Configurar Timer2. Tic 5.33 ms.
    OCR2 = 0x52;            //0x52    
    TCCR2 |=((1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20));
    TIMSK |= (1<<OCIE2);
    sei();

    //Inicializar I2C.
    TWBR = 0b01001111;    //Período SCL 11 us

    //Inicializar ADC
       //Free Running Mode, por defecto seleccionado
    ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));    //Prescaler 128, Fadc 125 KHz @ 16MHz.
    ADCSRA |= (1<<ADATE);
//    ADMUX |= (1<<ADLAR);                            //8 bits.
    ADCSRA |= (1<<ADEN);                              //Enable ADC
    ADCSRA |= (1<<ADSC);                            //Comenzar conversiones.

    //Inicializar timers encoders.
    TCCR0 |=((1<<CS02)|(1<<CS01)|(1<<CS00));         //Normal Mode y reloj externo flanco de subida.
    TCCR1B |=((1<<CS12)|(1<<CS11)|(1<<CS10));        //Normal Mode y reloj externo flanco de subida.   
}


ISR(TIMER2_COMP_vect)
{
    static unsigned char cont;
    unsigned int copia_posicion;
    unsigned int copia_velocidad;
    unsigned char cuenta0_actual;
    static unsigned char cuenta0_old;
    static unsigned char contador_encoders;
    static unsigned int suma_cuenta0;
    unsigned int cuenta1_actual;
    static unsigned int cuenta1_old;
    static unsigned int suma_cuenta1;

//    unsigned int suma_adc_alto = 0;        //
//    unsigned int suma_adc_bajo = 0;        //

    
    cont++;

    switch(cont)
    {
        case 1:        //Generar señal de control
        {

            comunicaciones=0;

            copia_posicion=posicion*16;
            copia_velocidad=velocidad*16;

            PORTD |=(1<<PORTD2);
            _delay_us(400);
            PORTD &= ~(1<<PORTD2);
            _delay_loop_2(2400+copia_posicion);        //4000 = 1ms.

            PORTD|=(1<<PORTD2);
            _delay_us(400);
            PORTD&= ~(1<<PORTD2);
            _delay_loop_2(2400+copia_velocidad);

            PORTD|=(1<<PORTD2);
            _delay_us(420);
            PORTD&= ~(1<<PORTD2);

            ADCSRA |= (1<<ADEN);
            ADCSRA |= (1<<ADSC);
            _delay_us(350);
            baterial=ADCL;               //Lectura ADC Batería.
            bateriah=ADCH;
            ADCSRA &= ~(1<<ADEN);
            ADMUX  &= ~(1<<MUX0);     //Se selecciona ADC para la dirección.

 /*           PORTD |=(1<<PORTD2);
            _delay_ms(2);
            PORTD &= ~(1<<PORTD2);*/

        
        }break;

        case 2:        //Comunicaciones, leer ADC batería.
        {
            comunicaciones=1;
    
        }break;

        case 3:        //Leer ADC, Encoders, Errores, Establecer variable.
        {
            comunicaciones=0;
            cont=0;


            //*********************************//Lectura ADC dirección.
            ADCSRA |= (1<<ADEN);
            ADCSRA |= (1<<ADSC);
            _delay_us(350);
            direccionl=ADCL;        
            direccionh=ADCH;
            ADCSRA &= ~(1<<ADEN);
            ADMUX  |= (1<<MUX0);     //Se selecciona ADC para la batería.


/*            ADCSRA |= (1<<ADEN);
            ADCSRA |= (1<<ADSC);
            _delay_us(350);
            suma_adc_bajo = suma_adc_bajo + ADCL;        
            suma_adc_alto = suma_adc_alto + ADCH;
            _delay_us(350);
            suma_adc_bajo = suma_adc_bajo + ADCL;        
            suma_adc_alto = suma_adc_alto + ADCH;
            _delay_us(350);
            suma_adc_bajo = suma_adc_bajo + ADCL;        
            suma_adc_alto = suma_adc_alto + ADCH;
            _delay_us(350);
            suma_adc_bajo = suma_adc_bajo + ADCL;        
            suma_adc_alto = suma_adc_alto + ADCH;

            suma_adc_bajo = suma_adc_bajo/4;
            suma_adc_alto = suma_adc_alto/4;

            direccionl = (char)suma_adc_bajo;
            direccionh = (char)suma_adc_alto;*/

              
                                      //Se leen los encoders  
                                    //Encoder 0, 8 bits.
            cuenta0_actual=TCNT0;
            if (cuenta0_actual>cuenta0_old)             
                suma_cuenta0 = suma_cuenta0 + cuenta0_actual - cuenta0_old;              
            else if(cuenta0_actual<cuenta0_old)
                suma_cuenta0 = suma_cuenta0 + 256 + cuenta0_actual - cuenta0_old;
            cuenta0_old=TCNT0;

            cuenta1_actual=TCNT1;
            if (cuenta1_actual>cuenta1_old)             
                suma_cuenta1 = suma_cuenta1 + cuenta1_actual - cuenta1_old;              
            else if(cuenta0_actual<cuenta0_old)
                suma_cuenta1 = suma_cuenta1 + 1024 + cuenta1_actual - cuenta1_old;
            cuenta1_old=TCNT1;


            contador_encoders++;

            if(contador_encoders>20)
            {
                encoder0 = suma_cuenta0;
                encoder1 = suma_cuenta1;
                suma_cuenta0 = 0;
                suma_cuenta1 = 0;
                contador_encoders = 0;
            }    
            
                                    //Leer sensores;
            sensoresi = PINC;
            sensoresd = PINA;                                    

        }break;

    }
    TIFR |= (1<<OCF2);
}

void i2c_MT(unsigned char direccion, unsigned char dato)
{  
    TWCR |= (1<<TWEA);                                //Se enciende el módulo
    TWCR &= ~(1<<TWSTO);                              //enviar señal de start.
    TWCR |= ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))                      //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                                      //comprobar resultado de la operación anterior.
    if ((TWSR & 0xF8) != 0x08)                        //(xxxxx000) != (0x08 Start)
        i2c_error();

                                                                        
    TWDR = ((direccion)&(0b11111110));                //Enviar dirección y escritura
    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))                      //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                                      //comprobar condición.
    if ((TWSR & 0xF8) != 0x18)                        //(xxxxx000) != (0x18 SLA +W)
        i2c_error();


    TWDR = dato;                                      //Cargar byte a enviar
    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))                      //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                                      //comprobar condición.
    if ((TWSR & 0xF8) != 0x28)                        //(xxxxx000) != (0x28 dato+ack)
        i2c_error();   
                                     
    TWCR &= ~(1<<TWSTA);                              //enviar señal de stop.
    TWCR |= ((1<<TWINT)|(1<<TWEN)|(1<<TWSTO));
    _delay_us(20);
}

unsigned char i2c_MR(unsigned char direccion)
{
    unsigned char dato=0;

    TWCR |= (1<<TWEA);   
    TWCR &= ~(1<<TWSTO);                   //enviar señal de start.
    TWCR |= ((1<<TWINT)|(1<<TWSTA)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                         //comprobar resultado de la operación anterior.
    if ((TWSR & 0xF8) != 0x08)           //(xxxxx000) != (0x08 Start)
        i2c_error();

                                        //enviar byte.
    TWDR = ((direccion)|(0b00000001));  //Cargar byte de dirección
    TWCR &= ~((1<<TWSTO)|(1<<TWSTA));
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
                                        //comprobar condición.
    if ((TWSR & 0xF8) != 0x40)          //(xxxxx000) != (0x40 SLA +R)
        i2c_error();

    TWCR &= ~((1<<TWSTO)|(1<<TWSTA)|(1<<TWEA));//Leer segundo byte NO ACK
    TWCR |= ((1<<TWINT)|(1<<TWEN));

    while (!(TWCR & (1<<TWINT)))        //Esperar a TWINT
    {
        if(comunicaciones!=0)
            break;
    }
   
    if ((TWSR & 0xF8) != 0x58)          //(xxxxx000) != (0x58 dato+ no ack)
        i2c_error();

    dato=TWDR;

    TWCR &= ~(1<<TWSTA);                //enviar señal de stop.
    TWCR |= ((1<<TWEA)|(1<<TWINT)|(1<<TWEN)|(1<<TWSTO));
    _delay_us(20);

    return(dato);
}

void i2c_error(void)
{
}