/**
 * @file eps_ctrlr.c
 *
 * @brief This file contains APIs for EPS controller.
 *
 * The functions provided in the file has eps control thread that monitors and controls eps battery mode,interrupt errors and output channels
 */
/*********************************************************************/


#include "eps_ctrlr_init.h"
#include "exo_types.h"
#include "exo_io_al_sos_timer.h"
#include "exo_common.h"
#include "nvm.h"
#include "eps.h"
#include "eps_config.h"
#include "logger.h"
#include "eps_fw_update.h"
#include "eps_fw_ctrlr.h"
#include "eps_btlr_driver.h"
#include "exo_ahw_al_psm_common.h"
#include "exo_tctm_ipc.h"
#include "obc_tc_tm.h"
#include "obc_ipc.h"
#include "tc_tm_mngr_buffer.h"
#include "err_handler.h"
#include "eps_btlr_driver.h"

sat_btry_info_s    sat_btry_info;
extern sat_dev_sts_s sat_dev_sts[MAX_SAT_DEV_CNT];
#define EPS_TEMPR_THRSHOLD 5
uint16_t eps_chnl_num = 0;
epc_chnl_ovr_cur_err_s epc_chnl_ovr_cur_err[12];
uint16_t eps_alert_flag_tmr_flag=1;
uint8_t eps_fw_start_flag=0;

extern eps_fw_data_s PLACE_IN_EXT_RAM_MEM fw_conv_status;
extern eps_fw_data_s PLACE_IN_EXT_RAM_MEM fw_op_chnl_status;
extern eps_fw_data_s PLACE_IN_EXT_RAM_MEM bckup_fw_conv_status;
extern eps_fw_data_s PLACE_IN_EXT_RAM_MEM bckup_fw_op_chnl_status;
static os_timer_handle_ptr 	eps_chnl_ovr_cur_err_tmr;
static os_timer_handle_ptr 	eps_chnl_pwr_dwn_ste_check_tmr;
os_timer_handle_ptr  eps_rd_tmr;
static uint8_t eps_buf_max_cnt=EPS_RD_BFR_MAX_SIZE;
static uint8_t eps_rd_buff_cnt[4]={0};
static uint8_t eps_init_done=0;
static uint8_t mode_change_cntr=0;
static uint8_t eps_btry_tempr_rd_cb_trig_st= 0 ;

uint8_t state=0;
uint8_t *eps_get_buf;
uint32 eps_get_buff_len;

uint8_t eps_alert_flag_intr_cb_flag = 0;
uint16_t nvm_eps_chnl_ovr_cur_err = 0;
extern uint8_t eps_chnl_pwr_dwn_flg;

extern uint8_t eps_com_fail_flg;
uint8_t eps_ctrlr_tmr_cnt[2]={0};

#ifdef EXT_SDRAM_BUFF_EPS_ENB
eps_btry_thrshld_s PLACE_IN_EXT_RAM_MEM eps_btry_thr;
eps_hlth_info_s    PLACE_IN_EXT_RAM_MEM eps_hlth_info;
eps_alert_flag_tmr_s     PLACE_IN_EXT_RAM_MEM eps_get_alert[EPS_RD_BFR_MAX_SIZE];
eps_get_btry_brd_tmr_s 	 PLACE_IN_EXT_RAM_MEM eps_get_btry_brd[EPS_RD_BFR_MAX_SIZE];
eps_get_conv_brd_tmr_s   PLACE_IN_EXT_RAM_MEM eps_get_conv_brd[EPS_RD_BFR_MAX_SIZE];
eps_get_chnl_par_tmr_s   PLACE_IN_EXT_RAM_MEM eps_get_out_chnl[EPS_RD_BFR_MAX_SIZE];
eps_get_btry_brd_stng_s  PLACE_IN_EXT_RAM_MEM eps_get_btry_brd_st;
#else
eps_btry_thrshld_s  eps_btry_thr;
eps_hlth_info_s     eps_hlth_info
eps_alert_flag_tmr_s     eps_get_alert[EPS_RD_BFR_MAX_SIZE];
eps_get_btry_brd_tmr_s 	 eps_get_btry_brd[EPS_RD_BFR_MAX_SIZE];
eps_get_conv_brd_tmr_s   eps_get_conv_brd[EPS_RD_BFR_MAX_SIZE];
eps_get_chnl_par_tmr_s   eps_get_out_chnl[EPS_RD_BFR_MAX_SIZE];
eps_get_btry_brd_stng_s   eps_get_btry_brd_st;
#endif

eps_beakcon_info_s  eps_get_info;


/**
 * @brief This API packs ipc data and trigger itc send to destination thread
 *
 */
eps_ctrlr_err_sts_s eps_ctrl_send_ipc_msg_pld(uint8_t dst_id, uint8_t pld_info, uint16_t msg_id, uint8_t *pld, uint8_t pld_size)
{
	os_itc_msg_handle_t sch_send_ipc;
	sch_send_ipc.src_entity = EPS_TASK;
	if(eps_init_done)
	{
		sch_send_ipc.Msg_id 	  = msg_id;
		sch_send_ipc.pld_info 	  = pld_info;
		sch_send_ipc.Msg_len	  = pld_size;

		if(pld_size)
		{
			sch_send_ipc.pld.pld_ptr = os_malloc_eram(pld_size);
			os_memcpy(sch_send_ipc.pld.pld_ptr,pld,pld_size);
		}
		else
			sch_send_ipc.pld.pld_ptr = NULL;

		if(os_itc_msg_send(&sch_send_ipc,dst_id,os_send_itc_wait) != ral_success)
		{
			return EPS_CTRL_ERR;
		}
	}
	return EPS_CTRL_SUCCESS;
}

/**
 * @brief This API packs ipc data and trigger itc send to destination thread
 *
 */
void eps_ctrlr_btry_vs_mode(float _btry_volt)
{
	uint8_t eps_mode;

	if((_btry_volt > 9.0) &&  (_btry_volt< 14.0))
	{
		sat_btry_info.volt = _btry_volt;
		DEBUG_CPRINT(("Btry_volt=%d.%d\n",(uint8_t)sat_btry_info.volt,(uint8_t)(sat_btry_info.volt*10)%10));
#ifdef EPS_DBG_EN
		log_id_with_two_arg(LOG_INFO_L1,LOG_EPS,BATTERY_VOLT__u8__pt__u8_,(uint8_t)sat_btry_info.volt,(uint8_t)(sat_btry_info.volt*10)%10);
#endif

		if(_btry_volt < eps_btry_thr.volt[HW_BTRY_SAFE])
			eps_mode = HW_BTRY_CRTCAL;
		else if(_btry_volt < eps_btry_thr.volt[HW_BTRY_NORMAL])
			eps_mode = HW_BTRY_SAFE;
		else
			eps_mode =  HW_BTRY_NORMAL;
		if(sat_btry_info.status != eps_mode)
		{
			if(mode_change_cntr++ >= BTRY_MODE_CHNG_CNTR)
			{
				mode_change_cntr=0;
				sat_btry_info.status = eps_mode;
				eps_hlth_info.alrt_value &= 0xFFFFFFFFFFFFFFF8;
				eps_hlth_info.alrt_value |= eps_mode & 0x07;
				eps_ctrl_send_ipc_msg_pld(EPS_TASK, EPS_BTRY_MODE_CHNL_STATE,0,NULL,0);
			}
		}
		os_memcpy(&eps_hlth_info.btry_params,&eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]],sizeof(eps_get_btry_brd_tmr_s));
	}
}

/**
 * @brief This API packs eps health information  and triggers ipc data for same.
 *
 */
void eps_ctrlr_tx_hlth_info()
{
	static uint8_t cntr = 0;
	uint8_t _size = sizeof(eps_get_conv_brd_tmr_s);
	uint8_t *data_ptr = NULL;
	os_itc_msg_handle_t sch_send_ipc;

	data_ptr 	= (uint8_t *)os_malloc_eram(_size+3);
	data_ptr[0] = cntr++;
	data_ptr[1]	= 0;
	data_ptr[2] = 0;
	os_memcpy(&data_ptr[3],(uint8_t *)&eps_hlth_info,_size);

	sch_send_ipc.src_entity   = EPS_TASK;
	sch_send_ipc.Msg_id 	  = 522;  // TM ID
	sch_send_ipc.pld_info 	  = 0;
	sch_send_ipc.Msg_len	  = _size;
	sch_send_ipc.pld.pld_ptr  = (uint8_t *)data_ptr;

	os_itc_msg_send(&sch_send_ipc,TM_STORAGE,500);

	if(cntr== 0xFF)
		cntr = 0;
}

/**
 * @brief This API gets data from eps driver and extract re-pack the information
 *
 */
eps_ctrlr_err_sts_s eps_hw_values_read(uint8_t _chnl)
{
	static uint8_t _eps_rd_chnl=EPS_GET_ALRT_FLAG;
	uint64_t get_time;
	eps_err_sts eps_sts=EPS_ERR;
	uint8_t rd_chnl=0;
	uint8_t eps_mode = 0;
	float totl_panel_pwr=0;
	eps_get_btry_brd_tmr_s *eps_get_btry_brd_buff;
	eps_get_conv_brd_tmr_s *eps_get_conv_brd_buff;
	eps_get_chnl_par_tmr_s *eps_get_out_chnl_buff;
	eps_alert_flag_tmr_s *eps_get_alert_buff;
	get_time=get_crnt_time_date_in_epoch();

	if(_chnl != 0)
		rd_chnl =_chnl;
	else
		rd_chnl = _eps_rd_chnl;

	switch(rd_chnl)
	{
	case EPS_GET_CONV_BRD_RD:
	{
		eps_sts =  eps_get_conv_brd_params_read(&eps_get_conv_brd[eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF]]);
		if(eps_sts == EPS_SUCCESS || 	(eps_sts ==	EPS_CRC_FAIL))
		{
			eps_get_conv_brd[eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF]].time = get_time;
			eps_get_conv_brd[eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF]].buff_cnt = eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF];
			os_memcpy(&eps_hlth_info.conv_params,&eps_get_conv_brd[eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF]],sizeof(eps_get_conv_brd_tmr_s));
			for(uint8_t n = 0; n<MAX_SLR_PNL_CNT ;n++)
			{
				totl_panel_pwr += (eps_get_conv_brd[eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF]].pv_volt[n])*(eps_get_conv_brd[eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF]].pv_cur[n]);
			}
			eps_get_info.totl_panel_pwr= (uint8_t)totl_panel_pwr;
			/** Buffer it to FW */
			eps_get_conv_brd_buff = os_malloc(sizeof(eps_get_conv_brd_tmr_s));
			if(eps_get_conv_brd_buff)
			{
				os_memcpy(eps_get_conv_brd_buff,&eps_get_conv_brd[eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF]],sizeof(eps_get_conv_brd_tmr_s));
				tc_eps_buff_fw_enqueue_req((uint8_t*)eps_get_conv_brd_buff, EPS_CONV_BRD_QUEUE_ID);
			}
			else
			{
				//malloc failed
			}			
			if(++eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF] >= eps_buf_max_cnt)
				eps_rd_buff_cnt[EPS_GS_GET_CONV_BRD_BUFF] = 0;
		}
		if((_chnl != 0) || (_eps_rd_chnl ==EPS_GET_CONV_BRD_RD))
			_eps_rd_chnl = EPS_GET_OP_CHNL_PARM;

	}
	break;

	case EPS_GET_OP_CHNL_PARM:
	{
		eps_sts =  eps_get_chnl_params_read(&eps_get_out_chnl[eps_rd_buff_cnt[EPS_GS_GET_CHNL_PARM_BUFF]]);
		if(eps_sts == EPS_SUCCESS || 	(eps_sts ==	EPS_CRC_FAIL))
		{
			eps_get_out_chnl[eps_rd_buff_cnt[EPS_GS_GET_CHNL_PARM_BUFF]].time = get_time;
			eps_get_out_chnl[eps_rd_buff_cnt[EPS_GS_GET_CHNL_PARM_BUFF]].buff_cnt = eps_rd_buff_cnt[EPS_GS_GET_CHNL_PARM_BUFF];
			/** Buffer it to FW */
			eps_get_out_chnl_buff = os_malloc(sizeof(eps_get_chnl_par_tmr_s));
			if(eps_get_out_chnl_buff)
			{
				os_memcpy(eps_get_out_chnl_buff,&eps_get_out_chnl[eps_rd_buff_cnt[EPS_GS_GET_CHNL_PARM_BUFF]],sizeof(eps_get_chnl_par_tmr_s));
				tc_eps_buff_fw_enqueue_req((uint8_t*)eps_get_out_chnl_buff, EPS_CHNL_PAR_QUEUE_ID);
			}
			else
			{
				//malloc failed
			}
			if(++eps_rd_buff_cnt[EPS_GS_GET_CHNL_PARM_BUFF] >= eps_buf_max_cnt)
				eps_rd_buff_cnt[EPS_GS_GET_CHNL_PARM_BUFF] = 0;
		}
		if((_chnl != 0) || (_eps_rd_chnl ==EPS_GET_OP_CHNL_PARM))
			_eps_rd_chnl = EPS_GET_ALRT_FLAG;


	}
	break;

	case EPS_GET_ALRT_FLAG:
	{
		eps_get_alert_buff = os_malloc(sizeof(eps_alert_flag_tmr_s));
		eps_sts =  eps_get_alert_flag_read(eps_get_alert_buff);
		if(eps_sts == EPS_SUCCESS || (eps_sts ==	EPS_CRC_FAIL))
		{
			if(eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF] == 0 || eps_get_alert_buff->value != eps_get_alert[eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF]-1].value)
			{
				eps_get_alert_buff->time=get_time;
				eps_get_alert_buff->buff_cnt = eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF];
				os_memcpy(&eps_get_alert[eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF]],eps_get_alert_buff,sizeof(eps_alert_flag_tmr_s));

				eps_mode =  (eps_get_alert[eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF]].value & 0x07);
				if(eps_mode > 0)
				{
					eps_mode = eps_mode-1;
				}
				if(eps_mode > HW_BTRY_NORMAL)
					eps_mode = HW_BTRY_NORMAL;

				eps_hlth_info.alrt_value = eps_get_alert[eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF]].value;

				eps_get_info.overcrnt_err_flg_byte1 = eps_get_info.overcrnt_err_flg_byte1 & 0xf0;
				eps_get_info.overcrnt_err_flg_byte1 = eps_get_info.overcrnt_err_flg_byte1 | eps_mode;
				eps_get_info.overcrnt_err_flg_byte1 = eps_get_info.overcrnt_err_flg_byte1 | (((eps_get_alert[eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF]].value) >> 19) & 0x03) << 2;
				eps_get_info.overcrnt_err_flg_byte2 = ((eps_get_alert[eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF]].value) >> 3) & 0xffff;
				if(eps_alert_flag_intr_cb_flag == 1)
				{
					eps_alert_flag_intr_cb_flag = 0;
					eps_chnl_ovr_cur_err_flag_indication(eps_get_info.overcrnt_err_flg_byte2);
				}
				if(sat_btry_info.status != eps_mode)
				{
					sat_btry_info.status = eps_mode;
					eps_hlth_info.alrt_value |= sat_btry_info.status & 0x07;    //doubt
					eps_ctrl_send_ipc_msg_pld(EPS_TASK, EPS_BTRY_MODE_CHNL_STATE,0,NULL,0);
				}
				/** Buffer it to FW */
				tc_eps_buff_fw_enqueue_req((uint8_t*)eps_get_alert_buff, EPS_ALRT_FLAG_QUEUE_ID);
				if(++eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF] >= eps_buf_max_cnt)
					eps_rd_buff_cnt[EPS_GS_GET_ALRT_BRD_BUFF] = 0;

				mode_change_cntr = 0 ;
			}
			else
			{
				os_free(eps_get_alert_buff);
			}
		}
		else
		{
			sat_btry_info.volt = ahw_al_psm_get_vbus(PSM_INA230_OBC);

			eps_ctrlr_btry_vs_mode(sat_btry_info.volt);
			os_free(eps_get_alert_buff);
		}

		if((_chnl != 0) || (_eps_rd_chnl ==EPS_GET_ALRT_FLAG))
			_eps_rd_chnl = EPS_GET_BTRY_BRD_RD;

	}
	break;

	case EPS_GET_BTRY_BRD_RD:
	{
		eps_sts =  eps_get_btry_brd_params_read(&eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]]);
		if(eps_sts == EPS_SUCCESS || 	(eps_sts ==	EPS_CRC_FAIL))
		{
			eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]].time = get_time;
			eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]].buff_cnt = eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF];
			os_memcpy(&eps_hlth_info.btry_params,&eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]],sizeof(eps_get_btry_brd_tmr_s));

			eps_get_info.totl_btry_volt = (uint8_t)((eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]].totl_vol)*10);
			eps_get_info.overcrnt_err_flg_byte1 = eps_get_info.overcrnt_err_flg_byte1 & 0xef;
			eps_get_info.overcrnt_err_flg_byte1 = eps_get_info.overcrnt_err_flg_byte1 | (eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]].btry_chrg_sts) << 4;

			sat_btry_info.volt = eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]].totl_vol;
			eps_ctrlr_btry_tempr_rd_cb_trig(&eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]]);
			//check the timer start function
			/** Buffer it to FW */
			eps_get_btry_brd_buff = os_malloc(sizeof(eps_get_btry_brd_tmr_s));
			if(eps_get_btry_brd_buff)
			{
				os_memcpy(eps_get_btry_brd_buff,&eps_get_btry_brd[eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF]],sizeof(eps_get_btry_brd_tmr_s));
				tc_eps_buff_fw_enqueue_req((uint8_t*)eps_get_btry_brd_buff, EPS_BTRY_BRD_QUEUE_ID);
			}
			else
			{
				//malloc failed
			}
			if(++eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF] >= eps_buf_max_cnt)
				eps_rd_buff_cnt[EPS_GS_GET_BTRY_BRD_BUFF] = 0;
		}
		else
		{
			sat_btry_info.volt = ahw_al_psm_get_vbus(PSM_INA230_OBC);

		}

		if((_chnl != 0) || (_eps_rd_chnl ==EPS_GET_BTRY_BRD_RD))
			_eps_rd_chnl = EPS_GET_CONV_BRD_RD;
	}
	break;
	}

	if(eps_sts == EPS_SUCCESS)
		return EPS_CTRL_SUCCESS;
	else if(eps_sts == EPS_CRC_FAIL)
		eps_hlth_info.crc_fail_cnt++;
	else
		eps_hlth_info.com_fail_cnt++;

	return EPS_CTRL_COMM_ERR;
}

/*
 * @brief This function will give the channel number
 */
uint8_t eps_to_get_cur_lmt_chnl(uint8_t i)
{
	uint8_t eps_chnl = 0;
	switch(i)
	{
	case 0:
		eps_chnl = HW_PL_TRANSCELESTIAL;
		break;
	case 1:
		eps_chnl = HW_S_BAND;
		break;
	case 2:
		eps_chnl = HW_X_BAND;
		break;
	case 3:
		eps_chnl = HW_PL_STS300;
		break;
	case 4:
	case 5:
	case 6:
		eps_chnl = HW_ADCS;
		break;
	case 7:
	case 8:
		eps_chnl = HW_PROP_UNIT_THRUSTER;
		break;
	case 9:
	case 10:
		eps_chnl = HW_UHF;
		break;
	case 11:
		eps_chnl = HW_PL_SCANWAY;
		break;
	case 12:
		eps_chnl = HW_PL_NETRA;
		break;
	case 13:
		eps_chnl = HW_EDGE_BRD;
		break;
	case 14:
		eps_chnl = HW_OBC_PS_GPS_STD_PL_BRD;
		break;
	case 15:
		eps_chnl = HW_HRM;
		break;
	default:
		break;
	}
	return eps_chnl;
}

/*
 * @brief This is channel over-current error timer callback function
 */
void eps_chnl_ovr_cur_err_tm_cb()
{
	uint32_t data[2];
	uint16_t get_eps_chnl_num = 0;
	for(int i =0; i < 12; i++)
	{
		if(epc_chnl_ovr_cur_err[i].chnl_enb_dis)
		{
			get_eps_chnl_num |= (0x01 << i);
			data[0] = i;
			data[1] = 1;
			eps_ctrl_send_ipc_msg_pld(EPS_TASK, EPS_CHNL_OVR_CUR_ERR_CB,0,(uint8_t*)&data,8);
			epc_chnl_ovr_cur_err[i].chnl_enb_dis =0;
		}
		else
		{

		}
	}
	if(get_eps_chnl_num == 0)
	{
		os_timer_stop(eps_chnl_ovr_cur_err_tmr);
		eps_alert_flag_tmr_flag=1;
	}
}

/*
 * @brief This function indicates the channel over-current error
 */
void eps_chnl_ovr_cur_err_flag_indication(uint16_t eps_chnl_ovr_cur_flag)
{
	uint8_t eps_chnl;
	for(uint8_t i = 0;i< MAX_VOLT_RAIL_CNT;i++)
	{
		if(((eps_chnl_ovr_cur_flag >> i) & 0x01) == 1) 					// overcurrent value -16 rail count
		{
			eps_chnl = eps_to_get_cur_lmt_chnl(i);						// From the occured ovr cur err,chnl is identified
			if(epc_chnl_ovr_cur_err[eps_chnl].eps_chnl_ovr_cur_cntr < 3) //if the cntr valie is less than 3 -pass
			{
				if((eps_chnl_num >> eps_chnl) & 0x01)						// this checks the chnl eligibility and enters
				{
					epc_chnl_ovr_cur_err[eps_chnl].chnl_enb_dis = 1;
					epc_chnl_ovr_cur_err[eps_chnl].tmr_cntr=1;
					epc_chnl_ovr_cur_err[eps_chnl].rst_cntr = 60;
					if(eps_alert_flag_tmr_flag==1)
					{
						eps_alert_flag_tmr_flag = 0;
						os_timer_start(eps_chnl_ovr_cur_err_tmr,(os_tick_time_t)OVR_CUR_ERR_TM);
					}
				}
				epc_chnl_ovr_cur_err[eps_chnl].eps_chnl_ovr_cur_cntr++;
			}
			else
			{
				epc_chnl_ovr_cur_err[eps_chnl].eps_chnl_ovr_cur_cntr = 0;
				nvm_eps_chnl_ovr_cur_err |= (1 << eps_chnl) ;
				nvm_parameter_write(NVM_DATA,EPS_CHNL_OVR_CUR_ERR,(uint8_t*)&nvm_eps_chnl_ovr_cur_err);
			}
		}
		else
		{

		}
	}
}

/**
 * @brief This API gets data from eps driver and extract re-pack the information
 *
 */
void eps_gs_hlth_chk(uint8_t *data)
{
	if(data != NULL)
	{
		data[0]  = sizeof(eps_hlth_info_s);
		os_memcpy(&data[1],&eps_hlth_info,data[0]);
	}
}

/**
 * @brief API for eps alert interrupt callback
 *
 */
void eps_alert_cb()
{
#if 0
#ifdef EPS_NVM_GET_ALERT_CNT
	eps_nvm_get_alert_cnt++;
#endif
#endif
	eps_ctrl_send_ipc_msg_pld(EPS_TASK, EPS_ALRT_SEM,0,NULL,0);
}

/*
 * @brief This Function read the FW version
 */
eps_err_sts_e eps_rd_fw_vers()
{
	eps_err_sts_e eps_sts=EPS_COM_FAIL;
	eps_get_fw_s eps_get_fw[2];
	eps_sts = eps_get_fw_update(eps_get_fw);
	return eps_sts;
}

/*
 * @brief This is one minute timer callback function
 */
void eps_tmr_cb_func()
{
#ifndef EPS_SIMU_ENABLE
	/* EPS FW vers rd */
	eps_rd_fw_vers();
#endif
	/* hw read values, com fail handle, ovr cur err */
	if((eps_ctrlr_tmr_cnt[0]++) > EPS_ONE_MIN_TMR)					//Triggering for 1 min
	{
		eps_ctrlr_tmr_cnt[0]= 0;
		eps_hw_values_read(0);
		if(eps_com_fail_flg==1)
		{
			eps_com_fail_cb();
		}
		for(uint8 i = 0; i<12;i++)
		{
			if(epc_chnl_ovr_cur_err[i].tmr_cntr)
			{
				if(epc_chnl_ovr_cur_err[i].rst_cntr)
					epc_chnl_ovr_cur_err[i].rst_cntr--;
				if(epc_chnl_ovr_cur_err[i].rst_cntr == 0)
				{
					epc_chnl_ovr_cur_err[i].tmr_cntr = 0;
					epc_chnl_ovr_cur_err[i].eps_chnl_ovr_cur_cntr = 0;
				}
			}
		}
	}
	/* Battery temp handle */
	if(eps_btry_tempr_rd_cb_trig_st)
	{
		if((eps_ctrlr_tmr_cnt[1]++) > EPS_BTRY_TRMP_CB_TMR)                      //Triggering for 20 sec
		{
			eps_ctrl_send_ipc_msg_pld(EPS_TASK,EPS_BTRY_TEM_CB,0,NULL,0);
			eps_ctrlr_tmr_cnt[1]=0;
		}
	}
}

/**
 * @brief API for eps timer callback
 *
 */
void eps_rd_tmr_cb()
{
	eps_ctrl_send_ipc_msg_pld(EPS_TASK, EPS_ONE_TMR_CB,0,NULL,0);
}

/**
 * @brief API for eps read timer init
 *
 */
void eps_rd_tmr_init()
{
	os_timer_create(&eps_rd_tmr,"eps_rd_tmr",PERIODIC,eps_rd_tmr_cb,NULL);
	os_timer_start(eps_rd_tmr,(os_tick_time_t)RD_TMR_SECS);
	os_timer_create(&eps_chnl_ovr_cur_err_tmr,"eps_chnl_ovr_cur_err_tmr",PERIODIC,eps_chnl_ovr_cur_err_tm_cb,NULL);
}

/**
 * @brief API for eps read timer deinit
 *
 */
void eps_btry_tmr_deinit()
{
	os_timer_stop(eps_rd_tmr);
}

/**
 * @brief This API set the default values of EPS parameters
 *
 */
void eps_hw_dflt_values_write()
{
	uint8_t  *response = NULL;
	eps_set_btry_brd_s  *set_bat_brd = NULL;
	eps_set_out_chnl_crnt_lmt_s *out_ch_cur_lmt_set = NULL;

	set_bat_brd = (eps_set_btry_brd_s *)os_malloc_eram(sizeof(eps_set_btry_brd_s));
	out_ch_cur_lmt_set = (eps_set_out_chnl_crnt_lmt_s *)os_malloc_eram(sizeof(eps_set_out_chnl_crnt_lmt_s));
	response 	= os_malloc_eram(sizeof(uint8_t)*40);

	eps_set_batt_defaults(set_bat_brd);
	eps_set_out_chnl_cur_lmt_defaults(out_ch_cur_lmt_set);
	eps_set_btry_brd_params(set_bat_brd, response);
	eps_set_chnl_crnt_lmt(out_ch_cur_lmt_set, response);
	os_free(set_bat_brd);
	os_free(out_ch_cur_lmt_set);
	os_free(response);
}

/**
 * @brief This API sets battery threshold limit for all 4 modes that can be changed dynamically from GS
 *
 */
void eps_set_btry_thrshld(eps_btry_thrshld_s *_eps_btry_thrshld)
{
	os_memcpy(&eps_btry_thr,_eps_btry_thrshld,sizeof(eps_btry_thrshld_s));
	nvm_parameter_write(NVM_DATA,EPS_BTRY_THRSHLD,(uint8_t*)&eps_btry_thr.volt);
}

/*
 * @brief This function read the OBC communication failure reset timeout from NVM
 * and set the value
 */
void eps_init_com_time_out()
{
	uint16_t eps_com_fail_timeout=0;
	nvm_parameter_read(NVM_DATA,EPS_COM_FAIL_TIMEOUT,(uint8_t*)&eps_com_fail_timeout);
	eps_set_obc_com_timeout_s eps_set_obc_com_timeout;
	uint8_t *eps_set_obc_com_tmout_resp = (uint8_t*)os_malloc(SET_EPS_COM_TIMEOUT_RESP_LEN);
	eps_set_obc_com_timeout.obc_com_timeout_sec=eps_com_fail_timeout;
	eps_set_obc_com_timeout.num_of_obc_rst_for_eps_rst=3;
	eps_set_obc_com_time_out(&eps_set_obc_com_timeout,eps_set_obc_com_tmout_resp);
}

/**
 * @brief This API read the EPS parameter
 *
 */
void eps_init_dflt_values()
{
	eps_get_rtc_tm_s get_rtc_time;
	struct tm tm_time_date;
	uint64_t epoch_time;
	sat_btry_info.volt = 12;
	sat_btry_info.status = HW_BTRY_NORMAL;
	nvm_parameter_read(NVM_DATA,EPS_BTRY_THRSHLD,(uint8_t*)&eps_btry_thr.volt);
	eps_hw_dflt_values_write();
	eps_get_btry_brd_rd_val();
	memset(eps_get_out_chnl,0,sizeof(eps_get_chnl_par_tmr_s)*EPS_RD_BFR_MAX_SIZE);
	memset(eps_get_conv_brd,0,sizeof(eps_get_conv_brd_tmr_s)*EPS_RD_BFR_MAX_SIZE);
	memset(eps_get_btry_brd,0,sizeof(eps_get_btry_brd_tmr_s)*EPS_RD_BFR_MAX_SIZE);
	memset(eps_get_alert,0,sizeof(eps_alert_flag_tmr_s)*EPS_RD_BFR_MAX_SIZE);
	eps_init_com_time_out();
	eps_hw_values_read(EPS_GET_ALRT_FLAG);
	eps_hw_values_read(EPS_GET_BTRY_BRD_RD);
	eps_hw_values_read(EPS_GET_OP_CHNL_PARM);
	eps_hw_values_read(EPS_GET_CONV_BRD_RD);
	if(eps_get_rtc_time(&get_rtc_time) == EPS_SUCCESS)
	{
		//TO DO : update system time
		tm_time_date.tm_year = get_rtc_time.year+100;
		tm_time_date.tm_mon  = get_rtc_time.month -   1;
		tm_time_date.tm_mday = get_rtc_time.date       ;
		tm_time_date.tm_hour = get_rtc_time.hour       ;
		tm_time_date.tm_min  = get_rtc_time.minute     ;
		tm_time_date.tm_sec  = get_rtc_time.second;
		tm_time_date.tm_wday  = get_rtc_time.weekday;
		tm_time_date.tm_isdst = 0;
		epoch_time=mktime(&tm_time_date);
		set_crnt_time_date(epoch_time);
	}
	log_id_with_two_arg(LOG_INFO_L1,LOG_EPS,BATTERY_VOLT__u8__pt__u8_,(uint8_t)sat_btry_info.volt,(uint8_t)(sat_btry_info.volt*10)%10);
}

/**
 * @brief This API trigger the battery temperature callback function
 *
 */
void eps_ctrlr_btry_tempr_rd_cb_trig(eps_get_btry_brd_tmr_s *eps_get_btry_brd)
{
	if(eps_btry_tempr_rd_cb_trig_st==0)
	{
		uint8_t cnt;
		for(cnt = 0; cnt < MAX_BTRY_TMP_SNSR_CNT ; cnt++) //MAX_BTRY_CONT
		{
			if(eps_get_btry_brd->tempr[cnt] < (eps_get_btry_brd_st.temp_lmt[cnt][0] + EPS_TEMPR_THRSHOLD))
			{
				// function for start timer
				eps_btry_tempr_rd_cb_trig_st = 1;
			}
		}
	}
	else
	{
		uint8_t cnt;
		eps_set_btry_brd_s *set_bat_brd = NULL ;
		uint8_t response[SET_BTRY_BRD_RESP_LEN];
		uint8_t eps_btry_tempr_rd_cb_trig_st_check=0;
		uint8_t eps_btry_set_trig=0;

		set_bat_brd = os_malloc_eram(sizeof(eps_set_btry_brd_s));
		set_bat_brd->temp_lmt_sns_cnt=eps_get_btry_brd_st.btry_temp_sns_cnt;
		set_bat_brd->mem_set = 0;
		os_memcpy(&set_bat_brd->cur_lmt_chrg,&eps_get_btry_brd_st.cur_lmt_chrg,26);
		for(cnt = 0; cnt < MAX_BTRY_TMP_SNSR_CNT ; cnt++) //MAX_BTRY_CONT
		{
			if(eps_get_btry_brd->tempr[cnt] < eps_get_btry_brd_st.temp_lmt[cnt][0] + EPS_TEMPR_THRSHOLD)
			{
				set_bat_brd->heat_mode = 1;
				set_bat_brd->heat_mode_flgs = set_bat_brd->heat_mode_flgs | (1 << cnt);
				eps_btry_set_trig = 1;
			}
			else if(eps_get_btry_brd->tempr[cnt] > (eps_get_btry_brd_st.temp_lmt[cnt][0] + EPS_TEMPR_THRSHOLD))
			{
				eps_btry_tempr_rd_cb_trig_st_check++;
			}
		}

		if (eps_btry_tempr_rd_cb_trig_st_check >= MAX_BTRY_TMP_SNSR_CNT) //MAX_BTRY_CONT
		{
			eps_btry_tempr_rd_cb_trig_st = 0; //timer stop
		}

		if(eps_btry_set_trig)
			eps_set_btry_brd_params(set_bat_brd,response);
		os_free(set_bat_brd);
	}
}

/**
 * @brief This API get the battery board read value
 *
 */
void eps_get_btry_brd_rd_val()
{
	eps_get_btry_brd_set_params(&eps_get_btry_brd_st);
}

/*
 * @brief This function read the FW version from NVM
 */
void eps_nvm_read_fw_vers(eps_get_fw_s *eps_get_fw)
{

	nvm_parameter_read(NVM_DATA,EPS_OP_CHNL_FW_MJR_VERS,(uint8_t*)&eps_get_fw[0].fw_mjr_vers);
	nvm_parameter_read(NVM_DATA,EPS_OP_CHNL_FW_MNR_VERS,(uint8_t*)&eps_get_fw[0].fw_mnr_vers);
	nvm_parameter_read(NVM_DATA,EPS_OP_CHNL_FW_PATCH_VERS,(uint8_t*)&eps_get_fw[0].fw_patch_vers);
	nvm_parameter_read(NVM_DATA,EPS_CONV_BRD_FW_MJR_VERS,(uint8_t*)&eps_get_fw[1].fw_mjr_vers);
	nvm_parameter_read(NVM_DATA,EPS_CONV_BRD_FW_MNR_VERS,(uint8_t*)&eps_get_fw[1].fw_mnr_vers);
	nvm_parameter_read(NVM_DATA,EPS_CONV_BRD_FW_PATCH_VERS,(uint8_t*)&eps_get_fw[1].fw_patch_vers);

}

/*
 * @brief This function write the current EPS FW version in NVM
 */
void eps_nvm_write_fw_vers()
{
	eps_get_fw_s eps_get_fw[2];
	eps_get_fw_update(eps_get_fw);
	nvm_parameter_write(NVM_DATA,EPS_OP_CHNL_FW_MJR_VERS,(uint8_t*)&eps_get_fw[0].fw_mjr_vers);
	nvm_parameter_write(NVM_DATA,EPS_OP_CHNL_FW_MNR_VERS,(uint8_t*)&eps_get_fw[0].fw_mnr_vers);
	nvm_parameter_write(NVM_DATA,EPS_OP_CHNL_FW_PATCH_VERS,(uint8_t*)&eps_get_fw[0].fw_patch_vers);
	nvm_parameter_write(NVM_DATA,EPS_CONV_BRD_FW_MJR_VERS,(uint8_t*)&eps_get_fw[1].fw_mjr_vers);
	nvm_parameter_write(NVM_DATA,EPS_CONV_BRD_FW_MNR_VERS,(uint8_t*)&eps_get_fw[1].fw_mnr_vers);
	nvm_parameter_write(NVM_DATA,EPS_CONV_BRD_FW_PATCH_VERS,(uint8_t*)&eps_get_fw[1].fw_patch_vers);
}

/*
 * @brief This API checks the EPS FW version
 */
eps_err_sts_e eps_fw_vers_check()
{
	eps_err_sts_e eps_sts = EPS_CTRL_ERR;

	eps_get_fw_s get_fw[2],eps_nvm_fw_vers[2]={0};
	eps_nvm_read_fw_vers(eps_nvm_fw_vers);
	eps_sts = eps_get_fw_update(get_fw);
	if(eps_sts == EPS_SUCCESS)
	{
		if(get_fw[0].fw_mnr_vers == eps_nvm_fw_vers[0].fw_mnr_vers &&\
				get_fw[0].fw_mjr_vers == eps_nvm_fw_vers[0].fw_mjr_vers &&\
				get_fw[0].fw_patch_vers == eps_nvm_fw_vers[0].fw_patch_vers &&\
				get_fw[1].fw_mjr_vers == eps_nvm_fw_vers[0].fw_mjr_vers &&\
				get_fw[1].fw_mnr_vers == eps_nvm_fw_vers[1].fw_mnr_vers && \
				get_fw[1].fw_patch_vers == eps_nvm_fw_vers[1].fw_patch_vers)
		{
			eps_sts = EPS_CTRL_SUCCESS;
			DEBUG_CPRINT(("EPS Firmware version read success/n"));
		}
		else
		{
			eps_sts = EPS_CTRL_FW_MISMATCH_ERR;
			DEBUG_CPRINT(("EPS Firmware version mismatch error/n"));
			log_id(LOG_ERROR,LOG_EPS,EPS_FW_VERSION_MISMATCH_ERR);
			/* TODO
			while(1)
			{

			}*/
			err_detected(ERR_GROUP_EPS, ERR_EPS_CTRL_FW_MISMATCH);
		}
	}
	return eps_sts;
}

/*
 * @brief This function deinit the one minute timer
 * Set the OBC communication failure reset timeout to 10 minute
 */
void eps_deinit_other_process_before_fw_upd()
{
	eps_fw_start_flag=1;
	eps_btry_tmr_deinit();
	eps_set_obc_com_timeout_s eps_set_obc_com_timeout;
	uint8_t *eps_set_obc_com_tmout_resp = (uint8_t*)os_malloc(SET_EPS_COM_TIMEOUT_RESP_LEN);
	eps_set_obc_com_timeout.obc_com_timeout_sec=600;
	eps_set_obc_com_timeout.num_of_obc_rst_for_eps_rst=3;
	eps_set_obc_com_time_out(&eps_set_obc_com_timeout,eps_set_obc_com_tmout_resp);
}

/**
 * @brief API for initialize the EPS thread
 *
 */
void eps_init()
{
	eps_fw_upt_init();
	eps_gpio_exp_init();
	eps_fw_mcu1_upd_check();
	os_thread_create(EPS_TASK,T_EPS_STACK_SIZE,P_EPS,"eps_proc",(app_entry_func_t)eps_proc,NULL,NULL,NULL);
#ifndef EPS_SIMU_ENABLE
	eps_fw_vers_check();
#endif
#ifdef EPS_SIMU_ENABLE
	sock_sim_cntct_flag=0;
	os_thread_create(OBC_EPS_SIMU,T_EPS_STACK_SIZE,P_OBC_EPS_SIMU,"eps_skt_sim",(app_entry_func_t)eps_skt_simu,NULL,NULL,NULL);
#endif

}

/**
 * @brief API for deinitialize timer and thread
 *
 */
void eps_deinit()
{
	eps_btry_tmr_deinit();
	os_thread_delete(EPS_TASK);
	eps_ctrl_dev_deinit();
}

/*
 * @brief This API send the beacon data to SDR APP
 */
void eps_beackon_data_update()
{
	for(uint8_t i = 0 ; i < MAX_EPS_OUT_CH_CNT ; i++)
	{
		if(sat_dev_sts[i].hw_sts < 2)
			eps_get_info.chnl_sts = eps_get_info.chnl_sts| sat_dev_sts[i].hw_sts << i;
	}

	eps_ctrl_send_ipc_msg_pld(SDR_APP,0,EPS_SDR_APP_MH_RSP,(uint8_t *)&eps_get_info,sizeof(eps_beakcon_info_s));
}

/*
 * @brief This API controls the TC and TM for EPS controller
 */
void eps_ctrl_tctm_code(obc_pck_data_eps *data)
{
	eps_ctrlr_err_sts_s eps_ctrl_sts;
	eps_dev_sts_s eps_dec;
	switch(data->tm_rsp_id)
	{
	case TM_SET_EPS_CTRL_CHNL_ST:
		os_memcpy(&eps_dec,data->tx_data,sizeof(eps_dev_sts_s));
		data->rx_data_len = 1;
		data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
		if(data->rx_data != NULL)
		{
			eps_ctrl_sts=eps_ctrl_en_chnl(eps_dec.ch_no,eps_dec.ch_st);
			os_memcpy(&data->rx_data[0],&eps_ctrl_sts,1);
		}
		break;
	case TM_SET_EPS_CTRL_DEV_TMR:
		data->rx_data_len = 1;
		data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
		if(data->rx_data != NULL)
		{
			eps_ctrl_sts = eps_ctrl_set_pwr_tmr((eps_dev_tmr_c *)data->tx_data);
			os_memcpy(&data->rx_data[0],&eps_ctrl_sts,1);
		}
		break;
	case TM_SET_EPS_BTRY_CTRL_CH_MAP:
		data->rx_data_len = 1;
		data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
		if(data->rx_data != NULL)
		{
			eps_ctrl_sts = eps_ctrl_set_btry_ch_map((eps_btry_ch_map_s *)data->tx_data);
			os_memcpy(&data->rx_data[0],&eps_ctrl_sts,1);
		}
		break;
	case TM_GET_EPS_BTRY_CTRL_CH_MAP:
		data->rx_data_len = sizeof(eps_btry_ch_map_s)+1;
		data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
		if(data->rx_data != NULL)
		{
			eps_ctrl_sts= eps_ctrl_get_btry_ch_map((eps_btry_ch_map_s *)&data->rx_data[1]);
			os_memcpy(&data->rx_data[0],&eps_ctrl_sts,1);
		}
		break;
	case TM_GET_EPS_DEV_HW_STS:
		data->rx_data_len =sizeof(sat_dev_sts)+1;
		data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
		if(data->rx_data != NULL)
		{
			data->rx_data[0]=1;
			os_memcpy(&data->rx_data[1],sat_dev_sts,sizeof(sat_dev_sts));
		}
		break;
	case TM_EPS_GET_BUFFER:
		switch(data->tx_data[0])
		{
		case  EPS_GS_GET_CONV_BRD_BUFF:
		{
			data->rx_data_len = (sizeof(eps_get_conv_brd_tmr_s)*EPS_RD_BFR_MAX_SIZE)+2;
			data->rx_data = (uint8_t*) os_malloc_eram(data->rx_data_len);
			if(data->rx_data != NULL)
			{
				data->rx_data[0]=1;
				os_memcpy(&data->rx_data[1],&data->tx_data[0],1);
				os_memcpy(&data->rx_data[2],eps_get_conv_brd,sizeof(eps_get_conv_brd_tmr_s)*EPS_RD_BFR_MAX_SIZE);
			}
		}
		break;

		case EPS_GS_GET_BTRY_BRD_BUFF:
		{
			data->rx_data_len = (sizeof(eps_get_btry_brd_tmr_s)*EPS_RD_BFR_MAX_SIZE)+2;
			data->rx_data = (uint8_t*) os_malloc_eram(data->rx_data_len);
			if(data->rx_data != NULL)
			{
				data->rx_data[0]=1;
				os_memcpy(&data->rx_data[1],&data->tx_data[0],1);
				os_memcpy(&data->rx_data[2],eps_get_btry_brd,sizeof(eps_get_btry_brd_tmr_s)*EPS_RD_BFR_MAX_SIZE);
			}
		}
		break;

		case EPS_GS_GET_CHNL_PARM_BUFF:
		{
			data->rx_data_len = (sizeof(eps_get_chnl_par_tmr_s)*EPS_RD_BFR_MAX_SIZE)+2;
			data->rx_data = (uint8_t*) os_malloc_eram(data->rx_data_len);
			if(data->rx_data != NULL)
			{
				data->rx_data[0]=1;
				os_memcpy(&data->rx_data[1],&data->tx_data[0],1);
				os_memcpy(&data->rx_data[2],eps_get_out_chnl,sizeof(eps_get_chnl_par_tmr_s)*EPS_RD_BFR_MAX_SIZE);
			}
		}
		break;

		case EPS_GS_GET_ALRT_BRD_BUFF:
		{
			data->rx_data_len = (sizeof(eps_alert_flag_tmr_s)*EPS_RD_BFR_MAX_SIZE)+2;
			data->rx_data = (uint8_t*) os_malloc_eram(data->rx_data_len);
			if(data->rx_data != NULL)
			{
				data->rx_data[0]=1;
				os_memcpy(&data->rx_data[1],&data->tx_data[0],1);
				os_memcpy(&data->rx_data[2],eps_get_alert,sizeof(eps_alert_flag_tmr_s)*EPS_RD_BFR_MAX_SIZE);
			}
		}
		break;
		default:
			break;
		}
		break;

		case TM_EPS_HEALTH_STS:
			data->rx_data_len =sizeof(eps_hlth_info_s)+2;	//2- 1 byte is for status and other 1 byte is for length of the data
			data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
			if(data->rx_data != NULL)
			{
				data->rx_data[0]=1;
				eps_gs_hlth_chk(&data->rx_data[1]);
			}
			break;
		case TM_EPS_FW_UPDATE:
			if(sat_btry_info.status == HW_BTRY_NORMAL)
			{
				eps_fw_update_ctrl(data);
			}
			else
			{
				data->rx_data_len = 1;
				data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
				if(data->rx_data != NULL)
				{
					data->rx_data[0] = EPS_BATTERY_ERR;
				}
			}
			break;
		case TM_ALERT_FLAG_OVR_CUR_ERR_HANDLE:
			if(data->tx_data[0] == 0)
			{
				data->rx_data_len =3;
				data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
				if(data->rx_data != NULL)
				{
					data->rx_data[0] = data->tx_data[0];
					os_memcpy(&data->rx_data[1],&nvm_eps_chnl_ovr_cur_err,2);
				}
			}
			else if(data->tx_data[0] == 1 )
			{
				data->rx_data_len =3;
				data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
				if(data->rx_data != NULL)
				{
					data->rx_data[0] = data->tx_data[0];
					if(data->tx_data[1] == 0)
					{
						nvm_eps_chnl_ovr_cur_err =0;
					}
					else
					{
						nvm_eps_chnl_ovr_cur_err &= ~(0x01 << data->tx_data[2]);
					}
					data->rx_data[2] = 1;
				}
			}
			else
			{
				os_memcpy(&eps_chnl_num,&data->tx_data[1],data->tx_data_len-1);
				data->rx_data_len =2;
				data->rx_data =(uint8_t*)os_malloc_eram(data->rx_data_len);
				if(data->rx_data != NULL)
				{
					data->rx_data[0] = data->tx_data[0];
					data->rx_data[1] = 1;
				}
			}
			break;
		case TM_EPS_MCU_RST:
			eps_fw_update_ctrl(data);
			break;
		default:
			break;
	}
}

/*
 * @brief Channel power down status timer callback function
 */
void eps_chnl_pwr_dwn_ste_check_tmr_cb(void *arg)
{
	uint16_t *len = (uint16_t*)arg;
	eps_ctrl_send_ipc_msg_pld(EPS_TASK,EPS_RESET_TRIG,0,(uint8_t*)arg,*len + 2);
	os_free(arg);
}

/*
 * @brief EPS FW update control IPC
 */

void eps_fw_update_ctrl_ipc(uint8_t *data)
{
	obc_pck_data_eps eps_fw_info_1 = {0};
	eps_fw_info_1.tx_data = &data[2];
	os_memcpy(&eps_fw_info_1.tx_data_len,data,2);
	eps_fw_update_ctrl(&eps_fw_info_1);
}

/*
 * @brief EPS FW update control function
 */
eps_ctrlr_err_sts_s eps_fw_update_ctrl(obc_pck_data_eps *eps_fw_info)
{
	uint32_t *len_temp;
	uint32_t *crc_temp;
	uint8_t *locl_data = os_malloc(eps_fw_info->tx_data_len + 2); //instead of pointer use local var
	os_memcpy(locl_data, &eps_fw_info->tx_data_len, sizeof(eps_fw_info->tx_data_len));
	os_memcpy(&locl_data[2], eps_fw_info->tx_data, eps_fw_info->tx_data_len);
	eps_ctrlr_err_sts_s eps_sts = EPS_CTRL_ERR;
	if(locl_data[2] == 9 || locl_data[2] == 10 || locl_data[2] == 1 || locl_data[2] == 3 || locl_data[2] == 4)
	{
		state = 2;
	}
	switch(state)
	{
	case 0:
		crc_temp = (uint32_t*)(&locl_data[8]);
		len_temp = (uint32_t*)(&locl_data[4]);
		if(locl_data[3] == 1)
		{
			if((fw_conv_status.fw_size == *len_temp && fw_conv_status.fw_crc == *crc_temp) || (bckup_fw_conv_status.fw_size == *len_temp && bckup_fw_conv_status.fw_crc == *crc_temp))
			{
				eps_pwr_dwn_all_chnl();
				state++;
				eps_ctrl_send_ipc_msg_pld(EPS_TASK,EPS_RESET_TRIG,0,(uint8_t*)locl_data,eps_fw_info->tx_data_len + 2);
				os_free(locl_data);
			}
			else
			{
				state=0;
				log_id(LOG_ERROR, LOG_EPS, EPS_MCU1_FW_SIZE_OR_CRC_FAIL);
				eps_fw_info->rx_data_len=2;
				eps_fw_info->rx_data=(uint8_t*)os_malloc(eps_fw_info->rx_data_len);
				eps_fw_info->rx_data[0]=locl_data[3];
				eps_fw_info->rx_data[1]=EPS_MCU1_FW_SIZE_CRC_FAIL;
			}
		}
		else if(locl_data[3] == 2)
		{
			if((fw_op_chnl_status.fw_size == *len_temp && fw_op_chnl_status.fw_crc == *crc_temp) || (bckup_fw_op_chnl_status.fw_size == *len_temp && bckup_fw_op_chnl_status.fw_crc == *crc_temp))
			{
				eps_pwr_dwn_all_chnl();
				state++;
				eps_ctrl_send_ipc_msg_pld(EPS_TASK,EPS_RESET_TRIG,0,(uint8_t*)locl_data,eps_fw_info->tx_data_len + 2);
				os_free(locl_data);
			}
			else
			{
				state=0; // add error logger & tm response
				log_id(LOG_ERROR, LOG_EPS, EPS_MCU2_FW_SIZE_OR_CRC_FAIL);
				eps_fw_info->rx_data_len=2;
				eps_fw_info->rx_data=(uint8_t*)os_malloc(eps_fw_info->rx_data_len);
				eps_fw_info->rx_data[0]=locl_data[3];
				eps_fw_info->rx_data[1]=EPS_MCU2_FW_SIZE_CRC_FAIL;
			}
		}
		else
		{
			log_id(LOG_ERROR, LOG_EPS, EPS_INVALID_MCU_TYPE);
			DEBUG_CPRINT(("Invalid ID\n")); // add error logger
		}
		break;
	case 1:
		eps_check_chnl_pwr_dwn_state();
		if(eps_chnl_pwr_dwn_flg == 12)
		{
			state++;
			eps_sts = EPS_SUCCESS;
			eps_ctrl_send_ipc_msg_pld(EPS_TASK,EPS_RESET_TRIG,0,(uint8_t*)locl_data,eps_fw_info->tx_data_len + 2);
			os_free(locl_data);
		}
		else
		{
			os_timer_create(&eps_chnl_pwr_dwn_ste_check_tmr,"eps_chnl_pwr_dwn_ste_check_tmr",ONESHOT,eps_chnl_pwr_dwn_ste_check_tmr_cb,locl_data);
			os_timer_start(eps_chnl_pwr_dwn_ste_check_tmr,(os_tick_time_t)EPS_CHNL_PWR_DWN_CHECK_TMR);
			state = 1;
		}
		break;
	case 2:
		if(eps_fw_info->tx_data[0] == 7 || eps_fw_info->tx_data[0] == 9)
		{
			eps_fw_boot_dis_mcu1();
		}
		else if(eps_fw_info->tx_data[0] == 8 || eps_fw_info->tx_data[0] == 10)
		{
			eps_fw_boot_dis_mcu2();
			eps_pwr_up_chnl_after_fw_upd();
		}
		else if(eps_fw_info->tx_data[1] == 1 || eps_fw_info->tx_data[1] == 2 )			//can be modified
		{
			eps_fw_update_tc_decode(eps_fw_info);
			eps_pwr_up_chnl_after_fw_upd();
		}
		else
		{
			DEBUG_CPRINT(("Invalid input \n"));
		}
		state=0;
		break;

	default:
		break;
	}
	return eps_sts;

}

/*
 * @brief This API send the TC to EPS control function and
 * sends back the TM response
 */
void eps_ctrl_tc_tm_pack(uint16_t eps_tc_len,void *eps_tc_buff,uint16_t eps_tc_id)
{
	obc_pck_data_eps data;
	data.tm_rsp_id=eps_tc_id;
	data.tx_data= eps_tc_buff+3;
	data.tx_data_len=eps_tc_len;
	data.rx_data=NULL;
	set_seq_no_radio_id(eps_tc_buff);
	if(data.tm_rsp_id == TM_GET_EPS_FW ||data.tm_rsp_id == TM_SET_EPS_COM_TIMEOUT || data.tm_rsp_id == TM_GET_EPS_COM_TIMEOUT || (data.tm_rsp_id >= TM_EPS_GET_CRC && data.tm_rsp_id <=TM_SET_EPS_SIM_BTRY_TEMP) || (data.tm_rsp_id >= TM_SET_CONV_BOARD_PARM && data.tm_rsp_id <=TM_GET_EPS_ALERT_INFO))
	{
		eps_tctm_code(&data);
	}
	else if(data.tm_rsp_id == TM_EPS_MCU_RST || data.tm_rsp_id == TM_EPS_GET_BUFFER || data.tm_rsp_id == TM_EPS_HEALTH_STS || data.tm_rsp_id == TM_ALERT_FLAG_OVR_CUR_ERR_HANDLE ||data.tm_rsp_id == TM_EPS_FW_UPDATE || (data.tm_rsp_id >= TM_SET_EPS_CTRL_CHNL_ST && data.tm_rsp_id <= TM_GET_EPS_DEV_HW_STS))
	{
		eps_ctrl_tctm_code(&data);
	}
	else
	{
		DEBUG_CPRINT(("Invalid TC ID\n"));
	}
	if(data.rx_data != NULL)
	{
		obc_prepare_ipc_msg(data.rx_data, data.rx_data_len,data.tm_rsp_id ,TM_SRC_EPS);
		os_free(data.rx_data);
	}
}

/*
 * @brief EPS simulation socket contact
 */
void eps_simu_socket_cntct()
{
	os_itc_msg_handle_t eps_itc_msg;
	DEBUG_CPRINT(("EPS simultaion socket is not connected with OBC\n"));
	if(os_itc_msg_rcv(EPS_TASK, &eps_itc_msg,2000)==1)
	{
		switch(eps_itc_msg.src_entity)
		{
		case TC_TM_MANAGER_IPC_RECEIVE:
		{
			if(eps_itc_msg.pld.pld_ptr)
			{
				eps_ctrl_tc_tm_pack(eps_itc_msg.Msg_len,eps_itc_msg.pld.pld_ptr,eps_itc_msg.Msg_id);
			}
		}
		break;
		case HM_MANAGER_IPC_RECEIVE:
		{
			if(OBC_TC_TM_BUFFER_RSP == eps_itc_msg.Msg_id)
			{
				if(TC_TM_BUFFER_SUCC == eps_itc_msg.pld.pld_data)
				{
					DEBUG_CPRINT(("EPS BUFFER REQUEST FOR HEALTH DATA SUCCESS\n"));
				}
				else
				{
					DEBUG_CPRINT(("EPS BUFFER REQUEST FOR HEALTH DATA FAILED\n"));
				}
			}
		}
		break;
		default:
			break;
		}
	}
}

/**
 * @brief EPS thread manages eps parameter read from driver and control output channel
 *
 */
void *eps_proc(void *args)
{
	os_itc_msg_handle_t eps_itc_msg;
	uint32_t *eps_chl_pwr_info;

	tc_eps_req_hlt_buff();

#ifdef EPS_SIMU_ENABLE
	while(sock_sim_cntct_flag==0)
	{
		eps_simu_socket_cntct();
	}
	DEBUG_CPRINT(("EPS simultaion socket is connected with OBC\n"));

	eps_fw_vers_check();
#endif
	eps_rd_tmr_init();
	eps_init_dflt_values();
	eps_init_done=1;
	eps_ctrl_dev_init();

	while(1)
	{
		os_itc_msg_rcv(EPS_TASK, &eps_itc_msg,os_wait_forever);

		switch(eps_itc_msg.src_entity)
		{
		case OBC_MAIN:
		{
#ifdef JANUS1
			if(eps_itc_msg.Msg_id == OBC_EPS_HEALTH_CHECK_REQ)
				eps_ctrlr_tx_hlth_info();
#endif

			if(eps_itc_msg.Msg_id == TC_SET_CUR_TIME)
			{
				uint8_t *eps_rtc_response = os_malloc(SET_RTC_RESV_LEN);
				eps_set_rtc_time(eps_itc_msg.pld.pld_ptr, eps_rtc_response);
				os_free(eps_rtc_response);
			}
		}
		break;
		case TC_TM_MANAGER_IPC_RECEIVE:
		{
			if(eps_itc_msg.pld.pld_ptr)
			{
				eps_ctrl_tc_tm_pack(eps_itc_msg.Msg_len,eps_itc_msg.pld.pld_ptr,eps_itc_msg.Msg_id);
			}
		}
		break;
		case EPS_TASK:
		{
			switch(eps_itc_msg.pld_info)
			{
			case EPS_ONE_TMR_CB:
				eps_tmr_cb_func();
				break;
			case EPS_RESET_TRIG:  	        eps_fw_update_ctrl_ipc(eps_itc_msg.pld.pld_ptr);			break;
			case EPS_ALRT_SEM:
				eps_alert_flag_intr_cb_flag=1;
				eps_hw_values_read(EPS_GET_ALRT_FLAG);	break;
			case EPS_BTRY_MODE_CHNL_STATE:	eps_ctrl_btry_mode_map();				break;
			case EPS_HW_PWR_SEQ:			eps_pwr_seq_st(eps_itc_msg.Msg_id);		break;
			case EPS_BTRY_TEM_CB:			eps_hw_values_read(EPS_GET_BTRY_BRD_RD);break;
			case EPS_CHNL_OVR_CUR_ERR_CB:
				eps_chl_pwr_info = eps_itc_msg.pld.pld_ptr;
				eps_ctrl_en_chnl(eps_chl_pwr_info[0],eps_chl_pwr_info[1]);
				break;
			default:
#ifdef EPS_DBG_EN
				DEBUG_CPRINT(("INVALID EPS STATE INPUT"));
				log_id(LOG_ERROR,LOG_EPS,INVALID_EPS_STATE_INPUT);
				break;
#endif
			}
		}
		break;


		case SDR_APP:
		{
			switch(eps_itc_msg.Msg_id)
			{
			case SDR_APP_EPS_MH_REQ:
			{
				eps_beackon_data_update();
			}
			break;
			default:
				break;
			}
		}
		break;
		default:

			if(eps_itc_msg.Msg_id == EPS_SET_CHNL_STATE)
			{
				eps_ctrlr_err_sts_s eps_sts = EPS_CTRL_ERR;
				eps_sts = eps_sts;
				eps_chl_pwr_info=eps_itc_msg.pld.pld_ptr;
				eps_sts=eps_ctrl_en_chnl(eps_chl_pwr_info[0],eps_chl_pwr_info[1]);
				eps_ctrl_send_ipc_msg_pld(eps_itc_msg.src_entity,0,EPS_SET_CHNL_STATE,(uint8_t *)&eps_sts,1);
#ifndef LINUX_TEMP_PORT
				DEBUG_CPRINT(("EPS ch no %ld pwr sts %ld by src id %hhu",eps_chl_pwr_info[0],eps_chl_pwr_info[1],eps_itc_msg.src_entity));
#endif
				log_id_with_three_arg(LOG_INFO_L1,LOG_EPS,EPS_CH_u8_PWR_STS_U8_SRC_ID_u8_,eps_chl_pwr_info[0],eps_chl_pwr_info[1],eps_itc_msg.src_entity);
			}
		}
		if(eps_itc_msg.pld.pld_ptr != NULL)
		{
			os_free(eps_itc_msg.pld.pld_ptr);
			eps_itc_msg.pld.pld_ptr = NULL;
		}
	}
}

/*
 * @brief This function packs the number of instance filled
 * and send an ITC msg to Health metric
 */
void tc_eps_buff_fw_req_queue(uint32_t instance_size, uint32_t num_of_instance, uint8_t queue_id)
{
	os_itc_msg_handle_t eps_req_ipc;
	s_tc_tm_buffer_req *buff_req = os_malloc(sizeof(s_tc_tm_buffer_req));
	if(buff_req)
	{
		os_memset(buff_req, 0, sizeof(s_tc_tm_buffer_req));
		buff_req->queue_id = queue_id;
		buff_req->instance_size = instance_size;
		buff_req->num_instance = num_of_instance;
		buff_req->wrap_dsb = 0;
		buff_req->priority = 0;
		buff_req->strg_flag = 0;
		buff_req->thresh = 0;
		eps_req_ipc.pld.pld_ptr = (void*)buff_req;
		eps_req_ipc.src_entity = EPS_TASK;
		eps_req_ipc.Msg_id = OBC_TC_TM_BUFFER_REQ;
		os_itc_msg_send(&eps_req_ipc, HM_MANAGER_IPC_RECEIVE, os_send_itc_wait);
	}
}

/*
 * @brief This function get the EPS health metric buffer ,pack and
 * send ITC msg to Health metric
 */
void tc_eps_buff_fw_enqueue_req(uint8_t* data, uint8_t queue_id)
{
	os_itc_msg_handle_t eps_req_ipc;
	eps_req_ipc.pld.pld_data = queue_id;
	eps_req_ipc.pld.pld_ptr = data;
	eps_req_ipc.src_entity = EPS_TASK;
	eps_req_ipc.Msg_id = OBC_TC_TM_ENQUEUE_REQ;
	os_itc_msg_send(&eps_req_ipc, HM_MANAGER_IPC_RECEIVE, os_send_itc_wait);
}

/*
 * @brief This function send the EPS health metric buffer framework queue
 */
void tc_eps_req_hlt_buff(void)
{
	/** TM buffering FW queue request for each health data */
	/** Total size
	 * (12+40+56+72)*90 = 16,200 */
	tc_eps_buff_fw_req_queue(sizeof(eps_alert_flag_tmr_s)  , EPS_RD_BFR_MAX_SIZE, EPS_ALRT_FLAG_QUEUE_ID);
	tc_eps_buff_fw_req_queue(sizeof(eps_get_btry_brd_tmr_s), EPS_RD_BFR_MAX_SIZE, EPS_BTRY_BRD_QUEUE_ID);
	tc_eps_buff_fw_req_queue(sizeof(eps_get_conv_brd_tmr_s), EPS_RD_BFR_MAX_SIZE, EPS_CONV_BRD_QUEUE_ID);
	tc_eps_buff_fw_req_queue(sizeof(eps_get_chnl_par_tmr_s), EPS_RD_BFR_MAX_SIZE, EPS_CHNL_PAR_QUEUE_ID);
}
