/* --COPYRIGHT--,BSD
 * Copyright (c) 2019, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
//*****************************************************************************
//   HAL IO functions using SAC L3 demo HW
//
// Texas Instruments, Inc.
// Jan 2020
// Luis R
// *****************************************************************************
#include <msp430.h>
#include <stdint.h>
#include <stdlib.h>
#include <DualRaySmokeAFE_HAL.h>
#include "DualRaySmokeAFE_HAL_Config_Private.h"

static tTestButtonCallback testButtonCallback;
static uint16_t testButtonCounter;
static int16_t TestButtonLPTimerCallbackID;

static bool TestButtonLPTimerCallback(void);

/**** Functions **************************************************************/
void DualRaySmokeAFE_HAL_IO_Init(void)
{
    // Port output low to save power consumption
    P1OUT = 0x00;
    P1DIR = (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7);
    // P2.3 used for Alarm Output
    // P2.5 used for Test button (input with pull-up)
    P2OUT = 0x00;
    P2DIR = (BIT0 | BIT1 | BIT2 | BIT3 | BIT4  | BIT6 | BIT7);
    // P3.4 used as LED indicator
    P3OUT = 0x00;
    P3DIR = (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7);
    P4OUT = 0x00;
#ifdef __ENABLE_GUI__
    P4DIR = (BIT0 | BIT1 | BIT4 | BIT5 | BIT6 | BIT7);
    // Configure UCA1TXD (P4.3) and UCA1RXD (P4.2)
    P4SEL0 |= (BIT2 | BIT3);
    P4SEL1 &= ~(BIT2 | BIT3);
#else
    P4DIR = (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7);
#endif
    P5OUT = 0x00;
    P5DIR = (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7);
    P6OUT = 0x00;
    P6DIR = (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7);


    //Red LED pin on P3.4 as indicator - off (output low)
    DualRaySmokeAFE_HAL_IO_ClearLEDIndicator();  // LED off
    // Set LED to output direction
    DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_PDIR |=
                        DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_BIT;

    // Alarm output on P2.3, default output low
    DualRaySmokeAFE_HAL_IO_SetAlarmOutputLow();
    // Set pin to output direction
    DUALRAYSMOKEAFE_HAL_IO_ALARM_OUTPUT_PDIR |=
                        DUALRAYSMOKEAFE_HAL_IO_ALARM_OUTPUT_BIT;

    testButtonCallback = NULL;
    // Initialize Test button I/O with pull-up
    DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PDIR &=
                            ~DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
    DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_POUT |=
                            DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
    DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PREN |=
                            DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
    DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIES |=
                            DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
    __delay_cycles(100000); // Wait for pull-up before clearing flag
    DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIFG &=
                            ~DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
    DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIE |=
                            DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;

    // Register Low-Power periodic timer Callback function to debounce
    //  and long press detection
    TestButtonLPTimerCallbackID =
            DualRaySmokeAFE_HAL_Timing_LPPerTimer_registerCallback(TestButtonLPTimerCallback);

    testButtonCounter = 0;

    PM5CTL0 &= ~LOCKLPM5;                   // Disable the GPIO power-on default high-impedance mode
                                            // to activate previously configured port settings
}

void DualRaySmokeAFE_HAL_IO_SetTestButtonCallback(tTestButtonCallback callback)
{
    testButtonCallback = callback;
}

void DualRaySmokeAFE_HAL_IO_ClearLEDIndicator(void)
{
    DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_POUT &=
                                ~DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_BIT;
}

void DualRaySmokeAFE_HAL_IO_SetLEDIndicator(void)
{
    DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_POUT |=
                                DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_BIT;
}

void DualRaySmokeAFE_HAL_IO_ToggleLEDIndicator(void)
{
    DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_POUT ^=
                                DUALRAYSMOKEAFE_HAL_IO_LED_INDICATOR_BIT;
}

void DualRaySmokeAFE_HAL_IO_SetAlarmOutputHigh(void)
{
    DUALRAYSMOKEAFE_HAL_IO_ALARM_OUTPUT_POUT |=
                                DUALRAYSMOKEAFE_HAL_IO_ALARM_OUTPUT_BIT;
}

void DualRaySmokeAFE_HAL_IO_SetAlarmOutputLow(void)
{
    DUALRAYSMOKEAFE_HAL_IO_ALARM_OUTPUT_POUT &=
                                ~DUALRAYSMOKEAFE_HAL_IO_ALARM_OUTPUT_BIT;
}

void DualRaySmokeAFE_HAL_IO_ToggleLEDIndicatorTimer(uint16_t num_toggles,
                                                      uint16_t delay_ms)
{
    uint16_t i;

    for (i = 0; i < num_toggles; i++)
    {
        DualRaySmokeAFE_HAL_IO_ToggleLEDIndicator();
        DualRaySmokeAFE_HAL_Timing_GPTimer_BlockingLPDelayms(delay_ms);
    }

}

static bool TestButtonLPTimerCallback(void)
{
    bool ret = false;   // don't wake-up MCU by default

    if ( (DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIN &
                DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT) != 0)
    {
        // if button was released before timeout, inform short press
        // Stop timer callback function
        DualRaySmokeAFE_HAL_Timing_LPPerTimer_disableCallback(TestButtonLPTimerCallbackID);
        if (testButtonCallback != NULL)
        {
            // Callback to indicate a short press
            ret = testButtonCallback(false);
        }
        // Re-enable button interrupt
        DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIFG &=
                                        ~DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
        DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIE |=
                                        DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
    }
    else
    {
        if (++testButtonCounter >=
                DUALRAYSMOKEAFE_HAL_IO_TESTBUTTONTIMER_LONGPRESSCYCLES)
        {
            // if button is still pressed after timeout, inform long press
            // Stop timer callback function
            DualRaySmokeAFE_HAL_Timing_LPPerTimer_disableCallback(TestButtonLPTimerCallbackID);
            if (testButtonCallback != NULL)
            {
                // Callback to indicate a long press
                ret = testButtonCallback(true);
            }
            // Re-enable button interrupt
            DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIFG &=
                                        ~DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
            DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIE |=
                                        DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
        }
    }
    return ret;
}

//! \brief ISR for Test Button
//!
//! \return none
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_VECTOR
__interrupt void TestButton_ISR(void)
#else
#error Compiler not supported!
#endif
{
    switch(__even_in_range(P2IV,P2IV__P2IFG7))
    {
    case  P2IV__NONE:   break;                  // No interrupt
    case  P2IV__P2IFG0: break;                  // P2.0
    case  P2IV__P2IFG1: break;                  // P2.1
    case  P2IV__P2IFG2: break;                  // P2.2
    case  P2IV__P2IFG3: break;                  // P2.3
    case  P2IV__P2IFG4: break;                  // P2.4
#if (DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT == BIT5)
    case  P2IV__P2IFG5:                         // P2.5
        // Enable TB1 to debounce and detect long press
        testButtonCounter = 0;
        // Enable the callback function to debounce and detect long press
        if (DualRaySmokeAFE_HAL_Timing_LPPerTimer_enableCallback(TestButtonLPTimerCallbackID)
                >= 0)
        {
            // Disable button Interrupt while timer is enabled
            DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_PIE &=
                                        ~DUALRAYSMOKEAFE_HAL_IO_TESTBUTTON_BIT;
        }
        break;
#else
#error "Configuration not supported. Modify HAL."
#endif
    case  P2IV__P2IFG6: break;                  // P2.6
    case  P2IV__P2IFG7: break;                  // P2.7
    default: break;
    }
}


