/*
 * otsu_ftm.c
 *
 *  Created on: 29-Dec-2023
 *      Author: Invcuser52
 */

#include "otsu_ftm.h"
#include "ft_dwnld.h"
#include "otsu.h"
#include "version.h"
#include "exo_common.h"
#include "logger.h"
#include "file_integrity_check.h"
#include "crc_cal.h"
#include "nvm.h"
#include "otsu_mem_def.h"
#include "flash_drive.h"
#include "exo_tctm_ipc.h"
#include "adcs_vapi_fw.h"
#include "eps_ftm.h"
#include "comms_ftm.h"
#include "btable_prepare.h"

#ifndef LINUX_TEMP_PORT
#include "stm32f7xx_hal_ext.h"
#endif
#define FLASH_COPY_RETRY_CNT 2
#define EXT_FLASH_ENABLED


#define OTSU_FTM_DWLD_FILE_OBC  1
#define OTSU_FTM_DWLD_FILE_NVM  2

#define OTSU_FIRMWARE_STORAGE_MEM (1024*1024)

/* @brief Handle of contex info
 * structure to handle file data stored in NOR flash when save context mode
 * is triggered by FTM
 * structure size is 12 bytes = 12B
 * it has to be stored in NVM memory
 */
typedef struct nor_savecontxt_info_def
{
	uint32_t file_size_stored;		///< Size of firmware
	uint32_t file_checksum;			///< Checksum of firmware
	uint32_t reserv3;				///< unused
	uint32_t file_stored_sts;  		///< Status of context info; it tells NORflash has data
}nor_savecontxt_info;


static uint8_t 								trig_noti=0;
s_fw_flash_handle 							s_flash_hdle;
static memcpy_info_save_otsu 				memcpy_inf;
extern e_otsu_err_flag 						otsu_fw_error_flag;
extern s_otsu_fw_update_cfg_tc_encode_def 	fw_reboot_config;
static uint8_t 								ftm_nor_write_avail;
uint8_t 									otsu_sct_data_avail;

 static uint8_t 								*gui_savecontext_ptr;
static  uint16 								savecontext_size;
extern firmware_upd_info_def 				fw_upd_info;

extern int8_t fmc_sdram_test();



/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from NOR flash to NOR SDRAM
 * after the resume context request was initiated
 *
 * @param[in]  cpy_sts  : status of memory copy completion status
 *
 * @return none
 * @retval void : none
 */
static uint8_t ftm_savecontext_sdram_copy_compld_cblk(uint8_t cpy_sts, memcpy_info_save_otsu *copy_info);


/**
 * @brief This is the callback function which will be invoked by file transfer module to update
 * the status to OTSU module regarding firmware downalod process
 *
 * @param[in]  ft_sts  : status of file transfer download process
 *
 * @return none
 * @retval void : none
 */
static void ft_otsu_receiver_notificataion_clbk(ft_notification_info *ft_sts);

static uint8_t ftmSaveConext_read_file_from_nor(uint8_t module_id);


static uint8_t otsu_sdram_write_clbk(ptr_typ mem_address, uint8_t *payload_ptr, uint16_t payload_len);


static uint8_t version_check(uint32_t addr);

/**
 * @brief This function is use to prepare boottable after the file download process has completed successfully
 *
 * @param[in]  ft_sts  : status of file transfer download process
 *
 * @return none
 * @retval void : none
 */
static void sdram_fmc_cpy_completed(void);




/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from SDRAM to NOR flash
 * after the savecontext request was initiated
 *
 * @param[in]  cpy_sts  : status of memory copy completion status
 *
 * @return none
 * @retval void : none
 */
static void ftm_savecontext_nor_copy_compld_cblk(uint8_t cpy_sts);



static uint8_t version_check(uint32_t addrs)
{
	uint8_t ret_sts =1;
	uint16_t sw_ver_exisiting_bin;
	uint16_t sw_ver_bin;

	sw_ver_bin = getVersion_downloaded_bin(addrs);
	/* read software version from running software*/
	VER_vidGetVersionInfo((uint8_t*)&sw_ver_exisiting_bin);

	DEBUG_CPRINT(("\n read sw ver: %X.%X",(sw_ver_bin >> 8),(sw_ver_bin & 0xFF)));
	if(sw_ver_bin != sw_ver_exisiting_bin)
	{
		ret_sts = 0;
	}
	else
	{
		/* downloaded binary already running in MCU */
	}
	return ret_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 SDRAM to NOR flash
 * after the savecontext request was initiated
 *
 *
 * callback for memcpy which perform SDRAM copy (0xc0300000) to NOR flash
 * this meory copy was initiated by FTM module when save context mode was initiated from GS
 */
static void ftm_savecontext_nor_copy_compld_cblk(uint8_t cpy_sts)
{
	uint32_t cal_checksum;
	nor_savecontxt_info nor_info_nvm_data;


	DEBUG_CPRINT(("[FTM savecontxt] NOR flash  callback called\n"));
	e_sus_res_state sus_state;

	sus_state =  ft_get_suspend_resume_sts();
	if(sus_state == no_suspend_reusume)
	{
		DEBUG_CPRINT(("FTM savecontext NOR cpy /nvm store discarded \n"));
		log_id(LOG_WARNING,LOG_OTSU,FTM_SAVECONTEXT__NOR_CPY_STORE_DISCARDED);

	}
	else
	{
		if(cpy_sts == 0)
		{

			/* if discovery board has used, checksum cal function will not directly
			 * read data from QSPI flash so memcpy is required to read back content from qspi to sdram
			 */
#ifdef COREBOARD
			cal_checksum = calc_checksum_memory((uint8_t*)memcpy_inf.des_addrs,memcpy_inf.size);
#else
		    os_memcpy_extmem((uint8_t*)memcpy_inf.src_addrs, (uint8_t*)memcpy_inf.des_addrs, memcpy_inf.size, NULL, MEM_CPY_RUN_SAME_THREAD,1);
			cal_checksum = calc_checksum_memory((uint8_t*)memcpy_inf.src_addrs,memcpy_inf.size);
#endif
			if(cal_checksum == memcpy_inf.checksum)
			{
				nor_info_nvm_data.file_size_stored = memcpy_inf.size;
				nor_info_nvm_data.file_checksum = memcpy_inf.checksum;
				nor_info_nvm_data.file_stored_sts = 1;
				/* store in NVM */
				nvm_parameter_write(NVM_DATA,NVM_OTSU_FTM_FILE_CONTXT_DATA,(uint8_t*)&nor_info_nvm_data);
				otsu_sct_data_avail = 1;
				DEBUG_CPRINT(("[FTM savecontxt] NOR flash CRC pass\n"));
				log_id(LOG_INFO_L1,LOG_OTSU,FTM_SAVECONTEXT__NOR_FLASH_CRC_PASS);
				otsu_state_change(e_otsu_ftm_saveconext_norcopy_progress);
				/*
				 * GS notify is required ?
				 */
			}
			else
			{
				DEBUG_CPRINT(("[FTM savecontxt] NOR flash CRC FAIL\n"));
				log_id(LOG_ERROR,LOG_OTSU,FTM_SAVECONTEXT__NOR_FLASH_CRC_FAIL);
				otsu_state_change(e_otsu_ftm_saveconext_norcopy_fail);
				otsu_fw_error_flag = sct_nor_copy_err;
				otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_flash_copy_fail,0xCD);

			}
		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] NOR MEMCPY copy  - Fail\n"));
			log_id(LOG_ERROR,LOG_OTSU,FTM_SAVECONTEXT__NOR_MEMCPY_COPY_FAIL);
			otsu_state_change(e_otsu_ftm_saveconext_norcopy_fail);
			otsu_fw_error_flag = mem_cpy_err;
			otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_flash_copy_fail,otsu_fw_error_flag);
		}
	}
}



static void firmware_downloaded(uint32_t bin_size)
{
	os_itc_msg_handle_t send_msg;

	send_msg.src_entity	 	= FTM_FSM_HANDLER;
	send_msg.pld_info 		= 0;
	send_msg.Msg_id 		= OTSU_FW_DWNLD;
	send_msg.Msg_len 		= 0;
	send_msg.pld.pld_ptr 	= NULL;

    os_itc_msg_send(&send_msg,OBC_OTSU, os_send_itc_wait);
}


/**
 * @brief This is the callback function which will be invoked by memory copy module
 * once it completed the copy operation for firmware copy from NOR flash to NOR SDRAM
 * after the resume context request was initiated
 *
 * callback for memcpy which perform SDRAM copy (0xc0300000) to NOR flash
 * this meory copy was initiated by FTM module when save context mode was initiated from GS
 */
static uint8_t ftm_savecontext_sdram_copy_compld_cblk(uint8_t cpy_sts, memcpy_info_save_otsu *copy_info)
{
	uint32_t cal_checksum;


	DEBUG_CPRINT(("[FTM savecontxt] SDRAM flash  callback called\n"));

	if(cpy_sts == 0)
	{
		cal_checksum = calc_checksum_memory((uint8_t*)copy_info->des_addrs,copy_info->size);
		if(cal_checksum == copy_info->checksum)
		{
			/* Notify GS that SDRAM is ready to resume download */
			DEBUG_CPRINT(("[FTM savecontxt] SDRAM flash CRC pass\n"));
			log_id(LOG_INFO_L1,LOG_OTSU,FTM_SAVECONTEXT__SDRAM_FLASH_CRC_PASS);
			otsu_state_change(e_otsu_ftm_saveconext_norcopy_pass);

			otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_ready_4resume_cntxt,0xCD);
			return 0;

		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] SDRAM flash CRC FAIL\n"));
			log_id(LOG_ERROR,LOG_OTSU,FTM_SAVECONTEXT__SDRAM_FLASH_CRC_FAIL);
			otsu_state_change(e_otsu_ftm_saveconext_norcopy_fail);
			otsu_fw_error_flag = sct_sdram_err;

			otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_flash_copy_fail,0xCD);
			return 1;

		}
	}
	else
	{
		DEBUG_CPRINT(("[FTM savecontxt] NOR flash callback called - Fail\n"));
		log_id(LOG_ERROR,LOG_OTSU,FTM_SAVECONTEXT__NOR_FLASH_CALLBACK_CALLED_FAIL);
		otsu_state_change(e_otsu_ftm_saveconext_norcopy_fail);
		otsu_fw_error_flag = mem_cpy_err;

		otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_flash_copy_fail,0xCD);
		return 2;

	}
}



static uint8_t otsu_sdram_write_clbk(ptr_typ mem_address, uint8_t *payload_ptr, uint16_t payload_len)
{
	uint8_t ret_busy_sts = 0;
	uint16_t u16cnt;
	uint8_t test_ram=0;

	if(test_ram == 1)
	{
		fmc_sdram_test();
		test_ram = 0;
	}
	mem_address = mem_address & 0xffffffff;
	if(payload_ptr != NULL)
	{
		  for (u16cnt = 0; u16cnt < payload_len; u16cnt = u16cnt+1)
		  {
			*(__IO uint8_t*) (mem_address + u16cnt) = payload_ptr[u16cnt];
		  }
		  ret_busy_sts = 1;
	}
	return ret_busy_sts;
}




/**
 * @brief This is the callback function which will be invoked by file transfer module to update
 * the status to OTSU module regarding firmware downalod process
 *
 *  Application API which will be invoked during file transmission by FT framework
 *
 */
static void ft_otsu_receiver_notificataion_clbk(ft_notification_info *ft_sts)
{



	/*
	 *
	 *  THis callback service function should not wait for long time
	 *
	 *
	 */
	uint16_t u16cnt;
	uint8_t ret_sts;
	uint32_t mem_address_alloc;
	uint16_t sw_ver_bin;
	e_avtive_type node_act_type;

	static uint8_t nack_test = 1;


	DEBUG_CPRINT(("App notification API invoked !!!!\n"));

	if(ft_sts->status == transfer_download_success)
	{
		DEBUG_CPRINT(("1. download success\n"));
		log_id(LOG_INFO_L1,LOG_OTSU,OTSU_FILE_DOWNLOAD_SUCCESS);
		if(ft_sts->dwld_info.tx_mode == 1)
		{
			DEBUG_CPRINT(("2. Transfer mode : DATA\n"));
			DEBUG_CPRINT(("3. Bulkdata received :"));

			for (u16cnt = 0; u16cnt < ft_sts->dwld_info.size_file_or_data; u16cnt++)
			{
				DEBUG_CPRINT(("%d,",ft_sts->dwld_info.bulkdata_ptr[u16cnt]));
			}
			DEBUG_CPRINT(("\n"));
		}
		else
		{
			if(trig_noti !=1)
			{
				DEBUG_CPRINT(("2. Transfer mode : FILE\n"));
				DEBUG_CPRINT(("3. File Stored path : "));
				for (u16cnt = 0; u16cnt < ft_sts->dwld_info.path_filename_buf_length; u16cnt++)
				{
					DEBUG_CPRINT(("%c",ft_sts->dwld_info.storage_path_and_File_name[u16cnt]));
				}
				DEBUG_CPRINT(("\n4. File size : %ld",ft_sts->dwld_info.size_file_or_data));

				DEBUG_CPRINT(("\n5. Bin data: \n"));
				for (u16cnt = 0; u16cnt < 20; u16cnt++)
			//	for (u16cnt = 0; u16cnt < ft_sts->dwld_info.size_file_or_data; u16cnt++)
				{
					DEBUG_CPRINT(("%c",ft_sts->dwld_info.bulkdata_ptr[u16cnt]));
				}
				DEBUG_CPRINT(("\n"));
			}


			if(ft_sts->dwld_info.tx_file_id == OTSU_FTM_DWLD_FILE_OBC)
			{
				ret_sts = header_integrity_check((uint32_t)ft_sts->dwld_info.bulkdata_ptr);
				if (ret_sts == R_OK1)
				{
					ret_sts = version_check((uint32_t)ft_sts->dwld_info.bulkdata_ptr);
					if(ret_sts == 0)
					{
						s_flash_hdle.storage_address = (uint32_t)ft_sts->dwld_info.bulkdata_ptr; //EXT_SDRAM_MEM_ADDR;
						sw_ver_bin = getVersion_downloaded_bin(s_flash_hdle.storage_address);
						//prepare_reboot_config_param(sw_ver_bin);
						s_flash_hdle.sw_version_bin = sw_ver_bin;
						s_flash_hdle.flash_sts = 1;
						s_flash_hdle.module_id = 0;
						s_flash_hdle.binary_size = ft_sts->dwld_info.size_file_or_data;
						s_flash_hdle.storage_address = (uint32_t)ft_sts->dwld_info.bulkdata_ptr; //EXT_SDRAM_MEM_ADDR;
						s_flash_hdle.input_buffer_ptr = ft_sts->dwld_info.bulkdata_ptr; //EXT_SDRAM_MEM_ADDR;
						mem_address_alloc = otsu_get_fw_storage_address();
						s_flash_hdle.flash_address_inc = mem_address_alloc; //DWNLD_CODE_LOC;
						s_flash_hdle.bin_checksum = ft_sts->dwld_info.checksum;
						s_flash_hdle.flash_write_option = 1;
						s_flash_hdle.input_buffer_index_cntr = 0;
						s_flash_hdle.bin_copy_trial = 0;
					    mem_address_alloc = otsu_get_ftm_download_address();
						DEBUG_CPRINT(("Current OTSU state when FTM notify arrives :%d\n",get_otsu_state()));
						/* TBD need to check the 5sec delay is required */
						otsu_state_change(e_otsu_dwld_copy);
						DEBUG_CPRINT(("FTM Sdram to Nor LOC C copy wait for 10 mins\n"));

						firmware_downloaded(s_flash_hdle.binary_size);
					}
					else
					{
						DEBUG_CPRINT(("\r\nNOR copy from SDRAM cancelled due to existing sft received again"));
						sw_ver_bin = getVersion_downloaded_bin((uint32_t)ft_sts->dwld_info.bulkdata_ptr);
						otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_sft_ver_exists,sw_ver_bin);
						otsu_state_change(e_otsu_dwnd_cancel_fw_exists);
					}

				}
				else
				{

					DEBUG_CPRINT(("\r\n Invalid FW received. File discarded"));
					log_id(LOG_ERROR,LOG_OTSU,INVALID_FW_RECEIVED_FILE_DISCARDED);
				}

			}
			else if(ft_sts->dwld_info.tx_file_id == OTSU_FTM_DWLD_FILE_NVM)
			{
				nvm_fw_download_in_c(ft_sts->dwld_info.bulkdata_ptr, ft_sts->dwld_info.size_file_or_data, ft_sts->dwld_info.checksum);
			}
			else
			{
				// invalid file id received
				// add log
			}

		}


	}
	else if(ft_sts->status == crc_error)
	{
		DEBUG_CPRINT(("1. download failed/ CRC error\n"));
		if(ft_sts->dwld_info.tx_mode == 1)
		{
			DEBUG_CPRINT(("2. Transfer mode : DATA\n"));
		}

	}
	else if(ft_sts->status == transfer_suspended)
	{
		DEBUG_CPRINT(("1. download suspended by sender [Timeout mode]\n"));

	}
	else if(ft_sts->status == transfer_suspended_savecontext ||
			ft_sts->status == transfer_suspended_auto_savecontext ||
			ft_sts->status == transfer_suspend_savecontext_accepeted ||
		    ft_sts->status == transfer_suspended_savecontext_etended_sts)
		{

		if(ft_sts->status != transfer_suspended_savecontext_etended_sts)
		{
			ftm_nor_write_avail = 0;
				 if(ft_sts->status == transfer_suspended_savecontext)
				 {
						DEBUG_CPRINT(("1. download suspended by sender [Save Context Mode]\n"));
						log_id(LOG_ERROR,LOG_OTSU,DOWNLOAD_SUSPENDED_BY_SENDER__SAVE_CONTEXT_MODE);
				 }
				 else if(ft_sts->status == transfer_suspended_auto_savecontext)
				 {
						DEBUG_CPRINT(("1. Auto [Save Context Mode] activated\n"));
						log_id(LOG_INFO_L1,LOG_OTSU,AUTO__SAVE_CONTEXT_MODE__ACTIVATED);
				 }
				 else if(ft_sts->status == transfer_suspend_savecontext_accepeted)
				 {
						DEBUG_CPRINT(("1. Manual [Save Context Mode] activated\n"));
						log_id(LOG_INFO_L1,LOG_OTSU,MANUAL__SAVE_CONTEXT_MODE__ACTIVATED);
				 }
				 else
				 {

				 }

				DEBUG_CPRINT(("2. malloc req: %d \n",ft_sts->context_info.context_info_size));
				//gui_savecontext_ptr = os_malloc(ft_sts->context_info.context_info_size);
				gui_savecontext_ptr = os_malloc(200);
				if(gui_savecontext_ptr != NULL)
				{
					memset(gui_savecontext_ptr,0,200);
					savecontext_size = ft_sts->context_info.context_info_size;
					DEBUG_CPRINT(("2. context data size: %d\n",savecontext_size));
					DEBUG_CPRINT(("3. context data : "));
					for (u16cnt = 0; u16cnt < savecontext_size; u16cnt++)
					{
						gui_savecontext_ptr[u16cnt] = ft_sts->context_info.context_info_buf_ptr[u16cnt];
						//DEBUG_CPRINT(("%x ",gui_savecontext_ptr[u16cnt]));
					}
					/* send ack */

					display_context_info();

					node_act_type = ft_get_master_slave_status();
					if(node_act_type == sus_res_slave)
					{
						 if(ft_sts->status == transfer_suspended_savecontext)
						 {
							if(nack_test != 0)
							{
								ft_transfer_request(Suspend_Savecontext_ack_rqst,0);
								//file_tx_running = 0;
							}
							else
							{
								ft_transfer_request(Suspend_Savecontext_nack_rqst,0);
								nack_test = 1;
							}
						 }
						 else
						 {
							 // do nothing // skip response frame if auto suspend is actiavted
						 }
						/* store FTM structure/global variables in NVM */

					   /* TODO */
						nvm_parameter_write(NVM_DATA,NVM_OTSU_FTM_CONTXT_DATA,gui_savecontext_ptr);
						os_free(gui_savecontext_ptr);
						gui_savecontext_ptr = NULL;
						/* initiate NOR copy to save file which is stored in SDRAM */
						memcpy_inf.src_addrs = ft_sts->context_info.bulkdata_mem_addr & 0xffffffff;
						memcpy_inf.des_addrs = otsu_get_fw_storage_address();
						memcpy_inf.size = ft_sts->context_info.bulkdata_len;
						memcpy_inf.checksum = ft_sts->context_info.bulkdata_checksum;
						ftm_nor_write_avail = 1;
					}
				}
		}
		else
		{
		     DEBUG_CPRINT(("FTM - SCT 100%% completed <<<\n"));
		     log_id(LOG_INFO_L1,LOG_OTSU,FTM__SCT_100_COMPLETED);
			 if(ft_sts->status == transfer_suspended_savecontext_etended_sts)
			 {
					if(ftm_nor_write_avail == 1)
					{
						DEBUG_CPRINT(("NOR copy initiated\n"));
						ret_sts = os_memcpy_extmem((uint8_t*)memcpy_inf.des_addrs, (uint8_t*)memcpy_inf.src_addrs, memcpy_inf.size, NULL, MEM_CPY_RUN_SAME_THREAD,1);
						otsu_state_change(e_otsu_ftm_saveconext_norcopy_progress);
						ftm_savecontext_nor_copy_compld_cblk(ret_sts);
						ftm_nor_write_avail = 0;
					}
					else
					{
						DEBUG_CPRINT(("NOR copy not initiated.\n"));
					}
			 }
			 else
			 {
					DEBUG_CPRINT(("0. Invalid case ??? \n"));
			 }
		}
	}
	else if(ft_sts->status == transfer_resumed)
	{
		DEBUG_CPRINT(("1. downloading resumed by sender\n"));
	}
	else if(ft_sts->status == transfer_resume_accepted)
	{
		DEBUG_CPRINT(("1. downloading resumed back by sender\n"));
	}
	else if(ft_sts->status == tx_terminated_suspend_timeout_expired)
	{
		DEBUG_CPRINT(("1. download Terminated due to suspend timeout expired\n"));

	}
	else if(ft_sts->status == transfer_suspend_accepted)
	{
		DEBUG_CPRINT(("1. download Suspend - Timeout mode Accepted by Sender\n"));

	}
	else if(ft_sts->status == transfer_suspend_savecontext_accepeted)
	{

	}
	else if(ft_sts->status == transfer_resumed_restorecontext)
		{
			ftm_nor_write_avail = 0;
			DEBUG_CPRINT(("1. Download Resume Savecontext mode Requested by Sender\n"));


			DEBUG_CPRINT(("\r\nResume-SaveContext mode [Bulkdata] selected \r\n"));

			/*
			 * Read FTM context info in NVM
			 *
			 */
			gui_savecontext_ptr = os_malloc(200);
			if(gui_savecontext_ptr != NULL)
			{
				nvm_parameter_read(NVM_DATA,NVM_OTSU_FTM_CONTXT_DATA,gui_savecontext_ptr);
				ft_contextsave_info *c_inf = (ft_contextsave_info*)gui_savecontext_ptr;
				savecontext_size = c_inf->context_info_size;
	//			if(c_inf->tx_mode == 1)
				{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
					DEBUG_CPRINT(("Mem address passing 0x%lux of size %lu \n",c_inf->bulkdata_mem_addr,c_inf->bulkdata_len));
#pragma GCC diagnostic pop
					ft_config_receiver_node_storage_address(c_inf->bulkdata_mem_addr&0xffffffff);
				}



			ret_sts = ft_resume_context(gui_savecontext_ptr,savecontext_size);
			if(ret_sts == 0)
			{
				/* resume context success */
				nor_savecontxt_info *nor_info_nvm_data =(nor_savecontxt_info*) os_malloc(sizeof(nor_savecontxt_info));
				os_memset(gui_savecontext_ptr,0,200);
				os_memset(&nor_info_nvm_data,0,sizeof(nor_info_nvm_data));
				nvm_parameter_write(NVM_DATA,NVM_OTSU_FTM_CONTXT_DATA,gui_savecontext_ptr);
				nvm_parameter_write(NVM_DATA,NVM_OTSU_FTM_FILE_CONTXT_DATA,(uint8_t*)&nor_info_nvm_data);
				otsu_sct_data_avail = 0;
				os_free(gui_savecontext_ptr);
				gui_savecontext_ptr = NULL;
				os_free(nor_info_nvm_data);
				nor_info_nvm_data = NULL;
			}
			else
			{
				/* resume fail */
				if(ret_sts == 0x04)
				{
					/*
					 * error code : 0x04 >> SDRAM copy is not valid ,
					 *    so need to prepare SDRAM with NOR flash content file data
					 * before that it need to confirm that is NOR location has really having file data
					 */
					ret_sts = ftmSaveConext_read_file_from_nor(FTM_GET_SCT_STATUS_OTSU);
					if(ret_sts == 0)
					{
						/* NOR flash is having file data , so memcpy can be done from NOR to SDARM */
					}
					else
					{

					}


				}
				DEBUG_CPRINT(("Resume-SaveContext Error %d\n",ret_sts));
				}
			}
		}
	else if(ft_sts->status == transfer_download_ready)
	{
	     DEBUG_CPRINT(("OTSU_check BLT ****m\n"));
		DEBUG_CPRINT(("1. Download request received\n"));
		log_id(LOG_INFO_L1,LOG_OTSU,DOWNLOAD_REQUEST_RECEIVED);
		if(ft_sts->dwld_info.tx_mode == 1)
		{
			DEBUG_CPRINT(("2. Transfer mode : DATA\n"));
		}
		else
		{
			DEBUG_CPRINT(("2. Transfer mode : FILE\n"));
			DEBUG_CPRINT(("3. File size: %ld\n",ft_sts->dwld_info.size_file_or_data));
			/* 0xC00000000 is allocated for firmware download */

			mem_address_alloc = obc_file_memory_alloc(ft_sts->dwld_info.size_file_or_data);
			DEBUG_CPRINT(("[OBC] Allocated memory for binary file, addr:0x%lux\n",mem_address_alloc));
			mem_address_alloc = otsu_get_ftm_download_address();
			if((ft_sts->dwld_info.size_file_or_data) < (OTSU_FIRMWARE_STORAGE_MEM))
			{
				ft_config_receiver_node_storage_address(mem_address_alloc);
			}
			else
			{
				// dont allocate memory if requested size is not in range, so FTM will discard download request
			}

		}
	}
	else if(ft_sts->status == transfer_resume_savecontext_accepeted)
	{
		DEBUG_CPRINT(("1. download Resume - Savecontext mode Accepted by Sender\n"));
	}
	else if(ft_sts->status == transmission_terminated_by_rx_node)
	{
		DEBUG_CPRINT(("1. download Terminated by Receiver node\n"));
	}
	else if(ft_sts->status == transfer_otsu)
	{

	}
	else if(ft_sts->status == transfer_suspend_tout_not_accepted)
	{
		DEBUG_CPRINT(("1. suspend timeout request not completed\n"));
	}
	else if(ft_sts->status == transfer_suspend_savecontext_failed)
	{
		DEBUG_CPRINT(("1. suspend savecontxt request not completed\n"));
	}
	else if(ft_sts->status == transfer_rseume_tout_not_accepted)
	{
		DEBUG_CPRINT(("1. resume timeout request not completed\n"));
	}
	else if(ft_sts->status == transfer_resume_restorecontext_failed)
	{
		DEBUG_CPRINT(("1. resume savecontxt request not completed\n"));
	}
	else
	{
		DEBUG_CPRINT(("Invalid Notification not processed\n"));
	}

	DEBUG_CPRINT(("\n-------------/End/---------------\n\n"));


}



/**
 * @brief This function is use to prepare boottable after the file download process has completed successfully
 *
 */
static void sdram_fmc_cpy_completed(void)
{
	uint32_t cal_checksum;
	uint8_t ret_sts;


	// fw_flash copy from SDRAM to flash has completed
	s_flash_hdle.flash_sts = 0;
	os_delay(1000);
	cal_checksum = calc_checksum_memory((uint8_t*)s_flash_hdle.flash_address_inc,s_flash_hdle.binary_size);

	if(cal_checksum == s_flash_hdle.bin_checksum)
	{
		// log
		otsu_state_change(e_otsu_dwld_complete);
		/* prepare boottable for module level */
		ret_sts = prepare_boottable_setup_for_module(s_flash_hdle.flash_address_inc,HEADER_INTG_TEST,SET_CLEAR_UNDEF);
		if (ret_sts)
		{
			fw_upd_info.nw_frmw_avail_sts = nw_frm_avail;

			nvm_parameter_write(NVM_DATA,NVM_OTSU_NW_FRMW_STS,(uint8_t*)&fw_upd_info.nw_frmw_avail_sts);
			os_memset(&fw_reboot_config,0,sizeof(s_otsu_fw_update_cfg_tc_encode_def));
			fw_reboot_config.boot_operation_ctrl = BOOT_CONTROL_FW_DWNLD;

			/* TODO save NEW FW available status in nvm */
			configure_reboot_schedule(TM_RES_REQ);
			nvm_parameter_write(NVM_DATA,NVM_OTSU_REBOOT_CONFIG,(uint8_t*)&fw_reboot_config);
            otsu_state_change(e_otsu_dwld_complete);
		}
		else
		{
			DEBUG_CPRINT(("\n[e_otsu_dwld_bin_header_error]rboot table update failed : invalid entry \n\r"));
            log_id(LOG_ERROR,LOG_OTSU,DWND_BIN_HWADER_INVALID);
            otsu_state_change(e_otsu_dwld_bin_header_error);
			/* TODO send report to GS */
		}
	}
	else
	{
		/* copy operation will be done again if first trail not done successfully */
		s_flash_hdle.bin_copy_trial = FLASH_COPY_RETRY_CNT +2;
		otsu_state_change(e_otsu_dwld_crc_error);
		if(s_flash_hdle.bin_copy_trial > (FLASH_COPY_RETRY_CNT-1))
		{
			/* failed at 2nd trial then send report to GS */
			otsu_fw_error_flag = sdram_fmc_cpy_err;
			otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_flash_copy_fail,s_flash_hdle.sw_version_bin);
			otsu_state_change(e_otsu_dwld_flash_copy_fail);
		}
	}

}



static uint8_t ftmSaveConext_read_file_from_nor(uint8_t module_id)
{
	uint8_t ret_sts =0;
	ft_contextsave_info* c_info_ptr;
	memcpy_info_save_otsu loc_memcpy_inf;

	c_info_ptr = (ft_contextsave_info*)gui_savecontext_ptr;

	/* read NVM flash */
	nor_savecontxt_info *nor_info_nvm_data =(nor_savecontxt_info*) os_malloc(sizeof(nor_savecontxt_info));
	switch (module_id)
	{
	case FTM_GET_SCT_STATUS_OTSU:
	    nvm_parameter_read(NVM_DATA,NVM_OTSU_FTM_FILE_CONTXT_DATA,(uint8_t*)nor_info_nvm_data);
	    break;
	case FTM_GET_SCT_STATUS_ADCS:
		nvm_parameter_read(NVM_DATA,NVM_ADCS_FTM_FILE_CONTXT_DATA,(uint8_t*)nor_info_nvm_data);
		break;
	case FTM_GET_SCT_STATUS_COMMS:
		nvm_parameter_read(NVM_DATA,NVM_COMMS_FTM_FILE_CONTXT_DATA,(uint8_t*)nor_info_nvm_data);
		break;
	case FTM_GET_SCT_STATUS_EPS_FILE_ONE:
		nvm_parameter_read(NVM_DATA,NVM_EPS_FTM_FILE_CONTXT_DATA,(uint8_t*)nor_info_nvm_data);
		break;
	default:
	    nvm_parameter_read(NVM_DATA,NVM_OTSU_FTM_FILE_CONTXT_DATA,(uint8_t*)nor_info_nvm_data);
		break;
	}

	if(c_info_ptr->bulkdata_len == nor_info_nvm_data->file_size_stored && c_info_ptr->bulkdata_len != 0 && c_info_ptr->bulkdata_len != 0xFFFFFFFF)
	{
		if(c_info_ptr->bulkdata_checksum == nor_info_nvm_data->file_checksum && c_info_ptr->bulkdata_checksum != 0 && c_info_ptr->bulkdata_checksum != 0xFFFFFFFF)
		{
			/* NOR flash is having file data , so memcpy can be done from NOR to SDARM */
			switch (module_id)
			{
				case FTM_GET_SCT_STATUS_OTSU:
					loc_memcpy_inf.des_addrs = otsu_get_ftm_download_address();
					loc_memcpy_inf.src_addrs = otsu_get_fw_storage_address();
					break;
				case FTM_GET_SCT_STATUS_ADCS:
					loc_memcpy_inf.des_addrs = (uint32_t)adcs_get_sdram_storage_address();
					loc_memcpy_inf.src_addrs = (uint32_t)adcs_get_nor_flash_address();
					break;
				case FTM_GET_SCT_STATUS_COMMS:
					loc_memcpy_inf.des_addrs = comms_get_ftm_download_address();
					loc_memcpy_inf.src_addrs = comms_get_fw_storage_address();
					break;
				case FTM_GET_SCT_STATUS_EPS_FILE_ONE:
					loc_memcpy_inf.des_addrs = eps_get_ftm_download_address();
					loc_memcpy_inf.src_addrs = eps_get_fw_storage_address();
					break;
				default:
					loc_memcpy_inf.des_addrs = otsu_get_ftm_download_address();
					loc_memcpy_inf.src_addrs = otsu_get_fw_storage_address();
					break;
			}

			loc_memcpy_inf.size = nor_info_nvm_data->file_size_stored;
			loc_memcpy_inf.checksum = nor_info_nvm_data->file_checksum;
			DEBUG_CPRINT(("Src addr: %lux\nDsc addr: %lux\nSize: %lu\nChecksum: %lux\n",loc_memcpy_inf.src_addrs,loc_memcpy_inf.des_addrs,loc_memcpy_inf.size,loc_memcpy_inf.checksum));
			otsu_state_change(e_otsu_ftm_saveconext_sdramcopy_progress);
			ret_sts = os_memcpy_extmem((uint8_t*)loc_memcpy_inf.des_addrs, (uint8_t*)loc_memcpy_inf.src_addrs, loc_memcpy_inf.size, NULL, MEM_CPY_RUN_SAME_THREAD,1);
			ret_sts = ftm_savecontext_sdram_copy_compld_cblk(ret_sts, &loc_memcpy_inf);
		        otsu_sct_data_avail = 1;
		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] NOR data not avail checksum Fail\n"));
			log_id(LOG_ERROR,LOG_OTSU,FTM_SAVECONTEXT__NOR_DATA_NOT_AVAIL_CHECKSUM_FAIL);
			ret_sts = 3;
			//otsu_encode_tm(otfs_flash_copy_fail,0xCD);
		}
	}
	else
	{
		DEBUG_CPRINT(("[FTM savecontxt] NOR data not avail\n"));
		log_id(LOG_INFO_L1,LOG_OTSU,FTM_SAVECONTEXT__NOR_DATA_NOT_AVAIL);
		ret_sts = 4;
		//otsu_encode_tm(otfs_flash_copy_fail,0xCD);
	}
	os_free(nor_info_nvm_data);
	nor_info_nvm_data = NULL;
	return ret_sts;
}




/*
This function will check sct info availabel in NVM are valid before initiate NOR read
*/
uint8_t ftmSaveConext_nvm_crc_verify(ftm_sct_module_id module_id)
{
	uint8_t ret_sts =0;
	uint32_t sct_size;
	uint32_t checksum;
	uint32_t *rx_checksum;

	ft_contextsave_info* c_info_ptr;

	c_info_ptr = (ft_contextsave_info*)gui_savecontext_ptr;
	sct_size = c_info_ptr->context_info_size;

	if(sct_size < 200 && sct_size > 7)
	{
		checksum = calc_checksum_bulkdata(gui_savecontext_ptr, sct_size-4);
		rx_checksum = (uint32_t*)&gui_savecontext_ptr[sct_size-4];

		if(checksum != *rx_checksum)
		{
			DEBUG_CPRINT(("[FTM savecontxt] Error !!! Context data Checksum fail\n"));
			log_id(LOG_ERROR,LOG_OTSU,FTM_SAVECONTEXT__ERROR__CONTEXT_DATA_CHECKSUM_FAIL);
			DEBUG_CPRINT(("[FTM savecontxt] Calculated context checksum %luX failed against %luX\n",checksum,*rx_checksum));
			DEBUG_CPRINT(("[FTM savecontxt] NOR data not avail\n"));
			ret_sts = 5;
		}
		else
		{
			ret_sts = ftmSaveConext_read_file_from_nor(module_id);
		}
	}
	else
	{
		DEBUG_CPRINT(("[FTM savecontxt] Size invalid, NOR data not avail\n"));
		log_id(LOG_INFO_L1, LOG_OTSU, SAVE_CONTEXT_NOT_AVAIL);
		ret_sts = 6;
	}


	return ret_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 SDRAM to NOR flash
 * after the file download
 */
 void sdram_fmc_flash_copy_clbk(uint8_t sts)
{
	if(sts == 0)
	{
		sdram_fmc_cpy_completed();
	}
	else
	{
		otsu_fw_error_flag = mem_cpy_err;
		otsu_encode_tm(TM_OTSU_NOTIFICATION, otfs_flash_copy_fail,s_flash_hdle.sw_version_bin);
		otsu_state_change(e_otsu_dwld_copy_error);
	}
}



 /*
  * Read FTM savecontext data has available for requested module
  *
  * 0 - success, rct can be initiated
  * 1 - file data corrupted
  * 2 - file copy error
  * 3 - file context checksum error
  * 4 - ftm context and file context mismatch
  * 5 - ftm context data checksum error
  * 6 - ftm context not available
  * 7 - malloc fail
  *
  */

uint8_t ftm_get_savecontext_status(ftm_sct_module_id module_id)
{
	uint8_t ret_sts;
        gui_savecontext_ptr = os_malloc(200);
 	if(gui_savecontext_ptr != NULL)
 	{

	 switch (module_id)
	 {
	 case FTM_GET_SCT_STATUS_OTSU:
	 	 nvm_parameter_read(NVM_DATA, NVM_OTSU_FTM_CONTXT_DATA, gui_savecontext_ptr);
	 	 break;
	 case FTM_GET_SCT_STATUS_ADCS:
		 nvm_parameter_read(NVM_DATA, NVM_ADCS_FTM_CONTXT_DATA, gui_savecontext_ptr);
		 break;
	 case FTM_GET_SCT_STATUS_COMMS:
		 nvm_parameter_read(NVM_DATA, NVM_COMMS_FTM_CONTXT_DATA, gui_savecontext_ptr);
		 break;
	 case FTM_GET_SCT_STATUS_EPS_FILE_ONE:
		 nvm_parameter_read(NVM_DATA, NVM_EPS_FTM_CONTXT_DATA, gui_savecontext_ptr);
		 break;
	 default:
		 module_id = 1;
	 	 nvm_parameter_read(NVM_DATA, NVM_OTSU_FTM_CONTXT_DATA, gui_savecontext_ptr);
		 break;
 	 }
 		ret_sts = ftmSaveConext_nvm_crc_verify(module_id);
 		os_free(gui_savecontext_ptr);
 		gui_savecontext_ptr = NULL;
 	}
 	else
 	{
 		ret_sts = 7;
 	}

 	return ret_sts;
}



void otsu_ftm_register(void)
{
	/* register notification callback api with file transfer */
	ft_register_receiver_app(TC_DST_FTM_OTSU, ft_otsu_receiver_notificataion_clbk);
	ft_register_ramwrite_cblk((ft_data_write_cblk_type)otsu_sdram_write_clbk);
}



void send_ftm_dwld_msg(void)
{
	s_flash_hdle.flash_address_inc = 0x60f00000;
	s_flash_hdle.storage_address = 0xc09dbcd4;
	s_flash_hdle.binary_size = 0x00091F1C;
	s_flash_hdle.bin_checksum = 0x9A5B3715;
	firmware_downloaded(s_flash_hdle.binary_size);
}
