/**
 * @file comms_ftm.c
 *
 * @brief This file has the file transfer functions for S-Band 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.
 *
 * 
 */

#ifndef LINUX_TEMP_PORT
#include "comms_ftm.h"
#include "exo_osal_mem_cpy.h"
#include "crc_cal.h"
#include "exo_common.h"
#include "logger.h"
#include "exo_tctm_ipc.h"
#include "nvm.h"
#include "ft_dwnld.h"
#include "otsu_tctm_man.h"

#define UHF_FW_STOARGE_SIZE_IN_BYTES    (1536*1024) ///< UHF firmware storage size (1.5 MB)
#define IQS1_FW_STOARGE_SIZE_IN_BYTES   (1536*1024) ///< IQS-1 firmware storage size (1.5 MB)  
#define IQS2_FW_STOARGE_SIZE_IN_BYTES   (1536*1024) ///< IQS-2 firmware storage size (1.5 MB)
#define IQS3_FW_STOARGE_SIZE_IN_BYTES   (1536*1024) ///< IQS-3 firmware storage size (1.5 MB)

#define FTM_FW_DOWNLOAD_SDRAM_SIZE_IN_BYTES   (1536*1024)  // 1.5 mb allocated sdram

#ifndef LINUX_TEMP_PORT
/* Allocated SDRAM for EPS module  1mb*/
uint8_t comms_ftm_file_dwnlod_storage[FTM_FW_DOWNLOAD_SDRAM_SIZE_IN_BYTES] PLACE_IN_EXT_RAM_MEM;

#ifdef COREBOARD
/* Allocated FMC NOR for EPS module  */
uint8_t comms_fw_storage_uhf[UHF_FW_STOARGE_SIZE_IN_BYTES] PLACE_IN_EXT_FMC_FLASH_MEM;
#else
/* Allocated QSPI NOR for EPS module , if board is discovery*/
uint8_t comms_fw_storage_uhf[UHF_FW_STOARGE_SIZE_IN_BYTES] PLACE_IN_EXT_QSPI_FLASH_MEM;
#endif

#else
uint8_t comms_ftm_file_dwnlod_storage_linux[200*1024];
#endif


/**
* @brief This function will return the download address to be allocated for file transfer
* @brief Get FTM firmware download address.
*  Returns the start address of the allocated SDRAM 
* region for downloading new firmware during
* FTM (firmware update) operation.
*
* @return Start address of the FTM download region.
*/
uint32_t comms_get_ftm_download_address()
{
	return (uint32_t)comms_ftm_file_dwnlod_storage;
}

/**
* @brief This function will return the storage addrewss to be used to move firmware stored in sdram to
* external flash
 * @brief Get firmware storage address.
 *
 * Returns the start address of the allocated SDRAM
 * region for storing the active firmware image.
 *
 * @return Start address of the firmware storage region. 
*/
uint32_t comms_get_fw_storage_address()
{
	return (uint32_t)comms_fw_storage_uhf;
}

//uint8_t comms_read_uhf_fw(void);

#ifndef LINUX_TEMP_PORT
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 comms_memcpy_inf;

extern comms_firmwre_info_save uhf_fw_buf;
#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;

comms_firmwre_info_save comms_fw_bin_info[4];

comms_firmwre_info_save uhf_firm_info;


static uint8_t ftm_nor_write_avail;

#ifndef LINUX_TEMP_PORT

static uint8_t comms_ftmSaveConext_read_file_from_nor(ft_contextsave_info* c_info_ptr);

static void comms_ftm_savecontext_sdram_copy_compld_cblk(uint8_t cpy_sts, memcpy_info_save *memcpy_inf_ptr);

static void comms_ftm_savecontext_nor_copy_compld_cblk(uint8_t cpy_sts);

void comms_ftm_init(void);

void comms_ft_receiver_notificataion_clbk(ft_notification_info *ft_sts);


uint8_t comms_read_fw_info(comms_fw_name fw_id, comms_firmwre_info_save* fw_info);



#endif

static void comms_store_fw_info(comms_fw_name fw_id, comms_firmwre_info_save* fw_info);


/**
* @brief Application API which will be invoked during file transmission by FT
*  framework it handles all FTM related notification published by FTM module
*
* @param ft_sts : pointer to file transmission status
*/
//void comms_ft_receiver_notificataion_clbk(ft_notification_info *ft_sts);



/**
* @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 comms_sdram_nor_cpy_completed(comms_fw_name fw_id, comms_firmwre_info_save *copy_info);


/**
 * @brief Initialize FTM handler.
 * 
 * It should be called in initialization of thread, it should not be called before the FTM module
 * initialization routine has not complete
 */
void comms_ftm_init()
{
	ft_register_receiver_app(TC_DST_FTM_OBC_COMMS, comms_ft_receiver_notificataion_clbk);

	// TODO Read array comms_fw_bin_info from NVM
	nvm_parameter_read(NVM_DATA,NVM_UHF_FW_CRC,(uint8_t*)&comms_fw_bin_info[COMMS_UHF_FW].checksum);
	nvm_parameter_read(NVM_DATA,NVM_UHF_FW_SIZE,(uint8_t*)&comms_fw_bin_info[COMMS_UHF_FW].size);
	comms_fw_bin_info[COMMS_UHF_FW].des_addrs = (uint32_t)comms_fw_storage_uhf;
	comms_fw_bin_info[COMMS_UHF_FW].src_addrs = (uint32_t)comms_ftm_file_dwnlod_storage;
}


#ifndef LINUX_TEMP_PORT
/**
 * @brief SDRAM copy complete callback.
 * 
 * Callback invoked when SDRAM copy of context data completes.
 * Handles logging result and triggering NOR flash copy.
 * 
 * @param cpy_sts Copy status (success/fail)
 * @param memcpy_inf_ptr Pointer to memcpy info  
*/
static void comms_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"));
	log_id(LOG_INFO_L1,LOG_COMMS,FTM_SAVECONTEXT__SDRAM_FLASH_CALLBACK_CALLED);
	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"));
			log_id(LOG_INFO_L1,LOG_COMMS,FTM_SAVECONTEXT__SDRAM_FLASH_CRC_PASS);
		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] SDRAM flash CRC FAIL\n"));
			log_id(LOG_ERROR,LOG_COMMS,FTM_SAVECONTEXT__SDRAM_FLASH_CRC_FAIL);

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

	}
}


/**
 * @brief NOR flash copy complete callback. 
 * 
 * Callback when NOR flash copy of context data completes.
 * Handles logging result.
 *
 * @param cpy_sts Copy status (success/fail)
*/
static void comms_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"));
	log_id(LOG_INFO_L1,LOG_COMMS,FTM_SAVECONTEXT__SDRAM_FLASH_CRC_PASS);
	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*)comms_memcpy_inf.des_addrs, comms_memcpy_inf.size);
#else
		    os_memcpy_extmem((uint8_t*)comms_memcpy_inf.src_addrs, (uint8_t*)comms_memcpy_inf.des_addrs, comms_memcpy_inf.size, NULL, 1,1);
			cal_checksum = calc_checksum_memory((uint8_t*)comms_memcpy_inf.src_addrs, comms_memcpy_inf.size);
#endif
			if(cal_checksum == comms_memcpy_inf.checksum)
			{
				nor_info_nvm_data.file_size_stored = comms_memcpy_inf.size;
				nor_info_nvm_data.file_checksum = comms_memcpy_inf.checksum;
				nor_info_nvm_data.file_stored_sts = 1;
				/* store in NVM */
				//nvm_parameter_write(NVM_DATA,NVM_MAGIC_NUM,(uint8_t*)&nvm_wr_magic_num);
				//nvm_parameter_write(NVM_DATA,NVM_VERSION,(uint8_t*)&nvm_wr_vrsn);
				nvm_parameter_write(NVM_DATA,NVM_COMMS_FTM_FILE_CONTXT_DATA,(uint8_t*)&nor_info_nvm_data);
//				sct_data_avail = 1;
				//nvm_commit();
				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"));
		}
	}
}

/**
 * @brief Read context data from NOR flash.
 *
 * Reads context save data from NOR flash to buffer.
 * 
 * @param c_info_ptr Pointer to context info struct
 * @return Status of read operation 
*/
static uint8_t comms_ftmSaveConext_read_file_from_nor(ft_contextsave_info* c_info_ptr)
{
	uint8_t ret_sts =0;
	memcpy_info_save comms_memcpy_inf;
//	ft_contextsave_info* c_info_ptr;

//	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));
    nvm_parameter_read(NVM_DATA,NVM_COMMS_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 */
			comms_memcpy_inf.des_addrs = (uint32_t)comms_ftm_file_dwnlod_storage;
			comms_memcpy_inf.src_addrs = (uint32_t)comms_fw_storage_uhf;
			comms_memcpy_inf.size = nor_info_nvm_data->file_size_stored;
			comms_memcpy_inf.checksum = nor_info_nvm_data->file_checksum;
			DEBUG_CPRINT(("Src addr: %lux\nDsc addr: %lux\nSize: %lu\nChecksum: %lux\n", comms_memcpy_inf.src_addrs, comms_memcpy_inf.des_addrs, comms_memcpy_inf.size, comms_memcpy_inf.checksum));
			ret_sts = os_memcpy_extmem((uint8_t*)comms_memcpy_inf.des_addrs, (uint8_t*)comms_memcpy_inf.src_addrs, comms_memcpy_inf.size, NULL, 1,1);
			comms_ftm_savecontext_sdram_copy_compld_cblk(ret_sts, &comms_memcpy_inf);
//		    sct_data_avail = 1;
			ret_sts =1;
		}
		else
		{
			DEBUG_CPRINT(("[FTM savecontxt] NOR data not avail checksum Fail\n"));
			//otsu_encode_tm(otfs_flash_copy_fail,0xCD);
		}
	}
	else
	{
		DEBUG_CPRINT(("[FTM savecontxt] NOR data not avail\n"));
		//otsu_encode_tm(otfs_flash_copy_fail,0xCD);
	}
	os_free(nor_info_nvm_data);
	nor_info_nvm_data = NULL;
	return ret_sts;
}

#endif

/*
 * This function will be invoked by memcopy module once firmware fully moved from SDRAM to
 * permanent storage memory NOR flash
 * 
 * @brief NOR to SDRAM copy complete handler.
 *
 * Handles completion of NOR to SDRAM firmware image copy.
 * Logs results and updates status.
 *
 * @param fw_id Firmware image ID enum
 * @param copy_info Pointer to copy info  
 */

static void comms_sdram_nor_cpy_completed(comms_fw_name fw_id, comms_firmwre_info_save *copy_info)
{
	uint32_t cal_checksum;
	
	// fw_flash copy from SDRAM to flash has completed

#ifndef COREBOARD
	os_memcpy_extmem((uint8_t*)copy_info->src_addrs, (uint8_t*)copy_info->des_addrs, copy_info->size, NULL, 1,1);
	cal_checksum = calc_checksum_memory((uint8_t*)copy_info->src_addrs,copy_info->size);
#else
	cal_checksum = calc_checksum_memory((uint8_t*)copy_info->des_addrs,copy_info->size);
#endif

	if(cal_checksum == copy_info->checksum)
	{

    	// TODO:: log >> COMMS FW copied at NOR Pass
		DEBUG_CPRINT(("COMMS FW copied at NOR Pass\n"));
		log_id(LOG_INFO_L1,LOG_COMMS,COMMS_FW_COPIED_AT_NOR_PASS);
		comms_store_fw_info(fw_id, copy_info);
/**TODO: to handle UHF fw upload success*/
		otsu_encode_tm(TM_OTSU_NOTIFICATION,otfs_ready_for_boot, 0);
		/*
		 * sample function calls to get firmware information from comms module
		 * 		comms_read_fw_info(COMMS_UHF_FW, &uhf_firm_info);
		 *
		 */

		/*
		 *  Add IPC here, if required
		 *  FW stored address :copy_info->des_addrs
		 *  FW size : copy_info->size
		 */
	}
	else
	{
		/* copy operation will be done again if first trail not done successfully */
		DEBUG_CPRINT(("COMMS FW copied at NOR Fail\n"));
        log_id(LOG_ERROR,LOG_COMMS,COMMS_FW_COPIED_AT_NOR_FAIL);

	}

}

/**
 * @brief Store firmware info. 
 * 
 * Stores firmware image metadata to global struct.
 *
 * @param fw_id Firmware image ID enum 
 * @param fw_info Pointer to firmware info struct
*/
static void comms_store_fw_info(comms_fw_name fw_id, comms_firmwre_info_save* fw_info)
{
	switch(fw_id)
	{
		case COMMS_UHF_FW:
		case COMMS_IQS_1_FW:
		case COMMS_IQS_2_FW:
		case COMMS_IQS_3_FW:
			memcpy(&comms_fw_bin_info[fw_id], fw_info, sizeof(comms_firmwre_info_save));
			// TODO ::
			// Store the array "comms_fw_bin_info" in NVM and read back at POR
			nvm_parameter_write(NVM_DATA,NVM_UHF_FW_SIZE,(uint8_t*)&comms_fw_bin_info[fw_id].size);
			nvm_parameter_write(NVM_DATA,NVM_UHF_FW_CRC,(uint8_t*)&comms_fw_bin_info[fw_id].checksum);

			break;
		default :
			break;
	}
}

/**
 * @brief Read UHF firmware image.
 *
 * Reads UHF firmware from external memory to buffer.
 *
 * @return Status of read operation
*/                                
int8_t comms_read_uhf_fw(void)
{
	uint8_t ret_sts;
	comms_firmwre_info_save uhf_fw_info;
	ret_sts = comms_read_fw_info(COMMS_UHF_FW, &uhf_fw_info);
	if(!ret_sts)
	{
	memcpy(&uhf_fw_buf, &uhf_fw_info, sizeof(comms_firmwre_info_save));
}

	return ret_sts;
}


/**
 * This API is used to get firmware information such as firmware size , firmware checksum
 * and firmware stored address
 *
 *  src_addrs - sdrram buffer where fw is stored
 *  size - size of firmware
 *  checksum - checksum of firmware
 *
 *  return values are
 *   0 - success , firmware information available
 *   1 - fail , external mem copy error
 *   2 - fail, firmware corrupted
 *   3 - fail, no firmware available
 *   4 - fail, invalid input argument
 *
 */


uint8_t comms_read_fw_info(comms_fw_name fw_id, comms_firmwre_info_save* fw_info)
{

	uint32_t cal_checksum;
	uint8_t ret_sts = 0;

	memset(fw_info, 0, sizeof(comms_firmwre_info_save));

	switch(fw_id)
	{
		case COMMS_UHF_FW:
		case COMMS_IQS_1_FW:
		case COMMS_IQS_2_FW:
		case COMMS_IQS_3_FW:

			// fw_flash copy from external flash to SDRAM

			/*
			 *  input address should be verified before initiate the mem copy process,
			 *  size should not be greater than 1.5 mb
			 */

			if( (comms_fw_bin_info[fw_id].des_addrs != 0) &&       \
				(comms_fw_bin_info[fw_id].checksum  != 0) &&       \
				(comms_fw_bin_info[fw_id].size      != 0) &&       \
				(comms_fw_bin_info[fw_id].size      < 0x180000))   \
			{

				cal_checksum = calc_checksum_memory(comms_ftm_file_dwnlod_storage, comms_fw_bin_info[fw_id].size);
				if(cal_checksum != comms_fw_bin_info[fw_id].checksum)
				{

					ret_sts = os_memcpy_extmem(comms_ftm_file_dwnlod_storage, (uint8_t*)comms_fw_bin_info[fw_id].des_addrs, comms_fw_bin_info[fw_id].size, NULL, 1,1);

					if(ret_sts == CPY_OK)
					{
						cal_checksum = calc_checksum_memory(comms_ftm_file_dwnlod_storage, comms_fw_bin_info[fw_id].size);

						if(cal_checksum == comms_fw_bin_info[fw_id].checksum)
						{
							memcpy(fw_info, &comms_fw_bin_info[fw_id], sizeof(comms_firmwre_info_save));
							fw_info->src_addrs = (uint32_t)comms_ftm_file_dwnlod_storage;
							ret_sts = 0;
						}
						else
						{
							/* data corrupted in flash , firmware integrity fail*/
							ret_sts = 2;
						}

					}
					else
					{
						/* os external memcpy failed */
						ret_sts =1;
					}

				}
				else
				{
					/* firmware not required to read from external memory, since sdram memory
                                           data is already valid */
                                    memcpy(fw_info, &comms_fw_bin_info[fw_id], sizeof(comms_firmwre_info_save));
                                    fw_info->src_addrs = (uint32_t)comms_ftm_file_dwnlod_storage;
                                    ret_sts = 0;
				}



			}
			else
			{
				/* no firmware available */
				ret_sts = 3;
			}

			break;

		default :
			ret_sts = 4;
			break;

	}

	return ret_sts;
}

/**
 * @brief Get firmware availability status.
 *
 * Checks if a firmware image with the given ID, length 
 * and CRC is available in storage.
 *
 * @param fw_id Firmware image ID enum
 * @param bin_length Expected binary length 
 * @param bin_crc Expected binary CRC
 * @return Availability status (available or not available)
*/
uint8_t comms_get_firmware_availablity_status(comms_fw_name fw_id, uint32_t bin_length, uint32_t bin_crc)
{
    uint8_t ret=0;
	comms_firmwre_info_save temp;

	if((comms_fw_bin_info[fw_id].checksum  == bin_crc) && (comms_fw_bin_info[fw_id].size  == bin_length))
	{
		ret = comms_read_fw_info(fw_id, &temp);
		if(ret == 0)
		{
			// firmware integrity pass
			return 0;
		}
		else
		{
			/* firmware corrupted */
			return 1;
		}
	}
	else
	{
		// nvm data mismatch
		return 2;
	}

}



/**
 *  Application API which will be invoked during file transmission by FT framework
 *  it handles all FTM related notification published by FTM module
 *
 * @brief Firmware transfer notification callback.
 *
 * Callback invoked upon firmware transfer events/status updates.
 * Handles logging transfer status and statistics.
 *
 * @param ft_sts Pointer to firmware transfer status struct 
 */
void comms_ft_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;
	comms_firmwre_info_save s_comms_ftm_handle;
	comms_fw_name fw_id;
	e_avtive_type node_act_type;
	static uint8_t nack_test = 1;
	uint8_t *comms_savecontext_ptr;


	DEBUG_CPRINT((" FTM for COMMS module >> notification API invoked !!!!\n"));
    log_id(LOG_INFO_L1,LOG_COMMS,FTM_FOR_COMMS_MODULE__NOTIFICATION_API_INVOKED);
	if(ft_sts->status == transfer_download_success)
	{
		DEBUG_CPRINT(("1. download success\n"));
        log_id(LOG_INFO_L1,LOG_COMMS,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
		{

			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]));
			}
			DEBUG_CPRINT(("\n4. File size : %ldkb",ft_sts->dwld_info.size_file_or_data));
			DEBUG_CPRINT(("\nNOR copy initiated !!!\n"));

			s_comms_ftm_handle.src_addrs = (uint32_t)ft_sts->dwld_info.bulkdata_ptr;
			s_comms_ftm_handle.size = ft_sts->dwld_info.size_file_or_data;
			s_comms_ftm_handle.checksum = ft_sts->dwld_info.checksum;
			s_comms_ftm_handle.des_addrs = 0;

			s_comms_ftm_handle.des_addrs = (uint32_t)comms_fw_storage_uhf;
			fw_id = COMMS_UHF_FW;
			ret_sts = 0;

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

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

			}
			else
			{
			}
		}


	}
	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"));
                log_id(LOG_INFO_L1,LOG_COMMS, dwnld_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_COMMS,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_COMMS,Manual_Save_Context_Mode_activated);
            }
            else
            {

            }

            DEBUG_CPRINT(("2. malloc req: %d \n", ft_sts->context_info.context_info_size));
            log_id_with_one_arg(LOG_INFO_L1, LOG_COMMS, Malloc_req__u16_, ft_sts->context_info.context_info_size);
            comms_savecontext_ptr = os_malloc(200);
            if(comms_savecontext_ptr != NULL)
            {
                memset(comms_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++)
                {
                	comms_savecontext_ptr[u16cnt] =
                    ft_sts->context_info.context_info_buf_ptr[u16cnt];
//                    DEBUG_CPRINT(("%x ",comms_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_COMMS_FTM_CONTXT_DATA,comms_savecontext_ptr);
                    os_free(comms_savecontext_ptr);
                    comms_savecontext_ptr = NULL;
                    /*initiate NOR copy to save file which is stored in SDRAM*/
                    comms_memcpy_inf.src_addrs = ft_sts->context_info.bulkdata_mem_addr & 0xffffffff;
                    comms_memcpy_inf.des_addrs = (uint32_t) comms_fw_storage_uhf;
                    comms_memcpy_inf.size      = ft_sts->context_info.bulkdata_len;
                    comms_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_COMMS,FTM_SCT_100_per_completed);
            if(ft_sts->status == transfer_suspended_savecontext_etended_sts)
            {
                if(ftm_nor_write_avail == 1)
                {
                    DEBUG_CPRINT(("NOR copy initiated\n"));
                    log_id(LOG_INFO_L1,LOG_COMMS,NOR_copy_initiated);
                    ret_sts = os_memcpy_extmem((uint8_t*)comms_memcpy_inf.des_addrs, (uint8_t*)comms_memcpy_inf.src_addrs, comms_memcpy_inf.size, NULL, 1,1);
                    comms_ftm_savecontext_nor_copy_compld_cblk(ret_sts);
                    ftm_nor_write_avail = 0;
                }
                else
                {
                    DEBUG_CPRINT(("NOR copy not initiated.\n"));
                     log_id(LOG_WARNING,LOG_COMMS,NOR_copy_not_initiated);
                }
            }
            else
            {
                DEBUG_CPRINT(("0. Invalid case ??? \n"));
                log_id(LOG_WARNING,LOG_COMMS,Invalid_case);
            }
        }
#endif
	}
	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"));
					log_id(LOG_INFO_L1,LOG_COMMS,DOWNLOAD_RESUME_SAVECONTEXT_MODE_REQUESTED_BY_SENDER);

					DEBUG_CPRINT(("\r\nResume-SaveContext mode [Bulkdata] selected \r\n"));
					log_id(LOG_INFO_L1,LOG_COMMS,RESUME__SAVECONTEXT_MODE__BULKDATA__SELECTED);
					/*
					 * Read FTM context info in NVM
					 *
					 */
					comms_savecontext_ptr = os_malloc(200);
					if(comms_savecontext_ptr != NULL)
					{
						nvm_parameter_read(NVM_DATA,NVM_COMMS_FTM_CONTXT_DATA,comms_savecontext_ptr);
						ft_contextsave_info *c_inf = (ft_contextsave_info*)comms_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(comms_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(comms_savecontext_ptr,0,200);
						os_memset(&nor_info_nvm_data,0,sizeof(nor_info_nvm_data));
						nvm_parameter_write(NVM_DATA, NVM_COMMS_FTM_CONTXT_DATA, comms_savecontext_ptr);
						nvm_parameter_write(NVM_DATA, NVM_COMMS_FTM_FILE_CONTXT_DATA, (uint8_t*)&nor_info_nvm_data);
//						sct_data_avail = 0;
						os_free(comms_savecontext_ptr);
						comms_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 = comms_ftmSaveConext_read_file_from_nor((ft_contextsave_info*)comms_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));
						}
					}
		}
	else if(ft_sts->status == transfer_download_ready)
	{
	    DEBUG_CPRINT(("OTSU_check BLT ****m\n"));
		DEBUG_CPRINT(("1. Download request received\n"));
		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));
			if((ft_sts->dwld_info.size_file_or_data) < (FTM_FW_DOWNLOAD_SDRAM_SIZE_IN_BYTES))
			{

				ft_config_receiver_node_storage_address((uint32_t)comms_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->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"));


}
#endif
