#include <string.h>
#include <stdlib.h>
#include "application.h"
#include "globals.h"
#include "strutil.h"
#include "diag.h"
#include "usart_handler.h"
#include "crc_handler.h"
#include "console_handler.h"
#include "memcpy_dma.h"

#define PACKAGE_DELAY_MS 0
#define STATS_DELAY_MS 1000

//	USART	DMA	RX	TX
//	1		2	2	7
//	2		1	5	6
//	3		1	1	3
//	6		2	1	6
// console USART
//	4		1	2	4

void MainLoop()
{
	uint8_t const text2Send[]  __attribute__((aligned(4))) =
			"Megszentsegtelenithetetlensegeskedeseitekert\r\n"
			"--------------------------------------------\r\n\0\0\0";

	struct initdata_t {
		USART_TypeDef* uart;
		DMA_TypeDef* dma;
		uint32_t stream_rx;
		uint32_t stream_tx;
	} static const initdata[] = {
		{ USART1, DMA2, LL_DMA_STREAM_2, LL_DMA_STREAM_7 },
		{ USART2, DMA1, LL_DMA_STREAM_5, LL_DMA_STREAM_6 },
		{ USART3, DMA1, LL_DMA_STREAM_1, LL_DMA_STREAM_3 },
		{ USART6, DMA2, LL_DMA_STREAM_1, LL_DMA_STREAM_6 },
	};

	uint32_t lastStatsTick = 0;
	uint32_t prevSentTick = 0;
	uint8_t	statId = 0;

	uint32_t	tmp = sizeof(text2Send) - 1;
	uint32_t	randmask = 0x80000000;
	do
		if(randmask & tmp)
			break;
	while((randmask = randmask >> 1));
	randmask -= 1;

	for(uint16_t idx = 0; idx < sizeof(g_uartStatuses) / sizeof(g_uartStatuses[0]); ++idx) {
		struct initdata_t const *id = &initdata[idx];
		InitUartStatus(&g_uartStatuses[idx], id->uart, id->dma, id->stream_rx, id->stream_tx,
				&g_crcStatus, idx + USARTCOUNT, idx, NULL, NULL);
		memcpy(GetTxBuffer(&g_uartStatuses[idx]), text2Send, sizeof(text2Send) -1);
	}

	InitCrcStatus(&g_crcStatus, DMA2, LL_DMA_STREAM_4);

	InitDmaInfo(&g_ConsoleTxDmaInfo, CONSOLE_DMA_ENGINE, CONSOLE_TX_DMA_STREAM);
	LL_DMA_EnableIT_TC(g_ConsoleTxDmaInfo.dma, g_ConsoleTxDmaInfo.stream);

	InitMemcpyDma(MEMCPY_DMA_ENGINE, MEMCPY_DMA_STREAM);

	lastStatsTick = HAL_GetTick();

	for(uint16_t idx = 0; idx < sizeof(g_uartStatuses) / sizeof(g_uartStatuses[0]); ++idx)
		SetupReceive(&g_uartStatuses[idx]);

	for(;;) {
		uint32_t tick = HAL_GetTick();
		uint8_t	send = PACKAGE_DELAY_MS ? (tick - prevSentTick > PACKAGE_DELAY_MS) : 1;
		if(send)
			prevSentTick += PACKAGE_DELAY_MS;

		for(uint16_t idx = 0; idx < sizeof(g_uartStatuses) / sizeof(g_uartStatuses[0]); ++idx) {
			if(!g_uartStatuses[idx].txBuffer.busy && send) {
				DIAG_ENTER_BUSY();
				PostPacket(&g_uartStatuses[idx], text2Send, sizeof(text2Send) - 1 - (rand() & randmask), &g_crcStatus);
				DIAG_EXIT_BUSY();
			}
			for(uint16_t rIdx = 0; rIdx < 2; ++rIdx)
				if(g_uartStatuses[idx].rxBuffers[rIdx].busy || g_uartStatuses[idx].rxBuffers[rIdx].error) {
					DIAG_ENTER_BUSY();
					ConsumePacket(&g_uartStatuses[idx], rIdx, &g_crcStatus);
					DIAG_EXIT_BUSY();
				}
		}
		if(tick - lastStatsTick > STATS_DELAY_MS) {
			PrintStats((char*)g_statsBuf, statId, &g_uartStatuses[statId].stats, UART4, &g_ConsoleTxDmaInfo);
			lastStatsTick += STATS_DELAY_MS;
			++statId;
			if(statId >= USARTCOUNT)
				statId = 0;
		}
		uint32_t ein = LL_GPIO_ReadInputPort(KEY1_GPIO_Port);
		if(!(ein & KEY1_Pin)) {
			void (*fptr)(void) = (void (*)(void))(void*)0xa0000000;
			fptr();
		}
	}
}
