/*
 * ll_testbed.cpp
 *
 *  Created on: Oct 28, 2019
 *      Author: abody
 */
#include <string.h>
#include <stdlib.h>
#include "ll_hsusart.h"
#include "ll_crchandler.h"
#include "ll_testbed.h"
#include "main.h"
extern "C" {
	#include "globals.h"
	#include "strutil.h"
}

#define PACKAGE_DELAY_MS 0
#define STATS_DELAY_MS 1000

f4ll::LL_CrcHandler	*g_crc = nullptr;

f4ll::LL_HsUsart *g_usarts[4];

extern "C" void _HandleCrcDmaIrq(void)
{
	f4ll::LL_CrcHandler::Instance().DmaTransferCompleted();
}

extern "C" void _HandleUsartIrq(int offset)
{
		f4ll::LL_HsUsart::HandleUsartIrq(g_usarts[offset]);
}

extern "C" void _HandleUsartRxDmaIrq(int offset)
{
		f4ll::LL_HsUsart::HandleRxDmaIrq(g_usarts[offset]);
}

extern "C" void _HandleUsartTxDmaIrq(int offset)
{
		f4ll::LL_HsUsart::HandleTxDmaIrq(g_usarts[offset]);
}

#define ADDINFO(b,s,u) \
	b += strcpy_ex(b,s); \
	b += uitodec(b,u);

void _PrintStats(char *buffer, uint8_t id, f4ll::LL_HsUsart &handler, USART_TypeDef *usart, DMAINFO* dmaInfo)
{
	char ids[] = " : ";
	char *bs = buffer;

	f4ll::LL_HsUsart::Stats const & stats(handler.GetStats());

	ids[0] = id + '0';
	buffer += strcpy_ex(buffer, ids);
	ADDINFO(buffer, " s: ", stats.sent);
	ADDINFO(buffer, " r: ", stats.rcvd);
	ADDINFO(buffer, " sk: ", stats.skiped);
	ADDINFO(buffer, " or: ", stats.overrun);
	ADDINFO(buffer, " he: ", stats.hdrError);
//	buffer += strcpy_ex(buffer,",0x");
//	buffer += uitohex(buffer, stats.lastErrHdr, 8);
	ADDINFO(buffer, " pe: ", stats.payloadErrror);
	buffer += strcpy_ex(buffer,",0x");
	buffer += uitohex(buffer, stats.pep1, 8);
	buffer += strcpy_ex(buffer,",0x");
	buffer += uitohex(buffer, stats.pep2, 8);
	ADDINFO(buffer, " de: ", stats.dmaError);
	ADDINFO(buffer, " pmh: ", stats.premature_hdr);
	ADDINFO(buffer, " pmp: ", stats.premature_payload);
	buffer += strcpy_ex(buffer, "\r\n");

	SetupTransmit(usart, dmaInfo->dma, dmaInfo->stream, bs, buffer - bs + 1);
}



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

	f4ll::LL_CrcHandler::Init(DMA2, LL_DMA_STREAM_4);

	f4ll::LL_CrcHandler::TSlot<2> slt;
	f4ll::LL_HsUsart u1{USART1, DMA2, LL_DMA_STREAM_2, LL_DMA_STREAM_7};
	f4ll::LL_HsUsart u2{ USART2, DMA1, LL_DMA_STREAM_5, LL_DMA_STREAM_6 };
	f4ll::LL_HsUsart u3{ USART3, DMA1, LL_DMA_STREAM_1, LL_DMA_STREAM_3 };
	f4ll::LL_HsUsart u6{ USART6, DMA2, LL_DMA_STREAM_1, LL_DMA_STREAM_6 };

	f4ll::LL_HsUsart * usarts[] = { & u1, &u2, &u3, &u6 };
	for(unsigned int i=0; i < sizeof(usarts) / sizeof(usarts[0]); ++i)
		g_usarts[i] = usarts[i];

	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;

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

	lastStatsTick = HAL_GetTick();

	for(auto u : usarts)
		u->SetupReceive();

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

		if(send)
			prevSentTick += PACKAGE_DELAY_MS;

		for(auto u : usarts) {
			if(!u->IsTxBusy() && send) {
				//DIAG_ENTER_BUSY();
				u->PostPacket(text2Send, sizeof(text2Send) - 1 - (rand() & randmask));
				//DIAG_EXIT_BUSY();
			}
			for(uint16_t rIdx = 0; rIdx < 2; ++rIdx)
				if(u->IsRxBusy((bool)rIdx) || u->IsRxFailed(rIdx)) {
					u->RxProcessed((bool)rIdx);
				}
		}
		if(tick - lastStatsTick > STATS_DELAY_MS) {
			_PrintStats((char*)g_statsBuf, statId, *usarts[statId], 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();
		}
	}
}
