/*
 * mainloop.cpp
 *
 *  Created on: Sep 11, 2019
 *      Author: abody
 */

#include <f4ll_cpp/ili9341.h>
#include <application.h>
#include <initializer_list>
#include "main.h"
#include "globals.h"
#include "strutil.h"

#define BORDER 60
#define BARWIDTH 2

using namespace f4ll_cpp;

TaskHandle_t g_handle;
StaticTask_t g_tcb;
StackType_t g_stack[200];

void TaskFn(void * param)
{
	for(;;) {
		vTaskDelay(100);
	}
}

void MainLoop()
{
//	Application	m;
//
//	m.Start();
	g_handle = xTaskCreateStatic(TaskFn, "lofasz", sizeof(g_stack)/sizeof(g_stack[0]),
					nullptr, 5, g_stack, &g_tcb);
}

#define CMD_X_READ  0b10010000
#define CMD_Y_READ  0b11010000


uint8_t SpiIo(SPI_TypeDef *spi, uint8_t data)
{
	while(!LL_SPI_IsActiveFlag_TXE(spi));
	LL_SPI_TransmitData8(spi, data);
	while(!LL_SPI_IsActiveFlag_RXNE(spi));
	return LL_SPI_ReceiveData8(spi);
}

uint16_t ReadTouch(SPI_TypeDef *spi, bool x)
{
	uint16_t tmp;

	LL_GPIO_ResetOutputPin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin);
	SpiIo(spi, x ? CMD_X_READ: CMD_Y_READ);
	tmp = (uint16_t)SpiIo(spi, 0) << 8;
	tmp |= SpiIo(spi, 0);
	LL_GPIO_SetOutputPin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin);

	return tmp >> 3;
}

Application::Application()
: GlobalsInitializer(&m_console)
, Task(3)
, m_console(USART1, DMA2, LL_DMA_STREAM_2, LL_DMA_STREAM_7, this, nullptr)
{
}

void Application::TaskFn(void *taskObj)
{
	static_cast<Application*>(reinterpret_cast<fsl::Task<Application, 1024>*>(taskObj))->Loop();
}

void Application::Loop()
{
	Ili9341Fsmc &lcd(Ili9341Fsmc::Init(nullptr, nullptr, DMA2, LL_DMA_STREAM_4, false));
	lcd.SetScrollMode(true);

	lcd.FillRect(Ili9341Fsmc::ILI9341_BLACK, false);

	LL_SPI_Enable(SPI2);

	for(int i = 0; i < 100; ++i) {
		m_console.SendLine("Lofasz a seggedbe!\r\n");
	}

	for(;;) {
		if(m_lineReceived && m_transmissionCompleted) {
			m_transmissionCompleted = false;
			const char *line = const_cast<const char*>(m_rcvdBuffer->buffer);
			m_console.SendLine(line, m_rcvdBuffer->len);
			lcd.Print(line);
			lcd.Print("\r\n", 2);
			m_lineReceived = false;
			m_rcvdBuffer->busy = false;
		}

		if(LL_GPIO_IsInputPinSet(PENIRQ_GPIO_Port, PENIRQ_Pin))
			LL_GPIO_SetOutputPin(LED1_GPIO_Port, LED1_Pin);
		else {
			LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);

			uint16_t x = ReadTouch(SPI2, true);
			uint16_t y = ReadTouch(SPI2, false);
			unsigned len = strcpy_ex(m_appBuffer, "X: ");
			len += uitodec(m_appBuffer+len, x);
			len += strcpy_ex(m_appBuffer + len, ",  Y: ");
			len += uitodec(m_appBuffer + len, y);
			len += strcpy_ex(m_appBuffer + len, "\r\n");
			lcd.Print(m_appBuffer, len);
			m_console.SendLine(m_appBuffer, len);
		}
	}
}

void Application::LineReceived(void *userParam, SerialConsole<257>::Buffer *buffer)
{
	m_lineReceived = true;
	m_rcvdBuffer = buffer;
}

void Application::TransmissionComplete(void *userParam, SerialConsole<257>::Buffer *buffer)
{
	m_transmissionCompleted = true;
}

