/**
 *@file ftds_decode.c
 *
 *@brief This file contains functions that provides demonstration of
 *       usage of FTDS frame decoding APIs
 *
 *The functions provided in the file provides demonstration on
 *usage of FTDS frame decoding APIs
 */
#include "ftds_decode.h"

#include "stdio.h"
#include "stdlib.h"

#include "download_def.h"
#include "file_integrity_check.h"
#include "file_transfer.h"
#include "fsm.h"
#include "ft_timer.h"
#include "ftci_decode.h"
#include "ftsr.h"
#include "message_frame_def.h"
#include "notify_apps.h"
#include "ftfci_decode.h"

#include "upload_def.h"
#include "segmentation.h"
#include "ftfci.h"
#include "ft_sender.h"
#include "ft_receiver.h"
#include "ft_debug.h"
#include "ftds.h"

uint32_t ft_retransmit_rec_seq_cntr = 0;
uint32_t seq_cntr = 0;

tc_tm_id_e_ft tctm_id_inform_ftds = FT_TC_FTDS;
/*
 *  packet loss detcetion mechanism
 *  it will report every FTSR_SEQ_LOSS_REPORT_LIMIT
 *  If maximum loss count is reached it will send head change request
 *
 */


#define FTSR_SEQ_LOSS_REPORT_LIMIT 4

/* if missing sequence are not sent by sender, it will ask
 * re transmission for every 20 seq are received
 * */
#define PERIODIC_RESEND_RQST_CNT_LIMIT 20


static uint8_t ftds_busy = 0;
extern uint8_t ftds_ack_en;


uint8_t check_lost_packet_is_recived(uint32_t seq_num)
{
	uint8_t ret_sts = 0;
	uint16_t u16cntr=0;
	while(u16cntr < MAX_PCKT_LOSS_DETECTION_CNTR)
	{
		if(seq_num == dwnld_rqst.data_loss.lost_packet_list[u16cntr])
		{
			ret_sts = 1;
			dwnld_rqst.data_loss.lost_packet_list[u16cntr] = 0;
			dwnld_rqst.data_loss.total_lost_segment_count--;
			break;
		}
		u16cntr++;
	}
	return ret_sts;
}


uint8_t get_missing_sequnec_buffer_status()
{
	uint8_t ret =0;;
	if(dwnld_rqst.data_loss.total_lost_segment_count < MAX_PCKT_LOSS_DETECTION_CNTR)
	{
		ret = 1;
	}
	return ret;
}


uint8_t get_missing_sequnec_status()
{
	uint8_t ret =0;;
	if(dwnld_rqst.data_loss.total_lost_segment_count == 0)
	{
		ret = 1;
	}
	return ret;
}


uint8_t save_lost_seq_id(uint32_t seq_num)
{
	uint8_t ret_sts = 0;
	uint16_t u16cntr=0;
	if(dwnld_rqst.data_loss.total_lost_segment_count < MAX_PCKT_LOSS_DETECTION_CNTR)
	{
		while(u16cntr < MAX_PCKT_LOSS_DETECTION_CNTR)
		{
			if(0 == dwnld_rqst.data_loss.lost_packet_list[u16cntr])
			{
				ret_sts = 1;
				dwnld_rqst.data_loss.lost_packet_list[u16cntr] = seq_num;
				dwnld_rqst.data_loss.total_lost_segment_count++;
				/* set resend request flag , it will be cleared once ID communicated with sender */
				dwnld_rqst.data_loss.resend_rqst_flag = dwnld_rqst.data_loss.resend_rqst_flag | (1 << u16cntr);
	            printf("saved lost id %d at pos %d\n",seq_num,u16cntr);

				break;
			}
			u16cntr++;
		}
	}
	else
	{
		/* maximum sequence ID carrier buffer is full; request sender side head position change request. */
		ret_sts = 0;
	}
	return ret_sts;
}

/*
 * This function will identify
 * a. missed sequence ID
 * b. store missed ID in tracker buffer
 * c. trigger sequence ID notification to sender when missing id count is reached limit
 * d. trigger head change request to sender if tracker buffer not able to hold new lost sequence
 */

uint8_t packet_loss_detection_recovery(uint32_t current_seq_num)
{
	uint16_t loss_count;
	uint16_t u16cnt;
	uint8_t ret_sts =1;
	static uint16_t data_loss_notify = 0;
	uint32_t copy_saved_seg;


	copy_saved_seg = dwnld_rqst.pckt_seq_head;

     if(current_seq_num > dwnld_rqst.pckt_seq_head)
     {
         if(current_seq_num == dwnld_rqst.pckt_seq_head+1)
         {
             printf("FNL%d\n",current_seq_num);
             dwnld_rqst.pckt_seq_head = current_seq_num;
             seq_cntr=dwnld_rqst.pckt_seq_head;
         }
         else
         {
        	 if(dwnld_rqst.seq_loss_detect_enable == SEQ_LOSS_DETECTION_OFF)
        	 {
				 dwnld_rqst.pckt_seq_head = current_seq_num;
				 ft_receiver_ping_rest();
				 return 1;
        	 }


             loss_count = (current_seq_num-1) - dwnld_rqst.pckt_seq_head;
             printf("loss %d to %d t=%d \n",dwnld_rqst.pckt_seq_head+1,current_seq_num-1,loss_count);


             ret_sts = get_missing_sequnec_buffer_status();
             if(ret_sts == 1)
             {
				 for(u16cnt=0; u16cnt < loss_count; u16cnt++)
				 {
					 /* save lost in sequence ID tracker buffer */
					 ret_sts = save_lost_seq_id(dwnld_rqst.pckt_seq_head+1+u16cnt);
					 if((ret_sts != 1) && (dwnld_rqst.data_loss.head_change_request !=1))
					 {
						 /* stop storing sequnece ID if seq tracker buf is full, then notify loss status to sender */
						 printf("high loss \n");
						 //prepare_packet_loss_notify_frame(&dwnld_rqst, ftsr_head_change);
						 dwnld_rqst.data_loss.head_change_request = 1;
						 data_loss_notify = FTSR_SEQ_LOSS_REPORT_LIMIT;
						 ret_sts = 0;
						 break;
					 }
					 else if(ret_sts == 1)
					 {
						 copy_saved_seg = dwnld_rqst.pckt_seq_head+1+u16cnt;
					 }
					 else
					 {

					 }
					 data_loss_notify++;
				 }
			}
			else
			{
				 ret_sts = 0;
				 dwnld_rqst.data_loss.head_change_request = 1;
			}
             if(dwnld_rqst.data_loss.head_change_request == 1)
             {
            	 dwnld_rqst.pckt_seq_head = copy_saved_seg;
                 ft_fsm_change_state(FT_Report_Head_Change);
	     }
             else
             {
            	 dwnld_rqst.pckt_seq_head = current_seq_num;
             }

             printf("loss count %d head:%d\n",data_loss_notify, dwnld_rqst.pckt_seq_head);

         }
         if(data_loss_notify >= FTSR_SEQ_LOSS_REPORT_LIMIT)
         {
        	 data_loss_notify = 0;
        	 /* send data loss info to sender */
        	 //prepare_packet_loss_notify_frame(&dwnld_rqst, ftsr_missing_pckts);
        	 set_resend_flag(&dwnld_rqst);
             printf("Report_Sequence_loss \n");
        	 ft_fsm_change_state(FT_Report_Sequence_loss);
         }
     }
     else
     {
         printf("re transmission %d\n",current_seq_num);
         ft_retransmit_rec_seq_cntr++;
         ret_sts = check_lost_packet_is_recived(current_seq_num);
         if(ret_sts != 1)
         {
             printf("Duplicate ID rxd...\n");
         }
     }
     return ret_sts;
}


void ft_receive_ftds(uint8_t *ftds_data, uint16_t ftds_data_length)
{
	uint16_t u16cnt;

	if(ftds_busy != 1)
	{
		ftds_busy = 1;
		dwnld_rqst.ftds_payload_ptr = malloc(ftds_data_length);

		if (dwnld_rqst.ftds_payload_ptr != NULL)
		{
			for (u16cnt = 0; u16cnt < ftds_data_length; u16cnt++)
			{
				dwnld_rqst.ftds_payload_ptr[u16cnt] = ftds_data[u16cnt];
			}
			ft_fsm_change_state(FT_Receive_Sequence);
                        ftds_decode();
		}
		else
		{
			printf("\n malloc error\n");

		}
	}
	else
	{
		printf("\r\nFTDS-bsy");
	}
}


void save_context_info(ft_notification_info* sts)  //uint8_t *save_info, uint16_t *size)
{
	uint16_t calc_buf_size;
	e_ft_current_process ft_state;
	uint32_t checksum;
	uint32_t data_dwnld_sofar;

	ft_state =  get_file_transfer_state();
	if(ft_state == ft_upload)
	{
		if(tx_info.tx_mode == 1)
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) + 4;
		}
		else
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) + tx_info.file_name_size + 4;
		}

		sts->context_info.context_info_buf_ptr  = malloc(calc_buf_size);
		if(sts->context_info.context_info_buf_ptr != NULL)
		{
			printf("Malloc %d \n",calc_buf_size);


			if(tx_info.tx_mode == 1)
			{
				/* if suspend requested during bulk data tx mode,
				 * calculate checksum for input bufferr and save the checksum value in
				 * context header.
				 */
				sts->context_info.bulkdata_checksum = tx_info.checksum;
				sts->context_info.bulkdata_len = tx_info.size;
				sts->context_info.bulkdata_mem_addr = (uint64_t)tx_info.mptr;
				printf("BULKDATA Checksum: 0x%ux\n",sts->context_info.bulkdata_checksum);
				printf("BULKDATA Mem_ptr: 0x%lux\n",(uint64_t)tx_info.mptr);
			}

			sts->context_info.tx_mode = tx_info.tx_mode;
			sts->context_info.context_info_size = calc_buf_size;
			sts->context_info.session_id = 0;
			sts->context_info.node_operation = ft_upload;
			sts->context_info.file_name_size = tx_info.file_name_size;
			sts->context_info.fsm_state_save = ft_get_state_before_suspend();
			sts->context_info.mast_slave_sel = ft_get_master_slave_status();

			/* copy context info */
			memcpy(&sts->context_info.context_info_buf_ptr[0],&sts->context_info,sizeof(ft_contextsave_info));
			/* copy tx info */
			calc_buf_size = sizeof(ft_contextsave_info);
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&tx_info,sizeof(s_transfer_info));
			/* copy segment info */
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info);
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&seg_info,sizeof(s_segment_info));

			if(tx_info.tx_mode == 0)
			{
				/* copy file name and path info */
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info);
				memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],input_file_name,tx_info.file_name_size);
			}

			/* calculate checksum and apped CRC of 4 bytes */
			checksum = calc_checksum_bulkdata(sts->context_info.context_info_buf_ptr, sts->context_info.context_info_size-4);
			if(tx_info.tx_mode == 1)
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) ;
			}
			else
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_transfer_info) + sizeof(s_segment_info) +tx_info.file_name_size ;
			}
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&checksum,4);
			//sts->context_info.context_info_size += 4;

			printf("Calculated checksum %X\n",checksum);
			printf("Save upload context pass:%d\n",sts->context_info.context_info_size);

		}
		else
		{
			printf("Save upload context malloc fail \n");
			ft_set_err_sts(ft_sc_malloc_error);
		}
	}
	else if(ft_state == ft_download)
	{
		if(dwnld_rqst.tx_mode == 1)
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info) +4;
		}
		else
		{
			calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info) + dwnld_rqst.file_name_buf_length +4;
		}
		sts->context_info.context_info_buf_ptr = malloc(calc_buf_size);
		if(sts->context_info.context_info_buf_ptr != NULL)
		{


			if(dwnld_rqst.tx_mode == 1)
			{
				/* if suspend requested during bulk data tx mode,
				 * calculate checksum for bytes downloaded so far and save the checksum value in
				 * context header.
				 */
				data_dwnld_sofar = dwnld_rqst.pckt_seq_num * dwnld_rqst.seq_payload_len;
				sts->context_info.bulkdata_checksum = calc_checksum_bulkdata(dwnld_rqst.mptr, data_dwnld_sofar);
				sts->context_info.bulkdata_len = data_dwnld_sofar;
				sts->context_info.bulkdata_mem_addr = (uint64_t)dwnld_rqst.mptr;
				printf("BULKDATA Checksum: 0x%d for size %d\n",sts->context_info.bulkdata_checksum,data_dwnld_sofar);
				printf("BULKDATA Mem_ptr: 0x%lux\n",(uint64_t)dwnld_rqst.mptr);
			}

			sts->context_info.tx_mode = dwnld_rqst.tx_mode;
			sts->context_info.context_info_size = calc_buf_size;
			sts->context_info.session_id = 0;
			sts->context_info.node_operation = ft_download;
			sts->context_info.file_name_size = dwnld_rqst.file_name_buf_length;
			sts->context_info.fsm_state_save = ft_get_state_before_suspend();
			sts->context_info.mast_slave_sel = ft_get_master_slave_status();

			/* copy context info */
			memcpy(&sts->context_info.context_info_buf_ptr[0],&sts->context_info,sizeof(ft_contextsave_info));
			/* copy file name and path info */
			calc_buf_size = sizeof(ft_contextsave_info);
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&dwnld_rqst,sizeof(s_treceive_info));

			if(dwnld_rqst.tx_mode == 0)
			{
				/* copy file name and path info */
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info);
				memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],dwnld_rqst.file_name,dwnld_rqst.file_name_buf_length);
			}
			/* calculate checksum and apped CRC of 4 bytes */
			checksum = calc_checksum_bulkdata(sts->context_info.context_info_buf_ptr, sts->context_info.context_info_size-4);
			if(dwnld_rqst.tx_mode == 0)
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info) + dwnld_rqst.file_name_buf_length ;
			}
			else
			{
				calc_buf_size = sizeof(ft_contextsave_info) + sizeof(s_treceive_info);
			}
			memcpy(&sts->context_info.context_info_buf_ptr[calc_buf_size],&checksum,4);
			//sts->context_info.context_info_size += 4;

			printf("Calculated checksum %X\n",checksum);
			printf("Save download context pass, Size:%d\n",sts->context_info.context_info_size);

		}
		else
		{
			ft_set_err_sts(ft_sc_malloc_error);
			printf("Save download context malloc fail \n");
		}
	}
	else
	{
		printf("FTM Save context not prepared since state in ft_no _process\n");
		sts->context_info.context_info_buf_ptr = NULL;
	}

}


uint8_t prepare_sts_and_notify_receiver_app(ft_status_type status)
{
	uint8_t ret;
	ft_notification_info sts;
	sts.app_id = ft_get_app_id_rx();
	sts.status = status;

	switch(status)
	{
		case transfer_download_success:
		{
			sts.dwld_info.tx_mode = dwnld_rqst.tx_mode;
			sts.dwld_info.size_file_or_data = dwnld_rqst.size;
			sts.dwld_info.checksum = dwnld_rqst.checksum;
                        sts.dwld_info.rx_file_id = dwnld_rqst.file_id;
                        sts.dwld_info.retranmission_status = ft_get_retranmission_status();

			if(dwnld_rqst.tx_mode == 0)
			{
				sts.dwld_info.storage_path_and_File_name = dwnld_rqst.file_name;
				sts.dwld_info.path_filename_buf_length = dwnld_rqst.file_name_buf_length;
#ifdef FT_OBC
				sts.dwld_info.bulkdata_ptr = dwnld_rqst.mptr;
#endif
			}
			else
			{
				sts.dwld_info.bulkdata_ptr = dwnld_rqst.mptr;
			}

		}
		break;

		case crc_error:
		{

		}
		break;

		case transfer_suspended:
		{

		}
		break;

		case transfer_resumed:
		{

		}
		break;

		case transfer_suspended_savecontext:
		{
			printf("Close file %s\n",dwnld_rqst.file_name);
#ifndef FT_OBC
			ft_file_close(dwnld_rqst.fptr,&dwnld_rqst.file_opened, dwnld_rqst.tx_mode);
#endif
			save_context_info(&sts);
			if(sts.context_info.context_info_buf_ptr == NULL)
			{
				ft_transfer_request(Suspend_Savecontext_nack_rqst,0);
				return 0;
			}
		}
		break;

		case transfer_suspend_savecontext_accepeted:
			printf("Save context accepted by Sender !!! \n");
#ifndef FT_OBC
			ft_file_close(dwnld_rqst.fptr,&dwnld_rqst.file_opened, dwnld_rqst.tx_mode);
#endif
			sts.context_info.session_id = 0;
			sts.context_info.node_operation = ft_download;
			save_context_info(&sts);
			ft_fsm_change_state(FT_Inactive);
			set_file_transfer_state(ft_process_na);
			ft_ftds_busy_clear();
			break;

		case transfer_resumed_restorecontext:
		{

		}
		break;

		case tx_terminated_suspend_timeout_expired:
		{

		}
		break;

		case transfer_download_ready:
		{
			sts.dwld_info.tx_mode = dwnld_rqst.tx_mode;
			sts.dwld_info.size_file_or_data = dwnld_rqst.size;
			sts.dwld_info.rx_file_id = dwnld_rqst.file_id;
		}
		break;

		default:
			break;


	}
	ret = ft_notify_receiver_app(&sts);
	return ret;
}
/*
 *This api is use get the session information in receiver side
 */
static void ft_derive_rec_session_throughput_status(void)
{
	/*
	 * kbps derivation
	 * kilobytes per second
	 *
	 * sample:
	 *  file size - 8kb > 8192
	 *  MTU - 128
	 *  FTDS - 10ms
	 *
	 *  FTM header 7 bytes for each sequnce
 	*  Sequence total = 8192 / (128-7) = 67
 	*  So it will take 670ms(67*10ms) to complete transmission.
 	*  hence speed is 12226 bytes pers second or 11.94 kbytes/sec
 	*
 	*     8192
 	*  =  ____         =>  8192 / 0.67 => 12226
 	*    (670/1000)
 	*
 	*/

	time_t session_time;
	float data_rate;

	
	printf("\r\nSession Info::\n");
	printf("a. File size                     - %d kilobyte (%d bytes)\n",(dwnld_rqst.size / 1024), dwnld_rqst.size);
	printf("b. MTU                           - %d\n", dwnld_rqst.mtu_size);
	printf("c. Total packets                 - %d\n", seq_cntr);

	printf("\nFTM Transmission data rate status in Kbits (kilobits per seconds)\n");

        session_time = ft_get_session_time();
        if(session_time != 0)
        {
            data_rate = dwnld_rqst.size / session_time;
        }
        else
        {
            data_rate = dwnld_rqst.size / 1;
        }

        if(6 < ft_get_rec_retranmission_status())
        {
            printf("    1. Actual rate is - %.1f Kbits, total session time taken %lu seconds\n",(data_rate / 1024)*8, session_time);
        }
        else
        {
            if(session_time != 0)
            {
                printf("    rate - %.1f Kbits, total session time taken %lu seconds\n",(data_rate / 1024)*8, session_time);
            }
            else
            {
                printf("    rate - %.1f Kbits, total session time taken less than 1 seconds\n",(data_rate / 1024)*8);
            }
        }

        if(ft_get_rec_retranmission_status() > 0)
        {
            printf("    \nRe - Transmitted packets count %d\n", ft_get_rec_retranmission_status());
        }
        else
        {

        }

}


void check_integrity()
{
	uint32_t file_checksum;

#ifndef FT_OBC
	ft_file_close(dwnld_rqst.fptr,&dwnld_rqst.file_opened, dwnld_rqst.tx_mode);
	printf("\nFile %s is downloaded \n", dwnld_rqst.file_name);
	file_checksum = file_integrity_check((char*)dwnld_rqst.file_name);
#else
	file_checksum = calc_checksum_bulkdata(dwnld_rqst.mptr,dwnld_rqst.size);
#endif
	if (file_checksum == dwnld_rqst.checksum)
	{
		printf("File integrity success \n");
		send_ftsr(ftsr_download_complete,0);
		dwnld_rqst.dwnld_cmp_sts = ftsr_download_complete;
                ft_save_session_end_time();
                ft_derive_rec_session_throughput_status();
		prepare_sts_and_notify_receiver_app(transfer_download_success);
                ft_clear_rec_retranmission_status();
                seq_cntr = 0;
	}
	else
	{
		printf("File size rxd: %u\n",dwnld_rqst.size);
		printf("File integrity failed CRC:0x%X against 0x%X\n",file_checksum,dwnld_rqst.checksum);
		send_ftsr(ftsr_crc_fail,0);
		dwnld_rqst.dwnld_cmp_sts = ftsr_crc_fail;
		prepare_sts_and_notify_receiver_app(crc_error);
	}
	ft_fsm_change_state(FT_Inactive);
	ft_process = ft_process_na;


//	free(dwnld_rqst.file_name);

}



void check_integrity_bulkdata()
{
	uint32_t data_checksum;
//	uint16_t u16cnt;



	printf("\nBulk data is downloaded \n");

//	for (u16cnt = 0 ; u16cnt < dwnld_rqst.size; u16cnt++)
//	{
//		printf("%d,",dwnld_rqst.mptr[u16cnt]);
//	}
//	printf("\n");



	data_checksum = calc_checksum_bulkdata(dwnld_rqst.mptr,dwnld_rqst.size);
	if (data_checksum == dwnld_rqst.checksum)
	{
		printf("Bulkdata integrity success \n");
		send_ftsr(ftsr_download_complete,0);
		prepare_sts_and_notify_receiver_app(transfer_download_success);
	}
	else
	{
		printf("Bulkdata size rxd: %u\n",dwnld_rqst.size);
		printf("File integrity failed CRC:0x%X against 0x%X\n",data_checksum,dwnld_rqst.checksum);
		send_ftsr(ftsr_crc_fail,0);
		prepare_sts_and_notify_receiver_app(crc_error);
	}
	ft_process = ft_process_na;



}




uint8_t ftds_decode()
{
	uint16_t u16cnt;
	uint8_t * loc_ptr;
	s_file_tx_data_pckt * ftds_loc;
	ftds_loc = (s_file_tx_data_pckt*) dwnld_rqst.ftds_payload_ptr;
	uint8_t frame_index_cntr;
	uint32_t file_position_calc;
	uint8_t ret_sts;
	uint8_t seq_type;
    uint8_t ses_id ;
#ifdef FT_OBC
	uint64_t obc_offset_addr;
#endif

	e_ft_current_process ft_state;

    ft_debug_save_prev_frame_info(tctm_id_inform_ftds,0);

	ft_state =  get_file_transfer_state();
	if(ft_state != ft_download)
	{
		/* it helps to close FTM if sender stopped transmission
		 * or sequence loss has detected, it doesn t required to receive FTDS
		 * if sequence loss has detected
		 */
		printf("FTM - No Service, FTDS discard\n");
		ftds_busy = 0;
		return 0;
	}


	dwnld_rqst.pckt_seq_num = 0;
	ft_fsm_change_state(FT_Idle_State);

  ses_id = ft_rx_session_id_read();
	if(ftds_loc->ctrl.bit.file_tx_session_id != ses_id )
	{
		// send session id mismatch response to gs
        printf("Session ID mismatch, the sequence is discared RCV %d != STR %d\n", ftds_loc->ctrl.bit.file_tx_session_id,ses_id);
		send_ftsr(ftsr_invalid_session_id, 0);
        ftds_busy = 0;
		return 0;
	}


	frame_index_cntr = sizeof(s_file_tx_data_pckt);



	/* read sequence number from FTDS frame*/
	loc_ptr = (uint8_t*) &dwnld_rqst.pckt_seq_num;
	for (u16cnt = 0; u16cnt <= ftds_loc->ctrl.bit.seq_num_field_size_sel; u16cnt++)
	{
		*loc_ptr = dwnld_rqst.ftds_payload_ptr[frame_index_cntr];
		loc_ptr++;
		frame_index_cntr++;
	}

	printf("SEQ:%u ", dwnld_rqst.pckt_seq_num);


	seq_type = ftds_loc->ctrl.bit.seg_type;
	if (seq_type == 2)
	{
		if(dwnld_rqst.pckt_seq_num == 1)
		{
			
			printf("This File has only Single Sequence \n");
		}
		else
		{
			printf("Last Sequence \n");
		}
	}


	dwnld_rqst.packet_data_size = 0;

	/* read payload data length from FTDS frame*/
	loc_ptr = (uint8_t*) &dwnld_rqst.packet_data_size;
	for (u16cnt = 0; u16cnt <= ftds_loc->ctrl.bit.data_length_field_size_sel; u16cnt++)
	{
		*loc_ptr = dwnld_rqst.ftds_payload_ptr[frame_index_cntr];
		loc_ptr++;
		frame_index_cntr++;
	}

	printf("DL:%u ", dwnld_rqst.packet_data_size);

	ret_sts = packet_loss_detection_recovery(dwnld_rqst.pckt_seq_num);

	/* save data into file */
	if(ret_sts != 0)
	{

		ft_check_suspend_status();
		file_position_calc = (dwnld_rqst.pckt_seq_num - 1) * dwnld_rqst.seq_payload_len;
		printf("FP:%u\n", file_position_calc);

		if(dwnld_rqst.tx_mode == 0)
		{
#ifndef FT_OBC
			fseek(dwnld_rqst.fptr, file_position_calc, SEEK_SET);
			fwrite(&dwnld_rqst.ftds_payload_ptr[frame_index_cntr], dwnld_rqst.packet_data_size, 1, dwnld_rqst.fptr);
#else
			obc_offset_addr = dwnld_rqst.obc_mem_addr + file_position_calc;
			ret_sts = ft_payload_obc_send(obc_offset_addr,&dwnld_rqst.ftds_payload_ptr[frame_index_cntr], dwnld_rqst.packet_data_size);
			if(ret_sts != 1)
			{
				printf("Warning !!! FTM driver Busy\n");
			}
#endif
		}
		else
		{
			for (u16cnt = 0; u16cnt < dwnld_rqst.packet_data_size; u16cnt++)
			{
				dwnld_rqst.mptr[file_position_calc + u16cnt] = dwnld_rqst.ftds_payload_ptr[frame_index_cntr+u16cnt];
			}
		}



		printf("Write success \n");


		if ((seq_type == 2) || (dwnld_rqst.download_pending_by_loss == 1))
		{
			/*last packet */
			printf("Last packet or Pending packets receive\n");
			ret_sts = get_missing_sequnec_status();
			if(ret_sts != 0)
			{
				printf("Integrity check \n");
				if(dwnld_rqst.tx_mode == 0)
				{
#ifdef FT_OBC
					ret_sts = 0;
					printf("Flash Handler Busy...\n");
					while(ret_sts != 1)
					{
						ret_sts = ft_payload_obc_busy_sts();
					}
					sleep(1);
#endif
					check_integrity();
				}
				else
				{
					check_integrity_bulkdata();

				}
				dwnld_rqst.receive_busy =0;
				ft_stop_timer();
			}
			else if(ftds_loc->ctrl.bit.seg_type == 2)
			{
				printf("Completion pending by seq loss..\n");
				set_resend_flag(&dwnld_rqst);
				ft_fsm_change_state(FT_Report_Sequence_loss);
				dwnld_rqst.download_pending_by_loss = 1;
			}

		}
		else
		{
				// do nothing
		}

		if(dwnld_rqst.data_loss.total_lost_segment_count != 0)
		{
			/* it will request lost sequence for every PERIODIC_RESEND_RQST_CNT_LIMIT */
			dwnld_rqst.data_loss.re_request_initiate_timer++;
			if(dwnld_rqst.data_loss.re_request_initiate_timer > PERIODIC_RESEND_RQST_CNT_LIMIT)
			{
				dwnld_rqst.data_loss.re_request_initiate_timer=0;
				set_resend_flag(&dwnld_rqst);
				ft_fsm_change_state(FT_Report_Sequence_loss);
			}
		}
		else
		{
			dwnld_rqst.data_loss.re_request_initiate_timer=0;
		}
	}
	ft_reset_timer();
	ftfci_clear_continous_ping_cntr();
	if(ftds_ack_en == 1)
	{
		send_ftsr(ftsr_ping,0);
	}
	free(dwnld_rqst.ftds_payload_ptr);
	ftds_busy = 0;
	return ret_sts;
}

void ft_seq_loss_handle_init(void)
{
	uint16_t u16cnt;
	dwnld_rqst.data_loss.total_lost_segment_count=0;
	dwnld_rqst.data_loss.resend_rqst_flag = 0;
	dwnld_rqst.pckt_seq_head =0;
	dwnld_rqst.download_pending_by_loss =0;

	for(u16cnt=0; u16cnt < MAX_PCKT_LOSS_DETECTION_CNTR ; u16cnt++)
	{
		dwnld_rqst.data_loss.lost_packet_list[u16cnt] =0;;
	}
}

uint32_t ft_get_receiver_head_seq_id(void)
{
	return dwnld_rqst.pckt_seq_head;
}


uint8_t ft_get_seq_loss_sts(void)
{
	uint8_t ret =0;
	if(dwnld_rqst.data_loss.total_lost_segment_count != 0)
	{
		ret =1;
	}
	return ret;
}


void ft_set_app_id_rx(uint16_t set)
{
	dwnld_rqst.app_id = set;
}

uint16_t ft_get_app_id_rx(void)
{
	return dwnld_rqst.app_id;
}


void ft_ftds_busy_clear(void)
{
	ftds_busy = 0;
}

/*
 * this api will return retransmission status
 */
uint32_t ft_get_rec_retranmission_status(void)
{
	return ft_retransmit_rec_seq_cntr;
}


/*
 * this api will clear retransmission status
 */
void ft_clear_rec_retranmission_status(void)
{
	ft_retransmit_rec_seq_cntr = 0;
}
