/**
 * @file main.c
 * @brief Demo UART Terminal C
 *
 * In this example ASCII code of 0-9 digit that is received using UART is saved
 * and displayed on 7-segment LED display. When one button is pressed, that
 * ASCII code is sent back to 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>
#include "function.h"

/** macro to convert ASCII code to digit */
#define ASCII2DIGIT(x)      (x - '0')
/** macro to convert digit to ASCII code */
#define DIGIT2ASCII(x)      (x + '0')

/**
 * @brief Timer period
 *
 * Timer is clocked by ACLK (32768Hz).
 * We want ~32ms period, so use 1023 for CCR0
 */
#define TIMER_PERIOD        (1048)  /* ~32ms (31.25ms) */

/** baud rate */
#define BR9600      (3)

/** variable where received character is placed */
volatile uint8_t data = 0;

/**
 * @brief Main function
 *
 * Demo initializes button and UART RX interrupt
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // Stop watchdog timer

    // sevenseg 1
    P7DIR |= BIT0;              // set P7.0 as out (SEL1)
    P7OUT &= ~BIT0;             // enable display 1

    // a,b,c,d,e,f,g
    P2DIR |= 0x48;              // configure P2.3 and P2.6 as out
    P3DIR |= BIT7;              // configure P3.7 as out
    P4DIR |= 0x09;              // configure P4.0 and P4.3 as out
    P8DIR |= 0x06;              // configure P8.1 and P8.2 as out
    P2OUT |= 0x48;              // set all segments to '1'
    P3OUT |= BIT7;              // to deactivate them
    P4OUT |= 0x09;              // display is with common anode
    P8OUT |= 0x06;

    // configure button S1
    P1REN |= BIT4;              // enable pull up/down
    P1OUT |= BIT4;              // set pull up
    P1DIR &= ~BIT4;             // configure P1.4 as in
    P1IES |= BIT4;              // interrupt on falling edge
    P1IFG &= ~BIT4;             // clear flag
    P1IE  |= BIT4;              // enable interrupt

    /* initialize Timer A */
    TA0CCR0 = TIMER_PERIOD;     // debounce period
    TA0CCTL0 = CCIE;            // enable CCR0 interrupt
    TA0CTL = TASSEL__ACLK;

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

    UCA1CTL1 |= UCSWRST;        // enter sw reset

    UCA1CTL0 = 0;
    UCA1CTL1 |= UCSSEL__ACLK;   // select ACLK as clk source
    UCA1BRW = BR9600;           // same as UCA1BR0 = 3; UCA1BR1 = 0
    UCA1MCTL |= UCBRS_3 + UCBRF_0;         // configure 9600 bps

    UCA1CTL1 &= ~UCSWRST;       // leave sw reset
    // after enabling uart enable interrupt
    UCA1IE |= UCRXIE;           // enable RX interrupt

    __enable_interrupt();       // GIE

    while (1);
}

/**
 * @brief USCIA1 ISR
 *
 * When data is received using UART, save it and display on 7seg display
 */
void __attribute__ ((interrupt(USCI_A1_VECTOR))) UARTISR (void)
{
    if (UCA1IV == USCI_UCRXIFG)
    {
        data = ASCII2DIGIT(UCA1RXBUF);  // save data
        WriteLed(data);     // write to 7seg
    }
}

/**
 * @brief PORT1 ISR
 *
 * On button press send data using UART
 */
void __attribute__ ((interrupt(PORT1_VECTOR))) P1ISR (void)
{
    if ((P1IFG & BIT4) != 0)        // check if P1.4 flag is set
    {
        /* start timer */
        TA0CTL |= MC__UP;

        P1IFG &= ~BIT4;             // clear P1.4 flag
        P1IE &= ~BIT4;              // disable P1.4 interrupt
    }
}

/**
 * @brief TIMERA0 Interrupt service routine
 *
 * ISR debounces P1.4 and sends data to TX buffer if button is pressed.
 */
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) CCR0ISR (void)
{
    if ((P1IN & BIT4) == 0) // check if button is still pressed
    {
        UCA1TXBUF = DIGIT2ASCII(data);  // send data
    }
    TA0CTL &= ~(MC0 | MC1); // stop and clear timer
    TA0CTL |= TACLR;
    P1IFG &= ~BIT4;         // clear P1.4 flag
    P1IE |= BIT4;           // enable P1.4 interrupt
    return;
}
