//***************************************************************************************
//  MSP430 Blink the LED Demo - Software Toggle P1.0
//
//  Description; Toggle P1.0 by xor'ing P1.0 inside of a software loop.
//  ACLK = n/a, MCLK = SMCLK = default DCO
//
//                MSP430x5xx
//             -----------------
//         /|\|              XIN|-
//          | |                 |
//          --|RST          XOUT|-
//            |                 |
//            |             P1.0|-->LED
//
//  Texas Instruments, Inc
//  July 2013
//***************************************************************************************
// forward declaration
/*Only use this for the BSL proper*/
static void config_port_pins(void);
void msp430_init(int isbsl);
void inittimer(void);
void delayus(unsigned int delayamt);
void delayms(unsigned int delayamt);
#define TEST_LPM_MODE LPM3_bits
#define DO_WAKE 0

#include <msp430.h>
#include <stdint.h>
#include <cs.h>
#if 0
#define TEST_LPM_MODE LPM3_bits

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;               // Stop watchdog timer
    //PM5CTL0 &= ~LOCKLPM5;
    msp430_init(0);
    inittimer();

    do{
#if DO_WAKE
        delayus(100000);    /* Sleep! */
#else
        __bis_SR_register(TEST_LPM_MODE | GIE);       // Go to sleep -- should be here forever

#endif
    }while(1);

}

#else


void sleep_handler(void);
/**
 * main.c
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;   // stop watchdog timer
    // enable interface level shifters, "zero bits" 3.4 to enable VCC3V_BAT & 3.7 to release ZYNC reset
    //P3OUT |= (PS_MON_SHDN | ZTEMP_SHDN );
    // Set HIGH
    msp430_init(0); // 1 is test example config  -- .0574mA under debug -- ??? without debugger attached
    //msp430_init(1); // Cogs runtime              -- .1391mA under debug .2780 without debug

    //LPM3;    /* Sleep! */

    /* Unreached.  If this code were reached, the LED would stay
     * continuously lit. */
    inittimer();

    do{
#if DO_WAKE
        delayus(0xFFFF);    /* Sleep! */
#endif
    //P4OUT &= ~(BIT1);
    sleep_handler();
    }while(1);

    return 0;
}
#endif

#define PS_MON_SHDN     BIT0
#define UART_LV_SHDN    BIT2    // Port J
#define DEBUG_SHDN      BIT3    // Port J
#define ZTEMP_SHDN      BIT3
#define BATT_SHDN       BIT4
#define ZYNC_RESET      BIT7
void sleep_handler(void)
{
    uint8_t p3Bits;
    p3Bits = P3OUT;
    p3Bits &= ~(ZTEMP_SHDN  | PS_MON_SHDN ); // disable level shifters
    p3Bits |= (ZYNC_RESET | BATT_SHDN ); // assert ZYNC reset, disable VCC3C_BAT
    P3OUT = p3Bits;
    PJOUT &= ~(UART_LV_SHDN);



    /* enter LPM3 (use macro) */
#if DO_WAKE
    delayus(0xFFFF);    /* Sleep! */
#else
    PM5CTL0 &= ~LOCKLPM5;
    CS_turnOffSMCLK();
    __bis_SR_register(TEST_LPM_MODE | GIE);       // Go to sleep -- should be here forever
#endif
    /* we stay right here until we exit from LPM3 */

    /* WAKEUP - execution will (now) return to receiveByte_UART() */
    p3Bits = P3OUT;
    p3Bits |= (ZTEMP_SHDN  | PS_MON_SHDN); // enable level shifters
    p3Bits &= ~(ZYNC_RESET | BATT_SHDN| BATT_SHDN); // assert ZYNC reset, disable VCC3C_BAT
    P3OUT = p3Bits;
    //PJOUT &= (UART_LV_SHDN);
}


static void config_port_pins(void){

  /* I/O Pin configuration section (setting all relevant bits):
   * this section has been optimized by setting all of the bits in
   * each PxSEL0 / PxSEL1 / PxDIR register with single writes -
   * but we are maintaining the code for doing it explicitly to
   * validate the "correctness" of each pin setting
   */

  /* PORT P1 */
  /* Configure P1.0 as Analog Input (A0) for BAT_DETECT*/
  /* Configure P1.1 as Analog Input (A1) for 12v_DETECT*/
  /* Configure P1.2 as Analog Input (A2) for PCIe 12v_DETECT*/
  /* Configure P1.3 as Analog Input (A2) for PCIe 3.3v_DETECT*/
  /* Configure P1.4 as Digital Input for ACC_INT2 */
  /* Configure P1.5 as Digital Input for ACC_INNT1 */
  /* Configure P1.6 & P1.7 as I2C (UCB0) for LCS_I2C_SDA / LSC_I2C_SCL */
#if 0 // .0552 on
    P1OUT = 0;
    P1DIR = 0xFF;
#else
    P1SEL0 = (BIT0 | BIT1 | BIT2 | BIT3);
    P1SEL1 = (BIT0 | BIT1 | BIT2 | BIT3 | BIT6 | BIT7);
    P1DIR = (0xFF & ~(BIT4 | BIT5));
#endif

  /* PORT P2 */
  /* Configure P2.0 & P2.1 as UART (USCIA0) for MSP_TXD / MSP_RXD */
  /* P2.2 not presently used  - configure as Digital Input */
  /* Configure P2.3 as SPI_CS (GPIO Output) */
  /* Configure P2.4, P2.5 & P2.6 as SPI (UCA1) SPI_CLK1_SCL / SPI_MOSI1_SDA / SPI_MISO1 */
  /* Configure P2.7 as Digital Input for PCIE_SLOTDET */
#if 0
    P2OUT = 0;
    P2DIR = 0xFF;
#else
    P2SEL0 = 0;
    P2SEL1 = (BIT0 | BIT1 | BIT4 | BIT5 | BIT6);
    P2DIR = (0xFF & ~(BIT2 | BIT7));
    P2OUT = BIT3;
#endif
  /* PORT P3 */
  /* Configure P3.0 as Digital Output for PS_MON_SHDN- */
  /* Configure P3.1 as Digital Output for UART_LV_SHDN- HW_REV_1  --- as Digital Output for MODE - HW_REV_2*/
  /* Configure P3.2 as Digital Output for DEBUG_SHDN- HW_REV_1    --- as Digital Output for PROVISION- HW_REV_2*/
  /* Configure P3.3 as Digital Output for ZTEMP_SHDN- */
  /* Configure P3.4 as Digital Output for 3V_BARR_SHDN- */
  /* Configure P3.5 as Digital Input for LC2_INT0 */
  /* Configure P3.6 as Digital Output for ZYNC_CLR_BAT HW_REV_1  --- as Digital Input for TMP108_INT HW_REV_2*/
  /* Configure P3.7 as Digital Output for ZYNC_RESET */
  P3SELC = 0;
  P3IES = 0;
  P3DIR = (0xFF & ~(BIT5 | BIT6 ));
  //P3OUT = ((provisioned == 0x42)? BIT2:0); //signal BSLMODE and keep provisioned status.
  //P3OUT |= (provisioned == 0x42)? BIT1:0 ; // if provisioned
  P3OUT &=  ~(BIT2 | BIT3 | BIT4 | BIT7); // BSL mode
  /* PORT P4 */
  /* Configure P4.0 as Digital Output for LCS_EN0 */
  /* Configure P4.1 as Digital Output for LCS_EN1 */
  /* Configure P4.2 as Digital Output for LCS_EN2 */
  /* Configure P4.3 as Digital Input for UCD_ALERT_MSP (and configure as wake-up interrupt for falling edge UCD_ALERT) */
  /* Configure P4.4 as Digital Input for PWR_FAULT_MSP */
  /* Configure P4.5 as Digital Input for LCS_INT1 */
  /* Configure P4.6 as Digital Input for LCS_INT2 */
  /* Configure P4.7 as Digital Input for MAX20734_SMALERT_MSP */
  P4SELC = 0;
  P4DIR = (BIT0 | BIT1 | BIT2);
  P4OUT = 0x00;
  // enable pull-downs for FLEX_TOP & FLEX_BOTTOM shields
  P4REN |= (BIT5 | BIT6);
  P4OUT &= ~(BIT5 | BIT6);

  /* PORT 5 */
  /* Configure P5.0 as I2C (UCB1) for MON_SDA_MSP */
  /* Configure P5.1 as I2C (UCB1) for MON_SCL_MSP */
  /* Configure P5.2 as Digital Input for PWR_PG   */
  /* Configure P5.3 as digital input for PWR_STAT */
  /* Configure P5.4 as Uart (USCIA2) for MSP430_CONSOLE_TXD */
  /* Configure P5.5 as Uart (USCIA2) for SP430_CONSOLE_RXD */
  /* Configure P5.6 as digital input  for ZYNQ_ALERT- */
  /* Configure P5.7 as digital input  for ZYNQ_OVERT- */
  P5SEL0 = (BIT0 | BIT1 | BIT4 | BIT5);
  P5SEL1 = 0;
  P5DIR = (0xFF & ~(BIT2 | BIT3 | BIT6 | BIT7));
  P5OUT = 0;

  /* PORT P6 -- not populated on 54 pin part
  P6SELC = 0;
  P6DIR = 0;
  P6OUT = 0;
  */
  /* PORT 7 */
  /* Configure P7.0 & P7.1 as I2C (UCB2) for PWR_SDA / PWR_SCL */
  /* Configure P7.2 as Digital Input for WDI_INOUT_MSP or MAX20734_STAT or  VCC0V85_PG_MSP*/
  /* Configure P7.3 as Digital Output for PWR_OTG */
  /* Configure P7.4 as Digital Output for PWR_CE- */
  P7SEL0 = (BIT0 | BIT1);
  P7SEL1 = 0;
  P7DIR = (BIT3 | BIT4);
  P7OUT = (BIT3 | BIT4);

  /* PORT P8 */
  /* Configure P8.0 as Digital Input for PWR_INT */
  P8SELC = 0;
  P8DIR = 0;

  /* PORT PJ - reset all port pins (high impedance) GPIO outputs (ULP 4.1) */
  /* Configure Pj.0  CLR_ZYNQ_BAT  */
  /* Configure Pj.1  Not Connected  */
  /* Configure Pj.2  UART_LVL_SHUTDN  */
  /* Configure Pj.3  DEBUG_SHDN */
  /* Configure Pj.4  LFXIN  32.7Khz */
  /* Configure Pj.5  LFXOUT 32.7Khz*/
  /* Configure Pj.6  HFXIN  24Mhz */
  /* Configure Pj.7  HFXOUT 24Mhz*/

  PJOUT=0;
  PJSELC = 0;
  PJSEL0 = BIT4 | BIT5 | BIT6 | BIT7;     // Initialize LFXT & HFXT pins
  PJSELC &= (~BIT0 | BIT1 | BIT2 | BIT3);  // GPIO
  PJDIR |= ( BIT0 | BIT1 | BIT2 | BIT3);   // Outputs

#if 0 // for debug
  PJSEL0 |= BIT0;            // BIT0 = output SMCLK on PJ.0, else GPIO output for debug
  PJDIR |= BIT0;
#endif

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

void lowest_pin_setting(){
    // Configure GPIO
#if 1
    P1OUT = 0;
    P1DIR = 0xFF;
#else
    P1SEL0 = (BIT0 | BIT1 | BIT2 | BIT3);
    P1SEL1 = (BIT0 | BIT1 | BIT2 | BIT3 | BIT6 | BIT7);
    P1DIR = (0xFF & ~(BIT4 | BIT5));
#endif
    P2OUT = 0;
    P2DIR = 0xFF;

    P3OUT = 0;
    P3DIR = 0xFF;
    P3OUT |= (ZYNC_RESET );

    P4OUT = 0;
    P4DIR = 0xFF;

    P5OUT = 0;
    P5DIR = 0xFF;

    P6OUT = 0;
    P6DIR = 0xFF;

    P7OUT = 0;
    P7DIR = 0xFF;

    P8DIR = 0xFF;
    P8OUT = 0;

    PJOUT = 0;
    PJOUT=0;
    PJSELC = 0;
    PJSEL0 = BIT4 | BIT5 | BIT6 | BIT7;     // Initialize LFXT & HFXT pins
    PJDIR=0xFFFF;
    /* Disable the GPIO power-on default high-impedance mode / activate configured port settings */
    PM5CTL0 &= ~LOCKLPM5;
}



void msp430_init(int isbsl){
  /* The I/O config is normally handled by the bootloader, so in the
   * normal (release build of the) app, all we need do here is
   * to reset the clock frequency to 16MHz and setup the FRAM controller
   * in the DEBUG version the pins need to be configured.
   */
  if(isbsl)
  config_port_pins();
  else
   lowest_pin_setting();

  /* This needs to be checked against
   *http://dev.ti.com/tirex/explore/node?node=ALMKUpgS2sr.Sf-qEyGcAQ__IOGqZri__LATEST
   *and
   * https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/609971?MSP430FR5994-Can-t-get-system-to-work-on-16-MHz
   */
#if 1
  /*Set DCO frequency to 16MHz */
  CS_setDCOFreq(CS_DCORSEL_1, CS_DCOFSEL_4);

  /* select DCO as SMCLK source */
  CS_initClockSignal(CS_SMCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);

  /* select DCO as MCLK source */
  CS_initClockSignal(CS_MCLK,CS_DCOCLK_SELECT,CS_CLOCK_DIVIDER_1);
#endif
#if 0
  /*Set FRAM wait state to 1 */
  FRAMCtl_A_configureWaitStateControl(FRAMCTL_ACCESS_TIME_CYCLES_1);
  FRAMCtl_A_clearInterrupt(0x00FF);
#endif
#if 1
  // Configure LFXT 32kHz crystal
  CSCTL0_H = CSKEY_H;                     // Unlock CS registers
  CSCTL4 &= ~LFXTOFF;                     // Enable LFXT
  CSCTL4 |= VLOOFF;
  do
  {
    CSCTL5 &= ~LFXTOFFG;                  // Clear LFXT fault flag
    SFRIFG1 &= ~OFIFG;
  } while (SFRIFG1 & OFIFG);              // Test oscillator fault flag
  CSCTL0_H = 0;                           // Lock CS registers
  /* select LFXT as ACLK source */
  CS_initClockSignal(CS_ACLK,CS_LFXTCLK_SELECT,CS_CLOCK_DIVIDER_1);
#endif
}


void inittimer(void){
    // Initialize Timer0 for a replacement of __delay_cycles once interrupts are enabled
    TA0EX0 = 0x0001; // Divide by 2
    TA0CTL = TASSEL_2 + MC_0 + TACLR + ID_3; // SMCLK, count up to TA0CCR0, Timer clear, Divide by 8
    TA0CCTL0 = CCIE; // TACCR0 interrupt enabled but no effect until Timer0 is running
    __bis_SR_register(GIE); // Enable all interrupts

}
void delayus(unsigned int delayamt)
{

    // Delay is 0-65535 usec; already initialized to use SMCLK, divide by 16 so timer increments once/usec; upon reaching delayamt, one interrupt is given and the delay is over
        TA0CCR0 = delayamt;                     // Interrupt when up-count to this value
        TA0CTL |= (MC_1 | TACLR);
      __bis_SR_register(TEST_LPM_MODE | GIE);       // Go to sleep. Timer0 ISR will wake us up when proper time has elapsed
}
void delayms(unsigned int delayamt)
{

    // Delay is 0-65535 usec; already initialized to use SMCLK, divide by 16 so timer increments once/usec; upon reaching delayamt, one interrupt is given and the delay is over
        TA0CCR0 = 100;                     // Interrupt when up-count to this value
        TA0CTL |= (MC_1 | TACLR);
        while(delayamt > 0){
      __bis_SR_register(TEST_LPM_MODE | GIE);       // Go to sleep. Timer0 ISR will wake us up when proper time has elapsed
        delayamt--;
        }
}
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
    TA0CTL |= MC_0;                             // Stop Timer0
    // __bic_SR_register_on_exit(LPM0_bits);       // Wakeup from LPM0 and continue after the Delayus function
     __bic_SR_register_on_exit(TEST_LPM_MODE);       // Wakeup from LPM0 and continue after the Delayus function
}
