#include <cstdint>
#include "hardware/5400tp194.h"
#include "uart_test.h"

static volatile int flag_irq_uart0;
static volatile int flag_irq_uart1;

extern "C"
void uart0IrqHandler() {
	//read data validation
	for (unsigned data = 0; data <= 7; data += 1) {
		unsigned rx0 = UART0->rx;
		while (1) if (data == rx0) break;
		if ((UART0->st & 0b100000000) == 0) break;
	}

	UART0->ctrl = 0;
	UART0->msk = 0;
	UART0->cfg = 0;
	UART0->bdr = 0;

	flag_irq_uart0 = 1;
}

extern "C"
void uart1IrqHandler() {
	//read data validation
	for (unsigned data = 0xF0; data >= 0x80 ; data -= 0x10) {
		unsigned rx1 = UART1->rx;
		while (1) if (data == rx1) break;
		if ((UART1->st & 0b100000000) == 0) break;
	}

	UART1->ctrl = 0;
	UART1->msk = 0;
	UART1->cfg = 0;
	UART1->bdr = 0;

	flag_irq_uart1 = 1;
}

void setting_plic_uart() {
	CMM->apb0clken |= CMM_APB0CLKEN_PLIC;

	PLIC->prio[PLIC_CC_UART0] = 1;
	PLIC->prio[PLIC_CC_UART1] = 1;
	PLIC->cpu.ie = PLIC_IE_UART0 | PLIC_IE_UART1;
	PLIC->le = PLIC_LE_UART0 | PLIC_LE_UART1;
}

void uart_test() {
	setting_plic_uart();

	//clocking on
	uint32_t clken = CMM_APB0CLKEN_UART0 | CMM_APB0CLKEN_UART1;
	CMM->apb0clken |= clken;

	//enabling alternative functions GPIOAs
	uint32_t altfen = GPIOA->altf0 | GPIOA_ALTF0_P8_UART0_TX | GPIOA_ALTF0_P9_UART0_RX | GPIOA_ALTF0_P10_UART0_RTS
					| GPIOA_ALTF0_P11_UART0_CTS | GPIOA_ALTF0_P12_UART1_TX | GPIOA_ALTF0_P13_UART1_RX
					| GPIOA_ALTF0_P14_UART1_RTS | GPIOA_ALTF0_P15_UART1_CTS;
	GPIOA->altf0 |= altfen;


	//interrupt resolution by TI event
	UART0->msk = 0x200;
	UART1->msk = 0x200;

	//setting UART0 & UART1
	UART0->cfg = 0x00000F10;
	UART1->cfg = 0x00000F10;
	UART0->bdr = 1;
	UART1->bdr = 1;

	//buffer filling
	for (uint32_t data = 0xF0; data >= 0x80; data -= 0x10) {
		UART0->tx = data;
	}

	for (uint32_t data = 0; data <= 7; data += 1) {
		UART1->tx = data;
	}

	//modules activation
	UART1->ctrl = 0b100100;
	UART0->ctrl = 0b110100;
	UART1->ctrl = 0b110100;

	while(!flag_irq_uart0 | !flag_irq_uart1);
	flag_irq_uart0 = 0;
	flag_irq_uart1 = 0;

	//clocking off
	CMM->apb0clken &= ~clken;

	//disabling alternative GPIOA functions
	GPIOA->altf0 &= ~altfen;
}
