/*
 * Basic ASCII UART example for MSP430FR2633 EVM
 * Demonstrates both transmit and receive handlers
 * Runs at 9600 or 115200 baud
 */
#include <msp430.h> 
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

//******************************************************************************
// PROGRAM DEFINES
//******************************************************************************
#define LED_OUT     P1OUT
#define LED_DIR     P1DIR
#define LED_PIN     BIT0

#define SMCLK_115200    0
#define SMCLK_9600      1

 // SELECT THE BAUD RATE
#define UART_MODE       SMCLK_9600
//#define UART_MODE       SMCLK_115200

//******************************************************************************
// GLOBAL PROGRAM VARIABLES
//******************************************************************************
unsigned char RXDataBuffer[64];
unsigned char TXDataBuffer[64];
unsigned char* pTXBuffer = &TXDataBuffer[0];
unsigned char* pRXBuffer = &RXDataBuffer[0];
unsigned int bytesToSend;
unsigned int bytesReceived;
bool msg_received = false;
bool uart_busy = false;

//******************************************************************************
// UART Initialization
//******************************************************************************
void initUART()
{
    // Configure USCI_A0 for UART mode
    UCA0CTLW0 |= UCSWRST;                      // Put eUSCI in reset
#if UART_MODE == SMCLK_115200

    UCA0CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK
    // Baud Rate Setting
    // Use Table 21-5
    UCA0BRW = 8;
    UCA0MCTLW |= UCOS16 | UCBRF_10 | 0xF700;   //0xF700 is UCBRSx = 0xF7

#elif UART_MODE == SMCLK_9600

    UCA0CTLW0 |= UCSSEL__SMCLK;               // CLK = SMCLK
    // Baud Rate Setting
    // Use Table 21-5
    UCA0BRW = 104;
    UCA0MCTLW |= UCOS16 | UCBRF_2 | 0xD600;   //0xD600 is UCBRSx = 0xD6
#else
    # error "Please specify baud rate to 115200 or 9600"
#endif

    UCA0CTLW0 &= ~UCSWRST;                    // Initialize eUSCI
    UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
}

//******************************************************************************
// GPIO Initialization
//******************************************************************************

void initGPIO()
{

    // Set the two pins that drive LEDs as outputs
    P1DIR = BIT6 | BIT7;
    P1OUT = 0x00;

    // Configure GPIO as USCI_A0 UART PINS
    P1SEL0 |= BIT4 | BIT5;

    // Not using PORT2 so set as outputs and drive low
    P2DIR = 0xFF;
    P2OUT = 0x00;

    // Not using PORT3 so set as outputs and drive low
    P3DIR = 0xFF;
    P3OUT = 0x00;

    // Disable the GPIO power-on default high-impedance mode to activate
    // previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;
}

//******************************************************************************
// Clock Initialization
//******************************************************************************

void initClockTo16MHz()
{
    // Configure one FRAM waitstate as required by the device datasheet for MCLK
    // operation beyond 8MHz _before_ configuring the clock system.
    FRCTL0 = FRCTLPW | NWAITS_1;

    __bis_SR_register(SCG0);    // disable FLL
    CSCTL3 |= SELREF__REFOCLK;  // Set REFO as FLL reference source
    CSCTL0 = 0;                 // clear DCO and MOD registers
    CSCTL1 &= ~(DCORSEL_7);     // Clear DCO frequency select bits first
    CSCTL1 |= DCORSEL_5;        // Set DCO = 16MHz
    CSCTL2 = FLLD_0 + 487;      // set to fDCOCLKDIV = (FLLN + 1)*(fFLLREFCLK/n)
                                //                   = (487 + 1)*(32.768 kHz/1)
                                //                   = 16 MHz
    __delay_cycles(3);
    __bic_SR_register(SCG0);                        // enable FLL
    while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1));      // FLL locked

    CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK;
}

//******************************************************************************
// Transmits data out UART
//******************************************************************************
void TransmitData(unsigned char* string, unsigned int length)
{
    // Turn on TX LED (P1.6) to show we are transmitting
    P1OUT |= BIT6;

    // Wait here in case transmission already in progress
    while(uart_busy == true);

    uart_busy = true;                           // Show the UART is busy
    pTXBuffer = string;                         // Set pointer to the transmit buffer
    bytesToSend = length;                       // Setup how many bytes to send
    UCA0IE |= UCTXIE;                           // Enable USCI_A0 TX interrupt

    // From here the UART will automatically transmit all the bytes in the string
    // while the CPU remains in LPM0.
}


int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;                 // Stop watchdog timer
    initGPIO();
    initClockTo16MHz();
    initUART();

    __bis_SR_register(GIE);

    // Example use of timer to send periodic message to PC
    // Skip this if you are sending other messages
    // Configure timer to periodically transmit string
    TA0CCTL0 |= CCIE;                             // TACCR0 interrupt enabled
    TA0CTL |= TASSEL__SMCLK | MC__CONTINUOUS | ID__8;     // SMCLK, continuous mode

    while (1)
    {
        // Enter LPM0 and wait for interrupt to wake the CPU
        __bis_SR_register(LPM0_bits | GIE);

        // Ok we are awake so
        // Check if message was received and send an acknowledgment
        if(msg_received == true)
        {
            TransmitData("Thanks!\r\n", 9);
            msg_received = false;
        }
    }
}


//******************************************************************************
// USCI_A0 ISR HANDLER
//******************************************************************************
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
    switch(__even_in_range(UCA0IV,USCI_UART_UCTXCPTIFG))
    {
        case USCI_NONE: break;
        case USCI_UART_UCRXIFG:
              P1OUT |= BIT7;                      // Turn on RX LED
              UCA0IFG &=~ UCRXIFG;              // Clear interrupt
              *pRXBuffer = UCA0RXBUF;             // Clear buffer
              if (UCA0RXBUF == '\r')            // This works because my terminal app sends CR only (\r).  If yours sends CR + LF change this to '\n'
                  msg_received = true;
              P1OUT &= (~BIT7);                  // Turn off RX LED

              __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 on reti
              break;

        case USCI_UART_UCTXIFG:
            UCA0TXBUF = *pTXBuffer++;
            if(--bytesToSend == 0)
            {
                UCA0IE &= ~UCTXIE;            // Disable USCI_A0 TX interrupt after last byte of string has been transmitted.
                P1OUT &= (~BIT6);             // Turn off TX LED
                uart_busy = false;
                __bis_SR_register_on_exit(LPM0_bits); // Exit LPM0 on reti
            }

            break;
        case USCI_UART_UCSTTIFG: break;
        case USCI_UART_UCTXCPTIFG: break;
    }

}


// Set our test message as const so it will be placed in FRAM, not RAM
const uint8_t HelloMsg[] = "Hello MSP430 World - Have a great day!\r\n";

//******************************************************************************
// TIMER0_A0 ISR HANDLER - Automatically transmits message to PC terminal
//******************************************************************************
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
    static int count = 40;
    uint8_t length;

    if(--count == 0)
    {
        count = 40;
        // # of bytes to send is one less than the string length.
        // Compiler added '0' to end of our string and we don't want to send it.
// TO ENABLE SENDING STATIC MESSAGE, SET #if 1
// TO ENABLE SENDING DYNAMIC MESSAGE, SET #1 0

#if 0
       // Send static message
       TransmitData((uint8_t*) HelloMsg, sizeof(HelloMsg)-1);

#else
       // Send dynamic message - in this case the current value of timer
       //Use sprintf() function to automatically convert TA0R into ASCII
       length = sprintf((char*)TXDataBuffer, "%d\r\n", TA0R);

       TransmitData(TXDataBuffer, length);
#endif

    }
}
