#ifndef UART_H
#define UART_H

#include <avr/io.h>

#ifndef UART_BUFFER_SIZE
#define UART_BUFFER_SIZE 128
#endif

// Ring buffer - struct with an array, head and tail
typedef volatile struct uart_ringbuf 
{
    uint8_t buffer[UART_BUFFER_SIZE];
    uint8_t head;
    uint8_t tail;
} uart_ringbuf_t;

// Add data to ring buffer, returns false (0) on full
uint8_t uart_ringbuf_push(uart_ringbuf_t* buf, uint8_t v);
// Tries to remove data from ring buffer, returns false (0) on empty
uint8_t uart_ringbuf_trypop(uart_ringbuf_t* buf, uint8_t* out);
// Returns the ammount of data in the buffer
uint8_t uart_ringbuf_length(uart_ringbuf_t* buf);

// initializes that uart registers for sending and receiving
void uart_init(uint32_t baudrate, uint8_t doublespeed);

// Read char from buf, returns 0 if empty
uint8_t uart_read();
// Add string to buffer and start sending if not started already
void uart_send(char* str);
// Add string to buffer and start sending if not started already
void uart_sendn(char* str, uint8_t n);
// Add char to buffer and start sending if not started already
void uart_sendc(char c);

#endif


#include <avr/io.h>
#include <avr/interrupt.h>

// Ring buffer
// ========== ========== ========== ========== ========== ==========

// Add data to ring buffer, returns false (0) on full
uint8_t uart_ringbuf_push(uart_ringbuf_t* buf, uint8_t v)
{
    uint8_t n = buf->head + 1; // next pos
    if (n >= UART_BUFFER_SIZE) // loop to start
        n = 0;
    if (n == buf->tail) // buf full?
        return 0;
    buf->buffer[buf->head] = v; // write new data
    buf->head = n; // write new pos
    return 1;
}
// Tries to remove data from ring buffer, returns false (0) on empty
uint8_t uart_ringbuf_trypop(uart_ringbuf_t* buf, uint8_t* out)
{
    if (buf->head == buf->tail) // buf empty?
        return 0;
    uint8_t n = buf->tail + 1; // next pos
    if (n >= UART_BUFFER_SIZE) // loop to start
        n = 0;
    *out = buf->buffer[buf->tail]; // write new data
    buf->tail = n; // write new pos
    return 1;
}
// Returns the ammount of data in the buffer
uint8_t uart_ringbuf_length(uart_ringbuf_t* buf)
{
    if (buf->head == buf->tail) // empty buf
        return 0;
    else if (buf->tail < buf->head) // tail behind head
        return (UART_BUFFER_SIZE - buf->head + buf->tail);
    else return buf->tail - buf->head; // tail after head
}


// Uart
// ========== ========== ========== ========== ========== ==========

// Receive buffer
uart_ringbuf_t rxBuf;
// Send buffer
uart_ringbuf_t txBuf;
// Send status
volatile uint8_t txStatus = 0;

// If txBuf has chars start sending them
void uart_internal_sendchar()
{
    // check if buffer has data
    uint8_t tosend;
    if (uart_ringbuf_trypop(&txBuf, &tosend))
    {
        txStatus = 1; // sending data
        UDR0 = tosend; // add char to send buffer
    }
    // no data left to send
    else txStatus = 0;
}

// Returns the value for UBRRn for the chosen baudrate and U2Xn (double speed)
uint16_t uart_ubrrn_from_baud(uint32_t baudrate, uint8_t u2xn)
{
    if (u2xn)
    {
        switch (baudrate)
        {
            case    2400: return 832;
            case    4800: return 416;
            case    9600: return 207;
            case   14400: return 138;
            case   19200: return 103;
            case   28800: return 68;
            case   38400: return 51;
            case   57600: return 34;
            case   76800: return 25;
            case  115200: return 16;
            case  230400: return 8;
            case  250000: return 7;
            case  500000: return 3;
            case 1000000: return 1;
            default: return 16; // 115200
        }
    }
    switch (baudrate)
    {
        case    2400: return 416;
        case    4800: return 207;
        case    9600: return 103;
        case   14400: return 68;
        case   19200: return 51;
        case   28800: return 34;
        case   38400: return 25;
        case   57600: return 16;
        case   76800: return 12;
        case  115200: return 8;
        case  230400: return 3;
        case  250000: return 3;
        case  500000: return 1;
        case 1000000: return 0;
        default: return 8; // 115200
    }
}

// initializes that uart registers for sending and receiving
void uart_init(uint32_t baudrate, uint8_t doublespeed)
{
    // init buffers
    rxBuf.head = 0; rxBuf.tail = 0;
    txBuf.head = 0; txBuf.tail = 0;

    // set double speed mode
    if (doublespeed)
        UCSR0A |= (1 << U2X0);
    // Enable transmiter and receiver
    UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
    // Enable interrupts
    UCSR0B |= (1 << TXCIE0) | (1 << RXCIE0);
    // Set baudrate
    UBRR0 = uart_ubrrn_from_baud(baudrate, doublespeed);
}

// Read char from buf, returns 0 if empty
uint8_t uart_read()
{
    uint8_t c;
    if (uart_ringbuf_trypop(&rxBuf, &c))
        return c;
    return 0;
}

// Add string to buffer and start sending if not started already
void uart_send(char* str)
{
    while (*str != '\0') // while not '\0'
        uart_ringbuf_push(&txBuf, *str++);
    if (!txStatus) // if not sending, start sending
        uart_internal_sendchar();
}

// Add string to buffer and start sending if not started already
void uart_sendn(char* str, uint8_t n)
{
    for (int i = 0; i < n; i++) // send n ammount of chars
        uart_ringbuf_push(&txBuf, str[i]);
    if (!txStatus) // if not sending, start sending
        uart_internal_sendchar();
}
// Add char to buffer and start sending if not started already
void uart_sendc(char c)
{
    // send a single char
    uart_ringbuf_push(&txBuf, c);
    if (!txStatus) // if not sending, start sending
        uart_internal_sendchar();
}

// ISR
// ========== ========== ========== ========== ========== ==========

// Interrupt on receive
ISR(USART_RX_vect)
{
    uart_ringbuf_push(&rxBuf, UDR0);
}
// Interrupt on send
ISR(USART_TX_vect)
{
    uart_internal_sendchar();
}


#include <avr/io.h>
#include <avr/interrupt.h>

#define KEYBOARD_ROW_FIRSTPIN PD2
#define KEYBOARD_ROW_COUNT 4
#define KEYBOARD_COL_FIRSTPIN PC0
#define KEYBOARD_COL_COUNT 4

// keyboard chars
uint8_t btn_chars[KEYBOARD_ROW_COUNT][KEYBOARD_COL_COUNT] =
{
    {'1', '2', '3', 'A'},
    {'4', '5', '6', 'B'},
    {'7', '8', '9', 'C'},
    {'*', '0', '#', 'D'}
};
// current keyboard state
uint8_t btn_state[KEYBOARD_ROW_COUNT][KEYBOARD_COL_COUNT] = {{0}};
// last keyboard state
uint8_t btn_laststate[KEYBOARD_ROW_COUNT][KEYBOARD_COL_COUNT] = {{0}};

// initialize the keyboard
void keyboard_init()
{
    DDRD |= _BV(PD2) | _BV(PD3) | _BV(PD4) | _BV(PD5);
    PORTD |= _BV(PD2) | _BV(PD3) | _BV(PD4) | _BV(PD5);
    DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3));
    PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3);
}

void keyboard_update()
{
    for (uint8_t y = 0; y < KEYBOARD_ROW_COUNT; y++)
    {
        PORTD &= ~(_BV(KEYBOARD_ROW_FIRSTPIN + y));

        for (uint8_t x = 0; x < KEYBOARD_COL_COUNT; x++)
        {
            btn_laststate[y][x] = btn_state[y][x];
            btn_state[y][x] = !(PINC & _BV(KEYBOARD_COL_FIRSTPIN + x));
        }

        PORTD |= (_BV(KEYBOARD_ROW_FIRSTPIN + y));
    }
}

int main()
{
    uart_init(115200, 1);
    sei();

    keyboard_init();

    while (1)
    {
        keyboard_update();

        for (uint8_t y = 0; y < KEYBOARD_ROW_COUNT; y++)
            for (uint8_t x = 0; x < KEYBOARD_COL_COUNT; x++)
                if (btn_state[y][x] && !btn_laststate[y][x])
                    uart_sendc(btn_chars[y][x]);
    }

    return 0;
}