#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;
volatile unsigned char comunicaciones=0;

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

    while(9)
    {
        if(comunicaciones != 0)
        {
            comunicaciones=0;
            r_estado=i2c_MR(0xE2);
            _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(1000);
    PORTD &= ~((1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5));
    _delay_ms(1000);

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

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


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

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

    //Inicializar I2C.
    TWBR = 0b10011000;    //Período SCL 20 us
}


ISR(TIMER2_COMP_vect)
{
    static unsigned char cont;
    cont++;

    switch(cont)
    {
        case 1:        //Generar señal de control
        {
            comunicaciones=0;
            PORTD |= (1<<PD2);
            _delay_ms(3);
            PORTD &= ~(1<<PD2);
        
        }break;

        case 2:        //Comunicaciones
        {
            comunicaciones=1;
    
        }break;

        case 3:        //Leer ADC, Encoders, Errores, Estableces variable.
        {
            comunicaciones=0;
            cont=0;
        
        }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)
{
}