/**
 * @file main.c
 * @brief Demo Button Toggle Timer
 *
 * In this example one LED is toggled every time one button is pressed.
 * Button press is detected using port and timer interrupts.
 *
 * @date 2019
 * @author Strahinja Jankovic (jankovics@etf.bg.ac.rs)
 * @author Marija Bezulj (meja@etf.ba.ac.rs)
 *
 * @version [2.0 - 04/2021] Hardware change
 * @version [1.0 - 03/2019] Initial version
 */
#include <msp430.h> 
#include <stdint.h>

/**
 * @brief Timer period
 *
 * Timer is clocked by ACLK (32768Hz)
 * It takes 32768 cycles to count to 1s.
 * If we need a period of X ms, then number of cycles
 * that is written to the CCR0 register is
 * 32768/1000 * X
 */
#define TIMER_PERIOD        (1048)  /* ~32ms (31.26ms)  */

/**
 * @brief Global synchronization flag
 */
static volatile uint8_t flag = 0;

/**
 * @brief Main function
 * main.c
 * Main function only initializes ports and enables global interrupts
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer
    // LED1 init
    P2OUT &= ~BIT4;             // set P2.4 to '0'
    P2DIR |= BIT4;              // configure P2.4 as out
    // S2 (switch 2) init
    P1REN |= BIT5;              // enable pull up/down
    P1OUT |= BIT5;              // set pull up
    P1DIR &= ~BIT5;             // configure P1.5 as in
    P1IES |= BIT5;              // interrupt on high to low transition
    P1IFG &= ~BIT5;             // clear the flag initially
    P1IE  |= BIT5;              // enable interrupt on P1.5
    // Timer A init
    // Up mode, TA0CCR0 = TIMER_PERIOD
    TA0CCTL0 |= CCIE;           // enable c/c interrupt
    TA0CCR0 = TIMER_PERIOD;     // set timer period for compare mode
    TA0CTL = TASSEL__ACLK; // set timer with ACLK and DIV1


    __enable_interrupt();

    while(1)
    {
        /* NOTE: This is sub-optimal since we are polling flag.
         * The appropriate implementation would be using LPM,
         * where main loop would go into LPM and timer ISR would
         * trigger leaving LPM.
         */
        while (!flag);

        P2OUT ^= BIT4;          // toggle LD1
        flag = 0;

    }
}


/**
 * @brief PORT1 Interrupt service routine
 *
 * ISR blocks P1 interrupt, and enables timer for debounce counting.
 */
void __attribute__ ((interrupt(PORT1_VECTOR))) P1ISR (void)
{
    if ((P1IFG & BIT5) != 0)
    {
        P1IE &= ~BIT5;          // disable P1.5 interrupt
        TA0CTL |= MC__UP;       // enable Timer A0 in UP mode
        P1IFG &= ~BIT5;         // clear interrupt flag
    }
    return;
}
/**
 * @brief TIMERA0 Interrupt service routine
 *
 * ISR debounces P1.5, toggles LED if falling edge is detected,
 * and enables P1.5 interrupt.
 */
void __attribute__ ((interrupt(TIMER0_A0_VECTOR))) TACC0ISR (void)
{
    if ((P1IN & BIT5) == 0)
    {
        // button is pressed
        flag = 1;               // set flag, main loop toggles LD1
    }
    TA0CTL &= ~MC__UPDOWN;      // stop the timer
    TA0CTL |= TACLR;            // clear the timer
    P1IE |= BIT5;               // enable P1.5 interrupt
    return;
}
