#include <cstdio>
#include <cstdint>

#include "system_stm32h7xx.h"
#include "tim.h"

#include "fan_thread.h"
#include "utils.h"

static constexpr unsigned INPUT_BUF_SIZE = 512U;  // Must be dev by 4
static constexpr ULONG ONE_SHOT_TIMER = 0U;
static constexpr ULONG TIMER_PERIOD_MS = 20U;

alignas(32) static unsigned ibuf[INPUT_BUF_SIZE]								__attribute__((section(".DTCM_RAM")));
//alignas(32) static char obuf[INPUT_BUF_SIZE]									__attribute__((section(".RAM1")));

static volatile uint32_t rawCnt;

//TX_EVENT_FLAGS_GROUP fanEG;
static TX_TIMER timer;
static char timer_name[] = "IC overflow timer";


//------------------------------------------------------------------------------

static VOID icTimeout(ULONG);

//------------------------------------------------------------------------------

VOID fanThread(ULONG initial_input)
{
	(void)initial_input;
	//extern DMA_HandleTypeDef hdma_tim8_ch1;
	extern TX_THREAD fan_thread;

	// Compute the value of ARR register to generate signal frequency at 25Khz
	//uint32_t uwTimerPeriod = (uint32_t)((SystemCoreClock/2 /25000) - 1);

	//__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 200);
	//htim3.Instance->CCR2 = U;
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
	//HAL_TIM_IC_Start(&htim3, TIM_CHANNEL_1);


	//auto start = __HAL_TIM_GET_COMPARE(&htim3, TIM_CHANNEL_2);
	//auto end = __HAL_TIM_GET_AUTORELOAD(&htim3) - 300;

	//tx_event_flags_create(&fanEG, (char*)"FAN TACHO event group");
	//ULONG actual_flags;

	tx_timer_create(&timer, timer_name, icTimeout, 0, TIMER_PERIOD_MS, ONE_SHOT_TIMER, TX_NO_ACTIVATE);

	while(1)
	{
		for (auto i = 0U; i < INPUT_BUF_SIZE; i++)
		{
			HAL_TIM_IC_Start_IT(&htim8, TIM_CHANNEL_1);//, (uint32_t*)ibuf, INPUT_BUF_SIZE);
			tx_timer_change(&timer, TIMER_PERIOD_MS, ONE_SHOT_TIMER);
			tx_timer_activate(&timer);
			//__HAL_DMA_DISABLE_IT(&hdma_tim8_ch1, DMA_IT_HT);

			tx_thread_suspend(&fan_thread);
			//tx_event_flags_get(&fanEG, 1, TX_AND_CLEAR, &actual_flags, TX_WAIT_FOREVER);

			//printf("%u, ", rawCnt);
			ibuf[i] = rawCnt;
		}

		unsigned sum = 0;
		for (auto i = 0U; i < INPUT_BUF_SIZE; i += 4)
		{
			unsigned tmp = 0;
			for (auto j = 0U; j < 4U; j++)
				tmp += ibuf[i + j];
			sum += tmp;
		}

		sum /= (INPUT_BUF_SIZE / 4U); // T = T1 + T2 + T3 + T4

		uint32_t div = htim8.Instance->PSC + 1;
		uint32_t clockHz = SystemCoreClock / div;
		//uint32_t arr = htim8.Instance->ARR + 1;

		uint32_t rpm;
		if (sum) rpm  = (60U * clockHz) / sum;
		else rpm = 0;
		printf("RPM = %u\n", rpm);


		//SCB_InvalidateDCache_by_Addr((uint32_t*)ibuf, INPUT_BUF_SIZE);


		/*for (auto i = start; i < end; i++)
		{
			__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, i);
			tx_thread_sleep(10);
		}

		for (auto i = end; i > start; i--)
		{
			__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, i);
			tx_thread_sleep(10);
		}*/

		//while(__HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__));
		//HAL_DMA_PollForTransfer()

		//tx_thread_sleep(1);
	}
}

//------------------------------------------------------------------------------

void pulseMeasured(void)
{
	extern TX_THREAD fan_thread;
	//static uint32_t lastTime;
	/*extern DMA_HandleTypeDef hdma_tim3_ch1;
	SCB_InvalidateDCache_by_Addr((uint32_t*)ibuf, INPUT_BUF_SIZE);
	memcpy(obuf, ibuf, INPUT_BUF_SIZE);
	HAL_TIM_IC_Start_DMA(&htim3, TIM_CHANNEL_1, (uint32_t*)ibuf, INPUT_BUF_SIZE);
	__HAL_DMA_DISABLE_IT(&hdma_tim3_ch1, DMA_IT_HT);*/
	//printf("\t\t\t\t\t\t%u - %u\n", htim3.Instance->CCR1, HAL_GetTick() - lastTime);
	//__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_CC1OF);
	//lastTime = HAL_GetTick();

	tx_timer_deactivate(&timer);

	rawCnt = HAL_TIM_ReadCapturedValue(&htim8, TIM_CHANNEL_1);
	//tx_event_flags_set(&fanEG, 1, TX_OR);

	/*SCB_InvalidateDCache_by_Addr((uint32_t*)ibuf, INPUT_BUF_SIZE);

	for (auto i = 0U; i < INPUT_BUF_SIZE; i++)
	{
		printf("%u,", ibuf[i]);
	}*/
	//printf("%u\n", HAL_GetTick());

	tx_thread_resume(&fan_thread);
}

//------------------------------------------------------------------------------

static VOID icTimeout(ULONG)
{
	extern TX_THREAD fan_thread;
	rawCnt = 0;
	HAL_TIM_IC_Stop_IT(&htim8, TIM_CHANNEL_1);
	tx_thread_resume(&fan_thread);
}