/**
 * @file main.c
 * @brief Demo UART echo
 *
 * In this example 4 bytes that are received using UART are sent back in
 * reverse order to the PC.
 *
 * @date 2019
 * @author Strahinja Jankovic (jankovics@etf.bg.ac.rs)
 *
 * @version [2.0 @ 04/2021] Hardware change
 * @version [1.1 @ 03/2019] Code refactor.
 * @version [1.0 @ 03/2017] Initial version
 */
#include <msp430.h>
#include <stdint.h>


/**
 * @brief Baud rate prescaler value
 */
#define BR_38400     (27)
/**
 * @brief Baud rate modulation value
 */
#define BRS_38400    (UCBRS_2)
/**
 * @brief Package length
 */
#define PCKG_SIZE    (4)

/** Data counter */
volatile uint8_t data_cnt = 0;
/** Data buffer */
volatile uint8_t data[PCKG_SIZE] = {0};
/** Package received flag, when set the transmit phase begins */
volatile uint8_t package_received = 0;

/**
 * @brief Main function
 *
 * Demo implements packet receive and transmit transfer
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer

    /* configure UART */
    P4SEL |= BIT4 | BIT5;       // configure P4.4 and P4.5 for uart

    UCA1CTL1 |= UCSWRST;        // enter sw reset

    UCA1CTL0 = 0;
    UCA1CTL1 |= UCSSEL__SMCLK;      // select SMCLK as clk source
    UCA1BRW = BR_38400;             // same as UCA1BR0 = 27; UCA1BR1 = 0
    UCA1MCTL |= BRS_38400 + UCBRF_0;// configure 38400 bps

    UCA1CTL1 &= ~UCSWRST;           // leave sw reset

    // after enabling uart enable interrupt
    UCA1IE |= UCRXIE + UCTXIE;           // enable RX and TX interrupt

    __enable_interrupt();       // GIE

    while (1) {
        if (package_received == 1)
        {
            /* receive stage done, transmit starts */
            package_received = 0;
            data_cnt -= 1;              // note the last value of data_cnt
            UCA1TXBUF = data[data_cnt]; // send the last value first (LIFO)
        }
    }
}
/**
 * @brief USCIA1 ISR
 *
 * Implement packet transfers
 */
void __attribute__ ((interrupt(USCI_A1_VECTOR))) USCIA1 (void)
{
    switch (UCA1IV)                 // NOTE: reading the UCA1IV clears the register
    {                               // it can only be read once, so use switch or
    case 0:                         // save the data in some other variable
        break;
    case USCI_UCRXIFG:
        data[data_cnt] = UCA1RXBUF; // put new data into buffer
        data_cnt += 1;              // increment counter
        if (data_cnt >= PCKG_SIZE)  // if the buffer is full, start transmit phase
        {
            package_received = 1;
        }
        break;
    case USCI_UCTXIFG:
        if (data_cnt > 0)           // if the transmit is not over
        {
            data_cnt -= 1;          // decrement the counter, used as index
            UCA1TXBUF = data[data_cnt]; // send the data
        }                           // if data_cnt == 0, skip
        break;
    }
}

