/*
 * UART.c
 *
 *  Created on: Dec 8, 2016
 *      Author: B50961
 */

#include "device.h"
#include "derivative.h"
#include "UART.h"
#include "Interrupt.h"
#include "TPM.h"


#define SOPT2_UART0_MCGFLLCLK	1
#define UART_C5_BOTHEDGE_SHIFT	1
#define UART_S1_TDRE_MASk		(0x80)

uint8_t UART0_Rx_Buffer[UART_NB_BYTES_TO_RECEIVE];

volatile uint8_t UART0_RxBufferFull = 0;

void Init_UART0_General (void)
{
		uint8_t dummy;

	   /* Setup Clock Source for UART 0
	    * Select clock source to be MCGFLLCLK
	    * (we are in FEE mode with MCGFLLCLK=20.9MHz)
	    */
	   SIM_SOPT2 |= (SIM_SOPT2_UART0SRC(SOPT2_UART0_MCGFLLCLK));

	   /* Enable UART0 clock */
	   SIM_SCGC4 |= SIM_SCGC4_UART0_MASK;

	    /* Setup Port Control Register for RX pin */
	   gUART0_RX_PCR_REG_c = PORT_PCR_MUX(gUART0_PORT_MUX_c);

	    /* Setup Port Control Register for TX pin */
	   gUART0_TX_PCR_REG_c = PORT_PCR_MUX(gUART0_PORT_MUX_c);

	   /* Disable transceiver to do the configuration */
	   UART0_DISABLE_RECEPTION;
	   UART0_DISABLE_TRANSMISSION;

	   /* Configure BDH and BDL */
	   UART0_BDH = 0x00; // Keep default value for now
	   UART0_BDL = 0x04; // Keep default value for now

	   /* Configure C1 register */
	   UART0_C1 = 0x00; // 8-bit Mode ; No parity

	   /* Configure C2 register */
	   UART0_C2 = 0x00; // Disable all interrupts for now

	   /* Clear all flags */
	  // UART0_S1 = 0x1F; // w1c
	   UART0_S2 = 0x00;

	   /* Configure C3 register */
	   UART0_C3 = 0x00; // Keep default configuration

	   /* Configure C4 register */
	   UART0_C4 = 0x0F; // Disable Match Address ; OSR=16 (default)

	   /* Configure C5 register */
	   UART0_C5 = 0x00; // BOTHEDGE=0 as OSR=16 (BOTHEDGE must be set when 0SR is between 4 and 7


	    /* Enables the interrupts corresponding to UART_0 driver */
	    NVIC_EnableIRQ(UART0_IRQn);
	    NVIC_SetPriority(UART0_IRQn, UART0_INTERRUPT_PRIORITY);

	   // Init RX interrupts
	   // UART0_C3 |= UART0_C3_ORIE_MASK; // Implement later if useful
	    UART0_C2 |= UART0_C2_RIE_MASK;

	    /* Variable used in Rx ISR */
	    UART0_RxBufferFull = 0;

	    /* Read Rx buffer to clear the flags */
		dummy = UART0_D;

}

void UART0_SetBaudRate(uint8_t baudrate)
{

	/* Disable transceiver to do the configuration */
    UART0_DISABLE_RECEPTION;
    UART0_DISABLE_TRANSMISSION;

    switch (baudrate)
    {
		case (UART_BAUD_RATE_9600):
			UART0_C4 = 0x0F;
			UART0_C5 &= ~(1 << UART0_C5_BOTHEDGE_SHIFT); // OSR=F, disable BOTHEDGE as recommended
			UART0_BDH = 0x00;
			UART0_BDL = 0x88;
			break;

		case (UART_BAUD_RATE_19200):
			UART0_C4 = 0x0A;
			UART0_C5 &= ~(1 << UART0_C5_BOTHEDGE_SHIFT); // OSR=A, disable BOTHEDGE as recommended
			UART0_BDH = 0x00;
			UART0_BDL = 0x63;
			break;

		case (UART_BAUD_RATE_115200):
			UART0_C4 = 0x07;
			UART0_C5 |= (1 << UART0_C5_BOTHEDGE_SHIFT); // OSR=7, enable BOTHEDGE as recommended
			UART0_BDH = 0x00;
			UART0_BDL = 0x18; // Adjusted from 0x17 to 0x18
			break;

		default: // 115200
			UART0_C4 = 0x07;
			UART0_C5 |= (1 << UART0_C5_BOTHEDGE_SHIFT); // OSR=7, enable BOTHEDGE as recommended
			UART0_BDH = 0x00;
			UART0_BDL = 0x18;
			break;

    }

    return;
}

void UART0_TransmitBuffer(uint8_t *UART_Tx_Buffer , uint8_t nb_bytes)
{
	uint8_t dummy;
	uint8_t transmitted_bytes;

	transmitted_bytes = 0;

	UART0_DISABLE_RECEPTION;
	UART0_ENABLE_TRANSMISSION;

	// Clear the flags
	dummy = UART0_S1;

	while (transmitted_bytes < nb_bytes)
	{
		UART0_D = UART_Tx_Buffer[transmitted_bytes];
		while ((UART0_S1 & UART_S1_TDRE_MASk) != UART_S1_TDRE_MASk);

		transmitted_bytes ++;
	}

	UART0_DISABLE_TRANSMISSION;
	UART0_ENABLE_RECEPTION;

	return;
}



/****************************************
 * Interrupt handler
 * Only Rx interrupt is enabled
 ***************************************/
void UART0_IRQHandler ()
{
	static uint8_t nb_bytes_received = 0;
	uint8_t dummy;

	if (UART0_RxBufferFull == 0)
	{

		UART0_Rx_Buffer[nb_bytes_received++] = UART0_D;

		if (nb_bytes_received >= UART_NB_BYTES_TO_RECEIVE)
		{
			UART0_RxBufferFull = 1;
			nb_bytes_received = 0;

		} else {
			UART0_RxBufferFull = 0;
		}

	} else {
		dummy = UART0_D;
		nb_bytes_received = 0;
	}
/*
 * First solution is better because it saves the Rx buffer until we are done with it
 * (in case we are were occupied somewhere else)
 */
/*
	UART0_RxBufferFull = 0;

	UART0_Rx_Buffer[nb_bytes_received++] = UART0_D;

	if (nb_bytes_received >= UART_NB_BYTES_TO_RECEIVE)
	{
		UART0_RxBufferFull = 1;
		nb_bytes_received = 0;

	} else {
		UART0_RxBufferFull = 0;
	}
*/
}

