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


#include "exo_common.h"
#include "eps_btlr_driver.h"
#include "exo_types.h"
#include "file_integrity_check.h"
#include "nvm.h"
#include "eps_fw_update.h"
#include "logger.h"
#include "ft_dwnld.h"
#include "otsu.h"
#include "crc_cal.h"
#include "exo_io_al_crc_common.h"
#include "eps_ftm.h"
#include "exo_tctm_ipc.h"

extern firmware_status fw_conv_upt_progress_status;
extern firmware_status fw_op_chnl_upt_progress_status;
#define EPS_FIRMWARE_STORAGE_MEM (200*1024)
#ifndef LINUX_TEMP_PORT

typedef enum eps_fw_name_def
{
	EPS_CONV_FW=1,
	EPS_BATT_FW,
	EPS_CONV_BCKUP_FW,
	EPS_OP_CHNL_BCKUP_FW
}eps_fw_name;

/* Allocated SDRAM for EPS module 200kb*/
uint8_t eps_ftm_file_dwnlod_storage[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_RAM_MEM;

#ifdef COREBOARD
/* Allocated FMC NOR for EPS module 2kb*/
uint8_t eps_conv_fw_storage[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_FMC_FLASH_MEM;
uint8_t eps_op_chnl_fw_storage[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_FMC_FLASH_MEM;
uint8_t eps_conv_fw_storage_backup[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_FMC_FLASH_MEM;
uint8_t eps_op_chnl_fw_storage_backup[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_FMC_FLASH_MEM;
#else
/* Allocated QSPI NOR for EPS module 2kb, if board is discovery*/
uint8_t eps_conv_fw_storage[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_QSPI_FLASH_MEM;
uint8_t eps_op_chnl_fw_storage[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_QSPI_FLASH_MEM;
uint8_t eps_conv_fw_storage_backup[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_QSPI_FLASH_MEM;
uint8_t eps_op_chnl_fw_storage_backup[EPS_FIRMWARE_STORAGE_MEM] PLACE_IN_EXT_QSPI_FLASH_MEM;
#endif

#else
uint8_t eps_ftm_file_dwnlod_storage_linux[EPS_FIRMWARE_STORAGE_MEM];
#endif


#ifndef LINUX_TEMP_PORT
static uint8_t PLACE_IN_EXT_RAM_MEM ftm_nor_write_avail;

/**
* @brief This function will return the download address to be allocated for file transfer
*/
uint32_t eps_get_ftm_download_address()
{
	return (uint32_t) eps_ftm_file_dwnlod_storage;
}

/**
* @brief This function will return the storage addrewss to be used to move firmware stored in sdram to
* external flash
*/
uint32_t eps_get_fw_storage_address()
{
	return (uint32_t) eps_conv_fw_storage;
}


typedef struct memcpy_info_save_def
{
	uint32_t src_addrs;
	uint32_t des_addrs;
	uint32_t size;
	uint32_t checksum;
}memcpy_info_save;
static memcpy_info_save eps_memcpy_inf;
#endif

/* @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;


#ifndef LINUX_TEMP_PORT
static uint8_t eps_ftmSaveConext_read_file_from_nor(ft_contextsave_info* c_info_ptr);

/**
* @brief This function will be invoked by memcopy module once firmware
*  fully moved from SDRAM to permanent storage memory NOR flash
*
* @param sts : Unused variable
*/
static void eps_sdram_nor_cpy_completed(eps_fw_name fw_id, memcpy_info_save *s_eps_ftm_handle);

#endif

#ifndef LINUX_TEMP_PORT

/*
 * @brief This API calculate the CRC of copied data in SDRAM from NOR flash
 */
static void eps_ftm_savecontext_sdram_copy_compld_cblk(uint8_t cpy_sts, memcpy_info_save *memcpy_inf_ptr)
{
	uint32_t cal_checksum;


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

	if(cpy_sts == 0)
	{
		cal_checksum = calc_checksum_memory((uint8_t*)&memcpy_inf_ptr->des_addrs,memcpy_inf_ptr->size);
		if(cal_checksum == memcpy_inf_ptr->checksum)
		{
			/* Notify GS that SDRAM is ready to resume download */
			DEBUG_CPRINT(("[FTM savecontxt] SDRAM flash CRC pass\n"));
		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] SDRAM flash CRC FAIL\n"));

		}
	}
	else
	{
		DEBUG_CPRINT(("[FTM savecontxt] NOR flash callback called - Fail\n"));
	}
}

/*
 * @brief This API read the data from specified address location of NOR-flash memory and copy
 * the data in SDRAM memory
 */
static uint8_t eps_ftmSaveConext_read_file_from_nor(ft_contextsave_info* c_info_ptr)
{
	uint8_t ret_sts =0;
	memcpy_info_save loc_memcpy_inf;
	/* read NVM flash */
	nor_savecontxt_info *nor_info_nvm_data =(nor_savecontxt_info*) os_malloc(sizeof(nor_savecontxt_info));
    nvm_parameter_read(NVM_DATA,NVM_EPS_FTM_FILE_CONTXT_DATA,(uint8_t*)nor_info_nvm_data);

	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 */
			loc_memcpy_inf.des_addrs = (uint32_t)eps_ftm_file_dwnlod_storage;
			loc_memcpy_inf.src_addrs = (uint32_t)eps_conv_fw_storage;
			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));
			ret_sts = os_memcpy_extmem((uint8_t*)loc_memcpy_inf.des_addrs, (uint8_t*)loc_memcpy_inf.src_addrs, loc_memcpy_inf.size, NULL, 1,1);
			eps_ftm_savecontext_sdram_copy_compld_cblk(ret_sts, &loc_memcpy_inf);
			ret_sts =1;
		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] NOR data not avail checksum Fail\n"));
		}
	}
	else
	{
		DEBUG_CPRINT(("[FTM savecontxt] NOR data not avail\n"));
	}
	os_free(nor_info_nvm_data);
	nor_info_nvm_data = NULL;
	return ret_sts;
}

#endif

/**
 * @brief This function used to calculate CRC by applying CRC32 algorithm
 */
uint32_t Crc32_temp(uint32_t Crc, uint32_t Data)
{
  uint8_t index;

  Crc = Crc ^ Data;

  for(index=0; index<32; index++)
  {
    if (Crc & 0x80000000)
      Crc = (Crc << 1) ^ 0x04C11DB7; // Polynomial used in STM32
    else
      Crc = (Crc << 1);
  }
  return(Crc);
}


/**
 * @brief This function used to calculate integrity and return the calculated CRC
 * this function will calculate crc only if length is 4 byte aligned
 */
uint32_t calc_checksum_memory_temp(uint8_t *data_buf,uint32_t length)
{
	uint32_t read_buffer = 0xffffffff;
	uint32_t calc_CRC;
	uint32_t buf_inc;

	// checking if the file exist or not
	if (data_buf == NULL)
	{
		DEBUG_CPRINT(("INTG | Buffer ptr Null  !\n"));
		return 0;
	}
	buf_inc = 0;
	calc_CRC = 0xFFFFFFFF;
	while (length > 3)
	{
		memcpy(&read_buffer,&data_buf[buf_inc],4);
		calc_CRC = Crc32_temp(calc_CRC, read_buffer);
		length -= 4;
		buf_inc +=4;
	}

	return calc_CRC;
}




#ifndef LINUX_TEMP_PORT
/*
 * This function will be invoked by memcopy module once firmware fully moved from SDRAM to
 * permanent storage memory NOR flash
 */
static void eps_sdram_nor_cpy_completed(eps_fw_name fw_id, memcpy_info_save *s_eps_ftm_handle)
{
#ifdef COREBOARD
	uint32_t cal_checksum;
#endif


#ifdef COREBOARD
		// fw_flash copy from SDRAM to flash has completed
		//cal_checksum = calc_checksum_memory_temp((uint8_t*)s_eps_ftm_handle->des_addrs,s_eps_ftm_handle->size);
		cal_checksum = exo_io_hal_crc_calculate(EXO_HARDWARE_CRC_MODE,(uint8_t*)s_eps_ftm_handle->des_addrs,(s_eps_ftm_handle->size/4)*4);
		if(cal_checksum == s_eps_ftm_handle->checksum)
		{
	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wformat"
			DEBUG_CPRINT(("EPS FW copied in NOR at Address:0x%X of Size %lukb\n",s_eps_ftm_handle->des_addrs,s_eps_ftm_handle->size));
	#pragma GCC diagnostic pop */


	#pragma GCC diagnostic pop */
			log_id_with_two_arg(LOG_INFO_L1, LOG_EPS, FW_EPS_COPIED_AT_ADDRESS__hex__OF_SIZE__u32_, s_eps_ftm_handle->des_addrs,s_eps_ftm_handle->size);

			/*
			 *  Add IPC here,
			 *  FW stored address :s_eps_ftm_handle->des_addrs
			 *  FW size : s_eps_ftm_handle->size
			 */
			if(fw_id == EPS_CONV_FW)
			{
			eps_fw_conv_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
			fw_conv_upt_progress_status = FIRMWARE_AVAILABLE;
			}
			else if(fw_id == EPS_BATT_FW)
			{
			eps_fw_op_chnl_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
			fw_op_chnl_upt_progress_status = FIRMWARE_AVAILABLE;
			}
			else if(fw_id == EPS_CONV_BCKUP_FW)
			{
				eps_bckup_fw_conv_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
				fw_conv_upt_progress_status = FIRMWARE_AVAILABLE;
			}
			else if(fw_id == EPS_OP_CHNL_BCKUP_FW)
			{
				eps_bckupfw_op_chnl_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
				fw_op_chnl_upt_progress_status = FIRMWARE_AVAILABLE;
			}

			otsu_encode_tm(TM_OTSU_NOTIFICATION,otfs_ready_for_boot, 0);


		}
		else
		{

			/* copy operation will be done again if first trail not done successfully */
			DEBUG_CPRINT(("EPS FW copied at NOR Integrity Fail\n"));
	        log_id(LOG_ERROR,LOG_EPS,FW_COPIED_AT_NOR_FAIL);

		}

#else
		if(fw_id == EPS_CONV_FW)
		{
			eps_fw_conv_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
			fw_conv_upt_progress_status = FIRMWARE_AVAILABLE;
		}
		else if(fw_id == EPS_BATT_FW)
		{
			eps_fw_op_chnl_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
			fw_op_chnl_upt_progress_status = FIRMWARE_AVAILABLE;
		}
		else if(fw_id == EPS_CONV_BCKUP_FW)
		{
			eps_bckup_fw_conv_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
			fw_conv_upt_progress_status = FIRMWARE_AVAILABLE;
		}
		else if(fw_id == EPS_OP_CHNL_BCKUP_FW)
		{
			eps_bckupfw_op_chnl_info_nvm_write(FIRMWARE_AVAILABLE, s_eps_ftm_handle->size, s_eps_ftm_handle->checksum);
			fw_op_chnl_upt_progress_status = FIRMWARE_AVAILABLE;
		}

#endif

}

#endif

#ifndef LINUX_TEMP_PORT

/*
 * @brief This API is responsible for copying partial firmware to NOR flash
 */
static void eps_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"));
	}
	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*)eps_memcpy_inf.des_addrs,eps_memcpy_inf.size);
#else
		    os_memcpy_extmem((uint8_t*)eps_memcpy_inf.src_addrs, (uint8_t*)eps_memcpy_inf.des_addrs, eps_memcpy_inf.size, NULL, 1,1);
			cal_checksum = calc_checksum_memory((uint8_t*)eps_memcpy_inf.src_addrs,eps_memcpy_inf.size);
#endif
			if(cal_checksum == eps_memcpy_inf.checksum)
			{
				nor_info_nvm_data.file_size_stored = eps_memcpy_inf.size;
				nor_info_nvm_data.file_checksum = eps_memcpy_inf.checksum;
				nor_info_nvm_data.file_stored_sts = 1;
				/* store in NVM */
				nvm_parameter_write(NVM_DATA,NVM_EPS_FTM_FILE_CONTXT_DATA,(uint8_t*)&nor_info_nvm_data);
				DEBUG_CPRINT(("[FTM savecontxt] NOR flash CRC pass\n"));
				/*
				 * GS notify is required ?
				 */
			}
			else
			{
				DEBUG_CPRINT(("[FTM savecontxt] NOR flash CRC FAIL\n"));

			}
		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] NOR MEMCPY copy  - Fail\n"));
		}
	}
}

#endif


/*
 *  Application API which will be invoked during file transmission by FT framework
 *  it handles all FTM related notification published by FTM module
 */
void eps_ft_receiver_notificataion_clbk(ft_notification_info *ft_sts)
{
#ifndef LINUX_TEMP_PORT
	e_avtive_type node_act_type;
	static uint8_t nack_test = 1;
	uint8_t *loc_savecontext_ptr;
	memcpy_info_save s_eps_ftm_handle;
	eps_fw_name fw_id;

#endif
	/*
	 *  THis callback service function should not wait for long time
	 */
	uint16_t u16cnt;
#ifndef LINUX_TEMP_PORT
	uint8_t ret_sts;
#endif 

	DEBUG_CPRINT((" FTM for EPS module >> notification API invoked !!!!\n"));
	if(ft_sts->status == transfer_download_success)
	{
		DEBUG_CPRINT(("1. download success\n"));
        log_id(LOG_INFO_L1, LOG_EPS, FW_DOWNLOAD_SUCCESS);
		if(ft_sts->dwld_info.tx_mode == 1)
		{

		}
		else
		{
			DEBUG_CPRINT(("2. Transfer mode : FILE\n"));
			DEBUG_CPRINT(("3. File name : "));
			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]));
			}
#ifndef LINUX_TEMP_PORT
			DEBUG_CPRINT(("\n4. File size : %ldkb",ft_sts->dwld_info.size_file_or_data));
			DEBUG_CPRINT(("\nNOR copy initiated !!!\n"));

			/* copy downloaded firmware to external nor flash */
			s_eps_ftm_handle.src_addrs = (uint32_t)ft_sts->dwld_info.bulkdata_ptr;
			s_eps_ftm_handle.size = ft_sts->dwld_info.size_file_or_data;
			s_eps_ftm_handle.checksum = ft_sts->dwld_info.checksum;
			s_eps_ftm_handle.des_addrs = 0;
			ret_sts = 0;

			if(ft_sts->dwld_info.tx_file_id == EPS_CONV_FW)
			{
				s_eps_ftm_handle.des_addrs = (uint32_t)eps_conv_fw_storage;
				fw_id = EPS_CONV_FW;
			}
			else if(ft_sts->dwld_info.tx_file_id == EPS_BATT_FW)
			{
				s_eps_ftm_handle.des_addrs = (uint32_t)eps_op_chnl_fw_storage;
			    fw_id = EPS_BATT_FW;
			}
			else if(ft_sts->dwld_info.tx_file_id == EPS_CONV_BCKUP_FW)
			{
				s_eps_ftm_handle.des_addrs = (uint32_t)eps_conv_fw_storage_backup;
				fw_id = EPS_CONV_BCKUP_FW;
			}
			else if(ft_sts->dwld_info.tx_file_id == EPS_OP_CHNL_BCKUP_FW)
			{
				s_eps_ftm_handle.des_addrs = (uint32_t)eps_op_chnl_fw_storage_backup;
				fw_id = EPS_OP_CHNL_BCKUP_FW;
			}
			else
			{
			    DEBUG_CPRINT(("Invalid eps fw rxd.\n"));
				ret_sts = 1;
			}

			if(0 != s_eps_ftm_handle.des_addrs)
				{
					DEBUG_CPRINT(("NOR copy initiated !!!\n"));

					ret_sts = os_memcpy_extmem((uint8_t*)s_eps_ftm_handle.des_addrs, (uint8_t*)s_eps_ftm_handle.src_addrs, s_eps_ftm_handle.size, NULL, 1,1);
					if(ret_sts == CPY_OK)
					{
						eps_sdram_nor_cpy_completed(fw_id, &s_eps_ftm_handle);
					}
					else
					{
						DEBUG_CPRINT(("\nNOR copy fail !!!\n"));
					}

				}
				else
				{
				}

#endif
		}
	}
	else if(ft_sts->status == crc_error)
	{
		DEBUG_CPRINT(("1. download failed/ CRC error\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS, DOWLOAD_FAILED__CRC_ERROR);
		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"));
        //log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOAD_SUSPENDED_BY_SENDER__TIMEOUT_MODE);

	}
	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)
		{
#ifndef LINUX_TEMP_PORT

		if(ft_sts->status != transfer_suspended_savecontext_etended_sts)
		{
				 if(ft_sts->status == transfer_suspended_savecontext)
				 {
						DEBUG_CPRINT(("1. download suspended by sender [Save Context Mode]\n"));
				 }
				 else if(ft_sts->status == transfer_suspended_auto_savecontext)
				 {
						DEBUG_CPRINT(("1. Auto [Save Context Mode] activated\n"));
				 }
				 else if(ft_sts->status == transfer_suspend_savecontext_accepeted)
				 {
						DEBUG_CPRINT(("1. Manual [Save Context Mode] activated\n"));
				 }
				 else
				 {

				 }

				DEBUG_CPRINT(("2. malloc req: %d \n",ft_sts->context_info.context_info_size));
				//loc_savecontext_ptr = os_malloc(ft_sts->context_info.context_info_size);
				loc_savecontext_ptr = os_malloc(200);
				if(loc_savecontext_ptr != NULL)
				{
					memset(loc_savecontext_ptr,0,200);
					DEBUG_CPRINT(("2. context data size: %d\n",ft_sts->context_info.context_info_size));
					DEBUG_CPRINT(("3. context data : "));
					for (u16cnt = 0; u16cnt < ft_sts->context_info.context_info_size; u16cnt++)
					{
						loc_savecontext_ptr[u16cnt] = ft_sts->context_info.context_info_buf_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);
							}
							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_EPS_FTM_CONTXT_DATA,loc_savecontext_ptr);
						os_free(loc_savecontext_ptr);
						loc_savecontext_ptr = NULL;
						/* initiate NOR copy to save file which is stored in SDRAM */
						eps_memcpy_inf.src_addrs = ft_sts->context_info.bulkdata_mem_addr & 0xffffffff;
						eps_memcpy_inf.des_addrs = (uint32_t)eps_conv_fw_storage;
						eps_memcpy_inf.size = ft_sts->context_info.bulkdata_len;
						eps_memcpy_inf.checksum = ft_sts->context_info.bulkdata_checksum;
						ftm_nor_write_avail = 1;
					}
				}
		}
		else
		{
		     DEBUG_CPRINT(("FTM - SCT 100%% completed <<<\n"));
			 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*)eps_memcpy_inf.des_addrs, (uint8_t*)eps_memcpy_inf.src_addrs, eps_memcpy_inf.size, NULL, 1,1);
						eps_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"));
        //log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOADING_RESUMED_BY_SENDER);
	}
	else if(ft_sts->status == transfer_resume_accepted)
	{
		DEBUG_CPRINT(("1. downloading resumed back by sender\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOADING_RESUMED_BACK_BY_SENDER);
	}
	else if(ft_sts->status == tx_terminated_suspend_timeout_expired)
	{
		DEBUG_CPRINT(("1. download Terminated due to suspend timeout expired\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOAD_TERMINATED_DUE_TO_SUSPEND_TIMEOUT_EXPIRED);

	}
	else if(ft_sts->status == transfer_suspend_accepted)
	{
		DEBUG_CPRINT(("1. download Suspend - Timeout mode Accepted by Sender\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOAD_SUSPEND__TIMEOUT_MODE_ACCEPTED_BY_SENDER);
	}
	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
					 *
					 */
					loc_savecontext_ptr = os_malloc(200);
					if(loc_savecontext_ptr != NULL)
					{
						nvm_parameter_read(NVM_DATA,NVM_EPS_FTM_CONTXT_DATA,loc_savecontext_ptr);
						ft_contextsave_info *c_inf = (ft_contextsave_info*)loc_savecontext_ptr;
			//			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(loc_savecontext_ptr,c_inf->context_info_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(loc_savecontext_ptr,0,200);
						os_memset(&nor_info_nvm_data,0,sizeof(nor_info_nvm_data));
						nvm_parameter_write(NVM_DATA,NVM_EPS_FTM_CONTXT_DATA,loc_savecontext_ptr);
						nvm_parameter_write(NVM_DATA,NVM_EPS_FTM_FILE_CONTXT_DATA,(uint8_t*)&nor_info_nvm_data);
						os_free(loc_savecontext_ptr);
						loc_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 = eps_ftmSaveConext_read_file_from_nor((ft_contextsave_info*)loc_savecontext_ptr);
							if(ret_sts == 1)
							{
								/* 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));
						}
					}
#endif
		}
	else if(ft_sts->status == transfer_download_ready)
	{
		DEBUG_CPRINT(("1. Download request received for EPS \n"));
        log_id(LOG_INFO_L1, LOG_EPS, FW_DOWNLOAD_REQUEST_RECEIVED_FOR_EPS);

		if(ft_sts->dwld_info.tx_mode == 1)
		{
			DEBUG_CPRINT(("2. Transfer mode : DATA\n"));
		}
		else
		{
			DEBUG_CPRINT(("2. Transfer mode : FILE\n"));
#ifndef LINUX_TEMP_PORT
			DEBUG_CPRINT(("3. File size: %ld\n",ft_sts->dwld_info.size_file_or_data));


			if((ft_sts->dwld_info.size_file_or_data) < (EPS_FIRMWARE_STORAGE_MEM))
			{
				ft_config_receiver_node_storage_address((uint32_t)eps_ftm_file_dwnlod_storage);
			}
			else
			{
				// dont allocate memory if requested size is not in range, so FTM will discard download request
			}


#else
			if((ft_sts->dwld_info.size_file_or_data) < (1024*1024))
			{

				ft_config_receiver_node_storage_address((ptr_typ)eps_ftm_file_dwnlod_storage_linux);
			}
			else
			{
				// dont allocate memory if requested size is not in range, so FTM will discard download request
			}

#endif
		}
	}
	else if(ft_sts->status == transfer_resume_savecontext_accepeted)
	{
		DEBUG_CPRINT(("1. download Resume - Savecontext mode Accepted by Sender\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOAD_RESUME__SAVECONTEXT_MODE_ACCEPTED_BY_SENDER);
	}
	else if(ft_sts->status == transmission_terminated_by_rx_node)
	{
		DEBUG_CPRINT(("1. download Terminated by Receiver node\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOAD_TERMINATED_BY_RECEIVER_NODE);
	}
	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"));
        //log_id(LOG_INFO_L1,LOG_COMMS,SUSPEND_TIMEOUT_REQUEST_NOT_COMPLETED);
	}
	else if(ft_sts->status == transfer_suspend_savecontext_failed)
	{
		DEBUG_CPRINT(("1. suspend savecontxt request not completed\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,SUSPEND_SAVECONTEXT_REQUEST_NOT_COMPLETED);
	}
	else if(ft_sts->status == transfer_rseume_tout_not_accepted)
	{
		DEBUG_CPRINT(("1. resume timeout request not completed\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,RESUME_TIMEOUT_REQUEST_NOT_COMPLETED);
	}
	else if(ft_sts->status == transfer_resume_restorecontext_failed)
	{
		DEBUG_CPRINT(("1. resume savecontxt request not completed\n"));
        //log_id(LOG_INFO_L1,LOG_COMMS,RESUME_SAVECONTEXT_REQUEST_NOT_COMPLETED);
	}
	else
	{
		DEBUG_CPRINT(("Invalid Notification not processed\n"));
        //log_id(LOG_WARNING,LOG_COMMS,INVALID_NOTIFICATION_NOT_PROCESSED);
	}

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


}

/*
 * @brief This API get the sdram storage address
 */
uint8_t* eps_get_sdram_storage_address(void)
{
#ifndef LINUX_TEMP_PORT
	return eps_ftm_file_dwnlod_storage;
#else
	return eps_ftm_file_dwnlod_storage_linux;
#endif
}

/*
 * @brief This API get the NOR flash storage address
 */
uint8_t* eps_get_nor_flash_address(uint8_t board_selc)
{
#ifndef LINUX_TEMP_PORT
	if(board_selc == 1)
	{
		return eps_conv_fw_storage;
	}
	else
	{
		return eps_op_chnl_fw_storage;
	}
#else
	return eps_ftm_file_dwnlod_storage_linux;
#endif

}

/*
 * @brief This API get the NOR flash backup storage address
 */
uint8_t* eps_get_nor_flash_bckup_address(uint8_t board_selc)
{
#ifndef LINUX_TEMP_PORT
	if(board_selc == 1)
	{
		return eps_conv_fw_storage_backup;
	}
	else
	{
		return eps_op_chnl_fw_storage_backup;
	}
#else
	return eps_ftm_file_dwnlod_storage_linux;
#endif

}

