/**
 * @email support.ele@noritake.com
 * @website www.noritake-elec.com
 * @version v2.3
 * @ide Code Composer Studio
 * @brief UART library for MSP430 and Noritake GT-CP modules.
 *
 * @verbatim
 * Provide the UART interface between MSP430 and Noritake GT-CP modules.
 * Compatible hosts:
 * - MSP430F5529
 * - MSP430FR6989
 * @endverbatim
 *
 *
 * Wiring Reference | MSP430F5529:
 * RESET(Pin 1)     -> P1.5
 * RxD(Pin 3)       -> P3.3 (TX)
 * MBUSY/DTR(Pin 4) -> P4.0
 * HBUSY/DSR(Pin 5) -> P2.6
 * TxD(Pin 6)       -> P3.4 (RX)
 *
 * Wiring Reference | MSP430FR6989:
 * RESET(Pin 1)     -> P2.2
 * RxD(Pin 3)       -> P2.0 (TX)
 * MBUSY/DTR(Pin 4) -> P4.0
 * HBUSY/DSR(Pin 5) -> P2.6
 * TxD(Pin 6)       -> P2.1 (RX)
 */

#include "GTCP_UART.h"

/**
 * Initializes the UART interface for MSP430 to communicate with a Noritake
 * GT-CP series modules.
 *
 * @return none
 */
void initUART()
{
	WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer

	resetUSCIStateMachine_UART();

	initRESET();
	configureUARTGPIO();
	configureUART();

	initUSCIStateMachine_UART();

	clearHBUSY();
	__delay_cycles(10000); // Approx. 10ms delay to stabilize the MSP340 clock
}

/**
 * Put USCI in reset state.
 *
 * @return none
 */
void resetUSCIStateMachine_UART()
{
#ifdef __MSP430F5529__
    UCA0CTL1 |= UCSWRST; // Put state machine in reset
#elif defined __MSP430FR6989
    UCA0CTLW0 |= UCSWRST;
#endif
}

/**
 * Release USCI reset state.
 * Can also be seen as USCI initialize.
 *
 * @return none
 */
void initUSCIStateMachine_UART()
{
#ifdef __MSP430F5529__
    UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine
#elif defined __MSP430FR6989
    UCA0CTLW0 &= ~UCSWRST;
#endif
}

/**
 * Configure UART register settings.
 *
 * @return none
 */
void configureUART()
{
#ifdef __MSP430F5529__
    UCA0CTL1 |= UCSSEL_2; // Select SMCLK
    UCA0BR0 = 27; // 1MHz 38400
    UCA0BR1 = 0; // 1MHz 38400
    UCA0MCTL |= UCBRS_1 + UCBRF_0; // Modulation UCBRSx = 2, UCBRFx = 0
#elif defined __MSP430FR6989
    // Startup clock system with max DCO setting ~8MHz
    CSCTL0_H = CSKEY >> 8;                    // Unlock clock registers
    CSCTL1 = DCOFSEL_3 | DCORSEL;             // Set DCO to 8MHz
    CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers
    CSCTL0_H = 0;                             // Lock CS registers

    /**
     * UCOS16 = 1
     * UCBRx = 13
     * UCBRFx = 0
     * UCBRSx = 0x84
     */
    UCA0CTLW0 |= UCSSEL__SMCLK; // Select SMCLK
    UCA0BRW = 13;
    UCA0MCTLW |= UCOS16 | UCBRF0 | 0x8400;
#endif
}

/**
 * Configure GPIO settings for UART.
 *
 * @return none
 */
void configureUARTGPIO()
{
#ifdef __MSP430F5529__
    P3SEL |= BIT3 + BIT4; // Set P3.4 and P3.3 to RX and TX respectively
	P3DIR &= ~BIT4; // Set P3.4 as an input
	P2DIR |= BIT6; // Set P2.6 for HBUSY/DSR output
	P4DIR &= ~BIT0; // Set P4.0 for MBUSY/DTR input
#elif defined __MSP430FR6989
	/**
	 * Set UART pints to UCA0
	 * P2.0 (TXD)
	 * P2.1 (RXD)
	 */
	P2SEL0 |= BIT0 | BIT1;
	P2SEL1 &= ~(BIT0 | BIT1);

	P2DIR |= BIT6; // Set P2.6 for HBUSY/DSR output
	P4DIR &= ~BIT0; // Set P4.0 for MBUSY/DTR input

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

/**
 * Set the HBUSY signal HIGH.
 *
 * @return none
 */
void setHBUSY()
{
    P2OUT |= BIT6;
}

/**
 * Clear the HBUSY signal.
 *
 * @return none
 */
void clearHBUSY()
{
    P2OUT &= ~BIT6;
}

/**
 * Wait until MBUSY is clear(0) or LOW.
 *
 * @return none
 */
void waitMBUSYClear()
{
#ifdef __MSP430F5529__
    while(P4IN & BIT0); //Check MBUSY
#elif defined __MSP430FR6989
    while(P4IN & BIT0); //Check MBUSY
#endif
}

/**
 * Wait until the transmit buffer is clear/empty.
 *
 * @return none
 */
void waitTXBUFClear()
{
    while(!(UCA0IFG & UCTXIFG));

}

/**
 * Wait until a complete character is in the
 * receive buffer.
 *
 * @return none
 */
void waitRXBUFByte()
{
    while(!(UCA0IFG & UCRXIFG)); // Check for a complete character
}

/**
 * Sends a byte of data.
 *
 * @return none
 */
void writeUART(uint8_t data)
{
	waitMBUSYClear();
	waitTXBUFClear();
	UCA0TXBUF = data;
}

/**
 * Sends an array of bytes.
 *
 * @param  data The text string to be transmitted.
 * @return none
 */
void writeStringUART(unsigned char* data)
{
	writeArrayUART(data, arraySize(data));
}

/**
 * Write an array of data to the display module.
 *
 * @param data The data array to write.
 * @param size The size of the data array.
 * @return none
 */
void writeArrayUART(unsigned char* data, int size)
{
	for(unsigned int i = 0; i < size; i++)
	{
		writeUART(data[i]);
	}
}

/**
 * Reads in a byte of data.
 *
 * @return The byte of data read from the device.
 */
uint8_t readUART()
{
	waitRXBUFByte();
	return UCA0RXBUF;
}

/**
 * Read multiple bytes in.
 *
 * @param length Number of bytes to read.
 * @return none
 */
void readUARTMultiple(int length)
{
    for(unsigned int i = 0; i < length; i++)
    {
        RXDataArray[i] = readUART();
    }
}
