/******************************************************************************/
/**
 * @file otsu.c
 *
 * @brief This file contains functions that provides demonstration of
 *        usage of OTSU
 *
 * The functions provided in the file provides demonstration on
 * usage of OTSU
 *
 * @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 other headers                           */
/******************************************************************************/

#include "file_transfer.h"
#include "exo_ahw_al_ext_flash_common.h"
#include "file_integrity_check.h"
#include "exo_osal_mem_cpy.h"
#include "exo_debug.h"
#include "schedular.h"
#include "exo_osal.h"
#include "exo_io_al_sos_timer.h"
#include "comms_ftm.h"
#include "nvm.h"
#include "ft_dwnld.h"
#include "exo_common.h"
#include "exo_io_al_sos_timer.h"
#include "exo_types.h"
#include "adcs_ftm.h"
#include "exo_tctm_ipc.h"

/******************************************************************************/
/*                      Include headers of the module                      */
/******************************************************************************/
#include "otsu_tctm_man.h"
#include "otsu_ftm.h"
#include "otsu.h"
#include "eps_btlr_driver.h"
#include "crc_cal.h"
#include "otsu_tctm_msg_def.h"
#include "bin_header_def.h"
#include "otsu_shutdown.h"
#include "otsu_mem_def.h"
#include "otsu_tctm_man.h"
#include "version.h"
#include "flash_drive.h"
#include "logger.h"
#include "btable_prepare.h"
#include "bl_main_extern.h"
#include "bootloader_extern.h"
#include "notify_apps.h"
#include "otsu_shutdown.h"
#include "logger.h"
#include "otsu_validate_fw.h"
#include "FreeRTOS.h"
#include "task.h"

#ifndef LINUX_TEMP_PORT
#include "stm32f7xx_hal.h"
#endif


/******************************************************************************/
/*                  Definition of local macros                  */
/******************************************************************************/


#define OTSU_DEBUG_HOOK_CODE
//#define FTM_TEST_69_BOARD
//#define DONT_NEED_SFT_VALIDATAION
//#define GS_SYNC_INT_DEBUG

#define MOD_ID_CHK 2

#define DWNLD_CODE_LOC 			(uint32_t)0x8110000
#define EXT_SDRAM_MEM_ADDR	 	(uint32_t)0xC0000000


#define MEM_CPY_RUN_STANDALONE_THREAD 	 (uint8_t)0


#define FIRMWARE_SIZE_ASSUMPTION_FOR_CORRUPTION (400*1024)


//#define FAC_CPY_LOC_C_ADDRESS	(uint32_t)(0x60000000)
//#define FAC_CPY_LOC_D_ADDRESS	(uint32_t)(0x60100000)
#define LEVEL0_FALLBACK_CODE 0x00000000
#define LEVEL1_FALLBACK_CODE 0x11111111
#define LEVEL2_FALLBACK_CODE 0x22222222
#define LEVEL3_FALLBACK_CODE 0x33333333
#define SINGLE_BOOT_FLAG_SET 0xAA
#define SINGLE_BOOT_FLAG_SET_LOC_C 0xCC
#define SINGLE_BOOT_FLAG_SET_LOC_D 0xDD
#define SINGLE_BOOT_FLAG_CLEAR 0x55


#define OBC_SHUTDWN_TIMEOUT_TIME   30 // in seconds

/* address allocated for FTM save context purpose*/
#define FTM_SAVECONTEXT_NOR_ADDRESSS (0x60000000 + ((1024*1024)*3))

#ifdef GS_SYNC_INT_DEBUG
#define GS_SYNC_INT_TIMER_TICK_VAL (60)  /* 1 min */
#define GS_SYNC_DEFAULT_TIME_IN_HRS 300  /* 5 min */
#else
#define GS_SYNC_INT_TIMER_TICK_VAL (3600)  /* 1 hour */
#define GS_SYNC_DEFAULT_TIME_IN_HRS 86400  /* 24 hours */
#endif
#define GS_SYNC_PERIODIC_TIMER_VALUE_IN_SEC (30*1000)


/******************************************************************************/
/*          Definition of local types (typedef, enum, struct, union)          */
/******************************************************************************/







/******************************************************************************/
/*                       Definition of local variables                        */
/******************************************************************************/
static os_itc_msg_handle_t 		otsu_itc_msg_hdl;              ///< OTSU itc handle
static e_otsu_fw_update_man 	otsu_fw_update_process_info;

#ifdef OTSU_DEBUG_HOOK_CODE
//static uint8_t debug_ftm =0;
#endif
static uint32_t gs_sync_tim_ctr;


extern s_fw_flash_handle s_flash_hdle;


/******************************************************************************/
/*                     Definition of local constant data                      */
/******************************************************************************/

static const uint8_t fallback1_corrupt_bytes[16] = {
		0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff,0x00,
};


/******************************************************************************/
/*                     Definition of global variables                         */
/******************************************************************************/

e_otsu_err_flag otsu_fw_error_flag;
s_main_func_api_def *main_func_api;
s_btable_api_list_def *btable_api;
s_boot_api_list_def *boot_api;
//uint8_t sct_data_avail;
firmware_upd_info_def fw_upd_info;


/******************************************************************************/
/*                      Definition of exported variables                      */
/******************************************************************************/

extern NOR_HandleTypeDef hnor1;
extern s_otsu_fw_update_cfg_tc_encode_def fw_reboot_config;
extern int8_t fmc_sdram_test();
extern uint8_t *gui_savecontext_ptr;
extern uint16 savecontext_size;
extern uint32_t _sibtlr_api_addr;

#define MACRO_sibtlr_api_addr 0x20000800

/******************************************************************************/
/*                  Declaration of local function prototypes                  */
/******************************************************************************/




#ifdef BTLR_ON

/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from LOC D to LOC C
 * after the firmware copy initiated from factory location if all loc A,B and C failed
 *
 * @param[in]  sts  : status of memory copy completion status
 *
 * @return none
 * @retval void : none
 */
static void fall_bck_loc_c_cb(uint8_t sts);

/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from LOC B to LOC C
 * after the first boot has completed
 *
 * @param[in]  sts  : status of memory copy completion status
 *
 * @return none
 * @retval void : none
 */
static void vfb_prep_loc_c_cb(uint8_t sts);

/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from LOC B to LOC D
 * after the first boot has completed
 *
 * @param[in]  sts  : status of memory copy completion status
 *
 * @return none
 * @retval void : none
 */
static void vfb_prep_loc_d_cb(uint8_t sts);
#endif


static void check_any_nor_flsh_cpy_req();

#ifdef BTLR_ON
static void new_fw_availablity_check(uint8_t fw_sts);
#endif




/**
 * @brief This function is used to corrupt the firmware stored at location D
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void : none
 */
static void fallback4_corruption_enable(void);

/**
 * @brief This function is used to corrupt the firmware stored at location D
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void : none
 */
static void fallback3_corruption_enable(void);


/**
 * @brief This function is used to corrupt the firmware stored at location D
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void : none
 */
static void fallback2_corruption_enable(void);

/**
 * @brief This function is used to corrupt the firmware stored at location D
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void : none
 */
static void fallback1_corruption_enable(void);


/**
 * @brief This function is allocate sepcial memory that will be corrupted in fallback1 simulation
 *
 * @param[in]  void  : none
 *
 * @return none
 * @retval void : none
 */
static void internal_flash_corrupt_func(void);


static void save_software_version(uint16_t version);




uint64_t calculate_eppoc_time_otsu(s_time_set_def *sband_sync_utc_time,s_date_set_def *sband_sync_utc_date);



static void fallback_currupt(e_otsu_integ_test fallback_id)
{
	DEBUG_CPRINT(("\nManual fallback-%d corruption initiated\n",fallback_id));
	if(fallback_id == e_fallback_1_fail)
	{
		fallback1_corruption_enable();
	}
	else if(fallback_id == e_fallback_2_fail)
	{
		fallback2_corruption_enable();
	}
	else if(fallback_id == e_fallback_3_fail)
	{
		fallback3_corruption_enable();
	}
	else if(fallback_id == e_fallback_4_fail)
	{
		fallback4_corruption_enable();
	}
	else
	{
	}
}
/******************************************************************************/
/*                       Definition of local functions                        */
/******************************************************************************/


/**
 * @brief This function is allocate sepcial memory that will be corrupted in fallback1 simulation
 */
static void internal_flash_corrupt_func(void)
{
	uint8_t data[4];
	data[0] = fallback1_corrupt_bytes[0];
	data[1] = fallback1_corrupt_bytes[1];
	data[2] = fallback1_corrupt_bytes[2];
	data[3] = fallback1_corrupt_bytes[3];
	data[0] = data[0];
}

/**
 * @brief This function is used to corrupt the firmware stored at location D
 */
static void fallback1_corruption_enable()
{
	uint32_t corrupt_buff[3];
	uint32_t corrupt_fuc_addrs;
	corrupt_buff[0] = 0;
	corrupt_buff[1] = 0;
	corrupt_buff[2] = 0;
	corrupt_fuc_addrs = (uint32_t)internal_flash_corrupt_func;
	corrupt_fuc_addrs = corrupt_fuc_addrs -1;  // usually arm return address +1 so it needs to be decremented by 1
	Flash_Write_Data(corrupt_fuc_addrs, corrupt_buff, 2);
	otsu_fw_update_process_info = e_otsu_fallback_corrupt_locA;
	DEBUG_CPRINT(("Fallback 1 corrupted\n"));
    log_id(LOG_ERROR,LOG_OTSU,FALLBACK_1_CORRUPTED);
}


/**
 * @brief This function is used to corrupt the firmware stored at location D
 *
 */
static void fallback2_corruption_enable(void)
{
	uint32_t corrupt_buff[3];
	uint32_t corrupt_addr = get_previous_fwstored_address();
	uint32_t random_num;
	random_num = HAL_GetTick();
	random_num = random_num % FIRMWARE_SIZE_ASSUMPTION_FOR_CORRUPTION; // 400KB
	corrupt_addr = corrupt_addr + random_num;

	if((corrupt_addr % 4)!=0)
	{
		corrupt_addr =	(corrupt_addr - (corrupt_addr % 4));
	}
	corrupt_buff[0] = 0;
	corrupt_buff[1] = 0;
	corrupt_buff[2] = 0;

	Flash_Write_Data(corrupt_addr, corrupt_buff, 2);
	otsu_fw_update_process_info = e_otsu_fallback_corrupt_locB;
    log_id(LOG_ERROR,LOG_OTSU,FALLBACK_2_CORRUPTED);
    DEBUG_CPRINT(("Fallback 2 corrupted at addr 0x%x \n",(unsigned int)corrupt_addr));
}


/**
 * @brief This function is used to corrupt the firmware stored at location D
 */
static void fallback3_corruption_enable(void)
{
	uint8_t corrupt_buff[12];

	uint32_t corrupt_addr = otsu_get_fw_storage_address();
	uint32_t random_num;
	random_num = HAL_GetTick();
	random_num = random_num % FIRMWARE_SIZE_ASSUMPTION_FOR_CORRUPTION; // 400KB
	corrupt_addr = corrupt_addr + random_num;
	if((corrupt_addr % 1024)!=0)
	{
		corrupt_addr =	(corrupt_addr - (corrupt_addr % 1024));
	}
	memset(corrupt_buff, 0, 12);
    ahw_al_ext_mem_erase_and_write(EXT_MEM_MT28EW128_FMC, corrupt_addr, corrupt_buff, 8);
	otsu_fw_update_process_info = e_otsu_fallback_corrupt_locC;
	DEBUG_CPRINT(("Fallback 3 corrupted at addr 0x%x \n",(unsigned int)corrupt_addr));
    log_id(LOG_ERROR,LOG_OTSU,FALLBACK_3_CORRUPTED);

}


/**
 * @brief This function is used to corrupt the firmware stored at location D
 *
 */
static void fallback4_corruption_enable(void)
{
	uint8_t corrupt_buff[12];
	uint32_t corrupt_addr = get_factory_fwstored_address();

	uint32_t random_num;
	random_num = HAL_GetTick();
	random_num = random_num % FIRMWARE_SIZE_ASSUMPTION_FOR_CORRUPTION; // 400KB
	corrupt_addr = corrupt_addr + random_num;
	if((corrupt_addr % 1024)!=0)
	{
		corrupt_addr =	(corrupt_addr - (corrupt_addr % 1024));
	}
	memset(corrupt_buff, 0, 12);
    ahw_al_ext_mem_erase_and_write(EXT_MEM_MT28EW128_FMC, corrupt_addr, corrupt_buff, 8);
	otsu_fw_update_process_info = e_otsu_fallback_corrupt_locD;
	DEBUG_CPRINT(("Fallback 4 corrupted at addr 0x%x \n",(unsigned int)corrupt_addr));
    log_id(LOG_ERROR,LOG_OTSU,FALLBACK_4_CORRUPTED);
}









/**
 * @brief This function used to assume new firmwware can able to
 * make GS contact
 * it can be used for testing purpose
 */
void otsu_new_fw_validation_status_update(otsu_new_fw_validate_sts status)
{
	otsu_fw_update_process_info = e_otsu_new_fw_validated;
	fw_upd_info.e_new_fw_working_sts = status;
}


/**
 * @brief This function used to perform integrity check for firmware header section
 */
 e_ret_sts header_integrity_check(uint32_t flash_address)
{
	uint32_t start_address;
	uint32_t length;
	uint32_t crc_append_address;
	uint8_t crc_sts_header=0;
	e_ret_sts r_sts = R_NOK1;

	start_address = flash_address;
	length = (0x2C)/4;
	crc_append_address = flash_address + 0x2C;
	crc_sts_header = crc32_checking(start_address,length,crc_append_address);

	if (crc_sts_header != 0)
	{
		r_sts = R_OK1;
		DEBUG_CPRINT(("\n\rheader section :crc pass \n\r"));
	}
	else
	{
		DEBUG_CPRINT(("\n\rheader section :crc fail \n\r"));

	}
	return r_sts;
}



e_ret_sts flash_integrity_check(uint32_t flash_address, uint32_t bin_size )
{
	uint32_t start_address, sdram_addr;
	uint32_t length;
	uint32_t crc_append_address;
	uint8_t crc_sts_header=0;
	uint8_t crc_sts_binary=0;
	e_ret_sts r_sts = R_NOK1;

	length = (0x2C)/4;

	/* copy binary to sdram if bin saved in qspi flash since crc cal func will not handle qspi read */
	if(flash_address >= 0x90000000)
	{
		sdram_addr = otsu_get_ftm_download_address();
		os_memcpy_extmem((uint8_t*)sdram_addr, (uint8_t*)flash_address, bin_size, NULL, MEM_CPY_RUN_SAME_THREAD,1);
		crc_append_address = sdram_addr + 0x2C;
		crc_sts_header = crc32_checking(sdram_addr,length,crc_append_address);
	}
	else
	{
		crc_append_address = flash_address + 0x2C;
		crc_sts_header = crc32_checking(flash_address,length,crc_append_address);
	}

	if (crc_sts_header != 0)
	{
		//DEBUG_CPRINT(("\n\rheader section :crc pass \n\r"));
	}
	else
	{
		//DEBUG_CPRINT(("\n\rheader section :crc fail \n\r"));

	}

	if (crc_sts_header != 0)
	{
		//commented 11-11
		length = ((bin_size-0x30)-4)/4;

		/* copy binary to sdram if bin saved in qspi flash since crc cal func will not handle qspi read */
		if(flash_address >= 0x90000000)
		{
			start_address = sdram_addr + 0x30;
			crc_append_address = sdram_addr + bin_size-4;
			crc_sts_binary = crc32_checking(start_address,length,crc_append_address);
		}
		else
		{
			start_address = flash_address + 0x30;
			crc_append_address = flash_address + bin_size-4;
			crc_sts_binary = crc32_checking(start_address,length,crc_append_address);
		}
	//	crc_sts_binary = 1;
		if (crc_sts_binary != 0)
		{
			//DEBUG_CPRINT(("\n\rbinary section :crc pass \n\r"));
		}
		else
		{
			//DEBUG_CPRINT(("\n\rbinary section :crc fail \n\r"));

		}
	}

	// firmware integrity check
	if ((crc_sts_binary) != 0 && (crc_sts_header != 0))
	{
		DEBUG_CPRINT(("\n\r flash integrity test pass"));
		r_sts = R_OK1;
	}
	else
	{
		DEBUG_CPRINT(("\n\r flash integrity test fail"));
	}
	return r_sts;
}







/*
 * this will check the current time and scheduled boot config time
 *
 */
static void process_scheduled_boot(void)
{
	otsu_fw_update_process_info = e_otsu_sch_boot_alarm;
//	if(fw_upd_info.nw_frmw_avail_sts == nw_frm_avail)
	{

		/*
		 * perform integrity on location c then verify software version
		 */

		DEBUG_CPRINT(("OTSU Sch Alarm pass for sch boot\n"));
		otsu_fw_update_process_info = e_otsu_sch_boot_alarm;

		DEBUG_CPRINT(("OTSU -> OBC Shutdown request create for Reboot\n"));
		log_id(LOG_WARNING,LOG_OTSU,OBC_SHUTDOWN_REQUEST_CREATE_FOR_REBOOT);

		fw_reboot_config.boot_operation_ctrl = BOOT_CONTROL_NOW;
		configure_reboot_schedule(TM_RES_NOT_REQ);

	}
//	else
//	{
//		DEBUG_CPRINT(("Scheduled Boot Request rejected due to no fw avail to boot\n"));
//		log_id(LOG_ERROR,LOG_OTSU,SCHEDULED_BOOT_REQUEST_REJECTED_DUE_TO_NO_FW_AVAIL_TO_BOOT);
//		// TODO :: Logger
//	}

}







#ifdef BTLR_ON
static void new_fw_availablity_check(uint8_t fw_sts)
{
	os_itc_msg_handle_t sband_trans_msg;
    if(fw_sts == NW_FW_AVAILABLE_SET)
    {
    	/* new booted FW needs validation */
    	otsu_fw_update_process_info = e_otsu_new_fw_validate_init;
    	os_delay(5000);
        sband_trans_msg.src_entity= OBC_OTSU;
        sband_trans_msg.Msg_id = OTSU_SBAND_SYNC_REQ;
        sband_trans_msg.Msg_len = 0;
        sband_trans_msg.pld.pld_ptr = NULL;
        os_itc_msg_send(&sband_trans_msg,COMMS_SBAND_CTLR, os_send_itc_wait);
        DEBUG_CPRINT(("OTSU - sband gs sync test request create\n"));
        log_id(LOG_INFO_L1,LOG_OTSU,OTSU__SBAND_GS_SYNC_TEST_REQUEST_CREATE);
    	otsu_fw_update_process_info = e_otsu_gscontact_comms_request_sent;
    }
    else
    {
    }
}


#endif












/* Do software backup if software flashed using debugger
 *  */
static void check_any_nor_flsh_cpy_req()
{
#ifdef BTLR_ON
	uint8_t ret_sts;
	uint32_t dest_addr,src_addr;
	uint8_t u8temp;
	uint32_t bin_size_actual;

	u8temp = btable_get_singlebin_boot_sts();
	bin_size_actual = btable_get_module_bin_size(0);
	if((u8temp == SINGLE_BOOT_FLAG_SET_LOC_C) || (u8temp == SINGLE_BOOT_FLAG_SET_LOC_D))
	{
		fw_reboot_config.boot_operation_ctrl = BOOT_CONTROL_UNDEFINED;
		if(u8temp == SINGLE_BOOT_FLAG_SET_LOC_C)
		{
			otsu_fw_update_process_info = e_otsu_vfb_prepare_loc_c;
			DEBUG_CPRINT(("\n\r[BLT] [VFB] NOR copy - Prepare LOC C...\n\r"));
            log_id(LOG_ERROR,LOG_OTSU,VFB_LOC_C);
			dest_addr = otsu_get_fw_storage_address();
			src_addr= get_previous_fwstored_address();
			ret_sts = os_memcpy_extmem( (uint8_t*)dest_addr, (uint8_t*)src_addr,bin_size_actual, NULL, MEM_CPY_RUN_SAME_THREAD,1);
			vfb_prep_loc_c_cb(ret_sts);
			/* check any fallback copy is pending */
			u8temp = btable_get_singlebin_boot_sts();
		}
		if(u8temp == SINGLE_BOOT_FLAG_SET_LOC_D)
		{
			otsu_fw_update_process_info = e_otsu_vfb_prepare_loc_d;
			DEBUG_CPRINT(("\n\r[BLT] [VFB] NOR copy - Prepare LOC D...\n\r"));
                        log_id(LOG_ERROR,LOG_OTSU,VFB_LOC_D);
			dest_addr = get_factory_fwstored_address();
			src_addr= get_previous_fwstored_address();
			ret_sts = os_memcpy_extmem((uint8_t*)dest_addr, (uint8_t*)src_addr, bin_size_actual, NULL, MEM_CPY_RUN_SAME_THREAD,1);
			vfb_prep_loc_d_cb(ret_sts);
		}
	}
	if(btable_get_fallback_code(bootloader_lut_one) == LEVEL3_FALLBACK_CODE)
	{
		otsu_fw_update_process_info = e_otsu_fallback_3_prepare_loc_c;
		DEBUG_CPRINT(("\n\r[BLT] FALLBACK3 Overwrite LOC C NOR start...\n\r"));
        //        log_id(LOG_ERROR,LOG_OTSU,LOC_C_FALLBACK3);
		dest_addr = otsu_get_fw_storage_address();
		src_addr= get_previous_fwstored_address();
		ret_sts = os_memcpy_extmem((uint8_t*)dest_addr, (uint8_t*)src_addr, bin_size_actual, NULL, MEM_CPY_RUN_SAME_THREAD,1);
		fall_bck_loc_c_cb(ret_sts);
	}
#endif
}

#ifdef BTLR_ON

/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from LOC B to LOC D
 * after the first boot has completed
 */
static void vfb_prep_loc_d_cb(uint8_t sts)
{
	uint32_t start_addr;
	if(sts == 0)
	{
		os_delay(1000);
		uint32_t bin_size_actual = btable_get_module_bin_size(0);
		start_addr = get_factory_fwstored_address();
		sts = flash_integrity_check(start_addr,(bin_size_actual) );
		if(sts != 1)
		{
			DEBUG_CPRINT(("\n\r Trial 1 CRC fail - To Factory storage copy - FALLBACK3 \n\r"));
			log_id(LOG_ERROR,LOG_OTSU,TRAIL1_CRC_FAIL__TO_FACTORY_STORAGE_COPY__FALLBACK3);
			os_delay(1000);
			sts = flash_integrity_check(start_addr, bin_size_actual);
			if(sts != 1)
			{
				DEBUG_CPRINT(("\n\r Trial 2 CRC fail - To Factory storage copy - FALLBACK3 \n\r"));
				log_id(LOG_ERROR,LOG_OTSU,TRAIL2_CRC_FAIL__TO_FACTORY_STORAGE_COPY__FALLBACK3);
			}
			else
			{
				DEBUG_CPRINT(("\n\r  Trial 2 NOR copy - D location pass\n\r"));
				log_id(LOG_INFO_L1,LOG_OTSU,TRAIL2_NOR_COPY__D_LOCATION_PASS);

				vTaskSuspendAll();
				{
					btable_fwrite_vfb_nor_cpy_state_update(SINGLE_BOOT_FLAG_CLEAR);
				}
				( void ) xTaskResumeAll();

				otsu_fw_update_process_info = e_otsu_vfb_prepare_loc_d_pass;
				check_any_nor_flsh_cpy_req();
			}
		}
		else
		{
			DEBUG_CPRINT(("\n\r Factory copy - FALLBACK3 pass\n\r"));
			log_id(LOG_INFO_L1,LOG_OTSU,FACTORY_COPY__FALLBACK3_PASS);

			vTaskSuspendAll();
			{
				btable_fwrite_vfb_nor_cpy_state_update(SINGLE_BOOT_FLAG_CLEAR);
			}
			( void ) xTaskResumeAll();

			check_any_nor_flsh_cpy_req();
			otsu_fw_update_process_info = e_otsu_vfb_prepare_loc_d_pass;
		}
	}
	else
	{
		DEBUG_CPRINT(("\n\r Factory copy - FALLBACK3 CPY WRAPPER FAIL\n\r"));
		log_id(LOG_ERROR,LOG_OTSU,FACTORY_COPY__FALLBACK3_CPY_WRAPPER_FAIL);
	}
}


/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from LOC B to LOC C
 * after the first boot has completed
 */
static void vfb_prep_loc_c_cb(uint8_t sts)
{
	uint32_t start_addr;
	if(sts == 0)
	{
		os_delay(1000);
		uint32_t bin_size_actual = btable_get_module_bin_size(0);
		start_addr = otsu_get_fw_storage_address();
		sts = flash_integrity_check(start_addr, bin_size_actual);
		if(sts != 1)
		{
			DEBUG_CPRINT(("\n\r Trial1 CRC fail - To NOR copy - FALLBACK2 \n\r"));
			log_id(LOG_ERROR,LOG_OTSU,TRAIL1_CRC_FAIL__TO_NOR_COPY__FALLBACK2);
			os_delay(1000);
			sts = flash_integrity_check(start_addr, bin_size_actual);
			if(sts != 1)
			{
				DEBUG_CPRINT(("\n\r Trial12 CRC fail - To NOR copy - FALLBACK2 \n\r"));
				log_id(LOG_ERROR,LOG_OTSU,TRAIL2_CRC_FAIL__TO_NOR_COPY__FALLBACK2);
				otsu_fw_update_process_info = e_otsu_vfb_prepare_loc_c_fail;

			}
			else
			{
				DEBUG_CPRINT(("\n\r NOR copy - FALLBACK2 pass\n\r"));
				log_id(LOG_INFO_L1,LOG_OTSU,NOR_COPY__FALLBACK2_PASS);

				vTaskSuspendAll();
				{
					btable_fwrite_vfb_nor_cpy_state_update(SINGLE_BOOT_FLAG_SET_LOC_D);
				}
				( void ) xTaskResumeAll();

				otsu_fw_update_process_info = e_otsu_vfb_prepare_loc_c_pass;
			}
		}
		else
		{
			DEBUG_CPRINT(("\n\r NOR copy - FALLBACK2 pass\n\r"));
			log_id(LOG_INFO_L1,LOG_OTSU,NOR_COPY__FALLBACK2_PASS);

			vTaskSuspendAll();
			{
				btable_fwrite_vfb_nor_cpy_state_update(SINGLE_BOOT_FLAG_SET_LOC_D);
			}
			( void ) xTaskResumeAll();

			otsu_fw_update_process_info = e_otsu_vfb_prepare_loc_c_pass;
//			check_any_nor_flsh_cpy_req();
		}
	}
	else
	{
		DEBUG_CPRINT(("\n\r NOR copy - FALLBACK2 CPY WRAPPER FAIL\n\r"));
		log_id(LOG_ERROR,LOG_OTSU,NOR_COPY__FALLBACK2_CPY_WRAPPER_FAIL);
	}
}


/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from LOC D to LOC C
 * after the firmware copy initiated from factory location if all loc A,B and C failed
 */
static void fall_bck_loc_c_cb(uint8_t sts)
{
	uint32_t start_addr;
	if(sts == 0)
	{
		uint32_t bin_size_actual = btable_get_module_bin_size(0);
		start_addr = otsu_get_fw_storage_address();
		sts = flash_integrity_check(start_addr,(bin_size_actual) );
		if(sts != 1)
		{
			DEBUG_CPRINT(("\n\r NOR/FACTORY CRC fail - From D To C by FALLBACK3 code \n\r"));
			log_id(LOG_ERROR,LOG_OTSU,FACTORY_CRC_FAIL__FROM_D_TO_C_BY_FALLBACK3_CODE);
		}
		else
		{
			DEBUG_CPRINT(("\n\r NOR/FACTORY copy - From D To C by FALLBACK3 pass\n\r"));
			log_id(LOG_INFO_L1,LOG_OTSU,FACTORY_COPY__FROM_D_TO_C_BY_FALLBACK3_PASS);

			vTaskSuspendAll();
			{
				btable_fwrite_clear_fallback(LEVEL0_FALLBACK_CODE);
			}
			( void ) xTaskResumeAll();

//			check_any_nor_flsh_cpy_req();
		}
	}
	else
	{
		DEBUG_CPRINT(("\n\r NOR/FACTORY copy - From D To C by FALLBACK3 CPY WRAPPER FAIL\n\r"));
		log_id(LOG_ERROR,LOG_OTSU,FACTORY_COPY__FROM_D_TO_C_BY_FALLBACK3_CPY_WRAPPER_FAIL);
	}
}
#endif



static void check_new_sft_hasloaded(void)
{

#ifdef BTLR_ON
    /*
     * check that new software has been loaded and needs to be validated by other core modules
     */

	btable_get_active_boottable();

#ifndef DONT_NEED_SFT_VALIDATAION
    fw_upd_info.new_fw_loaded = btable_new_software_validataion_flag_read();
    if(fw_upd_info.new_fw_loaded == NW_FW_AVAILABLE_SET)
    {
    	/* new booted FW needs validation */
    	otsu_fw_update_process_info = e_otsu_new_fw_validate_init;
		//os_delay(5000);
		new_fw_availablity_check(fw_upd_info.new_fw_loaded);
		nvm_parameter_read(NVM_DATA,NVM_OTSU_REBOOT_CONFIG,(uint8_t*)&fw_reboot_config);
		fw_reboot_config.boot_operation_ctrl = BOOT_CONTROL_FW_WAIT_GS_CONTACT;
		gs_contact_wait_timer_init();

		if(fw_reboot_config.shutdwn_process_timeout < 300 && fw_reboot_config.shutdwn_process_timeout > 0)
		{
			shtdwn_time_config(fw_reboot_config.shutdwn_process_timeout);
		}
		else
		{
			shtdwn_time_config(90);
		}
    }
    
    
    else
    {
    	DEBUG_CPRINT(("No New FW avail for First ground contact check\n"));
		log_id(LOG_INFO_L1,LOG_OTSU,NO_NEW_FW_AVAIL_FOR_GS_SYNC_CHECK);
    }
#endif
#endif

}



static void save_software_version(uint16_t version)
{
	fw_reboot_config.sft_version = version;
	nvm_parameter_write(NVM_DATA,NVM_OTSU_REBOOT_CONFIG,(uint8_t*)&fw_reboot_config);
}


void read_boot_cfg_info(void)
{
#ifdef BTLR_ON
	nvm_parameter_read(NVM_DATA,NVM_OTSU_NW_FRMW_STS,(uint8_t*)&fw_upd_info.nw_frmw_avail_sts);
	nvm_parameter_read(NVM_DATA,NVM_OTSU_REBOOT_CONFIG,(uint8_t*)&fw_reboot_config);
    if(fw_upd_info.nw_frmw_avail_sts == nw_frm_avail)
    {
    	DEBUG_CPRINT(("New FW image available for Software upgrade\n"));
//      log_id(LOG_INFO_L1,LOG_OTSU,NEW_FW_IMAGE_AVAILABLE_FOR_SOFTWARE_UPGRADE);
    	configure_reboot_schedule(TM_RES_NOT_REQ);
    }
#endif
}

uint8_t fimrware_integrity_check(uint32_t fw_address, uint16_t sft_version)
{
	uint8_t frmwr_integrity_status = 0;
	uint16_t software_version = 0;
	nvm_firmware_info_def nvm_info;
	uint8_t *src_addrs;


	frmwr_integrity_status = prepare_boottable_setup_for_module(fw_address, INTG_TEST, SET_CLEAR_UNDEF);
	if(frmwr_integrity_status == 1)
	{
		software_version = getVersion_downloaded_bin(fw_address);
		if(software_version == sft_version)
		{
			src_addrs = nvm_get_nvm_fwupd_memory_partition_address(NVM_FW_UPDATE_LOC_C);
			frmwr_integrity_status = nvm_get_nvm_bin_info(src_addrs, &nvm_info);
			if(frmwr_integrity_status != 0)
			{
				return BOOT_CONTROL_NVM_FW_INTEGRITY_FAIL;
			}


			nvm_fw_update(NVM_FW_UPDATE_TRIGGER);
			src_addrs = nvm_get_nvm_fwupd_memory_partition_address(NVM_FW_UPDATE_LOC_A);
			frmwr_integrity_status = nvm_get_nvm_bin_info(src_addrs, &nvm_info);
			if(frmwr_integrity_status != 0)
			{
				return BOOT_CONTROL_NVM_FW_INTEGRITY_FAIL;
			}

			/* Immediate boot is initiated */
			prepare_boottable_setup_for_module(fw_address, BTL_WRITE, SET_LOADING);
			otsu_state_change(e_otsu_shutdown_publish);
			shtdwn_time_config(fw_reboot_config.shutdwn_process_timeout);
			shtdwn_timer_trig();
			obc_shutdown_trigger();
			return 0;
		}
		else
		{
            return BOOT_CONTROL_FAIL_VERSION_MISMATCH;
		}
	}
	else
	{
		return BOOT_CONTROL_FAIL_DWNLD_FW_CORRUPTD;
	}
}

/******************************************************************************/
/*                      Definition of exported functions                      */
/******************************************************************************/


/**
 * @brief This is the callback function which will be invoked by scheduler module to initiate scheduled boot process
 *
 *
 * This callback function will be invoked by scheduler for OTSU scheduled boot
 */
void otsu_schduled_boot_scheduler_cblk(void)
{
    otsu_state_change(e_otsu_sch_boot_alarm);
    DEBUG_CPRINT(("OTSU Sch Boot Alarming..\n"));
}


/**
 * @brief This is the callback function which will be invoked by scheduler module to indicate GS sync wait time is over
 *
*
 * This callback function will be invoked by scheduler for sband sync fail timeout
 */
void otsu_sband_sync_fail_scheduler_cblk(void)
{
    otsu_state_change(e_otsu_sch_sband_sync_fail_alarm);
    DEBUG_CPRINT(("OTSU Sch sband sync fail Alarming..\n"));
}


/**
 * @brief This is the callback function which will be invoked by OBC module to indicate system is ready for shutdown
 */
void otsu_shutdown_completed_cblk(void)
{
    if(fw_upd_info.nw_frmw_avail_sts == nw_frm_avail)
    {
		otsu_state_change(e_otsu_shutdown_timeout_expired);
		shtdwn_timer_deinit();
    }
    else
    {
    	/* normal shutdown , not for FW update */
    	otsu_state_change(e_otsu_boot_activated);
    	DEBUG_CPRINT(("OTSU ready for Reset, [Reset not triggered for FW update]\n"));
    }
}


void prepare_for_shutdown(void)
{
	shtdwn_timer_deinit();
    if(fw_upd_info.tc_soft_reset_rqst == 0)
    {
		otsu_state_change(e_otsu_shutdown_timeout_expired);

		if(fw_upd_info.e_new_fw_working_sts != new_fw_validate_fail)
		{
			/* Clear new firmware available status flag from NVM before reset */
			fw_upd_info.nw_frmw_avail_sts = nw_frm_not_avail;
			nvm_parameter_write(NVM_DATA,NVM_OTSU_NW_FRMW_STS,(uint8_t*)&fw_upd_info.nw_frmw_avail_sts);
			gs_sync_tim_ctr = 0;
			nvm_parameter_write(NVM_DATA,NVM_OTSU_GS_SYNC_INT_TIM_CTR,(uint8_t*)&gs_sync_tim_ctr);
			DEBUG_CPRINT(("Reboot Initiated for New FW update\n"));
			log_id(LOG_INFO_L1,LOG_OTSU,REBOOT_INITIATED_FOR_NEW_FW_UPDATE);

			vTaskSuspendAll();
			{
				/* This api will also set new FW validation request flag */
				btable_fwrite_set_reboot((uint8_t)1,ffs_set);
			}
			( void ) xTaskResumeAll();

			otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_boot_initiated, 0);
		}
		else
		{
			DEBUG_CPRINT(("Fallback applied due to new FW not working..\n"));
			log_id(LOG_ERROR,LOG_OTSU,FALLBACK_APPLIED_DUE_TO_NEW_FW_NOT_WORKING);

			vTaskSuspendAll();
			{
				btable_swap();
				btable_swap_for_reboot();
			}
			( void ) xTaskResumeAll();

			otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_fallback_boot_initiated, 0);

		}

    }
    else
    {
    	/* normal shutdown , not for FW update */
    	otsu_state_change(e_otsu_boot_activated);
    	DEBUG_CPRINT(("OTSU ready for Reset, [Reset not triggered for FW update]\n"));
		log_id(LOG_INFO_L1,LOG_OTSU,OTSU_READY_FOR_RESET_cm__RESET_NOT_TRIGGERED_FOR_FW_UPDATE);
    	fw_upd_info.tc_soft_reset_rqst = 0;
    }
}

/*
 * @brief This API send IPS message to OBC and wait for timeout
 * if response not received in timeout time, OTSU will forcedly trigger software reset for
 * new fw boot
 */
void obc_shutdown_trigger(void)
{
	os_itc_msg_handle_t shut_msg;

	shut_msg.src_entity= OBC_OTSU;
	shut_msg.pld_info = 0;
	shut_msg.Msg_id = OTSU_OBC_SHUTDOWN_REQ;
	shut_msg.Msg_len = 0;
	shut_msg.pld.pld_ptr = NULL;
	os_itc_msg_send(&shut_msg,OBC_MAIN, os_send_itc_wait);
	DEBUG_CPRINT(("OTSU -> OBC Shutdown request create for Reboot\n"));
	log_id(LOG_WARNING,LOG_OTSU,OBC_SHUTDOWN_REQUEST_CREATE_FOR_REBOOT);

}


/**
 * @brief This function return the software version of downloaded binary
 *
 */
uint16_t getVersion_downloaded_bin(uint32_t address_loc)
{
	s_binary_header_def *bin_header;
	/* read software version from dwonloaded bin*/
	bin_header = (s_binary_header_def*)address_loc; //EXT_SDRAM_MEM_ADDR;
	return (bin_header->module_sw_version & 0x0000FFFF);
}


/**
 * @brief This function used to update the OTSU state
 *
 */
void otsu_state_change(e_otsu_fw_update_man set)
{
	otsu_fw_update_process_info = set;
}


/**
 * @brief This function return the current OTSU state
 */
e_otsu_fw_update_man get_otsu_state(void)
{
	return otsu_fw_update_process_info;
}





void otsu_send_message_to_otsu_fsm(uint16_t msg_id, uint8_t pld_info_)
{
	os_itc_msg_handle_t msg_hdl;

	msg_hdl.src_entity 	= OBC_OTSU;
	msg_hdl.Msg_id 		= msg_id;
	msg_hdl.pld_info 	= pld_info_;
	msg_hdl.Msg_len 	= 0;
	msg_hdl.pld.pld_ptr = NULL;
    os_itc_msg_send(&msg_hdl,OBC_OTSU, os_send_itc_wait);

}





/**
 * @brief This function used to prepare and update the boot lookup table for the downaloded binary
 */
uint8_t prepare_boottable_setup_for_module(uint32_t bin_header_address,uint8_t boot_table_set_flag, uint8_t boot_cfg)
{
	/* read module id at 1st byte of binary header info */
	uint8_t *u8locPtr = (uint8_t*)bin_header_address;
	uint32_t decimal_num;
	uint32_t actual_bin_size;
	uint8_t modulus_num;
	uint32_t packet_count;
	uint8_t ret_sts = 0;
	uint8_t m_id;
	uint32_t start_address;
	uint32_t length;
	uint32_t crc_append_address;
	uint8_t crc_sts_binary=0;

	m_id = header_integrity_check(bin_header_address);
	if (m_id == 1)
	{

		/* read module id at 12th byte of binary header info */
		//u8locPtr = (uint8_t*)(DWNLD_CODE_LOC + 12);
		u8locPtr = (uint8_t*)(bin_header_address + 12);

		decimal_num = u8locPtr[0] * 1000000;
		decimal_num = decimal_num + (u8locPtr[1] * 10000);
		decimal_num = decimal_num + (u8locPtr[2] * 100);
		decimal_num = decimal_num + u8locPtr[3];

		actual_bin_size = decimal_num;
		/* 4 bytes for checksum */
		actual_bin_size = actual_bin_size + 4;

		modulus_num = actual_bin_size % 16;
		if (modulus_num > 0 )
		{
			/* padding correction for 16 byte format */
			decimal_num = actual_bin_size + (16-modulus_num);
		}
		else
		{
			decimal_num = actual_bin_size;
		}


		packet_count = actual_bin_size / 16;
		modulus_num = actual_bin_size % 16;
		if (modulus_num > 0 )
		{
		  packet_count = packet_count + 1;
		}
		/* again calculate size with packet count format */
		packet_count =  packet_count * 16;

		if(boot_table_set_flag == BTL_WRITE)
		{

			vTaskSuspendAll();
			{
				btable_get_active_boottable();
				ret_sts = btable_fwrite_stored_pos(m_id-1, bin_header_address, packet_count, actual_bin_size, boot_cfg);
			}
			( void ) xTaskResumeAll();

			// TODO : BOOTTABLE UPDATED, BIN SIZE = actual_bin_size  >> BOOTTABLE_UPDATED_cm__BIN_SIZE__eq___u32_
			log_id_with_one_arg(LOG_INFO_L1, LOG_OTSU, BOOTTABLE_UPDATED_cm__BIN_SIZE__eq___u32_, actual_bin_size);
		}
		else if(boot_table_set_flag == INTG_TEST)
		{

			start_address = bin_header_address + 0x30;
			length = ((actual_bin_size-0x30)-4)/4;
			crc_append_address = bin_header_address + actual_bin_size-4;
			crc_sts_binary = crc32_checking(start_address,length,crc_append_address);
			if ((crc_sts_binary) != 0)
			{
				DEBUG_CPRINT(("Binary integrity test pass\r\n"));
				log_id(LOG_INFO_L1,LOG_OTSU,BINARY_INTEGRITY_TEST_PASS);
				ret_sts = crc_sts_binary;
			}
			else
			{
				DEBUG_CPRINT(("Binary integrity test fail\r\n"));
				log_id(LOG_ERROR,LOG_OTSU,BINARY_INTEGRITY_TEST_FAIL);
			}
		}
		else
		{
			ret_sts = 1;
		}
	}
	return ret_sts;
}

uint16_t otsu_get_btable_size(void)
{
	return btable_get_table_size();
}

uint8_t otsu_copy_btable_data(uint8_t table_id, uint8_t * write_buf)
{
	return btable_copy_blt_table(table_id, write_buf);
}


void otsu_intf_init(void)
{
	log_id(LOG_INFO_L3, LOG_OTSU, OTSU_INIT_START);
	DEBUG_CPRINT(("OTSU initializing..\n"));

	/*
	 * taking access to bootloader api
	 * these api will be used to write boot table
	 */
	main_func_api = (s_main_func_api_def*) (MACRO_sibtlr_api_addr);
	boot_api = (s_boot_api_list_def*) (MACRO_sibtlr_api_addr + sizeof(s_main_func_api_def));
	btable_api = (s_btable_api_list_def*) (MACRO_sibtlr_api_addr + sizeof(s_boot_api_list_def) + sizeof(s_main_func_api_def));

	/* register notification callback api with file transfer */
	otsu_ftm_register();

    fw_upd_info.e_new_fw_working_sts = new_fw_validate_none;
//	ftm_nor_write_avail = 0;
	otsu_mem_init();
	shtdwn_timer_init();
	fw_upd_info.nw_frmw_avail_sts = nw_frm_not_avail;
	fw_upd_info.tc_soft_reset_rqst = 0;
}

void otsu_fsm(uint16_t msg_id, uint16_t msg_len, uint8_t *pld, uint16_t pld_id)
{

	uint32_t temp;

	switch(msg_id)
	{
	case OTSU_INIT_STATE:
		/* check external memory
		 * TODO */
		otsu_intf_init();
		check_new_sft_hasloaded();
		check_any_nor_flsh_cpy_req();
		read_boot_cfg_info();

		DEBUG_CPRINT(("OTSU Init complete\n"));
		log_id(LOG_INFO_L1, LOG_OTSU, OTSU_INIT_FSM_COMPLETE);
		break;

	case OTSU_FALLBACK_CORRUPT_TEST:
		fallback_currupt(pld_id);
		DEBUG_CPRINT(("OTSU fallback corrupt test completed\n"));
		log_id(LOG_INFO_L1, LOG_OTSU, OTSU_FALLBACK_CORRUPT_TEST_FSM_COMPLETED);
		break;

	case OTSU_FW_DWNLD:
		temp = os_memcpy_extmem((uint8_t*)s_flash_hdle.flash_address_inc, (uint8_t*)s_flash_hdle.storage_address, s_flash_hdle.binary_size, NULL, MEM_CPY_RUN_SAME_THREAD,1);
		sdram_fmc_flash_copy_clbk(temp);
		log_id(LOG_INFO_L1, LOG_OTSU, OTSU_FIRMWARE_DOWNLOAD_FSM_COMPLETED);//626
		break;

	case OTSU_TCTM_SERVICE:
		/* Decode telecommand and provide response */
		otsu_decode_tc(pld_id, pld, msg_len);
		log_id(LOG_INFO_L1, LOG_OTSU, OTSU_TCTM_SERVICE_FSM_COMPLETED);
		break;

	case OTSU_GS_SYNC_RCV:
		/* gs contact confirmation message received from GS */
		otsu_send_sband_sync_status_cblk(pld_id);
		new_fw_validation_completed();
		log_id(LOG_INFO_L1, LOG_OTSU, OTSU_GS_SYNC_RCV_FSM_COMPLETED);
		break;

	case OTSU_GS_SYNC_TIMEOUT_SCH:
		/* gs contact not established with in expected time,*/
		gs_contact_timer_stop();
		DEBUG_CPRINT(("OTSU Sch sband sync fail Alarming..\n"));
	    new_software_verification_fail();
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_GS_SYNC_TIMEOUT_SCH_FSM_COMPLETED);
		break;

	case OTSU_SCHBOOT_TIMEOUT_SCH:
		/* save software version */
		if(pld != NULL)
		{
			memcpy(&temp, pld, 4);
		}


		else
		{
			temp = 0;
		}
		save_software_version(temp);
		process_scheduled_boot();
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_SCHBOOT_TIMEOUT_SCH_FSM_COMPLETED);
	    break;

	case OTSU_SCHBOOT_TIMEOUT_BYOTSU:
		/* stop timer and then continue scheduled boot process*/
		otsu_stop_schduled_boot_timer();
		process_scheduled_boot();
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_SCHBOOT_TIMEOUT_SCH_FSM_COMPLETED);
	    break;

	case OTSU_START_SHUTDOWN_PROC:
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_START_SHUTDOWN_PROC_FSM_COMPLETED);
	    break;

	case OTSU_OBC_HANDSHAKE_DONE:
		//otsu_shutdown_completed_cblk();
		log_id(LOG_INFO_L1,LOG_OTSU,OBC_HANDSHAKE_FSM_DONE);
		prepare_for_shutdown();
		os_delay(3000);
		/* wait 2 seconds for TM to be sent then initiate Software reset */
		/* need more analysis TODO
		 *
		 */
		EXO_ASSERT(SW_TEST_RESET);
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_OBC_HANDSHAKE_DONE_FSM_COMPLETED);
	    break;

	case OTSU_GS_SOFT_RESET_RQST:
		DEBUG_CPRINT(("OTSU- GS SOFT REQUEST\n"));
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_GS_SOFT_RESET_RQST_FSM_COMPLETED);
	    shtdwn_timer_trig();
		obc_shutdown_trigger();
		fw_upd_info.tc_soft_reset_rqst = 1;
		break;

	case OTSU_INITIATE_FW_UPDATE:
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_INITIATE_FW_UPDATE_FSM_COMPLETED);
	    break;

#ifdef BTLR_ON
	case OTSU_GS_CONTACT_TIMER_CALBACK_SERVICE:
		check_gs_contact_time_is_expired();
		break;
#endif

	default:
		DEBUG_CPRINT(("OTSU_FSM_INVALID\n"));
	    log_id(LOG_INFO_L1, LOG_OTSU, OTSU_FSM_INVALID);
	    break;
	}

}


void otsu_thread_fn(void *params)
{

	os_delay(5000);

	/* init otsu */
	otsu_fsm(OTSU_INIT_STATE, 0, NULL, 0);
/*
 *
 */

	while(1)
	{
		/* wait for message queue */
        os_itc_msg_rcv(OBC_OTSU, &otsu_itc_msg_hdl, os_wait_forever);

        /* execute fsm  */
        otsu_fsm(otsu_itc_msg_hdl.Msg_id,otsu_itc_msg_hdl.Msg_len,otsu_itc_msg_hdl.pld.pld_ptr,otsu_itc_msg_hdl.pld_info);

	}
}

/*
 * create otsu handler
 */
void otsu_initialisation(void)
{
    os_thread_create(OBC_OTSU, T_OBC_OTSU_STACK_SIZE, P_OBC_OTSU, "otsu_thread",otsu_thread_fn , NULL, NULL, NULL);
}



