// usb_shell.c
// BCD -- Ben Hutton, Chris Leary, Devrin Talen
// 100-column width


#include "usb_shell.h"


/***********/
/* GLOBALS */
/***********/


uint8_t rx_buf[RX_BUF_SIZE];
uint8_t rx_buf_len = 0;

uint8_t tx_buf[TX_BUF_SIZE];
uint8_t tx_buf_len = 0;

uint8_t exec_cmd_flag = 0;

// a string that will make backspaces actually look like backspaces in a terminal connection
const uint8_t backspace_str[] = "\b \b";


/**************/
/* INTERRUPTS */
/**************/


ISR(USART_RXC_vect)
// Code executed when USART receives a byte.
{
    uint8_t received_char;

    // Fetch the recieved byte value.
    received_char = UDR;

    switch (received_char) {
        case '\b':
            rx_buf[rx_buf_len] = '\0';
            /* Need rx_buf_len to be non-zero before decrement to prevent unsigned integer 
             * underflow. */
            if (rx_buf_len) {
                rx_buf_len--;
                // Need the following cast to avoid the warning.
                usart_putstr((uint8_t *)backspace_str);
            }
            break;
        case '\r':
        case '\n':
            UDR = received_char;
            rx_buf[rx_buf_len] = '\0';
            exec_cmd_flag = 1;
            break;
        default:
            UDR = received_char;
            //sprintf(rx_buf, "0x%x ", received_char);
            //usart_putstr(rx_buf);
            rx_buf[rx_buf_len++] = received_char;
            // Prevent buffer overflows.
            if (rx_buf_len >= RX_BUF_SIZE) rx_buf_len = 0;
            break;
    }
}


/************************/
/* FUNCTION DEFINITIONS */
/************************/

void usart_putchar(uint8_t char_to_put)
/*
 * Waits for transmit flag to become clear, then sends a single byte.
 */
{
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = char_to_put;
}

void usart_putstr(char *str_to_put)
/*
 * Transmits the given string over USART.
 */
{
    uint8_t iter;
    uint8_t char_to_put;
    for (iter = 0; (char_to_put = str_to_put[iter]); iter++) {
        usart_putchar(char_to_put);
    }
}

void initialize_usart()
{
    // Enable usart for transmit and receive.
    UCSRB |= (1 << RXEN) | (1 << TXEN);
    // 8-bit chars (uint8_t)
    UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1);

    // load lower 8-bits of the baud rate value into the low byte of the UBRR register
    UBRRL = BAUD_PRESCALE;
    // load upper 8-bits of the baud rate value into the high byte of the UBRR register
    UBRRH = (BAUD_PRESCALE >> 8);

    // enable 'recieve complete' interrupt (USART_RXC)
    UCSRB |= (1 << RXCIE);

    // Enable interrupts globally
    sei();
}