/*
 * UART0.c
 *
 * Created: Mon May 03 2021 19:57:05
 *  Author Chris
 */
#include "UART0.h"

#include "pico/stdlib.h"
#include "hardware/irq.h"
#include "hardware/uart.h"


// ============================================================================================
// Defines
#define UART_ID 			uart0
/*
	Baudrate is supposed to be 1000000 (1 Mio.). Due to the overclocking and the not adjusted peripeheral clock (See Clock.c)
	a alternative baudrate has to be defined in order to acheive a baudrate of 1000000. The given values has indentified 
	experimentally by measuring via the logic analyzer,
*/
#define BAUD_RATE 			31250u
#define DATA_BITS 			8
#define STOP_BITS 			1
#define PARITY    			UART_PARITY_NONE

#define UART_TX_PIN 		28 // Not connected
#define UART_RX_PIN 		17

#define UART_BUFFER_SIZE	128


// ============================================================================================
// Variables
struct UART_BUFFER_s
{
	uint8_t Data[UART_BUFFER_SIZE];
	uint8_t	Read;
	uint8_t	Write;
} _UART_Buffer;

volatile uint _Actual_Baudrate;


// ============================================================================================
// Function Declarations


/*******************************************************************
	Interrupt Service Routines
*******************************************************************/
void UART0_RX_ISR()
{
    while(uart_is_readable(UART_ID))
	{
       // Fetch the Received Byte
	   _UART_Buffer.Data[_UART_Buffer.Write++] = uart_getc(UART_ID);		
	
		if(_UART_Buffer.Write == UART_BUFFER_SIZE)
		{
			_UART_Buffer.Write = 0;
		}
    }
}


/*******************************************************************
	Functions
*******************************************************************/
void UART0_Init(void)
{
	_UART_Buffer.Read	= 0;
	_UART_Buffer.Write	= 0;
	
	uart_init(UART_ID, 2400);

	// Only Receive is needed for MIDI function
//	gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

	_Actual_Baudrate = uart_set_baudrate(UART_ID, BAUD_RATE);

	// Set UART flow control CTS/RTS, we don't want these, so turn them off
	uart_set_hw_flow(UART_ID, false, false);

	// Set our data format
    uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);

    // Turn off FIFO's - we want to do this character by character
    uart_set_fifo_enabled(UART_ID, false);

    // Select correct interrupt for the UART we are using
    int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;

	// And set up and enable the interrupt handlers
    irq_set_exclusive_handler(UART_IRQ, UART0_RX_ISR);
    irq_set_enabled(UART_IRQ, true);

	// Now enable the UART to send interrupts - RX only
    uart_set_irq_enables(UART_ID, true, false);
}

uint UART0_Get_Actual_Baudrate(void)
{
	return _Actual_Baudrate;
}

void UART0_Send_Byte(uint8_t byte)
{
	while (!uart_is_writable(UART_ID))
	{
		tight_loop_contents();
	}
	
	uart_putc(UART_ID, (char)byte);
}

void UART0_Send_Array(uint8_t* array, uint length)
{
	for(uint16_t i=0;i<length;i++)
	{
		UART0_Send_Byte(array[i]);
	}
}

void UART0_Send_Int_Dec(uint val, uint8_t numbers)
{
	uint8_t 	i;
	uint8_t 	num;
	uint 		Factor = 1;
	
	for(i=0;i<numbers-1;i++)
	{
		Factor *= 10;
	}
	for(i=0;i<numbers;i++)
	{
		num = val / Factor;
		UART0_Send_Byte((uint8_t)('0' + num));
		
		val %= Factor;
		Factor /= 10;
	}
}

void UART0_Send_Int_Hex(uint val, uint8_t numbers, uint8_t Send_0x)
{
	uint8_t i;
	uint8_t Hex_Number;

	if(Send_0x>0)
	{
		UART0_SEND_STRING((uint8_t*)"0x");
	}
	
	for(i=0;i<numbers;i++)
	{
		Hex_Number = (uint8_t)(val >> ((numbers-i-1) * 4)) & 0x0F;
		
		if(Hex_Number < 10)
			Hex_Number = '0' + Hex_Number;
		else
			Hex_Number = 'A' + (Hex_Number - 10);
		
		UART0_Send_Byte((uint8_t)Hex_Number);
	}
}

uint UART0_Data_Available(void)
{
	if(_UART_Buffer.Write >= _UART_Buffer.Read)
	{
		return (_UART_Buffer.Write - _UART_Buffer.Read);
	}
	else
	{
		return ((_UART_Buffer.Write + UART_BUFFER_SIZE) - _UART_Buffer.Read);
	}
}

uint8_t	UART0_Get_Byte(void)
{
	uint8_t Return_Value = 0;
	
	if(UART0_Data_Available() > 0)
	{
		Return_Value = _UART_Buffer.Data[_UART_Buffer.Read++];
		
		if(_UART_Buffer.Read == UART_BUFFER_SIZE)
		{
			_UART_Buffer.Read = 0;
		}
	}
	
	return Return_Value;
}

/*******************************************************************
	Internal Functions
*******************************************************************/