/* --COPYRIGHT--,BSD
 * Copyright (c) 2015, 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--*/
/**********************************************************************
 *
 * Demo_Host.c
 *
 * This host program interfaces to the F66xx board running
 * RTC_B_with_Backup_driverlib. It controls DVcc provided to the F66x
 * target board and relays information back to the PC via UART.
 *
 **********************************************************************/
#include "driverlib.h"

#define VCC_OFF 0
#define VCC_ON	1

//#defines are used for pins for easier porting

//VCC controlled by P2.0
#define VCC_OUT 	P2OUT
#define VCC_DIR 	P2DIR
#define VCC_PIN 	BIT0

//RED LED = P1.0
//GREEN LED = P4.7
#define RED_LED_OUT 	P1OUT
#define RED_LED_DIR 	P1DIR
#define GREEN_LED_OUT 	P4OUT
#define GREEN_LED_DIR 	P4DIR
#define RED_LED			BIT0
#define GREEN_LED 		BIT7

//Button S1 on P2.1
#define BUTTON_OUT 	P2OUT
#define BUTTON_DIR 	P2DIR
#define BUTTON_IFG 	P2IFG
#define BUTTON_IE 	P2IE
#define BUTTON_IES	P2IES
#define BUTTON_REN 	P2REN
#define BUTTON_PIN 	BIT1

//UART 0 = Receive data from F6xx
//P3.3 = TXD
//P3.4 = RXD
//connect these pins to the F6xx
#define UART0_PORT_DIR		P3DIR
#define UART0_PORT_SEL		P3SEL
#define UART0_TXD_PIN		BIT3
#define UART0_RXD_PIN		BIT4

//UART 1 = Transmit data to PC through backchannel UART
//P4.4 = TXD
//P4.5 = RXD
#define UART1_PORT_DIR		P4DIR
#define UART1_PORT_SEL		P4SEL
#define UART1_TXD_PIN		BIT4
#define UART1_RXD_PIN		BIT5

//strings for messages
#define STARTUP_STRING_LENGTH 44
const unsigned char StartupString[STARTUP_STRING_LENGTH] = "Program start. Press button to enable Vcc.\r\n";
#define VCCON_STRING_LENGTH 9
const unsigned char VccOnString[VCCON_STRING_LENGTH] = "Vcc On.\r\n";
#define VCCOFF_STRING_LENGTH 10
const unsigned char VccOffString[VCCOFF_STRING_LENGTH] = "Vcc Off.\r\n";

//state and string variables
unsigned char state = VCC_OFF;
unsigned char buttonPress = 0;
unsigned char stringReceived = 0;
unsigned char RXData[45] = {0};
unsigned char i = 0;
unsigned char stringLength = 0;

void transmitString(unsigned char* stringArray, unsigned char strLen);

void main(void)
{
    WDT_A_hold(WDT_A_BASE);

    PMM_setVCore(PMM_CORE_LEVEL_1);
    UCS_initFLLSettle(8000, 244);

    //set up P2.1 button
    BUTTON_DIR &= ~BUTTON_PIN;
    BUTTON_OUT |= BUTTON_PIN;
    BUTTON_REN |= BUTTON_PIN;
    BUTTON_IES |= BUTTON_PIN;
    BUTTON_IFG &= ~BUTTON_PIN;
    BUTTON_IE |= BUTTON_PIN;

    //P2.0 control vcc
    VCC_OUT &= ~VCC_PIN;
    VCC_DIR |= VCC_PIN;

    //P1.0 = red LED - means not outputting Vcc
    RED_LED_DIR |= RED_LED;
    RED_LED_OUT |= RED_LED; //start on
    //P4.7 = green LED - means outputting Vcc
    GREEN_LED_DIR |= GREEN_LED;
    GREEN_LED_OUT &= ~GREEN_LED; //start off

    //UCA1 = TX to PC through backchannel UART
    UART1_PORT_SEL |= UART1_RXD_PIN | UART1_TXD_PIN;

    //UCA0 = RX from F6xx
    UART0_PORT_SEL |= UART0_RXD_PIN | UART0_TXD_PIN;

    //Baudrate = 9600, clock freq = 8MHz
    //UCBRx = 833, UCBRFx = 0, UCBRSx = 2, UCOS16 = 0
    USCI_A_UART_initParam param = {0};
    param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
    param.clockPrescalar = 833;
    param.firstModReg = 0;
    param.secondModReg = 2;
    param.parity = USCI_A_UART_NO_PARITY;
    param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
    param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
    param.uartMode = USCI_A_UART_MODE;
    param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;

    USCI_A_UART_init(USCI_A0_BASE, &param);
    USCI_A_UART_init(USCI_A1_BASE, &param);

    USCI_A_UART_enable(USCI_A0_BASE);
    USCI_A_UART_enable(USCI_A1_BASE);

    //receiving on USCI_A0
    USCI_A_UART_clearInterruptFlag(USCI_A0_BASE,
                                    USCI_A_UART_RECEIVE_INTERRUPT);
    // Enable USCI_A0 RX interrupt
    USCI_A_UART_enableInterrupt(USCI_A0_BASE,
                                 USCI_A_UART_RECEIVE_INTERRUPT);      // Enable interrupt

    //send message to PC indicating program start
    transmitString((unsigned char*)StartupString, STARTUP_STRING_LENGTH);

    while(1)
    {
    	__bis_SR_register(LPM0_bits + GIE);
    	__no_operation();

    	//state machine
    	if(buttonPress)
    	{
			if(state == VCC_OFF)
			{
				state = VCC_ON;

				//enable F6xx TX/RX pins to receive messages
				UART0_PORT_SEL |= UART0_RXD_PIN | UART0_TXD_PIN;

				//Set Vcc pin high to restore Vcc power
				VCC_DIR |= VCC_PIN;
				VCC_OUT |= VCC_PIN;

				//set LEDs indicating Vcc off
				GREEN_LED_OUT |= GREEN_LED;
				RED_LED_OUT &= ~RED_LED;

				//transmit message indicating VCC is now on
			    transmitString((unsigned char*)VccOnString, VCCON_STRING_LENGTH);
			}
			else
			{
				state = VCC_OFF;

				//disable F6xx TX/RX pins to not back-power the part
				UART0_PORT_SEL &= ~(UART0_RXD_PIN | UART0_TXD_PIN);

				//disable Vcc pin to go to backup power
				VCC_DIR &= ~VCC_PIN;
				VCC_OUT &= ~VCC_PIN;

				//set LEDs indicating Vcc off
				RED_LED_OUT |= RED_LED;
				GREEN_LED_OUT &= ~GREEN_LED;

				//transmit message indicating Vcc is now off
			    transmitString((unsigned char*)VccOffString, VCCOFF_STRING_LENGTH);
			}
			buttonPress = 0;
    	}

    	if(stringReceived)
    	{
    		//pass received message on up to PC
    		transmitString(RXData, stringLength);
    		stringReceived = 0; //reset
    	}
    }
}

//function to transmit string back to PC
void transmitString(unsigned char* stringArray, unsigned char strLen)
{
	unsigned char j;
	for(j=0; j<strLen; j++)
		USCI_A_UART_transmitData(USCI_A1_BASE, stringArray[j]);
}

//******************************************************************************
//
//This is the USCI_A0 interrupt vector service routine.
//
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A0_VECTOR)))
#endif
void USCI_A0_ISR(void)
{
    switch(__even_in_range(UCA0IV,4))
    {
		//Vector 2 - RXIFG
		case 2:
			RXData[i] = USCI_A_UART_receiveData(USCI_A0_BASE);
			if(RXData[i] == '\n')	//search for delimiter
			{
				//done receiving string
				stringReceived = 1;
				stringLength = i;
				i = 0;
				//wake to handle string
				__bic_SR_register_on_exit(LPM3_bits);
				__no_operation();
			}
			else
				i++;
			break;
		default: break;
    }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT2_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(PORT2_VECTOR)))
#endif
void PORT2_ISR(void)
{
	//register button press
	buttonPress = 1;
	BUTTON_IFG &= ~BUTTON_PIN; //clear interrupt
	BUTTON_IE &= ~BUTTON_PIN; //disable interrupts

	//timer init for debounce ~250ms
    Timer_A_startUpMode(TIMER_A0_BASE,
    		TIMER_A_CLOCKSOURCE_ACLK,
    		TIMER_A_CLOCKSOURCE_DIVIDER_1,
    		8192,
    		TIMER_A_TAIE_INTERRUPT_DISABLE,
    		TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE,
    		TIMER_A_DO_CLEAR
    		);

    //wake to handle button press
	__bic_SR_register_on_exit(LPM3_bits);
	__no_operation();
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER0_A0_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(TIMER0_A0_VECTOR)))
#endif
void TIMER0_A0_ISR(void)
{
	//debouncing time has expired
	//stop timer
	Timer_A_stop(TIMER_A0_BASE);

	//re-enable button interrupt
	BUTTON_IFG &= ~BUTTON_PIN; //clear interrupt
	BUTTON_IE |= BUTTON_PIN; //re-enable interrupts
}
