/* --COPYRIGHT--,BSD
 * Copyright (c) 2020, 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--*/
//*****************************************************************************
//
//  MSP430FR235x Demo - Timer3_B7, PWM TB3.1-4, Up Mode, 32KHz ACLK, RTC, GPIO ISR, and ADC
//
//  Description: This program generates four PWM outputs on P6.0, P6.1, P6.2, P6.3
//  using Timer3_B configured for up mode. The value in CCR0, 100-1, defines the PWM
//  period and the values in CCR1, CCR2, CCR3, CCR4 define the PWM duty cycles. Using
//  ACLK as TBCLK, the timer period is ~3ms with a 80% duty cycle on P6.0, a 50%
//  duty cycle on P6.1, a 30% duty cycle on P6.2 and a 20% duty cycle on P6.3.
//  ACLK =TBCLK = XT1~32768Hz, MCLK = SMCLK = default DCODIV ~1MHz
//  This program also configures 9 different ADC channels which can be used to measure battery cell and thermistor voltages.
//  A variety of GPIOs are also configured for charging faults and control functions.

//

//
//           MSP430FR2355
//         ---------------
//     /|\|            XIN|--
//      | |               |  ~32768Hz
//      --|RST        XOUT|--
//        |               |
//        |     P6.0/TB3.1|--> CCR1 - X% PWM
//        |     P6.1/TB3.2|--> CCR2 - X% PWM
//        |     P6.2/TB3.3|--> CCR3 - X% PWM
//        |     P6.3/TB3.4|--> CCR4 - X% PWM
//        |     P6.6      |--> LED2
//        |     P1.0      |--> LED1
//        |     P4.1      |--> GPIO Interrupt (switch 1)
//        |     P4.0      |--> GPIO Interrupt
//        |     P3.0      |--> GPIO Interrupt
//        |     P2.3      |--> GPIO Interrupt (switch 2)
//        |     P1.1      |--> ADC12 Input
//        |     P1.4      |--> ADC12 Input
//        |     P1.5      |--> ADC12 Input
//        |     P1.6      |--> ADC12 Input
//        |     P1.7      |--> ADC12 Input
//        |     P5.0      |--> ADC12 Input
//        |     P5.1      |--> ADC12 Input
//        |     P5.2      |--> ADC12 Input
//        |     P5.3      |--> ADC12 Input
//
//
//   Leo Estevez
//   Texas Instruments Inc.
//   Dec. 2020
//   Built with Code Composer Studio v10.0.0.00007
// ******************************************************************************

#include <msp430.h>
#include <stdbool.h>
#include <stdint.h>
#include <HAL.h>
#include <GUI.h>
#include <Include/GUIComm.h>
#include <Include/QmathLib.h>
#include <Include/callbacks.h>
#include "SCA_config.h"

unsigned int ADC_Result;
unsigned int Send_Data;
volatile unsigned char RXData;
#define STR_LEN_TWO 2
#define STR_LEN_SEVEN 7

//! \brief RX Command structure.
//! The corresponding callback will be called when the command is
//! received from GUI.
//! Note: shorter command names take less time to process
const tGUI_RxCmd GUI_RXCommands[] =
{
     {"VREF",    GUICallback_VREF},
     {"FREQ",    GUICallback_FREQ},
     {"PWM0",    GUICallback_PWM0},
     {"PWM1",    GUICallback_PWM1},
     {"PWM2",    GUICallback_PWM2},
     {"PWM3",    GUICallback_PWM3},
     {"INT0",    GUICallback_INT0},
     {"INT1",    GUICallback_INT1},
     {"INT2",    GUICallback_INT2},
     {"INT3",    GUICallback_INT3},
     {"ADC0_MODE",    GUICallback_ADC0_MODE},
     {"ADC1_MODE",    GUICallback_ADC1_MODE},
     {"ADC2_MODE",    GUICallback_ADC2_MODE},
     {"ADC3_MODE",    GUICallback_ADC3_MODE},
     {"PGA0_MODE",    GUICallback_PGA0_MODE},
     {"PGA0_INPUTP",    GUICallback_PGA0_INPUTP},
     {"PGA0_GAIN",    GUICallback_PGA0_GAIN},
     {"PGA0_DAC",    GUICallback_PGA0_DAC},
     {"PGA1_MODE",    GUICallback_PGA1_MODE},
     {"PGA1_INPUTP",    GUICallback_PGA1_INPUTP},
     {"PGA1_GAIN",    GUICallback_PGA1_GAIN},
     {"PGA1_DAC",    GUICallback_PGA1_DAC},
     {"PGA2_MODE",    GUICallback_PGA2_MODE},
     {"PGA2_INPUTP",    GUICallback_PGA2_INPUTP},
     {"PGA2_GAIN",    GUICallback_PGA2_GAIN},
     {"PGA2_DAC",    GUICallback_PGA2_DAC},
     {"PGA3_MODE",    GUICallback_PGA3_MODE},
     {"PGA3_INPUTP",    GUICallback_PGA3_INPUTP},
     {"PGA3_GAIN",    GUICallback_PGA3_GAIN},
     {"PGA3_DAC",    GUICallback_PGA3_DAC},
     {"COMP0_MODE",    GUICallback_COMP0_MODE},
     {"COMP0_INPUTP",    GUICallback_COMP0_INPUTP},
     {"COMP0_INPUTN",    GUICallback_COMP0_INPUTN},
     {"COMP0_DAC",    GUICallback_COMP0_DAC},
     {"COMP1_MODE",    GUICallback_COMP1_MODE},
     {"COMP1_INPUTP",    GUICallback_COMP1_INPUTP},
     {"COMP1_INPUTN",    GUICallback_COMP1_INPUTN},
     {"COMP1_DAC",    GUICallback_COMP1_DAC},
     {"UPDATE",    GUICallback_UPDATE},
};

void main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer

    // Initialize clocks
    HAL_System_Init();

    // Initialize GUI layer
    GUI_Init();
    GUI_InitRxCmd( &GUI_RXCommands[0], (sizeof(GUI_RXCommands)/sizeof(GUI_RXCommands[0])) );

    do
    {
       CSCTL7 &= ~(XT1OFFG | DCOFFG);                // Clear XT1 and DCO fault flag
       SFRIFG1 &= ~OFIFG;
    }while (SFRIFG1 & OFIFG);                         // Test oscillator fault flag

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

    // RTC count re-load compare value at 32.
    // 1024/32768 * 32 = 1 sec.
    RTCMOD = 32-1;
    // Initialize RTC
    // Source = 32kHz crystal, divided by 1024
    RTCCTL = RTCSS__XT1CLK | RTCSR | RTCPS__1024 | RTCIE;

    // Configure ADC12
    ADCCTL0 |= ADCSHT_2 | ADCON;                             // ADCON, S&H=16 ADC clks
    ADCCTL1 |= ADCSHP;                                       // ADCCLK = MODOSC; sampling timer
    ADCCTL2 &= ~ADCRES;                                      // clear ADCRES in ADCCTL
    ADCCTL2 |= ADCRES_2;                                     // 12-bit conversion results
    ADCIE |= ADCIE0;                                         // Enable ADC conv complete interrupt

    // Configure I2C
    // Configure USCI_B0 for I2C mode
    UCB0CTLW0 |= UCSWRST;                   // Software reset enabled
    UCB0CTLW0 |= UCMODE_3 | UCMST | UCSYNC; // I2C mode, Master mode, sync
    UCB0CTLW1 |= UCASTP_2;                  // Automatic stop generated
                                            // after UCB0TBCNT is reached
    UCB0BRW = 0x0008;                       // baudrate = SMCLK / 8
    UCB0TBCNT = 0x0005;                     // number of bytes to be received
    UCB0I2CSA = 0x0048;                     // Slave address
    UCB0CTL1 &= ~UCSWRST;
    UCB0IE |= UCRXIE | UCNACKIE | UCBCNTIE;


    // Initialize GPIOs and Configure Software Configurable Analog
    SCA_initGPIO();
    SCA_configGlobal(&globalParams);
    SCA_configPGA(&pgaParams[0],0);
    SCA_configPGA(&pgaParams[1],1);
    SCA_configPGA(&pgaParams[2],2);
    SCA_configPGA(&pgaParams[3],3);
    SCA_configCOMP(&compParams[0],0);
    SCA_configCOMP(&compParams[1],1);
    SCA_configPWM(&pwmParams[0],0);
    SCA_configPWM(&pwmParams[1],1);
    SCA_configPWM(&pwmParams[2],2);
    SCA_configPWM(&pwmParams[3],3);
    SCA_configINT(&intParams[0],0);
    SCA_configINT(&intParams[1],1);
    SCA_configINT(&intParams[2],2);
    SCA_configINT(&intParams[3],3);

    while (1)
    {

        #ifdef __ENABLE_GUI__
            if(Send_Data){                         // Send Data if Send_Data flag set by RTC
                if(adcParams[0].mode){
                SCA_getADC(&adcResults,0);}
                if(adcParams[1].mode){
                SCA_getADC(&adcResults,1);}
                if(adcParams[2].mode){
                SCA_getADC(&adcResults,2);}
                if(adcParams[3].mode){
                SCA_getADC(&adcResults,3);}
                Send_Data=0;
                GUIComm_sendInt16("ADC0", STR_LEN_SEVEN, (int16_t) adcResults.adcResult1);
                GUIComm_sendInt16("ADC1", STR_LEN_SEVEN, (int16_t) adcResults.adcResult5);
                GUIComm_sendInt16("ADC2", STR_LEN_SEVEN, (int16_t) adcResults.adcResult10);
                GUIComm_sendInt16("ADC3", STR_LEN_SEVEN, (int16_t) adcResults.adcResult11);
                GUIComm_sendInt16("PWM0", STR_LEN_SEVEN, (int16_t) pwmParams[0].dutyValue);
                GUIComm_sendInt16("PWM1", STR_LEN_SEVEN, (int16_t) pwmParams[1].dutyValue);
                GUIComm_sendInt16("PWM2", STR_LEN_SEVEN, (int16_t) pwmParams[2].dutyValue);
                GUIComm_sendInt16("PWM3", STR_LEN_SEVEN, (int16_t) pwmParams[3].dutyValue);
                GUIComm_sendBool("COMP0", STR_LEN_SEVEN, (int8_t) (0x0001 & CP0CTL1));
                GUIComm_sendBool("COMP1", STR_LEN_SEVEN, (int8_t) (0x0001 & CP1CTL1));
            }
        #endif
            {
            __bis_SR_register(LPM3_bits | GIE); // Enter LPM3 w/interrupt
            __no_operation();                   // For debug
            }
    }
}

// Timer B0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER0_B0_VECTOR
__interrupt void Timer_B(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER0_B0_VECTOR))) Timer_B (void)
#else
#error Compiler not supported!
#endif
{

    __bic_SR_register_on_exit(LPM3_bits);   // Exit LPM3
}

// Port 4 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT4_VECTOR
__interrupt void Port_4(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT1_VECTOR))) Port_3 (void)
#else
#error Compiler not supported!
#endif
{
          P4IFG &= ~BIT1;                         // Clear P4.1 IFG
          P4IFG &= ~BIT0;                         // Clear P4.0 IFG
          P6OUT ^= BIT6;                          // Toggle LED1
          __bic_SR_register_on_exit(LPM0_bits);   // Exit LPM0
}


// Port 2 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT1_VECTOR))) Port_2 (void)
#else
#error Compiler not supported!
#endif
{
    P2IFG &= ~BIT3;                         // Clear P2.3 IFG
    P6OUT ^= BIT6;                          // Toggle LED1
    __bic_SR_register_on_exit(LPM3_bits);   // Exit LPM3
}

// Port 3 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT3_VECTOR
__interrupt void Port_3(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT4_VECTOR))) Port_4 (void)
#else
#error Compiler not supported!
#endif
{
    P3IFG &= ~BIT0;                         // Clear P3.0 IFG
    P6OUT ^= BIT6;                          // Toggle LED1
    __bic_SR_register_on_exit(LPM0_bits);   // Exit LPM0
}

// ADC interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC_VECTOR
__interrupt void ADC_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC_VECTOR))) 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:
            ADC_Result = ADCMEM0;
            __bic_SR_register_on_exit(LPM0_bits);            // Clear CPUOFF bit from LPM0
            break;
        default:
            break;
    }
}


// I2C ISR
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCIB0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
  {
    case USCI_NONE: break;                  // Vector 0: No interrupts
    case USCI_I2C_UCALIFG: break;           // Vector 2: ALIFG
    case USCI_I2C_UCNACKIFG:                // Vector 4: NACKIFG
      UCB0CTL1 |= UCTXSTT;                  // I2C start condition
      break;
    case USCI_I2C_UCSTTIFG: break;          // Vector 6: STTIFG
    case USCI_I2C_UCSTPIFG: break;          // Vector 8: STPIFG
    case USCI_I2C_UCRXIFG3: break;          // Vector 10: RXIFG3
    case USCI_I2C_UCTXIFG3: break;          // Vector 14: TXIFG3
    case USCI_I2C_UCRXIFG2: break;          // Vector 16: RXIFG2
    case USCI_I2C_UCTXIFG2: break;          // Vector 18: TXIFG2
    case USCI_I2C_UCRXIFG1: break;          // Vector 20: RXIFG1
    case USCI_I2C_UCTXIFG1: break;          // Vector 22: TXIFG1
    case USCI_I2C_UCRXIFG0:                 // Vector 24: RXIFG0
      RXData = UCB0RXBUF;                   // Get RX data
      __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
      break;
    case USCI_I2C_UCTXIFG0: break;          // Vector 26: TXIFG0
    case USCI_I2C_UCBCNTIFG:                // Vector 28: BCNTIFG
      P1OUT ^= BIT0;                        // Toggle LED on P1.0
      break;
    case USCI_I2C_UCCLTOIFG: break;         // Vector 30: clock low timeout
    case USCI_I2C_UCBIT9IFG: break;         // Vector 32: 9th bit
    default: break;
  }
}

// RTC interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=RTC_VECTOR
__interrupt void RTC_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(RTC_VECTOR))) RTC_ISR (void)
#else
#error Compiler not supported!
#endif
{
    switch(__even_in_range(RTCIV,RTCIV_RTCIF))
    {
        case  RTCIV_NONE:   break;          // No interrupt
        case  RTCIV_RTCIF:                  // RTC Overflow
            P1OUT ^= BIT0;                  // Toggle LED1
            Send_Data=1;                    // Send ADC data via UART
            break;
        default: break;
    }
}

