/* --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--*/
//*****************************************************************************
//         Dual Ray Smoke Sensor Library HAL for MSP430FR2355 using SAC_L3
//
// Driver using SAC_L3 in FR2355 to obtain data reflective data from LED
// Texas Instruments, Inc.
// Luis R
// *****************************************************************************
#include <DualRaySmokeAFE_HAL.h>
#include <IQmathLib.h>
#include "DualRaySmokeAFE_HAL_Config_Private.h"

/**** Local Variables *********************************************************/
// ADC State/Mode
static enum tADC
{
   ADC_Disabled = 0,
   ADC_AFE_Measurement,
   ADC_AFE_MeasurementComplete,
   ADC_AFE_Temperature,
}eADC;

static uint16_t u16PGA_Gain[DUALRAYSMOKEAFE_LED_TOTAL];
static uint16_t u16LED_Strength[DUALRAYSMOKEAFE_LED_TOTAL];
static uint16_t u16TIABiasVoltagemV[DUALRAYSMOKEAFE_LED_TOTAL];
static uint16_t u16PGABiasVoltagemV[DUALRAYSMOKEAFE_LED_TOTAL];
static uint16_t u16ADCCounter, u16ADCMeasurements;
#if (DUALRAYSMOKEAFE_HAL_AFE_LED_SAMPLE_BUFFER_SIZE <= 16)
static uint16_t u16ADCAccumulator;
#else
#error "More than 16 ADC samples can overflow uint16_t."
#endif


/**** Local Function Prototypes ***********************************************/
static uint16_t ADCCalibrateResult(uint16_t ADCData, uint16_t reference);
static _iq15 ADCTemperatureCalc(uint16_t ADCData, uint16_t reference);
static void disable_SAC(void);
static void enable_SAC_LED_reflection(tDualRaySmokeAFE_LED LED,
                                      uint16_t light_strength,
                                      uint16_t gain);
static void IntRefEnable(uint16_t settingmV);
static void IntRefDisable(void);

// ADC Offset
#define CAL_ADC_GAIN                    (*((unsigned int *)0x1A16))
// ADC Offset
#define CAL_ADC_OFFSET                  (*((unsigned int *)0x1A18))
// ADC temperature calibration, 1.5V ref, 30C
#define CAL_ADC_TEMPERATURE_1_5V_30C    (*((unsigned int *)0x1A1A))
// ADC temperature calibration, 1.5V ref, 105C
#define CAL_ADC_TEMPERATURE_1_5V_105C   (*((unsigned int *)0x1A1C))
// ADC temperature calibration, 2.0V ref, 30C
#define CAL_ADC_TEMPERATURE_2_0V_30C    (*((unsigned int *)0x1A1E))
// ADC temperature calibration, 2.0V ref, 105C
#define CAL_ADC_TEMPERATURE_2_0V_105C   (*((unsigned int *)0x1A20))
// ADC temperature calibration, 2.5V ref, 30C
#define CAL_ADC_TEMPERATURE_2_5V_30C    (*((unsigned int *)0x1A22))
// ADC temperature calibration, 2.5V ref, 105C
#define CAL_ADC_TEMPERATURE_2_5V_105C   (*((unsigned int *)0x1A24))
// VREF Calibration factor at 1.5V
#define CAL_INTVREF_1_5V                (*((unsigned int *)0x1A28))
// VREF Calibration factor at 2.0V
#define CAL_INTVREF_2_0V                (*((unsigned int *)0x1A2B))
// VREF Calibration factor at 2.5V
#define CAL_INTVREF_2_5V                (*((unsigned int *)0x1A2C))


/**** Functions ***************************************************************/
void DualRaySmokeAFE_HAL_AFE_Init(tDualRaySmokeAFE_HAL_AFE_Config * Config)
{
    uint16_t i;
    uint32_t temp;

    for (i=0; i < DUALRAYSMOKEAFE_LED_TOTAL; i++)
    {
        // Set PGA Gain register value based on desired setting
        switch(Config->u16PGA_Gain[i])
        {
            case 1:
                u16PGA_Gain[i] = (GAIN0);
            break;
            case 2:
                u16PGA_Gain[i] = (GAIN1);
            break;
            case 4:
                u16PGA_Gain[i] = (GAIN1|GAIN0);
            break;
            case 8:
                u16PGA_Gain[i] = (GAIN2);
            break;
            case 16:
                u16PGA_Gain[i] = (GAIN2|GAIN0);
            break;
            case 25:
                u16PGA_Gain[i] = (GAIN2|GAIN1);
            break;
            case 32:
                u16PGA_Gain[i] = (GAIN2|GAIN1|GAIN0);
            break;
        }
        // Set DAC value value based on desired setting
        temp = (uint32_t) Config->u16LED_CurrentmA[i] * (uint32_t) 4096;
        temp = temp / DUALRAYSMOKEAFE_HAL_AFE_VREF_MV;
        u16LED_Strength[i] = (uint16_t) temp;

        // Set TIA bias voltage DAC value
        temp = (uint32_t) Config->u16TIABiasmV[i] * (uint32_t) 4096;
        temp = temp / DUALRAYSMOKEAFE_HAL_AFE_VREF_MV;
        u16TIABiasVoltagemV[i] = (uint16_t) temp;

        // Set PGA bias voltage DAC value
        temp = (uint32_t) Config->u16PGABiasmV[i] * (uint32_t) 4096;
        temp = temp / DUALRAYSMOKEAFE_HAL_AFE_VREF_MV;
        u16PGABiasVoltagemV[i] = (uint16_t) temp;
    }


    eADC = ADC_Disabled; // ADC disabled by default
    u16ADCCounter = 0;
    u16ADCMeasurements = 0;
    u16ADCAccumulator = 0;
}

void DualRaySmokeAFE_HAL_AFE_Measurement(uint16_t *dark_measurement,
                                         uint16_t *light_measurement,
                                         tDualRaySmokeAFE_LED LED)
{
    IntRefEnable(DUALRAYSMOKEAFE_HAL_AFE_VREF_MV);    // enable internal Vref
    // Turn on IR LED light with strength = 0
    enable_SAC_LED_reflection(LED,
                              0,
                              u16PGA_Gain[LED]);

    // Configure ADC to repeat-single-channel mode
    ADCCTL0 = ADCSHT_1 | ADCMSC | ADCON;    // ADCON
    ADCCTL1 = ADCSHP | ADCCONSEQ_2;         // Repeat single channel
    ADCCTL2 = ADCRES_2;                     // 12-bit conversion results
    ADCMCTL0 = ADCINCH_1 | ADCSREF_1;       // A1 ADC input select = SAC0 output;
                                            //Vref = Internal Shared Vref 2.5v

    // Wait for Int Ref, SAC/SAC0 setup
    DualRaySmokeAFE_HAL_Timing_GPTimer_BlockingHPDelayus(
                                DUALRAYSMOKEAFE_HAL_AFE_DELAY_MEASUREMENT1);

    eADC = ADC_AFE_Measurement;         // Set ADC to perform AFE measurement
    // Use accumulator to add samples which will be averaged at the end
    u16ADCMeasurements = DUALRAYSMOKEAFE_HAL_AFE_LED_SAMPLE_BUFFER_SIZE;
    u16ADCCounter = 0;
    u16ADCAccumulator = 0;

    ADCIFG = 0; // Clear flag
    ADCIE = ADCIE0;                         // Enable ADC interrupt
    ADCCTL0 |= ADCENC | ADCSC;              // Sampling and conversion start

    __disable_interrupt();
    while(eADC != ADC_AFE_MeasurementComplete)
    {
        // Enter LPM0 with general interrupt enabled
        __bis_SR_register(LPM0_bits + GIE);
        // Wait for LPM wake-up by ADC Interrupt
        __no_operation();
        __disable_interrupt();
    }
    __enable_interrupt();

    // Turn on LED with corresponding light strength
    enable_SAC_LED_reflection(LED,
                              u16LED_Strength[LED],
                              u16PGA_Gain[LED]);

    // Peform ADC calculation while waiting for SAC to settle
    // Get the average for dark measurement
    u16ADCAccumulator = u16ADCAccumulator/DUALRAYSMOKEAFE_HAL_AFE_LED_SAMPLE_BUFFER_SIZE;
    // Get calibrated result for dark measurement
    *dark_measurement = ADCCalibrateResult(u16ADCAccumulator,
                                           DUALRAYSMOKEAFE_HAL_AFE_VREF_MV);
    // Delay waiting for SAC
    DualRaySmokeAFE_HAL_Timing_GPTimer_BlockingHPDelayus(
                                    DUALRAYSMOKEAFE_HAL_AFE_DELAY_MEASUREMENT2);

    // Set ADC to take dark measurements
    eADC = ADC_AFE_Measurement;         // Set ADC to perform AFE measurement
    u16ADCMeasurements = DUALRAYSMOKEAFE_HAL_AFE_LED_SAMPLE_BUFFER_SIZE;
    u16ADCCounter = 0;
    u16ADCAccumulator = 0;

    ADCIFG = 0; // Clear flag
    ADCIE = ADCIE0;                         // Enable ADC interrupt
    ADCCTL0 |= (ADCENC + ADCSC);

    __disable_interrupt();
    while(eADC != ADC_AFE_MeasurementComplete)
    {
        // Enter LPM0 with general interrupt enabled
        __bis_SR_register(LPM0_bits + GIE);
        // Wait for LPM wake-up by ADC Interrupt
        __no_operation();
        __disable_interrupt();
    }
    __enable_interrupt();

    disable_SAC();                      // disable LED emitter and light sensing
    ADCCTL0 &= ~ (ADCENC + ADCSC);      // Disable ADC
    ADCCTL0 &= ~ADCON;

    IntRefDisable();                    // disable internal Vref

    // Get the average of light measurement
    u16ADCAccumulator = u16ADCAccumulator/DUALRAYSMOKEAFE_HAL_AFE_LED_SAMPLE_BUFFER_SIZE;
    // Get calibrated result
    *light_measurement = ADCCalibrateResult(u16ADCAccumulator,
                                           DUALRAYSMOKEAFE_HAL_AFE_VREF_MV);

}


_iq15 DualRaySmokeAFE_HAL_AFE_TemperatureMeasurement(void)
{
    uint16_t measurement;
    _iq15 temp_meas;

    // enable internal Vref
    IntRefEnable(DUALRAYSMOKEAFE_HAL_AFE_TEMPERATURE_VREF_MV);
    // Enable internal temp sensor
    PMMCTL2 |= TSENSOREN;

    eADC = ADC_AFE_Temperature;         // Set ADC to perform Temp measurement

    // Configure ADC for single conversion of Temperature sensor
    // ADCON, sampling period > 30us
    //      SHT_8 = 256 cycles MODOSC(3MHz - 4.6MHz) = 55us to 85us
    ADCCTL0 = ADCSHT_8  | ADCON;
    // Pulse Sample mode, single channel, SW trigger, Use MODOSC
    ADCCTL1 = ADCSHP | ADCCONSEQ_0 | ADCSHS_0 | ADCSSEL_0;
    // 12-bit conversion results
    ADCCTL2 = ADCRES_2;
    // Input = temp sense, use Internal VREF
    ADCMCTL0 = ADCINCH_12 | ADCSREF_1;

    // Wait for Int Ref
    DualRaySmokeAFE_HAL_Timing_GPTimer_BlockingHPDelayus(
                                    DUALRAYSMOKEAFE_HAL_AFE_DELAY_TEMPERATURE);

    u16ADCCounter = 0;
    u16ADCMeasurements = 1; // Take only 1 measurement
    u16ADCAccumulator = 0;

    ADCIFG = 0; // Clear flag
    ADCIE = ADCIE0;                         // Enable ADC interrupt
    ADCCTL0 |= ADCENC | ADCSC;              // Sampling and conversion start

    __disable_interrupt();
    while(eADC != ADC_AFE_MeasurementComplete)
    {
        // Enter LPM0 with general interrupt enabled
        __bis_SR_register(LPM0_bits + GIE);
        // Wait for LPM wake-up by ADC Interrupt
        __no_operation();
        __disable_interrupt();
    }
    __enable_interrupt();

    ADCCTL0 &= ~ (ADCENC + ADCSC);      // Disable ADC
    ADCCTL0 &= ~ADCON;

    PMMCTL2 &= ~TSENSOREN;  // Disable temp sensor
    IntRefDisable();                    // disable internal Vref

    // Get ADC calibrated result
    measurement = ADCCalibrateResult(u16ADCAccumulator,
                                           DUALRAYSMOKEAFE_HAL_AFE_TEMPERATURE_VREF_MV);

    // Calculate temperature using 3 point calibration
    temp_meas = ADCTemperatureCalc(measurement,
                                           DUALRAYSMOKEAFE_HAL_AFE_TEMPERATURE_VREF_MV);
    return temp_meas;
}

/**** Local Functions *********************************************************/
//! \brief Adjusts the ADC result based on device calibration.
//!
//! \param[in] ADCData is the raw ADC
//! \param[in] reference is the reference in mV
//!
//! \return uint16_t with the calibrated ADC result
static uint16_t ADCCalibrateResult(uint16_t ADCData, uint16_t reference)
{
    uint32_t temp;

    // Adjust for ADC offset, simply add calibration value
    ADCData += CAL_ADC_OFFSET;

    // Adjust for ADC gain, multiply by gain factor and divide by 2^15
    temp = ADCData;
    temp = (uint32_t) temp * (uint32_t) CAL_ADC_GAIN;
    temp = temp >> 15;

    // Adjust for VREF calibration
    // Multiply by calibrated VREF factor
    if (reference == 2500)
    {
        temp = (uint32_t) temp * (uint32_t) CAL_INTVREF_2_5V;
    }
    else if (reference == 1500)
    {
        temp = (uint32_t) temp * (uint32_t) CAL_INTVREF_1_5V;
    }
    else
    {
        temp = (uint32_t) temp * (uint32_t) CAL_INTVREF_2_0V;
    }
    // Divide result by 2^15
    return (temp >> 15);
}

//! \brief Calculates temperature in C, given the ADC result
//!
//! \param[in] ADCData is the raw ADC
//! \param[in] reference is the reference in mV
//!
//! \return IQ15 with temperature in Celsius. 17 integer, 15 fractional.
static _iq15 ADCTemperatureCalc(uint16_t ADCData, uint16_t reference)
{
    _iq15 calib_30C, calib_105C;
    _iq15 tempC;

    // These calculations are done in IQMath to reduce overhead
    // IQ15 has a range of -65,536 to 65,535.999
    // It has a resolution of .000 030 518
    if (reference == 2500)
    {
        calib_30C = _IQ15(CAL_ADC_TEMPERATURE_2_5V_30C);
        calib_105C = _IQ15(CAL_ADC_TEMPERATURE_2_5V_105C);
    }
    else if (reference == 1500)
    {
        calib_30C = _IQ15(CAL_ADC_TEMPERATURE_1_5V_30C);
        calib_105C = _IQ15(CAL_ADC_TEMPERATURE_1_5V_105C);
    }
    else
    {
        calib_30C = _IQ15(CAL_ADC_TEMPERATURE_2_0V_30C);
        calib_105C = _IQ15(CAL_ADC_TEMPERATURE_2_0V_105C);
    }
    // Use calibration data to calculate using linear approximation
    //          (ADC - calib30C) * (105-30))
    //  tempC = ----------------------------- + 30
    //              (calib105C - calib30C)
    tempC = _IQ15mpy((_IQ15(ADCData) - calib_30C) , _IQ15(105-30));
    tempC = _IQ15div( tempC , (calib_105C - calib_30C) );
    tempC += _IQ15(30);

    return (tempC);
}

//! \brief Enables SAC0-3 to measure LED reflection.
//!
//! \param[in] LED is the LED used for measurement.
//! \param[in] light_strength is the 16-bit strength used for DAC to drive LED.
//! \param[in] gain is the PGA gain
//!
//! \return none
static void enable_SAC_LED_reflection(tDualRaySmokeAFE_LED LED,
                                      uint16_t light_strength,
                                      uint16_t gain)
{
    if (LED == DUALRAYSMOKEAFE_LED_RED)
    {
        //******* Configure SAC3 pins as IDAC for IR LED driving
        P3SEL0 |= BIT5 + BIT6 + BIT7;
        P3SEL1 |= BIT5 + BIT6 + BIT7;

        SAC3DAC = DACSREF_1;                        // Select internal Vref (1.5V, 2.0V, 2.5V) as SAC3 DAC reference
        SAC3DAT = light_strength;                   // Set SAC3 DAC output = 0.46V (Vref=2.5V)
        SAC3DAC |= DACEN;                           // Enable SAC3 DAC

        SAC3OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0; //Select positive and negative input: positive-DAC, negative-P3.6
        //SAC3OA |= OAPM;                             // Select low speed and low power mode
        SAC3OA |= SACEN + OAEN;                     // Enable SAC3 and OA3
    }
    else if (LED == DUALRAYSMOKEAFE_LED_BLUE)
    {
        //******* Configure SAC1 pins as IDAC for Blue LED driving
        P1SEL0 |= BIT5 + BIT6 + BIT7;
        P1SEL1 |= BIT5 + BIT6 + BIT7;

        SAC1DAC = DACSREF_1;                        // Select internal Vref (1.5V, 2.0V, 2.5V) as SAC3 DAC reference
        SAC1DAT = light_strength;                   // Set SAC1 DAC output = 0.46V (Vref=2.5V)
        SAC1DAC |= DACEN;                           // Enable SAC1 DAC

        SAC1OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0; //Select positive and negative input: positive-DAC, negative-P1.6
        //SAC1OA |= OAPM;                             // Select low speed and low power mode
        SAC1OA |= SACEN + OAEN;                     // Enable SAC1 and OA1
    }

    //******* Configure SAC2 pins as TIA (I-V conversion)
    P3SEL0 |= BIT1 + BIT2 + BIT3;
    P3SEL1 |= BIT1 + BIT2 + BIT3;

    SAC2DAC = DACSREF_1;                        // Select internal Vref (1.5V, 2.0V, 2.5V) as SAC2 DAC reference
    // Set SAC2 DAC output = 0.1v
    SAC2DAT = u16TIABiasVoltagemV[LED];
    SAC2DAC |= DACEN;                           // Enable SAC2 DAC

    SAC2OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_0; //Select positive and negative input: positive-DAC, negative-P3.2
    //SAC2OA |= OAPM;                             // Select low speed and low power mode
    //SAC2PGA = MSEL_1;                           // Set OA as buffer mode - for test
    SAC2OA |= SACEN + OAEN;                     // Enable SAC2 and OA2

    //******* Configure SAC0 pins as PGA inverting amplifier mode
    P1SEL0 |= BIT1 + BIT2 + BIT3;
    P1SEL1 |= BIT1 + BIT2 + BIT3;

    SAC0DAC = DACSREF_1;                        // Select internal Vref (1.5V, 2.0V, 2.5V) as SAC3 DAC reference
    // Set SAC0 DAC output = 0.85V
    SAC0DAT = u16PGABiasVoltagemV[LED];
    SAC0DAC |= DACEN;                           // Enable SAC0 DAC

    SAC0OA = NMUXEN + PMUXEN + PSEL_1 + NSEL_1; //Select positive and negative input: positive-DAC, negative-paired OA output
    SAC0PGA = MSEL_3;                           // Set negative input as paired OA output - SAC2
    //SAC0PGA |= GAIN0 + GAIN1;                   // set PGA gain to 4, corresponding DAC 500mV is better
    SAC0PGA |= gain;                           // set PGA gain to 2, corresponding DAC 800mV is better
    //  SAC0OA |= OAPM;                             // Select low speed and low power mode
    SAC0OA |= SACEN + OAEN;                     // Enable SAC1 and OA1

}

//! \brief Disables SAC0-3 to reduce power consumption
//!
//! \return none
static void disable_SAC(void)
{
    SAC3OA = 0;                         // disable SAC3
    P3SEL0 &= ~(BIT5 + BIT6 + BIT7);    // Select P3.5, P3.6, P3.7 as GPIO function
    P3SEL1 &= ~(BIT5 + BIT6 + BIT7);

    SAC1OA = 0;                         // disable SAC1
    P1SEL0 &= ~(BIT5 + BIT6 + BIT7);    // Select P1.5, P1.6, P1.7 as GPIO function
    P1SEL1 &= ~(BIT5 + BIT6 + BIT7);

    SAC2OA = 0;                         // disable SAC2
    P3SEL0 &= ~(BIT1 + BIT2 + BIT3);    // Select P3.1, P3.2, P3.3 as GPIO function
    P3SEL1 &= ~(BIT1 + BIT2 + BIT3);

    SAC0OA = 0;                         // disable SAC0
    P1SEL0 &= ~(BIT1 + BIT2 + BIT3);    // Select P1.1, P1.2, P1.3 as GPIO function
    P1SEL1 &= ~(BIT1 + BIT2 + BIT3);
}


//! \brief Enables the Internal Shared reference
//!
//! \param[in] settingmV sets reference voltage.
//!             1500=1.5V, 2000=2.0V, any other value = 2.5V
//!
//! \return none
static void IntRefEnable(uint16_t settingmV)
{
    // Configure reference module
    PMMCTL0_H = PMMPW_H;                      // Unlock the PMM registers
    if (settingmV == 1500)
    {
        PMMCTL2 = INTREFEN | REFVSEL_0;       // Enable internal 1.5V reference
    }
    else if (settingmV == 2000)
    {
        PMMCTL2 = INTREFEN | REFVSEL_1;       // Enable internal 2.0V reference
    }
    else
    {
        PMMCTL2 = INTREFEN | REFVSEL_2;       // Enable internal 2.5V reference
    }
    while(!(PMMCTL2 & REFGENRDY));            // Poll till internal reference settles
    PMMCTL0_H = 0xFF;                         // lock the PMM registers
}

//! \brief Disables the Internal Shared reference
//!
//! \return none
static void IntRefDisable(void)
{
    // Configure reference module
    PMMCTL0_H = PMMPW_H;                      // Unlock the PMM registers
    PMMCTL2 &= !INTREFEN;                     // Disable internal 2.5V reference
    PMMCTL0_H = 0xFF;                         // lock the PMM registers
}

//
//! \brief ADC interrupt service routine
//!
//! \return non
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC_VECTOR
__interrupt void DualRaySmokeAFE_ADC_ISR(void)
#else
#error Compiler not supported!
#endif
{
    switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
    {
        case ADCIV_NONE:
            break;
        case ADCIV_ADCOVIFG:
            break;
        case ADCIV_ADCTOVIFG:
            break;
        case ADCIV_ADCHIIFG:
            break;
        case ADCIV_ADCLOIFG:
            break;
        case ADCIV_ADCINIFG:
            break;
        case ADCIV_ADCIFG:
            if ( (eADC == ADC_AFE_Measurement) || (eADC == ADC_AFE_Temperature) )
            {
                if (u16ADCCounter < u16ADCMeasurements)
                {
                    // Accumulate result to obtain average
                    u16ADCAccumulator += ADCMEM0;
                    u16ADCCounter++;
                }
                if (u16ADCCounter >= u16ADCMeasurements)
                {
                    // Disable ADC
                    ADCCTL0 &= ~ (ADCENC + ADCSC);
                    ADCIE &= ~ADCIE0;   // Disable Interrupts
                    eADC = ADC_AFE_MeasurementComplete;
                    __bic_SR_register_on_exit(LPM4_bits);   // Exit LPM
                }
            }
            break;
        default:
            break;
    }
}
