/**
 *@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
 */
#include "ftci_decode.h"
#include "ftds_decode.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"

#include "data_type.h"
#include "file_transfer.h"
#include "fsm.h"
#include "ft_timer.h"
#include "ftsr.h"
#include "ftsr.h"
#include "message_frame_def.h"
#include "ft_receiver.h"
#include "ft_sender.h"
#include "ftfci_decode.h"

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



s_treceive_info dwnld_rqst;
s_treceive_info resume_ctxt_rqst;

FILE * fptr_write;


s_string_info ftci_rxd_frame;

tc_tm_id_e_ft tctm_id_inform_ftci = FT_TC_FTCI;


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));

    printf("\n ***FTCI - Decoding***\n");
	printf("Session id is %d\n", ftci_frame_loc.ctrl_1.file_tx_session_id);
	printf("File format is %d\n", ftci_frame_loc.ctrl_2.file_format);
	printf("Size field length is %d\n", ftci_frame_loc.ctrl_2.size_field_length);
	printf("Size of the MTU is %u\n", ftci_frame_loc.mtu_size);
	printf("User unit is %d\n", ftci_frame_loc.ctrl_2.unit);
	printf("Checksum is %X\n", ftci_frame_loc.checksum);
	printf("File ID is %d\n", ftci_frame_loc.ctrl_1.file_identification_number);
        printf("RX con fail time is %d  \n", ftci_frame_loc.rx_con_fail_timeout);

	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;
	if(dwnld_rqst.seq_loss_detect_enable == SEQ_LOSS_DETECTION_OFF)
	{
		 printf("UNACK Mode selected \n");
	}
	dwnld_rqst.dwnld_cmp_sts = 0;
	dwnld_rqst.file_id = ftci_frame_loc.ctrl_1.file_identification_number;
        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 */
		printf("File TX mode\n");

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

		dwnld_rqst.file_name = malloc(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++;
			}

			printf("File name: %s\n", dwnld_rqst.file_name);
			printf("File Size is %X  \n", dwnld_rqst.size);


#ifndef FT_OBC
			if ((dwnld_rqst.fptr = fopen((char*)dwnld_rqst.file_name, "wb")) == NULL)
			{
				printf("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
		{
			printf("FTM Malloc error\n");
            send_ftsr(ftsr_rx_system_error,0);
            ft_rx_session_id_store(sid);

		}
	}
	else
	{
		printf("Bulkdata mode \n");
		meme_addr = *(uint32_t*) &data[frame_index_cntr];
		printf("Mem Addr: %x \n", meme_addr);
		dwnld_rqst.mem_address = meme_addr;
		printf("RAM allocated: %d \n", dwnld_rqst.size);
		dwnld_rqst.mptr = malloc(dwnld_rqst.size);
		if(dwnld_rqst.mptr != NULL)
		{
			status = 1;
		}
		else
		{
			printf("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)
	{
		if(ft_payload_send != NULL)
		{
			ft_state =  get_file_transfer_state();
			if(ft_state == ft_process_na)
			{
				set_file_transfer_state(ft_download);

				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_payload_obc_send != NULL)
					{
#endif
						if(dwnld_rqst.mptr != NULL)
						{
							printf("FT Download_Ready !\n");
							ft_fsm_change_state(FT_Idle_State);
							send_ftsr(ftsr_receiver_ready,0);
							ft_set_timer(FTDP_WAITING_TIME_INTERVAL);
							dwnld_rqst.receive_busy =1;
							ft_ftds_busy_clear();
							ft_seq_loss_handle_init();
                            ft_clear_ftfci_queue_flag();

						}
						else
						{
							printf("FT Mem ptr NULL!\n");

							set_file_transfer_state(ft_process_na);
							/* it should be disk fll */
							send_ftsr(ftsr_dwnld_ptr_null,0);
							ft_rx_session_id_store(sid);                                                                                    
							ft_set_err_sts(ft_malloc_flash_error);
						}

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

				}
				else
				{
					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)
					{
						free(dwnld_rqst.mptr);
					}
					else
					{
#ifndef FT_OBC
						ft_file_close(dwnld_rqst.fptr,&dwnld_rqst.file_opened, dwnld_rqst.tx_mode);
#endif
					}
				}

			}
			else
			{
				printf("FT busy !\n");
				send_ftsr(ftsr_ftm_busy,0);
                ft_rx_session_id_store(sid);
				ft_set_err_sts(ft_framework_busy_error);
			}
		}
		else
		{
			ft_set_err_sts(ft_icd_tctm_pld_callback_error);
			printf("ICD/TCTM sender func not registered\n");
			/* can not send response since payload callback is not registered */
		}

	}
	else
	{
		printf("FTCI data error !\n");
		send_ftsr(ftsr_file_not_found,0);
        ft_rx_session_id_store(sid);
		}
	}
	else if(ftci_frame_loc.ctrl_1.resume_context_mode == 1)
	{
		printf("[FTM]FTCI RES_CTXT\n");

		resume_ctxt_rqst.size = calculated_size;
		resume_ctxt_rqst.mtu_size = ftci_frame_loc.mtu_size;
		resume_ctxt_rqst.checksum = ftci_frame_loc.checksum;

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

	}
	else
	{
		// do nothing
	}
}


void ft_receive_ftci(uint8_t *ftci_data, uint16_t ftci_data_length)
{
	uint16_t u16cnt;
	ftci_rxd_frame.str_ptr = malloc(ftci_data_length);

	if (ftci_rxd_frame.str_ptr != NULL)
	{
		ftci_rxd_frame.size = ftci_data_length;
		for (u16cnt = 0; u16cnt < ftci_data_length; u16cnt++)
		{
			ftci_rxd_frame.str_ptr[u16cnt] = ftci_data[u16cnt];
		}
		decode_ftci_frame(ftci_rxd_frame.str_ptr);
	}
	else
	{
		printf("FTM Malloc fail\n");
	}
        ft_save_session_start_time();
}

