/// © MiroZ 2024

#include "TaskMgr.h"

#include <Arduino.h>
#include <esp_log.h>

static const char * TAG = "taskmgr";

TaskMgr::TaskMgr()
{
	m_xMutex = xSemaphoreCreateMutex();
	assert(m_xMutex);
	ESP_LOGW(TAG, "Starting task manager...");
	
#ifdef TASKMGR_TASK_NAME
	createTask(std::bind(&TaskMgr::task, this), TASKMGR_TASK_NAME, TASKMGR_TASK_STACK_SIZE, TASKMGR_TASK_PRIORITY, TASKMGR_TASK_CORE);
#endif
}

TaskMgr::~TaskMgr()
{
	if(m_xMutex != NULL)
		vSemaphoreDelete(m_xMutex);
}

#ifdef TASKMGR_TASK_NAME
void TaskMgr::task()
{
	while(true)
	{
		delay(TASKMGR_TASK_DELAY);
		getInfo();
	}
}
#endif

TaskMgr & TaskMgr::getInstance()
{
	static TaskMgr taskmgr;
	return taskmgr;
}

TaskHandle_t TaskMgr::createTask(TASK_FUNCTION task_function, const char *name, uint32_t stack_size, UBaseType_t priority, BaseType_t core)
{
	TaskHandle_t task_handle = nullptr;

	if (xSemaphoreTake(m_xMutex, portMAX_DELAY)) 
	{
		m_task_function = task_function;
		xTaskCreatePinnedToCore(taskStarter, name, stack_size, this, priority, &task_handle, core);
		m_tasks.push_back(task_handle);

		xSemaphoreGive(m_xMutex);
	}

	return task_handle;
}

void TaskMgr::deleteTask(TaskHandle_t task)
{
	if(task == nullptr)
		return;

	if (xSemaphoreTake(m_xMutex, portMAX_DELAY)) 
	{
		vTaskDelete(task);
		m_tasks.remove(task);

		xSemaphoreGive(m_xMutex);
	}
}

void TaskMgr::getInfo()
{
	if (xSemaphoreTake(m_xMutex, portMAX_DELAY)) 
	{
		ESP_LOGW(TAG, "Current running tasks:");
		for(auto i : m_tasks)
		{
			const char * name = pcTaskGetName(i);
			uint32_t hwm = (uint32_t)uxTaskGetStackHighWaterMark(i);
			if(hwm < 256)
				ESP_LOGW(TAG, "%10s (%d)", name, hwm);
			else
				ESP_LOGI(TAG, "%10s (%d)", name, hwm);
		}
		ESP_LOGI(TAG, "Free heap: %d", esp_get_free_heap_size());

		xSemaphoreGive(m_xMutex);
		// char buf[512];
		// vTaskGetRunTimeStats(buf);
		// printf(buf);
	}
}