/*
 * err_hdlr.c
 *
 *  Created on: 03-Aug-2023
 *  Author: Invcuser81
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "err_handler.h"
#include "exo_types.h"
#include "obc_tc_tm.h"
#include "exo_tctm_ipc.h"


typedef enum
{
	BIST_RUN_ALL_ERROR,
	BIST_RUN_PARTICULAR_ERROR,
	BIST_SET_ALL_FAULT,
	BIST_CLEAR_ALL_FAIULT,
	BISt_SET_AN_FAULT,
	BIST_CLEAR_AN_FAULT,
	BISt_SET_AN_ERROR_HOOK,
	BIST_CLEAR_AN_ERROR_HOOK,
}bist_options;

extern const uint8_t error_grp_err_codes_cnt[ERROR_GROUP_TOTAL+1];
extern const uint8_t error_grp_offset[ERROR_GROUP_TOTAL+1];
extern uint32_t* error_fault_set[ERROR_GROUP_TOTAL];
extern err_code_status_info err_code_info[ERROR_CODES_TOTAL];
extern err_handler_history err_history_temp [ERR_HISTORY_SAVED_NUM];


#ifdef ERR_HANDL_TEST_HOOK_ENABLE
extern uint32_t*  error_fault_set_hook[ERROR_GROUP_TOTAL];
#endif

int8 err_tc_decoder(uint16_t tc_id, uint8* data)
{
	obc_pck_data err_hdlr;
	uint8_t start;
	uint8_t inc;
	uint8_t offset = 0;
	uint8_t grp_id;
	uint8_t tot_err_cnt;


	if(tc_id == TC_ERR_HANDLER_READ_FAULTS)
	{
		/*
		 * TM Frame : Message ID + ERR group total + Group1 fault status (Error count & Fault Status ) + Group n ,,...
		 * Message ID - 1 byte , ERR group total - 1 byte , Group1 fault status  - 5 byte
		 */
		// frame lenth calc : 2 + ERR group total * 5 =>> where 5 is fault = 4 byte + total err cnt = 1 byte)
	    err_hdlr.tx_data_len = (ERR_GROUP_MAX * 5) + 2;
		err_hdlr.tx_data = (uint8_t *) os_malloc_eram(err_hdlr.tx_data_len);

		err_hdlr.tx_data[0] = ERR_TCTM_GET_ALL_FAULTS;
		err_hdlr.tx_data[1] = ERR_GROUP_MAX;

		read_fault();

	    for (inc = 0; inc < ERR_GROUP_MAX; inc++)
	    {
		     err_hdlr.tx_data[2+offset] = error_grp_offset[inc+1];
		     offset=offset+1;
		     os_memcpy(&err_hdlr.tx_data[2+offset],error_fault_set[inc],4);
		     offset = offset+4;	
	    }
	    err_hdlr.tm_rsp_id = TC_ERR_HANDLER_READ_FAULTS;

	}

	else if(tc_id == TC_ERR_HANDER_READ_GROUP_ERROR_STATUS)
	{

        grp_id = (data[0] & 0x78) >> 3;

		if(grp_id < ERR_GROUP_MAX)
		{
		   start = error_grp_err_codes_cnt[grp_id];
		   tot_err_cnt = error_grp_offset[grp_id+1];

		   err_hdlr.tx_data_len = (tot_err_cnt * sizeof(err_code_status_info))+3;
		   err_hdlr.tx_data = (uint8_t *) os_malloc_eram(err_hdlr.tx_data_len);
		   err_hdlr.tx_data[0] = ERR_TCTM_ERR_CODE_STS;
		   err_hdlr.tx_data[1] = grp_id;
		   err_hdlr.tx_data[2] = tot_err_cnt;

		   offset = 3;
		   for(inc = 0; inc < tot_err_cnt; inc++)
		   {
			   os_memcpy(&err_hdlr.tx_data[offset],&err_code_info[start+inc],sizeof(err_code_status_info));
			   offset = offset+sizeof(err_code_status_info);
		   }

		}
		else
		{
		   err_hdlr.tx_data_len = 1;
		   err_hdlr.tx_data     = (uint8_t *) os_malloc_eram(err_hdlr.tx_data_len);
		   err_hdlr.tx_data[0]  = ERR_TCTM_INVALID_INPUT;
		}
	    err_hdlr.tm_rsp_id = TC_ERR_HANDER_READ_GROUP_ERROR_STATUS;

	}

    else if (tc_id == TC_ERR_HANDLER_GET_ERROR_HISTORY)
     {
    	 // here 10 is error history structure size
		 err_hdlr.tx_data_len =  (10 * NVM_ERROR_HISTORY_TOTAL_COUNT) + 2;
		 err_hdlr.tx_data = (uint8_t *) os_malloc_eram(err_hdlr.tx_data_len);

		 err_hdlr.tx_data[0] = ERR_TCTM_ERR_HISTORY;
		 err_hdlr.tx_data[1] = NVM_ERROR_HISTORY_TOTAL_COUNT;

		 read_err_history(&err_hdlr.tx_data[2], NVM_ERROR_HISTORY_TOTAL_COUNT);

		 err_hdlr.tm_rsp_id = TC_ERR_HANDLER_GET_ERROR_HISTORY;

     }

    else if (tc_id == TC_ERR_HANDLER_RUN_BIST)
     {


    	/*
    	 * TC_ERR_HANDLER_RUN_BIST  Command frame details:
    	 *
    	 *   ---------------------------------------------
    	 *  | bist option | group id | error code number  |
    	 *   ---------------------------------------------
    	 *
    	 *
    	 * bist option 			- 0 or 1
    	 * group id   			- 0- 7 based on max group count
    	 * error code number 	- 0 - 31
    	 */



    	/*
    	 * TM_ERR_HANDLER_RUN_BIST Respnse frame details:
    	 *
    	 *   -------------------------------------------------------
    	 *  | bist option | group id | error code number  | status |
    	 *   -------------------------------------------------------
    	 *
    	 *
    	 * bist option 			- 0 or 1
    	 * group id   			- 0- 7 based on max group count
    	 * error code number 	- 0 - 31
    	 * status				- based on result
    	 */



		if((data[0] >> 4 ) == BIST_RUN_ALL_ERROR)
		{
		    err_hdlr.tx_data_len = 3;
		    run_bist();
			err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
			err_hdlr.tx_data[0] = 0 << 4;
			err_hdlr.tx_data[1] = 0;
			err_hdlr.tx_data[2] = ERR_TCTM_ERR_BIST_STS;
		}
		else if((data[0] >> 4 ) == BIST_RUN_PARTICULAR_ERROR)
		{
			grp_id = data[0] & 0xf;
			tot_err_cnt = data[1];

			if(grp_id <  ERR_GROUP_MAX && tot_err_cnt < error_grp_offset[grp_id+1])
			{
				/*
				 * call particular recovery function
				 */
			    err_hdlr.tx_data_len = 3;
				err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
				err_hdlr.tx_data[0] =  1 << 4 | grp_id;
				err_hdlr.tx_data[1] = tot_err_cnt;
				err_hdlr.tx_data[2] = err_run_recovery_particular_error(grp_id, tot_err_cnt);
			}
			else
			{
			   err_hdlr.tx_data_len = 3;
			   err_hdlr.tx_data     = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
			   err_hdlr.tx_data[0] =  1 << 4 | grp_id;
			   err_hdlr.tx_data[1] = tot_err_cnt;
			   err_hdlr.tx_data[2]  = ERR_TCTM_INVALID_INPUT;
			}

		}


		else if ((data[0] >> 4 ) == BIST_SET_ALL_FAULT)
		{
			/*
			 * set all fault
			 */
			*error_fault_set[ERR_GROUP_IO] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_IO+1]);
			save_fault(ERR_GROUP_IO);

			*error_fault_set[ERR_GROUP_AHW_SET_1] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_AHW_SET_1+1]);
			save_fault(ERR_GROUP_AHW_SET_1);

			*error_fault_set[ERR_GROUP_AHW_SET_2] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_AHW_SET_2+1]);
			save_fault(ERR_GROUP_AHW_SET_2);

			*error_fault_set[ERR_GROUP_SYSTEM] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_SYSTEM+1]);
			save_fault(ERR_GROUP_SYSTEM);

			*error_fault_set[ERR_GROUP_SERVICES] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_SERVICES+1]);
			save_fault(ERR_GROUP_SERVICES);

			*error_fault_set[ERR_GROUP_COMMS] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_COMMS+1]);
			save_fault(ERR_GROUP_COMMS);

			*error_fault_set[ERR_GROUP_ADCS] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_ADCS+1]);
			save_fault(ERR_GROUP_ADCS);

			*error_fault_set[ERR_GROUP_EPS] = 0xFFFFFFFF >> (32-error_grp_offset[ERR_GROUP_EPS+1]);
			save_fault(ERR_GROUP_EPS);

			err_hdlr.tx_data_len = 3;
			err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);

			err_hdlr.tx_data[0] = 2 << 4;
			err_hdlr.tx_data[1] = 0;
			err_hdlr.tx_data[2] = ERR_TCTM_ERR_BIST_STS;


		}
		else if ((data[0] >> 4 ) == BIST_CLEAR_ALL_FAIULT)
		{
			/*
			 * To clear all fault
			 */
			*error_fault_set[ERR_GROUP_IO] = 0;
			save_fault(ERR_GROUP_IO);

			*error_fault_set[ERR_GROUP_AHW_SET_1] = 0;
			save_fault(ERR_GROUP_AHW_SET_1);

			*error_fault_set[ERR_GROUP_AHW_SET_2] = 0;
			save_fault(ERR_GROUP_AHW_SET_2);

			*error_fault_set[ERR_GROUP_SYSTEM] = 0;
			save_fault(ERR_GROUP_SYSTEM);

			*error_fault_set[ERR_GROUP_SERVICES] = 0;
			save_fault(ERR_GROUP_SERVICES);

			*error_fault_set[ERR_GROUP_COMMS] = 0;
			save_fault(ERR_GROUP_COMMS);

			*error_fault_set[ERR_GROUP_ADCS] = 0;
			save_fault(ERR_GROUP_ADCS);

			*error_fault_set[ERR_GROUP_EPS] = 0;
			save_fault(ERR_GROUP_EPS);

		    err_hdlr.tx_data_len = 3;
			err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);

			err_hdlr.tx_data[0] = 3 << 4;
			err_hdlr.tx_data[1] = 0;
			err_hdlr.tx_data[2] = ERR_TCTM_ERR_BIST_STS;
		}
		else if ((data[0] >> 4 ) == BISt_SET_AN_FAULT)
		{
			/*
			 * To set particular fault
			 */
			grp_id = data[0] & 0xf;
			tot_err_cnt = data[1];

			if(grp_id <  ERR_GROUP_MAX && tot_err_cnt < error_grp_offset[grp_id+1])
			{

				*error_fault_set[grp_id] |= 1 << tot_err_cnt;
				save_fault(grp_id);

			    err_hdlr.tx_data_len = 3;
				err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
				err_hdlr.tx_data[0] =  4 << 4 | grp_id;
				err_hdlr.tx_data[1] = tot_err_cnt;
				err_hdlr.tx_data[2] = ERR_TCTM_ERR_BIST_STS;
			}
			else
			{
			   err_hdlr.tx_data_len = 3;
			   err_hdlr.tx_data     = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
			   err_hdlr.tx_data[0] =  4 << 4 | grp_id;
			   err_hdlr.tx_data[1] = tot_err_cnt;
			   err_hdlr.tx_data[2]  = ERR_TCTM_INVALID_INPUT;
			}



		}
		else if ((data[0] >> 4 ) == BIST_CLEAR_AN_FAULT)
		{
			/*
			 * To clear particular fault
			 */

			grp_id = data[0] & 0xf;
			tot_err_cnt = data[1];

			if(grp_id <  ERR_GROUP_MAX && tot_err_cnt < error_grp_offset[grp_id+1])
			{
				*error_fault_set[grp_id] &= ~(1 << tot_err_cnt);
				save_fault(grp_id);
				err_clear_err_cntr(grp_id, tot_err_cnt);

			    err_hdlr.tx_data_len = 3;
				err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
				err_hdlr.tx_data[0] =  5 << 4 | grp_id;
				err_hdlr.tx_data[1] = tot_err_cnt;
				err_hdlr.tx_data[2] = ERR_TCTM_ERR_BIST_STS;
			}
			else
			{
			   err_hdlr.tx_data_len = 3;
			   err_hdlr.tx_data     = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
			   err_hdlr.tx_data[0] =  5 << 4 | grp_id;
			   err_hdlr.tx_data[1] = tot_err_cnt;
			   err_hdlr.tx_data[2]  = ERR_TCTM_INVALID_INPUT;
			}


		}

#ifdef ERR_HANDL_TEST_HOOK_ENABLE

		else if ((data[0] >> 4 ) == BISt_SET_AN_ERROR_HOOK)
		{
			/*
			 * To set particular error hook
			 */
			grp_id = data[0] & 0xf;
			tot_err_cnt = data[1];

			if(grp_id <  ERR_GROUP_MAX && tot_err_cnt < error_grp_offset[grp_id+1])
			{

				*error_fault_set_hook[grp_id] |= 1 << tot_err_cnt;

			    err_hdlr.tx_data_len = 3;
				err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
				err_hdlr.tx_data[0] =  6 << 4 | grp_id;
				err_hdlr.tx_data[1] = tot_err_cnt;
				err_hdlr.tx_data[2] = ERR_TCTM_ERR_BIST_STS;
			}
			else
			{
			   err_hdlr.tx_data_len = 3;
			   err_hdlr.tx_data     = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
			   err_hdlr.tx_data[0] =  6 << 4 | grp_id;
			   err_hdlr.tx_data[1] = tot_err_cnt;
			   err_hdlr.tx_data[2]  = ERR_TCTM_INVALID_INPUT;
			}



		}
		else if ((data[0] >> 4 ) == BIST_CLEAR_AN_ERROR_HOOK)
		{
			/*
			 * To clear particular fault hook
			 */

			grp_id = data[0] & 0xf;
			tot_err_cnt = data[1];

			if(grp_id <  ERR_GROUP_MAX && tot_err_cnt < error_grp_offset[grp_id+1])
			{
				*error_fault_set_hook[grp_id] &= ~(1 << tot_err_cnt);

			    err_hdlr.tx_data_len = 3;
				err_hdlr.tx_data = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
				err_hdlr.tx_data[0] =  7 << 4 | grp_id;
				err_hdlr.tx_data[1] = tot_err_cnt;
				err_hdlr.tx_data[2] = ERR_TCTM_ERR_BIST_STS;
			}
			else
			{
			   err_hdlr.tx_data_len = 3;
			   err_hdlr.tx_data     = (uint8_t *) os_malloc(err_hdlr.tx_data_len);
			   err_hdlr.tx_data[0] =  7 << 4 | grp_id;
			   err_hdlr.tx_data[1] = tot_err_cnt;
			   err_hdlr.tx_data[2]  = ERR_TCTM_INVALID_INPUT;
			}


		}

#endif


		else
		{
			/*
			 *
			 */
		}



	    err_hdlr.tm_rsp_id = TC_ERR_HANDLER_RUN_BIST;



     }

    else
    {

    }

	obc_pack_tm_data(&err_hdlr);


	return TCTM_OK;
}

