#include <avr/interrupt.h>
#include "uart.h"
#include "fifo.h"

Fifo_t uart0_rx_buffer = {{}, 0, 0};
Fifo_t uart0_tx_buffer = {{}, 0, 0};

const uint16_t bsel = 208;
const int8_t bscale = 0;

//FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

void init_uart(void){
    USARTD0_CTRLC= USART_CHSIZE0_bm | USART_CHSIZE1_bm;
    //USARTD0_BAUDCTRLB = 0;
    //USARTD0_BAUDCTRLA = 0;
    USARTD0.BAUDCTRLA = bsel;
    USARTD0.BAUDCTRLB = 0 | (bsel >> 8) | (bscale << USART_BSCALE0_bp);
    USARTD0_CTRLB = USART_TXEN_bm | USART_RXEN_bm;

    //USARTD0_CTRLA=USART_RXCINTLVL0_bm;

    PORTD_OUTSET = PIN3_bm;
    PORTD_DIRSET = PIN3_bm; 
    PORTD_OUTCLR = PIN2_bm;
    PORTD_DIRCLR = PIN2_bm;

    //stdout = &uart_output;
}

void uart_putchar(char c, FILE *stream)
{
    fifo_push(&uart0_tx_buffer, c);
    USARTD0_CTRLA |= USART_DREINTLVL_LO_gc;
}

//void puts(char * s){
//    while (*s) {
//        putchar(*s++);
//    }
//}

char get_uart0_char(void)
{
    while(1){
        char buffer;	

        while( !(USARTD0_STATUS & USART_RXCIF_bm) );
        buffer=USARTD0_DATA;	
        if ((USARTD0_STATUS & (USART_FERR_bm | USART_PERR_bm | USART_BUFOVF_bm))==0)
            return buffer;
    }
}

ISR(USARTD0_RXC_vect)
{
    uint8_t tmp = get_uart0_char();
    putchar(tmp);
    if(( tmp == 0x0D || tmp == 0x0A))
        printf("wurst\n\r");
    else
        fifo_push(&uart0_rx_buffer, tmp);
}

ISR(USARTD0_DRE_vect){
    uint8_t tmp;
    if(fifo_pop(&uart0_tx_buffer, &tmp) == FIFO_SUCCESS){
        USARTD0_DATA = tmp;
    } else {
        USARTD0_CTRLA &= ~USART_DREINTLVL_LO_gc;
    }
}
