//////////////////////////////////////////////////////////////////
//
// App:			Run LED Task
// Author:		Milan Korinek
// Version:		1.0
// Notice:		Blinking with LED
//////////////////////////////////////////////////////////////////

#include "run_led.h"

typedef struct {
	xQueueHandle control_pipe;
	ports_controller_handle_t * ports_controller_handle;
} run_led_task_param_t;

typedef enum {
	RUN_LED_STATE_IDLE = 0,
	RUN_LED_STATE_ON,
	RUN_LED_STATE_OFF,
} run_led_state_t;

const char *const run_led_msg_type_str[] = {
	FOREACH_run_led_msg_type(GENERATE_STRING)
};

status_code_t run_led_init(ports_controller_handle_t * ports_controller_handle, run_led_handle_t * task_handle)
{
	portBASE_TYPE retTask;
	
	static run_led_task_param_t task_param;
	
	task_param.control_pipe = 0;
	task_param.ports_controller_handle = ports_controller_handle;
	
	task_handle->task_handle = NULL;
	task_handle->control_pipe = 0;
	
	/* Create FreeRTOS queue for task control pipe */
	task_param.control_pipe = xQueueCreate(TASK_RUN_LED_CONTROL_PIPE_LEN, sizeof(run_led_task_param_t));
	if (task_param.control_pipe == 0) {
		return ERR_NO_MEMORY;
	}
	task_handle->control_pipe = task_param.control_pipe;

	/* Create the task. */
	retTask = xTaskCreate(run_led_task, (const signed char *const) TASK_RUN_LED_NAME,
		TASK_RUN_LED_STACK_DEPTH_WORDS, (void *)(& task_param), TASK_RUN_LED_PRIORITY, &(task_handle->task_handle));
	
	if ((retTask != pdPASS) || (task_handle->task_handle == NULL))	{
		return ERR_NO_MEMORY;
	}
	
	return STATUS_OK;
}

void run_led_task(void *pvParameters)
{
	run_led_task_param_t * task_param = (run_led_task_param_t *)pvParameters;
	run_led_msg_t control_msg;
	ports_controller_msg_t ports_controller_send_msg = {
		.message = PORTS_CNTR_MSG_LED_SET,
		.devices = 0,
		.settings = 0,
	};
	
	uint32_t light = 0;
	uint32_t run_led_mode = RUN_LED_MSG_OFF;
	run_led_state_t run_led_state = RUN_LED_STATE_IDLE;
	uint32_t time_counter = 0;
	uint32_t on_time_ticks = 1, off_time_ticks = 1;
	Bool change = false;
	portTickType xLastWakeTime;
	
	// Initialize the xLastWakeTime variable with the current time.
	xLastWakeTime = xTaskGetTickCount();
	
	debug_event(DIO_SEVERITY_IMPORTANT, "Task 'Run LED' running...");
	for(;;)	{
		if (xQueueReceive(task_param->control_pipe, (void *)(&control_msg), 0) == pdPASS) { /* Check queue */
			xLastWakeTime = xTaskGetTickCount();
			run_led_mode = control_msg.message;
			light = 0;
			run_led_state = RUN_LED_STATE_IDLE;
			change = true;
			time_counter = 0;
			switch(run_led_mode){
				case RUN_LED_MSG_ON:
					light = 1;
					break;
				case RUN_LED_MSG_OFF:
					break;
				case RUN_LED_MSG_RUN:
					on_time_ticks = RUN_LED_RUN_ON / TASK_RUN_LED_REFRESH;
					off_time_ticks = RUN_LED_RUN_OFF / TASK_RUN_LED_REFRESH;
					run_led_state = RUN_LED_STATE_OFF;
					break;
				case RUN_LED_MSG_WARNING:
					on_time_ticks = RUN_LED_WARNING_ON / TASK_RUN_LED_REFRESH;
					off_time_ticks = RUN_LED_WARNING_OFF / TASK_RUN_LED_REFRESH;
					run_led_state = RUN_LED_STATE_OFF;
					break;
				case RUN_LED_MSG_ERROR:
					on_time_ticks = RUN_LED_ERROR_ON / TASK_RUN_LED_REFRESH;
					off_time_ticks = RUN_LED_ERROR_ON / TASK_RUN_LED_REFRESH;
					run_led_state = RUN_LED_STATE_OFF;
					break;
				default:
					change = false;
					break;
			}
		}
		
		switch(run_led_state) {
			case RUN_LED_STATE_OFF:
				if (time_counter >= off_time_ticks)
				{
					run_led_state = RUN_LED_STATE_ON;
					light = 1U;
					change = true;
				}
				break;
			case RUN_LED_STATE_ON:
				if (time_counter >= on_time_ticks)
				{
					run_led_state = RUN_LED_STATE_OFF;
					light = 0U;
					change = true;
				}
				break;
			default:
				break;
		}
		
		if (change)
		{
			change = false;
			time_counter = 0;
			ports_controller_send_msg.enable = light;
			if (xQueueSend(task_param->ports_controller_handle->control_pipe, (void *)(& ports_controller_send_msg), 0) != pdPASS) {
				
			}
		}
		
		//vTaskDelay(TASK_RUN_LED_REFRESH);
		vTaskDelayUntil(&xLastWakeTime, TASK_RUN_LED_REFRESH);
		time_counter++;
	}

	/* If all is well, the following line will never be reached. */
	vTaskDelete(NULL);
}