/**
 *@file ftci_decode.c
 *
 *@brief This file contains functions that provides demonstration of
 *       usage of FTCI frame decoding APIs
 *
 *The functions provided in the file provides demonstration on
 *usage of  FTCI frame decoding APIs
 *
 * @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 headers of the component                      */
/******************************************************************************/


#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "ftci_decode.h"
#include "ftds_decode.h"
#include "data_type.h"
#include "file_transfer.h"
#include "ft_timer.h"
#include "ftsr.h"
#include "ftsr.h"
#include "message_frame_def.h"
#include "logger.h"
#include "ft_sender.h"
#include "ft_receiver.h"
#include "ft_debug.h"
#include "exo_osal_mem_cpy.h"

extern obc_memcpy_memory_layout look_up_table[MAX_MEM];         ///< Maximum memcpy size


/******************************************************************************/
/*                  Definition of local function like macros                  */
/******************************************************************************/

/* Total = control field 1 + control field 2 + checksum + mtu size *total = 1+1+4+2 >> 8 bytes */
#define FTCI_FIXED_FRAME_FIELD_SIZE 8

/* Total = memory address + size + file name length + file name/path *total = 4+4+1+50(assumption) >> 59 bytes */
#define FTCI_VARAIABLE_FRAME_FIELD_SIZE 59

/* FTCI frame max length in bytes */
#define FTCI_FRAME_MAX_LENGTH	(FTCI_FIXED_FRAME_FIELD_SIZE + FTCI_VARAIABLE_FRAME_FIELD_SIZE)

#define DATA_TX_FRAME_CTRL_FIELD_LEN 1
#define MAX_SEQ_NUM_FIELD			 4
#define MAX_DATA_LEN_FIELD 			 2


#define RX_CONN_FAILRE_MIN_TIMEOUT 45 // seconds

/******************************************************************************/
/*                       Definition of local variables                        */
/******************************************************************************/




/******************************************************************************/
/*                      Definition of exported variables                      */
/******************************************************************************/
s_treceive_info  		 			dwnld_rqst;
s_treceive_info  		 			resume_ctxt_rqst;
tc_tm_id_e_ft                       tctm_id_inform_ftci = FT_TC_FTCI;


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



/**
 * @brief This function decodes the FTCI frame data and approve the request
 *
 *
 * @param[in]  data  : pointer to received FTCI frame
 *
 * @return none
 * @retval void : none
 *
 */
static void decode_ftci_frame(uint8_t *data);




/******************************************************************************/
/*                       Definition of local functions                        */
/******************************************************************************/



/**
 * @brief This function decodes the FTCI frame data and approve the request
 *
 *
 */
static void decode_ftci_frame(uint8_t *data)
{
	uint8_t u8cnt;
	uint8_t * loc_ptr;
	uint32_t calculated_size = 0;
        uint8_t frame_index_cntr = 0;
	uint8_t str_len;
	uint32_t meme_addr;
	s_file_tx_ctrl_info ftci_frame_loc;
	e_ft_current_process ft_state;
	uint8_t status=0;
    uint8_t sid;

	memcpy(&ftci_frame_loc, data, sizeof(s_file_tx_ctrl_info));
	log_id(LOG_INFO_L1, LOG_FTM, FTCI_REQUEST_RECEIVED);

	DEBUG_CPRINT(("Session id is %d \n", ftci_frame_loc.ctrl_1.file_tx_session_id));
	DEBUG_CPRINT(("file format is %d \n", ftci_frame_loc.ctrl_2.file_format));
	DEBUG_CPRINT(("size field length is %d \n", ftci_frame_loc.ctrl_2.size_field_length));
	DEBUG_CPRINT(("Size of the MTU is %u  \n", ftci_frame_loc.mtu_size));
	DEBUG_CPRINT(("user unit is %d  \n", ftci_frame_loc.ctrl_2.unit));
	DEBUG_CPRINT(("RX con fail time is %d  \n", ftci_frame_loc.rx_con_fail_timeout));
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
	DEBUG_CPRINT(("Checksum is %luX  \n", ftci_frame_loc.checksum));
#pragma GCC diagnostic pop
	loc_ptr = (uint8_t*) &calculated_size;
	frame_index_cntr = sizeof(s_file_tx_ctrl_info);
	for (u8cnt = 0; u8cnt <= ftci_frame_loc.ctrl_2.size_field_length; u8cnt++)
	{
		*loc_ptr = data[frame_index_cntr];
		loc_ptr++;
		frame_index_cntr++;
	}
    ft_debug_save_prev_frame_info(tctm_id_inform_ftci ,ftci_frame_loc.ctrl_1.resume_context_mode);

	if(ftci_frame_loc.ctrl_1.resume_context_mode == 0)
	{

		/* Normal FTM required received */
	dwnld_rqst.file_format = ftci_frame_loc.ctrl_2.file_format;
	dwnld_rqst.size = calculated_size;
	dwnld_rqst.mtu_size = ftci_frame_loc.mtu_size;
	dwnld_rqst.checksum = ftci_frame_loc.checksum;
	dwnld_rqst.data_loss.re_request_initiate_timer =0;
	dwnld_rqst.seq_payload_len = dwnld_rqst.mtu_size - (DATA_TX_FRAME_CTRL_FIELD_LEN + MAX_SEQ_NUM_FIELD + MAX_DATA_LEN_FIELD);
	dwnld_rqst.seq_payload_len = dwnld_rqst.seq_payload_len / 4;
	dwnld_rqst.seq_payload_len = dwnld_rqst.seq_payload_len * 4;
	dwnld_rqst.tx_mode = ftci_frame_loc.ctrl_2.transfer_mode_sel;
	dwnld_rqst.seq_loss_detect_enable = ftci_frame_loc.ctrl_1.seq_loss_detection_mode;
	dwnld_rqst.dwnld_cmp_sts = 0;
	dwnld_rqst.file_id = ftci_frame_loc.ctrl_1.file_id;
	dwnld_rqst.rx_node_conn_fail_timeout = ftci_frame_loc.rx_con_fail_timeout;
	if(dwnld_rqst.rx_node_conn_fail_timeout < RX_CONN_FAILRE_MIN_TIMEOUT || dwnld_rqst.rx_node_conn_fail_timeout > 1800)
	{
		dwnld_rqst.rx_node_conn_fail_timeout = RX_CONN_FAILRE_MIN_TIMEOUT;
	}
	resume_ctxt_rqst.size = 0;
	resume_ctxt_rqst.checksum =0;
 
  sid =  ft_rx_session_id_read();
  ft_rx_session_id_store(ftci_frame_loc.ctrl_1.file_tx_session_id);
  
	if (ftci_frame_loc.ctrl_2.transfer_mode_sel == 0)
	{
		/*file transfer */
		DEBUG_CPRINT(("File TX mode\n"));

		str_len = data[frame_index_cntr];
		DEBUG_CPRINT(("FIle name and Path size:%d\n", str_len));
		frame_index_cntr++;

		dwnld_rqst.file_name = os_malloc_eram(str_len);
		dwnld_rqst.file_name_buf_length = str_len;
		if (dwnld_rqst.file_name != NULL)
		{
			for (u8cnt = 0; u8cnt < str_len; u8cnt++)
			{
				dwnld_rqst.file_name[u8cnt] = data[frame_index_cntr];
				frame_index_cntr++;
			}

			DEBUG_CPRINT(("File name: %s\n", dwnld_rqst.file_name));
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
			DEBUG_CPRINT(("File Size is %lu  \n", dwnld_rqst.size));
#pragma GCC diagnostic pop


#ifndef FT_OBC
			if ((dwnld_rqst.fptr = fopen((char*)dwnld_rqst.file_name, "wb")) == NULL)
			{
				DEBUG_CPRINT(("FTCI | File opening error %s !\n",dwnld_rqst.file_name));
				send_ftsr(ftsr_file_not_found,0);
                ft_rx_session_id_store(sid);
				ft_set_err_sts(ft_output_file_open_error);
			}
			else
			{
				dwnld_rqst.file_opened = 1;
				status =1;
			}
#else
			dwnld_rqst.file_opened = 0;
			status =1;
#endif
		}
		else
		{
			DEBUG_CPRINT(("FTM Malloc error\n"));
            send_ftsr(ftsr_rx_system_error,0);
            ft_rx_session_id_store(sid);
		}
	}
	else
	{
		DEBUG_CPRINT(("Bulkdata mode \n"));
		meme_addr = *(uint32_t*) &data[frame_index_cntr];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
		DEBUG_CPRINT(("Mem Addr: %luX \n", meme_addr));
#pragma GCC diagnostic pop
		dwnld_rqst.mem_address = meme_addr;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
		DEBUG_CPRINT(("RAM allocated: %lu \n", dwnld_rqst.size));
#pragma GCC diagnostic pop
#ifndef LINUX_TEMP_PORT
	if(((uint8_t *)meme_addr >= look_up_table[E_RAM].start_addr) && ((uint8_t *) meme_addr <= look_up_table[E_RAM].end_addr))
        {
		dwnld_rqst.mptr = (uint8_t*)meme_addr;
	}
	else
	{
		dwnld_rqst.mptr = NULL;
	}
#endif
#ifdef LINUX_TEMP_PORT
       dwnld_rqst.mptr = os_malloc_eram(dwnld_rqst.size);
#endif 
	if(dwnld_rqst.mptr != NULL)
	{
		status = 1;
	}
	else
	{
		DEBUG_CPRINT(("RAM allocation fail \n"));
		ft_set_err_sts(ft_malloc_ram_error);
                send_ftsr(ftsr_dwnld_ptr_null,0);
                ft_rx_session_id_store(sid);
	}

	}


	if(status != 0)
	{
		ft_state =  get_file_transfer_state();
		if(ft_state == ft_process_na)
		{
			set_file_transfer_state(ft_download);
			if (ftci_frame_loc.ctrl_2.transfer_mode_sel == 0)
			{
			    dwnld_rqst.mptr = NULL;
			}
			else
			{

			}
			status = prepare_sts_and_notify_receiver_app(transfer_download_ready);
			if(status != 0)
			{

#ifndef FT_OBC

				/* setting non zero value to pass next condition if software run in PS/GS for file TX mode
				 *
				 */
				if (ftci_frame_loc.ctrl_2.transfer_mode_sel == 0)
				{
					dwnld_rqst.mptr = (uint8_t*)0xff;
				}
#endif

#ifdef FT_OBC

				if(ft_ram_write_fp != NULL)
				{
#endif
					if(dwnld_rqst.mptr != NULL)
					{
						DEBUG_CPRINT(("FT Download_Ready !\n"));
						log_id(LOG_INFO_L1, LOG_FTM, FT_DOWNLOAD_READY);
						ft_fsm_change_state(FT_Idle_State);
						ft_service_enable();
						send_ftsr(ftsr_receiver_ready,0);
						ft_set_timer(FTDP_WAITING_TIME_INTERVAL);
						dwnld_rqst.receive_busy =1;
						ft_seq_loss_handle_init();
					}
					else
					{
                        DEBUG_CPRINT(("FTM Rx storage allocation failed\n"));
        				log_id(LOG_WARNING, LOG_FTM, FTM_RX_STORAGE_ALLOCATION_FAILED);
						set_file_transfer_state(ft_process_na);
						/* it should be disk fll */
						send_ftsr(ftsr_rx_system_error,0);
                        ft_rx_session_id_store(sid);
						ft_set_err_sts(ft_malloc_flash_error);
					}

#ifdef FT_OBC
				}
				else
				{
					DEBUG_CPRINT(("OBC Ramwrite func not registered\n"));
					send_ftsr(ftsr_file_not_found,0);
                    ft_rx_session_id_store(sid);
				}
#endif

			}
			else
			{
				log_id(LOG_WARNING, LOG_FTM, APP_NOTIFICATION_RETURN_FAIL);
				set_file_transfer_state(ft_process_na);
				send_ftsr(ftsr_rx_api_not_found,0);
                ft_rx_session_id_store(sid);

				if (ftci_frame_loc.ctrl_2.transfer_mode_sel == 1)
				{
					os_free(dwnld_rqst.mptr);
				}
				else
				{
#ifndef FT_OBC
					ft_file_close(dwnld_rqst.fptr,&dwnld_rqst.file_opened, dwnld_rqst.tx_mode);
#endif
				}
			}

		}
		else
		{
			DEBUG_CPRINT(("FT busy !\n"));
            log_id(LOG_WARNING, LOG_FTM, FT_BUSY_RX_REJECTED);
			send_ftsr(ftsr_ftm_busy,0);
            ft_rx_session_id_store(sid);
			ft_set_err_sts(ft_framework_busy_error);
		}

	}
	else
	{
		DEBUG_CPRINT(("FTCI data error !\n"));
		log_id(LOG_ERROR, LOG_FTM, FTCI_DATA_ERROR);
		send_ftsr(ftsr_rx_system_error,0);
        ft_rx_session_id_store(sid);
		}
	}
	else if(ftci_frame_loc.ctrl_1.resume_context_mode == 1)
	{
		DEBUG_CPRINT(("[FTM]FTCI RES_CTXT\n"));
		log_id(LOG_INFO_L1, LOG_FTM, FTM_FTCT_RES_CTXT);

		resume_ctxt_rqst.size             = calculated_size;
		resume_ctxt_rqst.mtu_size         = ftci_frame_loc.mtu_size;
		resume_ctxt_rqst.checksum         = ftci_frame_loc.checksum;
		dwnld_rqst.seq_loss_detect_enable = ftci_frame_loc.ctrl_1.seq_loss_detection_mode;
		ft_rx_session_id_store(ftci_frame_loc.ctrl_1.file_tx_session_id);

		ft_set_master_slave(sus_res_slave);
		set_file_transfer_state(ft_download);
		prepare_sts_and_notify_receiver_app(transfer_resumed_restorecontext);

	}
}




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


/**
 * @brief This API receives the FTCI frame data from TC-TM then decode FTCI frame
 *
 *
 */
void ft_receive_ftci(uint8_t *ftci_data, uint16_t ftci_data_length)
{
	decode_ftci_frame(ftci_data);
}

