/**
 * @file exo_osal_thread.c
 *
 * @brief This file contains function definitions for OS thread management.
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "exo_common.h"
#include "exo_osal_thread.h"
#include "exo_osal_mem_management.h"

volatile uint8_t system_error=0;
os_thread_handle_ptr thread_ptr[OS_TASK_MAX];

/*Array to declare default queue size of each task
 * All queue size are mapped to default size of 25
 */

uint16_t itc_queue_len[OS_TASK_MAX]= {

   [OS_TIMER]=OS_TMR_QUEUE_SIZE,
   [CSP_TASK]=CSP_TASK_QUEUE_SIZE,
   [CSP_TASK1]=CSP_TASK1_QUEUE_SIZE,
   [CSP_TASK2]=CSP_TASK2_QUEUE_SIZE,
   [CSP_TASK3]=CSP_TASK3_QUEUE_SIZE,
   [CSP_ETH_RX]=CSP_ETH_RX_QUEUE_SIZE,
   [ETHERNET_TASK]=ETHERNET_TASK_QUEUE_SIZE,
   [USB_TASK]=USB_TASK_QUEUE_SIZE,
   [UART_EDGE_CONTROLLER]=UART_EDGE_CONTROLLER_QUEUE_SIZE,
   [EPS_TASK]=EPS_TASK_QUEUE_SIZE,
   [LWIP_MBOX_TASK]=LWIP_MBOX_TASK_QUEUE_SIZE,
   [LWIP_TASK]=LWIP_TASK_QUEUE_SIZE,
   [SDR_APP]=SDR_APP_QUEUE_SIZE,
   [COMMS_RX]=COMMS_RX_QUEUE_SIZE,
   [COMMS_SBAND_CTLR]=COMMS_SBAND_CTLR_QUEUE_SIZE,
   [COMMS_UHF_CTLR]=COMMS_UHF_CTLR_QUEUE_SIZE,
   [COMMS_SBAND_IQ]=COMMS_SBAND_IQ_QUEUE_SIZE,
   [COMMS_SBAND_TX]=COMMS_SBAND_TX_QUEUE_SIZE,
   [COMMS_UHF_TX]=COMMS_UHF_TX_QUEUE_SIZE,
   [COMMS_XBAND_CTLR]=COMMS_XBAND_CTLR_QUEUE_SIZE,
   [ORBIT_CONOPS_SCHEDULER]=ORBIT_CONOPS_SCHEDULER_QUEUE_SIZE,
   [ADCS_SERVER_THREAD]=ADCS_SERVER_THREAD_QUEUE_SIZE,
   [ADCS_CONTROLLER]=ADCS_CONTROLLER_QUEUE_SIZE,
   [ADCS_EVENT_THREAD]=ADCS_EVENT_THREAD_QUEUE_SIZE,
   [TC_TM_MANAGER_IPC_RECEIVE]=TC_TM_MANAGER_IPC_RECEIVE_QUEUE_SIZE,
   [TC_TM_MANAGER_IPC_SEND]=TC_TM_MANAGER_IPC_SEND_QUEUE_SIZE,
   [TM_STORAGE]=TM_STORAGE_QUEUE_SIZE,
   [HM_MANAGER_IPC_RECEIVE]=HM_MANAGER_QUEUE_SIZE,
   [OBC_MAIN]=OBC_MAIN_QUEUE_SIZE,
   [FTM_FSM_HANDLER]=FTM_FSM_HANDLER_QUEUE_SIZE,
   [FTM_TCTM_RCV]=FTM_TCTM_RCV_QUEUE_SIZE,
   [FTM_TCTM_SEND]=FTM_TCTM_SEND_QUEUE_SIZE,
   [OBC_IPCC_RECEIVE]=OBC_IPCC_RECEIVE_QUEUE_SIZE,
   [OBC_IPCC_SEND]=OBC_IPCC_SEND_QUEUE_SIZE,
   [IO_THREAD]=IO_THREAD_QUEUE_SIZE,
   [OBC_OTSU]=OBC_OTSU_QUEUE_SIZE,
   [OBC_MEMCPY_THREAD]=OBC_MEMCPY_THREAD_QUEUE_SIZE,
   [DEBUG_LOGGER]=DEBUG_LOGGER_QUEUE_SIZE,
   [LOGGER_TRACE]=LOGGER_TRACE_QUEUE_SIZE,
   [ERR_HANDLER]=ERR_HANDLER_QUEUE_SIZE,
#if defined(TEST_LAYER)
   [TEST_TASK]=TEST_TASK_QUEUE_SIZE,
#endif
   [IDLE_TASK]=IDLE_TASK_QUEUE_SIZE,
   [OBC_MEM_DEBUG_TC]=OBC_MEM_DEBUG_TC_QUEUE_SIZE,
   [OBC_SENSOR_HDLR]=OBC_SENSOR_HDLR_QUEUE_SIZE,
   [HAL_INTR_HDLR]=HAL_INTR_HDLR_QUEUE_SIZE,
   [PLD_SRV_TASK]=PLD_SRV_TASK_QUEUE_SIZE,
   [GPS_TASK]=GPS_TASK_QUEUE_SIZE,
#if 0
   [THREAD_TX_1]=THREAD_TX_1_QUEUE_SIZE,
   [THREAD_TX_2]=THREAD_TX_2_QUEUE_SIZE,
   [THREAD_TX_3]=THREAD_TX_3_QUEUE_SIZE,
   [THREAD_TX_4]=THREAD_TX_4_QUEUE_SIZE,
#endif
   [SPI_TO_UART_RCV_TASK]=SPI_TO_UART_RCV_TASK_QUEUE_SIZE,
   [SPI_TO_UART_TRANS_TASK]=SPI_TO_UART_TRANS_TASK_QUEUE_SIZE,
#ifdef LINUX_TEMP_PORT
   [OBC_SNS_SIMU]=OBC_SNS_SIMU_QUEUE_SIZE,
#endif
#ifdef EPS_SIMU_ENABLE
   [OBC_EPS_SIMU]=OBC_EPS_SIMU_QUEUE_SIZE,
#endif
#if (PERIODIC_LOG_ENB == 1) || defined(ENABLE_SOC_PRINT)
   [OBC_LOGGER_SOCKET]=OBC_LOGGER_SOCKET_QUEUE_SIZE,
#endif
   [SPI_TO_UART_CALLBACK_TASK]=SPI_TO_UART_CALLBACK_TASK_QUEUE_SIZE,
#ifdef LWIP_THROW_TEST
   [TEST_SOC_UDP] = TEST_SOC_UDP_TASK_QUEUE_SIZE
#endif
};

/**
 * @brief Function to create the thread
 */
os_status_t os_thread_create(uint8_t task_id,uint32_t stack_size,os_thread_priority_t priority,const char* thread_name,app_entry_func_t app_entry_func,void* entry_args,app_init_func_t app_init_func,void* init_args)
{
	os_status_t thread_sts=ral_error;
	os_thread_handle_ptr cb_args;
	cb_args = (os_thread_handle_ptr)os_malloc_api(sizeof(os_thread_handle_t));
	if(cb_args!=NULL)
	{
		cb_args->app_entry_func = app_entry_func;
		cb_args->app_init_func = app_init_func;
		cb_args->app_entry_args = entry_args;
		cb_args->app_init_args = init_args;

		os_queue_handle_ptr itc_queue;
		thread_sts =os_queue_create(&itc_queue,itc_queue_len[task_id],MAX_ITC_Q_ITEM_SIZE,thread_name);
		if(thread_sts == ral_success)
		{
			os_itc_queue_info_t *itc_q_info;
			itc_q_info = (os_itc_queue_info_t*)ral_malloc(sizeof(os_itc_queue_info_t));
			if(itc_q_info!=NULL)
			{
				itc_q_info->itc_queue_id=itc_queue;
				itc_q_info->queue_length=itc_queue_len[task_id];
				itc_q_info->item_size=MAX_ITC_Q_ITEM_SIZE;
				cb_args->queue_info_t=itc_q_info;
				thread_ptr[task_id]=cb_args;

			}
			/* Need to add os entry function */
			ral_thread_handle_ptr ral_thread_id;
			thread_sts = ral_thread_create(&ral_thread_id,stack_size,priority,thread_name,app_entry_func,cb_args);
			if(thread_sts == ral_success)
			{
				/* ITC queue Creation */
				cb_args->ral_thread_handle=ral_thread_id;
			}
			else
			{
				thread_sts=ral_error;
				os_queue_delete(itc_queue);
				os_free(cb_args);
				cb_args = NULL;
			}
		}
		else
		{
			thread_sts =ral_error;
		}
	}

	return (thread_sts);
}

/**
 * @brief Function to delete the thread
 */
os_status_t os_thread_delete(uint8_t id)
{
	os_status_t sts;
	os_thread_handle_ptr cb = thread_ptr[id];

	os_queue_delete(cb->queue_info_t->itc_queue_id);
	sts=ral_thread_delete(cb->ral_thread_handle);
	os_free(cb);
	cb = NULL;
	return sts;
}

/**
 * @brief This API create software OS delay
 */
void sw_os_delay(uint32_t tick_time)
{
	volatile uint64_t delay_sw=(uint64_t)20000*tick_time;    //need to be tuned based on the CPU frequency
	while(delay_sw)
	{
		delay_sw--;
	}
}

/**
 * @brief This API to create thread delay
 */
os_status_t os_delay(os_tick_time_t tick_time)
{
	os_status_t sts=ral_error;
	if(system_error==1)
	{
		sw_os_delay(tick_time);
	}
	else
	{
#ifndef LINUX_TEMP_PORT
		if(kernel_init_done!=1)
		{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
			HAL_Delay(tick_time);
#pragma GCC diagnostic pop
		}
		else
		{
			sts=ral_delay(tick_time);
		}
#else
		sts=ral_delay(tick_time);
#endif
	}
	return sts;
}

/**
 * @brief This API to get the thread handle.
 */
os_thread_handle_ptr os_get_thread_hdl(uint8_t id)
{
	return(thread_ptr[id]);
}

/**
 * @brief This API to get the queue id for given thread handle.
 */
os_queue_handle_ptr os_get_queue_id(uint8_t id)
{
    if(NULL == thread_ptr[id])
    {
        return NULL;
    }
    else
    {
	return(thread_ptr[id]->queue_info_t->itc_queue_id);
    }
}

/**
 * @brief Function puts the thread from running to waiting state
 */
os_status_t os_thread_suspend(uint8_t task_id)
{
	os_status_t sts;
	os_thread_handle_ptr cb = thread_ptr[task_id];
	sts = ral_thread_suspend(cb->ral_thread_handle);
	return sts;
}

/**
 * @brief Function use to resume the thread
 */
os_status_t os_thread_resume(uint8_t task_id)
{
	os_status_t sts;
	os_thread_handle_ptr cb = thread_ptr[task_id];
	sts = ral_thread_resume(cb->ral_thread_handle);
	return sts;
}

