#include "uart_ints.h"

void uart_init(){
    uint8_t i;
    
    uart_rx_buff_end = 0;
    uart_rx_buff_position = 0;
    uart_status_bitfield = 0;

    for(i = 0; i < UART_RX_BUFFER_SIZE; i++){
        uart_rx_buffer[i] = 0;
    }

    uart_init_rx();
    uart_init_tx();
}

void uart_init_rx(){
    /* RX pin input and with pullup */
    UART_RX_DDR &= ~(1<<UART_RX_PIN);
    UART_RX_PORT |= 1<<UART_RX_PIN;

    PCMSK0 |= (1 << UART_RX_INTERRUPT);         /* enable interrupt on rx pin */
    sei();
    GIMSK |= (1 << UART_RX_INTERRUPT_PORT);     /* enable interrupt for PCI0 (PCINT7:0) */
}

void uart_init_tx() {
    /* TX pin as input and with pullup */
    UART_TX_DDR &= ~(1<<UART_TX_PIN);
}

uint8_t uart_available(){
    return uart_rx_buff_end != uart_rx_buff_position;
}

uint8_t uart_getc(){
    uint8_t result = 0;

    if(uart_available()){
        result = uart_rx_buffer[uart_rx_buff_position];
        uart_rx_buff_position++;
        uart_rx_buff_position = uart_rx_buff_position % UART_RX_BUFFER_SIZE;
    }

    return result;
}


void uart_putc(uint8_t c) {
    uint8_t i;

    /* output */
    UART_TX_DDR |= 1<<UART_TX_PIN;
    /* low for start bit */
    UART_TX_PORT &= ~(1<<UART_TX_PIN);
    _delay_us(UART_HALF_BIT_DELAY_US*2);

    /* data bits */
    for (i=0; i<=7; i++)
    {
        if (c & (1<<i))
            UART_TX_PORT |= 1<<UART_TX_PIN;

        else
            UART_TX_PORT &= ~(1<<UART_TX_PIN);

        _delay_us(UART_HALF_BIT_DELAY_US*2);
    }

    /* stop bit */
    UART_TX_PORT |= 1<<UART_TX_PIN;
    _delay_us(UART_HALF_BIT_DELAY_US*2);

    /* byte delay */
    _delay_us(UART_HALF_BIT_DELAY_US*2);

    /* disable */
    UART_TX_DDR &= ~(1<<UART_TX_PIN);


}





/*
 *
 * RX ISR
 *
 */

ISR(PCINT0_vect){
    uint8_t i;

    if(!(PINA & (1<<UART_RX_INTERRUPT))){                       /* if rx goes low */
        GIMSK &= ~(1 << UART_RX_INTERRUPT_PORT);
        _delay_us(UART_HALF_BIT_DELAY_US * 3);

        for(i = 0; i < 8; i += 1){
            if(PINA & (1<<UART_RX_INTERRUPT)){                  /* RX PIN IS HIGH */
                uart_rx_buffer[uart_rx_buff_end] |= (1 << i);
            }else{                                              /* RX PIN IS LOW */
                uart_rx_buffer[uart_rx_buff_end] &= ~(1 << i);
            }

            if(i != 7) _delay_us(UART_HALF_BIT_DELAY_US * 2);
        }

        _delay_us(UART_HALF_BIT_DELAY_US * 2);             /* Get past stop bit */
        uart_rx_buff_end++;
        uart_rx_buff_end= uart_rx_buff_end % UART_RX_BUFFER_SIZE;

        GIMSK |= (1 << UART_RX_INTERRUPT_PORT);
    }
}
