/*
 ============================================================================
 Name        : logger_1.c
 Author      : skm
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include "math.h"
#include "string.h"

#include "exo_osal.h"
#include "file_transfer.h"
#include "notify_apps.h"
#include "logger_linux_socket.h"
#ifndef LINUX_TEMP_PORT
#include "exo_io_al_uart_common.h"
#endif
#include "logger.h"
#include "logger_linux_socket.h"
#include "exo_types.h"
#include "exo_io_al_sos_timer.h"
#include "exo_ahw_al_ext_flash_common.h"
#include "nvm.h"
#include "obc_tc_tm.h"
#include "eps_ftm.h"
#include "exo_tctm_ipc.h"
#include "file_integrity_check.h"


/*
 * Allocated SDRAM for logger
 * Total = 64K  (1024 * 64) | (expected logs stored in 64 kb is 5760 (90*64)
 * Block size = 1024 bytes , it can accommodate 90 logs approx
 * Block count = 64
 */
#define SDRAM_STORAGE_SIZE		    	    (LOG_BLOCK_SIZE*LOG_TOTAL_BLOCK_CNT)  /// assume block cnt=10, blck size=100 => (10*100) = 1000 bytes will be reserved in sdram
#define LOG_BACKUP_MAX_INDEX_COUNT          120       //Maximum index count should be in multiples of 4
#define LOG_BACKUP_TOTAL_PARTITION_COUNT    6      /// 3 partition each partition of size (LOG_BACKUP_MAX_INDEX_COUNT * LOG_BLOCK_SIZE)
#define LOG_BACKUP_PARTITION_SIZE           (LOG_BACKUP_MAX_INDEX_COUNT*LOG_BLOCK_SIZE)

#define LOG_FRAME_HEADER_SIZE 		4 			 /// module id = 1 byte + enum = 2 byte + arg cnt = 1 byte
#define LOG_FRAME_NO_DATA 			(LOG_FRAME_HEADER_SIZE+3)
#define LOG_FRAME_ONE_DATA 			(LOG_FRAME_HEADER_SIZE+4+3)
#define LOG_FRAME_TWO_DATA 			(LOG_FRAME_HEADER_SIZE+8+3)
#define LOG_FRAME_THREE_DATA 		(LOG_FRAME_HEADER_SIZE+12+3)
#define LOG_FRAME_FOUR_DATA 		(LOG_FRAME_HEADER_SIZE+16+3)

#define LOG_MODUEL_ID_FIELD_LEN_BITS 0x7F		/// Logger header field size
#define LOG_ENUM_MODE 				 0x00		/// Mode of trace ; logging enum or plain string
#define LOG_STRING_MODE  			 0x01       /// Mode of trace ; logging enum or plain string

#define LOG_ONE_DATA_FIELD_VAL 		 0x00		/// Logger data fields size if one element is saved
#define LOG_TWO_DATA_FIELD_VAL 		 0x04		/// Logger data fields size if two element is saved
#define LOG_THREE_DATA_FIELD_VAL 	 0x08		/// Logger data fields size if three element is saved
#define LOG_FOUR_DATA_FIELD_VAL 	 0x0C		/// Logger data fields size if four element is saved


#ifdef COREBOARD
#define LOGGER_BACKUP_STORAGE_FLASH_TYPE EXT_MEM_MT28EW128_FMC
#else
#define LOGGER_BACKUP_STORAGE_FLASH_TYPE EXT_MEM_MX25L512_QSPI
#endif

#define LOGGER_TEST_FUNC_EXEC_TIMER_IN_MS 10
#define LOGGER_QUEUE_WAIT_TIMEOUT  500
#define LOGGER_PERIODIC_OUT_TIME_SEC (10*1000)



#define PERIODIC_LOGGER_SOCKET 1
#define PERIODIC_LOGGER_SERIAL 2
#define PERIODIC_LOGGER_OFF    0

#define LOG_BACKUP_ENABLE_CFG 0x5A

#ifdef LINUX_TEMP_PORT
uint8_t kernel_init_done =1;
#endif


uint8_t PLACE_IN_EXT_RAM_MEM logger_storage_mem_buf[SDRAM_STORAGE_SIZE+1024];
uint8_t PLACE_IN_EXT_RAM_MEM logger_tctm_mem_buf[SDRAM_STORAGE_SIZE+1024];






typedef enum
{
	LOG_NO_ARG,
	LOG_ONE_ARG,
	LOG_TWO_ARG,
	LOG_THREE_ARG,
	LOG_FOUR_ARG,
}log_arg_cnt_e;





typedef struct log_storage_blocks_def
{
	uint8_t id;
	uint16_t size;
}log_storage_blocks;


/**
 * Message queue which contains TCTM id, tctm payload, tctm lenth and source destination ID
 */
typedef struct log_queue_info_
{
	uint8_t Q_payload_len;      ///< Frame payload length
	uint8_t *Q_payload_ptr;     ///< frame payload ptr
}log_queue_pld;

#ifndef LINUX_TEMP_PORT
/**
 * This structure stores Partition number, Index number, and crc of logger data stored in flash memory
 */


static log_backup_info      log_backup_handle;
#endif
static PLACE_IN_EXT_RAM_MEM log_storage_handle 	log_storage_hdl;
static os_queue_handle_ptr 	log_queue_hdle;
static log_queue_pld 		log_rx_queue;
static uint16_t				queue_sendfailure_cntr;
static uint8_t				log_skip_cntr;
static sys_date_s           get_date;
uint8_t                     log_backup_en_dis_cfg;
uint8_t                     log_backup_write_cycle_block_count;
#ifdef LOGGER_TEST
static os_timer_handle_ptr  logger_test_timer;
#endif

#if (PERIODIC_LOG_ENB != PERIODIC_LOGGER_OFF)
static os_timer_handle_ptr  periodic_logger_out_timer_hdl;
#endif

#ifndef LINUX_TEMP_PORT
extern ioal_uart_hdle ioal_huart1;
extern ioal_uart_hdle ioal_huart6;
extern ioal_uart_hdle ioal_huart4;
extern ioal_uart_hdle ioal_huart5;
#endif

static const uint8_t log_level_bit_val[6]=
{
		0x00,
		0x01,
		0x02,
		0x04,
		0x08,
		0x10
};

#ifndef LINUX_TEMP_PORT
static uint8_t log_backup_sdram_ftm_buf[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_RAM_MEM;

#ifndef COREBOARD
static uint8_t logger_backup_storage1[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_QSPI_FLASH_MEM;
static uint8_t logger_backup_storage2[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_QSPI_FLASH_MEM;
static uint8_t logger_backup_storage3[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_QSPI_FLASH_MEM;
static uint8_t logger_backup_storage4[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_QSPI_FLASH_MEM;
static uint8_t logger_backup_storage5[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_QSPI_FLASH_MEM;
static uint8_t logger_backup_storage6[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_QSPI_FLASH_MEM;
#else
static uint8_t logger_backup_storage1[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_FMC_FLASH_MEM;
static uint8_t logger_backup_storage2[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_FMC_FLASH_MEM;
static uint8_t logger_backup_storage3[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_FMC_FLASH_MEM;
static uint8_t logger_backup_storage4[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_FMC_FLASH_MEM;
static uint8_t logger_backup_storage5[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_FMC_FLASH_MEM;
static uint8_t logger_backup_storage6[LOG_BACKUP_PARTITION_SIZE] PLACE_IN_EXT_FMC_FLASH_MEM;
#endif

#endif

#ifdef LINUX_TEMP_PORT
static uint8_t sdram_logger_storage_bank1[SDRAM_STORAGE_SIZE];
static uint8_t sdram_tctm_storage_bank2[SDRAM_STORAGE_SIZE];
#endif

#ifndef LINUX_TEMP_PORT
static uint32_t get_nor_flash_address(uint8_t partition_no);
static void     log_backup_init();
static void     log_backup(uint8_t *log_buf);
#endif
static void log_store(uint8_t *log_buf, uint8_t len);
static void log_handler(void* params);

#if (PERIODIC_LOG_ENB == PERIODIC_LOGGER_SERIAL)
static void log_serial_out(uint8_t *ptr, uint16_t len);



static void log_serial_out(uint8_t *ptr, uint16_t len)
{
	/*
	 * post message on serial port
	 *
	 */
#ifdef DBG_LOG_EN



#ifdef STM32F765xx

#ifdef COREBOARD

#ifdef PRINT_UART_4
	io_hal_uart_transmit(&ioal_huart4, (uint8_t *)ptr,(uint16_t)len,300);
#endif

#ifdef PRINT_UART_5
	io_hal_uart_transmit(&ioal_huart5, (uint8_t *)ptr,(uint16_t)len,300);
#endif

	// else serial out off

#else
	io_hal_uart_transmit(&ioal_huart6, (uint8_t *)ptr,(uint16_t)len,300);
#endif /* COREBOARD*/

#endif /* STM32F765xx */

#ifdef STM32F769xx
	io_hal_uart_transmit(&ioal_huart1, (uint8_t *)ptr,(uint16_t)len,300);
#endif


#endif

}

#endif

#ifndef LINUX_TEMP_PORT

/*
 * This api returns flash address based on the partition number
 */
static uint32_t get_nor_flash_address(uint8_t partition_no)
{
	uint32_t addr =0;
	if(partition_no == 1)
	{
    	addr = (uint32_t)logger_backup_storage1;
	}
	else if(partition_no == 2)
	{
		addr = (uint32_t)logger_backup_storage2;
	}
	else if(partition_no == 3)
	{
		addr = (uint32_t)logger_backup_storage3;
	}
	else if(partition_no == 4)
	{
		addr = (uint32_t)logger_backup_storage4;
	}
	else if(partition_no == 5)
	{
		addr = (uint32_t)logger_backup_storage5;
	}
	else if(partition_no == 6)
	{
		addr = (uint32_t)logger_backup_storage6;
	}
	return addr;
}

/*
 * This api will do the following functions
 * 1.Read logger backup informations like partition number, index number, CRC
 * 2.Calculate checksum and check with CRC stored in NVM
 * 3.If integrity fails change partition and index number to initial value and erase first partition
 */
static void log_backup_init()
{
	uint8_t sts = 0;
	uint32_t ext_mem_addr = 0;
	uint32_t check_sum;
	uint32_t temp_u32 =0;

	nvm_parameter_read(NVM_DATA, NVM_LOGGER_BACKUP_DATA, (uint8_t*)&log_backup_handle);
	temp_u32 = ((log_backup_handle.partition_no << 8) | log_backup_handle.index_no);
	check_sum = calc_checksum_memory_temp((uint8 *)&temp_u32, 4);
	if(check_sum != log_backup_handle.crc)
	{
		log_backup_handle.partition_no = 1;
		log_backup_handle.index_no = 0;
		ext_mem_addr = (uint32_t)get_nor_flash_address(log_backup_handle.partition_no);
		sts = ahw_al_ext_mem_erase(LOGGER_BACKUP_STORAGE_FLASH_TYPE, ext_mem_addr, (ext_mem_addr + LOG_BACKUP_PARTITION_SIZE)-1);

		temp_u32 = (log_backup_handle.partition_no << 8) | log_backup_handle.index_no;
		check_sum = calc_checksum_memory_temp((uint8_t *)&temp_u32, 4);
		log_backup_handle.crc = check_sum;
	    nvm_parameter_write(NVM_DATA, NVM_LOGGER_BACKUP_DATA, (uint8_t*)&log_backup_handle);

		sts = sts;

	}
	else
	{

	}
        nvm_parameter_read(NVM_DATA, NVM_LOGGER_BACKUP_CFG, &log_backup_en_dis_cfg);
        nvm_parameter_read(NVM_DATA, NVM_LOGGER_BACKUP_SAVE_THRLD, &log_backup_write_cycle_block_count);

        /*
         * 1,2,4,8,12 are acceptable values
         * this will update below cases
         *   3 will be changed as 4
         *   5 will be changed as 4
         *   7 will be changes as 8
         *   11 will be changed as 8
         */
        if(log_backup_write_cycle_block_count > 12 || log_backup_write_cycle_block_count == 0)
        {
                log_backup_write_cycle_block_count = 4;
        }

        if(log_backup_write_cycle_block_count > 2)
        {
                log_backup_write_cycle_block_count = ((log_backup_write_cycle_block_count+1)/4)*4;
        }


}

/*
 * This api stores the logs saved in sdram in external flash memory
 */
static void log_backup(uint8_t *log_buf)
{
	ptr_typ ext_mem_addr = 0, check_sum;
	uint32_t temp_u32 =0;

	if(log_backup_en_dis_cfg == LOG_BACKUP_ENABLE_CFG)
	{
		if(log_backup_handle.index_no < LOG_BACKUP_MAX_INDEX_COUNT)
		{
			ext_mem_addr = (get_nor_flash_address(log_backup_handle.partition_no) + (log_backup_handle.index_no * LOG_BLOCK_SIZE));
			log_backup_handle.index_no = log_backup_handle.index_no + log_backup_write_cycle_block_count;
		}
		else
		{

			log_backup_handle.partition_no++;
			if(log_backup_handle.partition_no > LOG_BACKUP_TOTAL_PARTITION_COUNT)
			{
				log_backup_handle.partition_no = 1;
			}

			log_backup_handle.index_no = 0;
			ext_mem_addr = (uint32_t)get_nor_flash_address(log_backup_handle.partition_no);
		    ahw_al_ext_mem_erase(LOGGER_BACKUP_STORAGE_FLASH_TYPE, ext_mem_addr, (ext_mem_addr + LOG_BACKUP_PARTITION_SIZE)-1);
			log_backup_handle.index_no = log_backup_handle.index_no + log_backup_write_cycle_block_count;
			log_storage_hdl.bkup_erase_cycle++;
		}

	#ifdef COREBOARD
		ahw_al_ext_mem_write(LOGGER_BACKUP_STORAGE_FLASH_TYPE, ext_mem_addr, log_buf, LOG_BLOCK_SIZE*log_backup_write_cycle_block_count);
	#else
		os_memcpy_extmem((uint8_t*)ext_mem_addr, log_buf, LOG_BLOCK_SIZE*log_backup_write_cycle_block_count, NULL, 0, 0);
	#endif

		temp_u32 = (log_backup_handle.partition_no << 8) | log_backup_handle.index_no;
		check_sum = calc_checksum_memory_temp((uint8_t *)&temp_u32, 4);
		log_backup_handle.crc = check_sum;
	    nvm_parameter_write(NVM_DATA, NVM_LOGGER_BACKUP_DATA, (uint8_t*)&log_backup_handle);

	}
	else
	{

	}

}

#endif

static void log_store(uint8_t *log_buf, uint8_t len)
{
#ifndef LINUX_TEMP_PORT
	uint8_t *print_buf_ptr;
#endif
	/* check the current block has required memory to save current buffer
	 * update write memory address to next block starting address
	 *
	 */
	if(len > log_storage_hdl.block_free_bytes[log_storage_hdl.current_block_id])
	{
		// fill remaining bytes with 0xff
		memset(log_storage_hdl.write_addr, 0xff, log_storage_hdl.block_free_bytes[log_storage_hdl.current_block_id]);
		/* set block full status */
		log_storage_hdl.is_block_empty[log_storage_hdl.current_block_id] = 1;

        /* update end block id with recent block which is full*/
		log_storage_hdl.end_block_id = log_storage_hdl.current_block_id;
#ifndef LINUX_TEMP_PORT
		print_buf_ptr = (uint8_t*)(log_storage_hdl.logger_storage_addr + (log_storage_hdl.current_block_id * LOG_BLOCK_SIZE));
		/*
		 * to transmit one block (if block size assumes 1kb) in serial will take 88ms
		 * baud rate 				; 115200
		 * 1 byte transmit time 	; 8 micro seconds
		 * 1 block of 1024 bytes 	; 88 milli seconds
		 */

		if(((log_storage_hdl.current_block_id + 1) % log_backup_write_cycle_block_count) == 0)
		{
			    print_buf_ptr = (uint8_t*)(log_storage_hdl.logger_storage_addr + \
			    		        ((log_storage_hdl.current_block_id + 1 -log_backup_write_cycle_block_count) * LOG_BLOCK_SIZE));
				log_backup(print_buf_ptr);
		}
#endif
		log_storage_hdl.current_block_id++;
		if(log_storage_hdl.current_block_id > LOG_TOTAL_BLOCK_CNT-1)
		{
			log_storage_hdl.current_block_id = 0;
			log_storage_hdl.mem_rotate_started = 1;
		}
		else
		{

		}

		/* if rollback write has started update the start block
		 * because start block will be next block not 0th block*/
		if(log_storage_hdl.mem_rotate_started != 0)
		{
			if(log_storage_hdl.current_block_id > LOG_TOTAL_BLOCK_CNT-2)
			{
				log_storage_hdl.start_block_id = 0;
			}
			else
			{
				log_storage_hdl.start_block_id = log_storage_hdl.current_block_id+1;
			}
		}

		log_storage_hdl.is_block_empty[log_storage_hdl.current_block_id] = 0;
		log_storage_hdl.block_free_bytes[log_storage_hdl.current_block_id] = LOG_BLOCK_SIZE;
		log_storage_hdl.write_addr = (uint8_t*)(log_storage_hdl.logger_storage_addr + (log_storage_hdl.current_block_id * LOG_BLOCK_SIZE));

		get_rtc_date(&get_date);
		log_date(LOG_INFO_L1, LOG_LOGGER, NEW_BLOCK_ID___u16__START_ON__u8___u8___u16_, log_storage_hdl.current_block_id,get_date.date, get_date.month, get_date.year);

		log_storage_hdl.first_block_empty = 0;
	}

	/* store log buffer in memory and increment the write address for next write
	 * and update remaining free bytes
	 */
	memcpy(log_storage_hdl.write_addr, log_buf, len);
	log_storage_hdl.block_free_bytes[log_storage_hdl.current_block_id] -= len;
	log_storage_hdl.write_addr += len;
}



/**
 * @brief This API manages sender and receiver operation of file transfer
 *
 */
static void log_handler(void* params)
{

/*
 *  Wait for trace and store in bank1 memory
 *
 */
    while(1)
    {
		os_queue_receive(log_queue_hdle, &log_rx_queue, os_wait_forever);
		log_store(log_rx_queue.Q_payload_ptr, log_rx_queue.Q_payload_len);
		if(log_rx_queue.Q_payload_ptr != NULL)
		{
			os_free(log_rx_queue.Q_payload_ptr);
		}
    }
}





/**
 * @brief This API to notify the file transfer error status.
 */
void log_ftm_notificataion_api_upld(ft_notification_info *ft_sts)
{
	DEBUG_CPRINT(("Logger App notification API invoked !!!!\n"));
	if(ft_sts->status == transfer_upload_success)
	{
		DEBUG_CPRINT(("1. upload success\n"));
	}
	else if(ft_sts->status == crc_error)
	{
		DEBUG_CPRINT(("1. upload failed; CRC error\n"));
	}
	else if(ft_sts->status == transfer_suspended)
	{
		DEBUG_CPRINT(("1. upload suspended by receiver [Timeout mode]\n"));
	}
	else if(ft_sts->status == transfer_suspend_accepted)
	{
		DEBUG_CPRINT(("1. upload Suspend - Timeout mode Accepted by Receiver\n"));
	}
	else if(ft_sts->status == transfer_resume_accepted)
	{
		DEBUG_CPRINT(("1. upload Resume - Timeout mode Accepted by Receiver\n"));
	}
	else if(ft_sts->status == transfer_resume_savecontext_accepeted)
	{
		DEBUG_CPRINT(("1. upload Resume - Savecontext mode Accepted by Receiver\n"));
	}
	else if(ft_sts->status == transfer_upload_ready)
	{
		DEBUG_CPRINT(("1. Receiver ready for Download\n"));
	}
	else if(ft_sts->status == invalid_receiver_app_id)
	{
		DEBUG_CPRINT(("1. Upload request cancelled - Receiver API not registered !!!\n"));
	}
	else if(ft_sts->status == transfer_upload_rejected)
	{
		DEBUG_CPRINT(("1. Upload request rejected - Issue in FTCI decoding in Rx node !!!\n"));
	}
	else if(ft_sts->status == transmission_terminated_receiver_not_responsive)
	{
		DEBUG_CPRINT(("1. Upload Terminated due to Receiver not responsive !!!\n"));
	}
	else if(ft_sts->status == transmission_terminated_by_rx_node)
	{
		DEBUG_CPRINT(("1. download Terminated by Receiver node\n"));
	}
	else if(ft_sts->status == transfer_suspend_tout_not_accepted)
	{
		DEBUG_CPRINT(("1. suspend timeout request not completed\n"));
	}
	else if(ft_sts->status == transfer_suspend_savecontext_failed)
	{
		DEBUG_CPRINT(("1. suspend savecontext request not completed\n"));
	}
	else if(ft_sts->status == transfer_rseume_tout_not_accepted)
	{
		DEBUG_CPRINT(("1. resume timeout request not completed\n"));
	}
	else if(ft_sts->status == transfer_resume_restorecontext_failed)
	{
		DEBUG_CPRINT(("1. resume savecontext request not completed\n"));
	}
	else
	{
		DEBUG_CPRINT(("Invalid Notification not processed\n"));
	}
	DEBUG_CPRINT(("\n-------------/End/---------------\n\n"));
}


#ifdef LOGGER_TEST
/*
 * test api to validate logger
 * This api can be called from other thread
 */
void log_test_func(void)
{
	static uint16_t log_test_2=0;
	uint8_t log_send_test=0;
	static uint32_t cntr=0;
    float temp = 22425.5255;


#ifdef LINUX_TEMP_PORT
    usleep(1000);
#else
    os_delay(10);
#endif
	/* Log the following data */
	log_test_2++;
	if((log_test_2 % 100) ==0) // = LOGGER_TEST_FUNC_EXEC_TIMER_IN_MS*10= 100ms > every 100ms 1 log will be saved
	{
		if(!cntr)
		{
		//	log_id(LOG_ERROR, LOG_EPS, EPS_INIT);
		}
		cntr++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
		//DEBUG_CPRINT(("Log %u",cntr));
#pragma GCC diagnostic pop
		log_id_with_one_arg(LOG_ERROR, LOG_COMMS,test_comms__hex_, 0x3452);
		log_id_with_one_arg(LOG_ERROR, LOG_ADCS,Total_retry__eq__u16_, cntr);
		log_id_with_two_arg(LOG_WARNING,LOG_ADCS,Values__s16__pt__s8_,cntr,cntr+1);
		log_id_with_three_arg(LOG_INFO_L1,LOG_ADCS,Xpos__u32__cm__Ypos__u32__cm__Zpos__u32__,cntr,cntr+1,cntr+2);
		log_id_with_four_arg(LOG_INFO_L2,LOG_ADCS,detumbling_started__u8__cm__u16__cm__u16__cm__u32_,cntr,cntr+1,cntr+2,cntr+3);
		log_id_with_one_arg(LOG_INFO_L3,LOG_ADCS,Level__u32_,cntr+4);
		log_id_with_float(LOG_ERROR,LOG_COMMS,TEST_COMMS__u16__pt__u16_,temp);
//		log_test_2 = 0;
//		log_string(LOG_INFO_L1, LOG_ADCS, "Test print Four -4");
//		log_string(LOG_INFO_L3, LOG_COMMS, "Test print Five -5");
//		log_string(LOG_INFO_L2, LOG_ADCS, "Test print Six -6");
//		log_string(LOG_INFO_L3, LOG_ADCS, "Test print Seven - 7");
//		log_string(LOG_INFO_L3, LOG_ADCS, "Test print Seven - 8");
//		log_string(LOG_INFO_L3, LOG_ADCS, "Test print Seven - 9");
//      DEBUG_CPRINT(("@@@ Logger_test_timer\n"));
	}


	/* Number of blocks to send to GS */
	if(log_send_test)
	{
		log_send_logs(log_send_test,64,100,0);
		log_send_test= 0;
	}

}


void logger_timeout_expired_cb(void* args)
{
	log_test_func();
}


#endif



#if (PERIODIC_LOG_ENB != PERIODIC_LOGGER_OFF)
/*
 * iteration 1:
 * previous block = 0;
 * previous len = 512;
 *
 * current block = 0
 * current len = 412; (filled 100)
 *
 * log_buffer_tx = 400000 + (0 *512) + ( 512 - 512)
 *               = 400000 + 0 + 0
 *
 * size_tx       = (512 - 412 ) - ( 512 - 512)= 100
 *

 * iteration 1:
 * previous block = 0;
 * previous len = 512;
 *
 * current block = 1
 * current len = 412; (filled 100)
 *
 * log_buffer_tx = 400000 + (0 *512) + ( 512 - 512)
 *               = 400000 + 0 + 0
 *
 * size_tx       = (512 - 412 ) - ( 512 - 512)= 100


 *
 * iteration 2:
 * previous block = 0;
 * previous len = 412;
 *
 * current block = 0
 * current len = 212; (filled sofar 300)
 *
 * log_buffer_tx = 400000 + (0 *512) + ( 512 - 412)
 *               = 400000 + 0 + 100 = 400100
 *
 * size_tx       = (512 - 212 ) - ( 512 - 412) = 300 - 100 = 200

 *
 * iteration 3:
 * previous block = 0;
 * previous len = 212;
 *
 * current block = 0
 * current len = 200; (filled sofar 312)
 *
 * log_buffer_tx = 400000 + (0 *512) + ( 512 - 212)
 *               = 400000 + 0 + 300 = 400300
 *
 * size_tx       = (512 - 200 ) - ( 512 - 212) = 312 - 300 = 12



 *
 * iteration 4:
 * previous block = 0;
 * previous len = 200;
 *
 * current block = 1
 * current len = 412; (filled sofar 100)
 *
 * log_buffer_tx = 400000 + (0 *512) + ( 512 - 200)
 *               = 400000 + 0 + 312 = 400312
 *
 * size_tx       = (512 - (512 - 200 )) + ( 512 - 412) = (512-312) + 100 = 200 + 100 = 300


 *
 * iteration 5:
 * previous block = 1;
 * previous len = 412;
 *
 * current block = 3
 * current len = 312; (filled sofar 200)
 *
 * log_buffer_tx = 400000 + (1 *512) + ( 512 - 412)
 *               = 400000 + 512 + 100 = 400612
 *
 * size_tx       = (512 - (512 - 412 )) + ( 512 - 312) = (512-100) + 200 = 412 + 200 = 612
 */

/**
 * @brief This is a Logger periodic callback function, that occurs for every 10msec.
 * Used for transferring logs per block at a time
 */
void logger_periodic_timeout_cb(void* args)
{
    static uint16_t prev_blk_len = LOG_BLOCK_SIZE;
    static uint16_t prev_blk_id = 0;
    uint16_t cur_blk_len;
    uint16_t cur_blk_id;
    uint16_t len;
    uint16_t blk_id;
    uint16_t blk_len;

    uint8_t *log_buffer_tx;
	uint32_t size_tx;

	cur_blk_len = log_storage_hdl.block_free_bytes[log_storage_hdl.current_block_id];
	cur_blk_id = log_storage_hdl.current_block_id;

	if(prev_blk_len != cur_blk_len  || cur_blk_id != prev_blk_id)
	{
		log_buffer_tx = log_storage_hdl.logger_storage_addr + (prev_blk_id * LOG_BLOCK_SIZE) + (LOG_BLOCK_SIZE - prev_blk_len);

		if(cur_blk_id != prev_blk_id)
		{
			size_tx = (prev_blk_len) + (LOG_BLOCK_SIZE * ((cur_blk_id - prev_blk_id)-1)) +\
					  (LOG_BLOCK_SIZE - cur_blk_len);
		}
		else
		{
			size_tx = (LOG_BLOCK_SIZE - cur_blk_len) - \
					  (LOG_BLOCK_SIZE - prev_blk_len);
		}
		blk_id = prev_blk_id;
		blk_len = prev_blk_len;
		while(size_tx)
		{
			if(size_tx <= LOG_BLOCK_SIZE && blk_id == cur_blk_id)
			{
#if (PERIODIC_LOG_ENB == PERIODIC_LOGGER_SERIAL)
		           log_serial_out(log_buffer_tx, size_tx);
		           log_serial_out((uint8_t*)"LGeZ", 4);  // magic key which will be used by run time decoder to assume block data receive is end
#else
					logger_simu_data_write(log_buffer_tx,size_tx);
#endif
					size_tx = 0;
			}
			else
			{
				len = LOG_BLOCK_SIZE -(LOG_BLOCK_SIZE - blk_len);
#if (PERIODIC_LOG_ENB == PERIODIC_LOGGER_SERIAL)
		           log_serial_out(log_buffer_tx, size_tx);
		           log_serial_out((uint8_t*)"LGeZ", 4);  // magic key which will be used by run time decoder to assume block data receive is end
#else
		           logger_simu_data_write(log_buffer_tx,len);
#endif
				os_delay(2);
				size_tx = size_tx - len;
				blk_id += 1;
				if(blk_id > (LOG_TOTAL_BLOCK_CNT-1))
				{
					size_tx = 0;
					cur_blk_len = LOG_BLOCK_SIZE;
					cur_blk_id = 0;
				}
				log_buffer_tx = log_storage_hdl.logger_storage_addr + (blk_id * LOG_BLOCK_SIZE);
				if(size_tx >= LOG_BLOCK_SIZE)
				{
					blk_len = LOG_BLOCK_SIZE;
				}
				else if(size_tx > 0)
				{
					blk_len = size_tx;
				}
			}
		}
		prev_blk_len = cur_blk_len;
		prev_blk_id  = cur_blk_id;
	}
}
#endif

/*
 * Log enum
 */
void log_id(log_level level, log_module_list m_id, uint16_t enum_val)
{
	uint8_t *log_frame_bug;
	log_frame_header *log_frame_hdr;
	log_queue_pld log_queue;
	uint8_t status;
	sys_time_s read_tm;
	
        /* since it is atomic , protection not required for log_level_cfg[]*/
	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		log_frame_bug = os_malloc_eram(LOG_FRAME_NO_DATA);
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_ENUM_MODE;
			log_frame_hdr->enum_strlen_val = enum_val;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_NO_ARG;

			get_rtc_time(&read_tm);
			log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;
			if(kernel_init_done)
			{
				log_queue.Q_payload_len = LOG_FRAME_NO_DATA;
				log_queue.Q_payload_ptr = &log_frame_bug[0];
				status = os_queue_send(log_queue_hdle, &log_queue, LOGGER_QUEUE_WAIT_TIMEOUT);
				if(status != ral_success)
				{
					os_free(log_frame_bug);
					queue_sendfailure_cntr++;
				}
			}
			else
			{
				os_free(log_frame_bug);
				log_skip_cntr++;
			}
		}
	}
	else
	{
		/* do nothing */
	}
}



/*
 * Log one argument
 */
void log_id_with_one_arg(log_level level, log_module_list m_id, uint16_t enum_val, uint32_t data)
{
	uint8_t *log_frame_bug;
	log_frame_header *log_frame_hdr;
	log_queue_pld log_queue;
	uint8_t status;
	sys_time_s read_tm;

	/* since it is atomic , protection not required for log_level_cfg[]*/
	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		log_frame_bug = os_malloc_eram(LOG_FRAME_ONE_DATA);
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_ENUM_MODE;
			log_frame_hdr->enum_strlen_val = enum_val;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_ONE_ARG;
			get_rtc_time(&read_tm);
			log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;
			*((uint32_t*)&log_frame_bug[7]) = data;

			if(kernel_init_done)
			{
				log_queue.Q_payload_len = LOG_FRAME_ONE_DATA;
				log_queue.Q_payload_ptr = &log_frame_bug[0];
				status = os_queue_send(log_queue_hdle, &log_queue, LOGGER_QUEUE_WAIT_TIMEOUT);
				if(status != ral_success)
				{
					os_free(log_frame_bug);
					queue_sendfailure_cntr++;
				}
			}
			else
			{
				os_free(log_frame_bug);
				log_skip_cntr++;
			}
		}
	}
	else
	{
		/* do nothing */
	}
}


void log_id_with_two_arg(log_level level, log_module_list m_id, uint16_t enum_val,uint32_t data1, uint32_t data2)
{
	uint8_t *log_frame_bug;
	log_frame_header *log_frame_hdr;
	log_queue_pld log_queue;
	uint8_t status;
	sys_time_s read_tm;

	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		log_frame_bug = os_malloc_eram(LOG_FRAME_TWO_DATA);
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_ENUM_MODE;
			log_frame_hdr->enum_strlen_val = enum_val;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_TWO_ARG;
			log_frame_hdr->reserv = 0;
			get_rtc_time(&read_tm);
		    log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;
			*((uint32_t*)&log_frame_bug[7]) = data1;
			*((uint32_t*)&log_frame_bug[11]) = data2;
			if(kernel_init_done)
			{
				log_queue.Q_payload_len = LOG_FRAME_TWO_DATA;
				log_queue.Q_payload_ptr = &log_frame_bug[0];
				status = os_queue_send(log_queue_hdle, &log_queue, LOGGER_QUEUE_WAIT_TIMEOUT);
				if(status != ral_success)
				{
					os_free(log_frame_bug);
					queue_sendfailure_cntr++;
				}
			}
			else
			{
				os_free(log_frame_bug);
				log_skip_cntr++;
			}
		}
	}
	else
	{
		/* do nothing */
	}
}


void log_id_with_three_arg(log_level level, log_module_list m_id, uint16_t enum_val, uint32_t data1, uint32_t data2, uint32_t data3)
{
	uint8_t *log_frame_bug;
	log_frame_header *log_frame_hdr;
	log_queue_pld log_queue;
	uint8_t status;
	sys_time_s read_tm;

	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		log_frame_bug = os_malloc_eram(LOG_FRAME_THREE_DATA);
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_ENUM_MODE;
			log_frame_hdr->enum_strlen_val = enum_val;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_THREE_ARG;
			log_frame_hdr->reserv = 0;
			get_rtc_time(&read_tm);
			log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;
			*((uint32_t*)&log_frame_bug[7]) = data1;
			*((uint32_t*)&log_frame_bug[11]) = data2;
			*((uint32_t*)&log_frame_bug[15]) = data3;
			if(kernel_init_done)
			{
				log_queue.Q_payload_len = LOG_FRAME_THREE_DATA;
				log_queue.Q_payload_ptr = &log_frame_bug[0];
				status = os_queue_send(log_queue_hdle, &log_queue, LOGGER_QUEUE_WAIT_TIMEOUT);
				if(status != ral_success)
				{
					os_free(log_frame_bug);
					queue_sendfailure_cntr++;
				}
			}
			else
			{
				os_free(log_frame_bug);
				log_skip_cntr++;
			}
		}
	}
	else
	{
		/* do nothing */
	}
}

void log_id_with_four_arg(log_level level, log_module_list m_id, uint16_t enum_val, uint32_t data1, uint32_t data2, uint32_t data3, uint32_t data4)
{
	uint8_t *log_frame_bug;
	log_frame_header *log_frame_hdr;
	log_queue_pld log_queue;
	uint8_t status;
	sys_time_s read_tm;

	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		log_frame_bug = os_malloc_eram(LOG_FRAME_FOUR_DATA);
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_ENUM_MODE;
			log_frame_hdr->enum_strlen_val = enum_val;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_FOUR_ARG;
			log_frame_hdr->reserv = 0;
			get_rtc_time(&read_tm);
			log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;
			*((uint32_t*)&log_frame_bug[7]) = data1;
			*((uint32_t*)&log_frame_bug[11]) = data2;
			*((uint32_t*)&log_frame_bug[15]) = data3;
			*((uint32_t*)&log_frame_bug[19]) = data4;
			if(kernel_init_done)
			{
				log_queue.Q_payload_len = LOG_FRAME_FOUR_DATA;
				log_queue.Q_payload_ptr = &log_frame_bug[0];
				status = os_queue_send(log_queue_hdle, &log_queue, LOGGER_QUEUE_WAIT_TIMEOUT);
				if(status != ral_success)
				{
					os_free(log_frame_bug);
					queue_sendfailure_cntr++;
				}
			}
			else
			{
				os_free(log_frame_bug);
				log_skip_cntr++;
			}
		}
	}
	else
	{
		/* do nothing */
	}
}



/*
 * Log string
 */
void log_string(log_level level, log_module_list m_id, const char* string)
{
	uint8_t *log_frame_bug;
	uint8_t str_len;
	log_queue_pld log_queue;
	uint8_t status;
	sys_time_s read_tm;

	log_frame_header *log_frame_hdr;
	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		str_len = strlen(string);
		if(str_len > LOG_STRING_BUFFER_MAX_LEN)
		{
			str_len = LOG_STRING_BUFFER_MAX_LEN;
		}

		log_frame_bug = os_malloc_eram(LOG_FRAME_HEADER_SIZE+str_len+3);
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_STRING_MODE;
			log_frame_hdr->enum_strlen_val = str_len;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_ONE_ARG;
			log_frame_hdr->reserv = 0;
			get_rtc_time(&read_tm);
			log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;

			memcpy(&log_frame_bug[7], string, str_len);

			if(kernel_init_done)
			{
				log_queue.Q_payload_len = LOG_FRAME_HEADER_SIZE+str_len+3;
				log_queue.Q_payload_ptr = &log_frame_bug[0];
				status = os_queue_send(log_queue_hdle, &log_queue, LOGGER_QUEUE_WAIT_TIMEOUT);
				if(status != ral_success)
				{
					os_free(log_frame_bug);
					queue_sendfailure_cntr++;
				}
			}
			else
			{
				os_free(log_frame_bug);
				log_skip_cntr++;
			}
		}
	}
	else
	{
		/* do nothing */
	}
}
void log_id_with_float(log_level level, log_module_list m_id, uint16_t enum_val,float data)
{
	uint8_t *log_frame_bug;
	log_frame_header *log_frame_hdr;
	log_queue_pld log_queue;
	uint8_t status;
	sys_time_s read_tm;
	double tdata1, tdata2;
	uint32_t data1, data2;

	/* since it is atomic , protection not required for log_level_cfg[]*/
	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		log_frame_bug = os_malloc_eram(LOG_FRAME_TWO_DATA);
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_ENUM_MODE;
			log_frame_hdr->enum_strlen_val = enum_val;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_TWO_ARG;
			log_frame_hdr->reserv = 0;
			get_rtc_time(&read_tm);
			log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;

			tdata2 = modf((double)data, &tdata1);
			data1 = tdata1;
			data2 = tdata2*1000000.0;

			*((uint32_t*)&log_frame_bug[7]) = data1;
			*((uint32_t*)&log_frame_bug[11]) = data2;

			if(kernel_init_done)
			{
				log_queue.Q_payload_len = LOG_FRAME_TWO_DATA;
				log_queue.Q_payload_ptr = &log_frame_bug[0];
				status = os_queue_send(log_queue_hdle, &log_queue, LOGGER_QUEUE_WAIT_TIMEOUT);
				if(status != ral_success)
				{
					os_free(log_frame_bug);
					queue_sendfailure_cntr++;
				}
			}
			else
			{
				os_free(log_frame_bug);
				log_skip_cntr++;
			}
		}
	}
	else
	{
		/* do nothing */
	}
}


void log_date(log_level level, log_module_list m_id, uint16_t enum_val, uint32_t data1, uint32_t data2, uint32_t data3, uint32_t data4)
{
    uint8_t temp_buf[LOG_FRAME_FOUR_DATA];
	uint8_t *log_frame_bug;
	log_frame_header *log_frame_hdr;
	sys_time_s read_tm;

	if(log_level_cfg[m_id] & log_level_bit_val[level])
	{
		log_frame_bug = temp_buf;
		if(log_frame_bug != NULL)
		{
			log_frame_hdr = (log_frame_header*)log_frame_bug;
			log_frame_hdr->module_id = m_id;
			log_frame_hdr->enum_str_sel = LOG_ENUM_MODE;
			log_frame_hdr->enum_strlen_val = enum_val;
			log_frame_hdr->log_level = level;
			log_frame_hdr->arg_cnt = LOG_FOUR_ARG;
			log_frame_hdr->reserv = 0;
			get_rtc_time(&read_tm);
			log_frame_bug[4]=read_tm.hour;
			log_frame_bug[5]=read_tm.min;
			log_frame_bug[6]=read_tm.sec;
			*((uint32_t*)&log_frame_bug[7]) = data1;
			*((uint32_t*)&log_frame_bug[11]) = data2;
			*((uint32_t*)&log_frame_bug[15]) = data3;
			*((uint32_t*)&log_frame_bug[19]) = data4;

			os_memcpy(log_storage_hdl.write_addr, temp_buf, LOG_FRAME_FOUR_DATA);

			log_storage_hdl.block_free_bytes[log_storage_hdl.current_block_id] -= LOG_FRAME_FOUR_DATA;
			log_storage_hdl.write_addr += LOG_FRAME_FOUR_DATA;
		}
	}

}


/*
 * This function will check the requested blocks are available in logger memory
 * This function will directly called from obc context.
 *
 * Copy bank2 memory with requested blocks from bank1 memory
 *
 * start = 2 end = 25
 * 2
 * 3
 * 4
 * .
 * .
 * 25
 * request 5 blocks
 *
 *
 */
void log_send_logs(uint16_t block_cnt, uint16_t mtu, uint16_t ftdsdelay, uint8_t seq_los_selection)
{
	int16_t temp;
	uint16_t cntr;
	uint16_t start_block;
	uint16_t end_block;
	uint32_t size_tx;
	uint8_t	*log_buffer_tx=NULL;

	/* shared variable protection enabled by reading */
	start_block = log_storage_hdl.start_block_id;
	end_block   = log_storage_hdl.end_block_id;

	/// calculate total available blocks in logger memory can be sent
	// end = 3 ; start = 0 >> 3-0+1 = 4
	temp = (end_block - start_block)+1;
	if(temp < 0)
	{
		temp += LOG_TOTAL_BLOCK_CNT;
	}

	if(temp != 0 || block_cnt == 0)
	{

		if(block_cnt > 0)
		{
			/// if available block count is lesser than requested block count
			if(block_cnt > temp)
			{
				block_cnt = temp;
				DEBUG_CPRINT(("WARNING : Blocks available are lesser than requested\n"));
			}

			/// Derive the starting block ID as per requested recent blocks
			temp = (end_block - block_cnt)+1;
			if(temp < 0)
			{
				temp += LOG_TOTAL_BLOCK_CNT;
			}


			/*
			 TODO : There might be data overwrite will happen in the start block
			 it can be avoided if requested block should not be greater than (Total blocks - 2)
			 */
			if(temp > LOG_TOTAL_BLOCK_CNT -2)
			{
				temp -=2;
			}

			if(temp > end_block)
			{
				/// Read blocks and copy the blocks to another memory if blocks are not in sequential order
				for(cntr = 0; cntr < block_cnt; cntr++)
				{
					memcpy((uint8_t*)(log_storage_hdl.tctm_log_store_addr + (cntr * LOG_BLOCK_SIZE)), (uint8_t*)(log_storage_hdl.logger_storage_addr + (temp * LOG_BLOCK_SIZE)),LOG_BLOCK_SIZE);
					temp++;
					if(temp > LOG_TOTAL_BLOCK_CNT-1)
					{
						temp -= LOG_TOTAL_BLOCK_CNT;
					}
				}
				log_buffer_tx = log_storage_hdl.tctm_log_store_addr;
				size_tx = block_cnt * LOG_BLOCK_SIZE;
			}
			else
			{
				/// It is used to skip memory copy operation(save execution time) from logger storage memory to tctm storage memory
				/// Blocks are logged in sequential order so not required to align blocks in another memory
				log_buffer_tx = log_storage_hdl.logger_storage_addr + (temp * LOG_BLOCK_SIZE);
				size_tx = block_cnt * LOG_BLOCK_SIZE;
			}


			if(log_storage_hdl.first_block_empty == 1)
			{
				// send size of 1st block so far filled
				log_buffer_tx = logger_storage_mem_buf;
				size_tx = LOG_BLOCK_SIZE - log_storage_hdl.block_free_bytes[0];
			}


		}
		else
		{
			// if block count = 0
			// send current block so far logs available
			log_buffer_tx = log_storage_hdl.logger_storage_addr + (log_storage_hdl.current_block_id * LOG_BLOCK_SIZE);
			size_tx = LOG_BLOCK_SIZE - log_storage_hdl.block_free_bytes[log_storage_hdl.current_block_id];
		}


		/*
		 * Initiate file transfer
		 */
		ft_register_sender_app(TM_SRC_FTM_DBGLOG, log_ftm_notificataion_api_upld);
		ft_config_app_id(TM_SRC_FTM_DBGLOG);
		ft_mode_select(M_DATA);
		ft_config_file_id(1);
		ft_config_mtu_size(mtu);
		ft_config_ftds_delay(ftdsdelay);
		ft_sequenceLoss_mode_select(seq_los_selection);
		ft_config_rx_node_conn_failure_time(45);
		ft_config_bulk_data_input_buffer(log_buffer_tx,size_tx);
		ft_transfer_request(Start_Transmission_rqst,0);

	}
	else
	{
		DEBUG_CPRINT(("No blocks available to send"));
	}

}

void log_send_logs_via_telementary(uint16_t block_cnt)
{
    obc_pck_data tm_pack;
	tm_pack.tx_data = os_malloc_eram(LOG_BLOCK_SIZE);
    tm_pack.tx_data_len = LOG_BLOCK_SIZE;
	memcpy(tm_pack.tx_data, (uint8_t*)(log_storage_hdl.logger_storage_addr + (block_cnt * LOG_BLOCK_SIZE)), LOG_BLOCK_SIZE);
	tm_pack.tm_rsp_id = TM_LOG_DOWNLOAD_BLOCKS ;
	obc_pack_tm_data(&tm_pack);

}


void log_backup_cfg(uint8_t cfg, uint8_t thrsld)
{
    if(cfg == 3)
    {
		/*
		* disable log backup
		*/
    	log_backup_en_dis_cfg = 0;
    	nvm_parameter_write(NVM_DATA, NVM_LOGGER_BACKUP_CFG, &log_backup_en_dis_cfg);
    }
    else if(cfg == 4)
    {
    	/*
    	 * enable log backup
    	 */
    	 log_backup_en_dis_cfg = LOG_BACKUP_ENABLE_CFG;
    	 nvm_parameter_write(NVM_DATA, NVM_LOGGER_BACKUP_CFG, &log_backup_en_dis_cfg);
    	 log_backup_write_cycle_block_count = thrsld;
    	 if(log_backup_write_cycle_block_count > 12 || log_backup_write_cycle_block_count == 0)
    	 {
    	    log_backup_write_cycle_block_count = 4;
    	 }

    		if(log_backup_write_cycle_block_count > 2)
    		{
    			log_backup_write_cycle_block_count = (log_backup_write_cycle_block_count/4)*4;
    		}

    	 nvm_parameter_write(NVM_DATA, NVM_LOGGER_BACKUP_SAVE_THRLD, &log_backup_write_cycle_block_count);
    }
    else
    {

    }


	obc_pck_data tm_pack;
	tm_pack.tx_data = os_malloc_eram(1);
	tm_pack.tx_data_len = 1;
	tm_pack.tx_data[0] = RESPONSE_BACKUP_ENABLE_CFG_ACK;
	tm_pack.tm_rsp_id = TM_LOG_DOWNLOAD_BACKUP_BLOCKS;
	obc_pack_tm_data(&tm_pack);

}



#ifndef LINUX_TEMP_PORT

void log_send_backup_data(uint8_t partition_num, uint16_t mtu, uint16_t ftdsdelay, uint8_t seq_los_selection, uint8_t dwn_size)
{

	uint8_t *log_backup_flash_addr = NULL;
	uint32_t log_backup_size_tx = 0;
	uint8_t sts = 1;

	if(dwn_size == 0)
	{
		dwn_size = 1;
	}

	log_backup_size_tx = 1024*dwn_size;
	if(partition_num > LOG_BACKUP_TOTAL_PARTITION_COUNT || partition_num == 0)
	{
		partition_num = 1;
	}

	if(log_backup_size_tx > LOG_BACKUP_PARTITION_SIZE || log_backup_size_tx == 0)
	{
		log_backup_size_tx = LOG_BACKUP_PARTITION_SIZE;
	}


	log_backup_flash_addr = (uint8_t*)get_nor_flash_address(partition_num);
	sts = os_memcpy_extmem(log_backup_sdram_ftm_buf, log_backup_flash_addr, log_backup_size_tx, NULL, 1, 1);

    if(CPY_OK == sts)
    {
		/*
		 * Initiate file transfer
		 */
		ft_register_sender_app(TM_SRC_FTM_DBGLOG, log_ftm_notificataion_api_upld);
		ft_config_app_id(TM_SRC_FTM_DBGLOG);
		ft_mode_select(M_DATA);
		ft_config_mtu_size(mtu);
		ft_config_ftds_delay(ftdsdelay);
		ft_sequenceLoss_mode_select(seq_los_selection);
		ft_config_rx_node_conn_failure_time(45);
		ft_config_bulk_data_input_buffer(log_backup_sdram_ftm_buf, log_backup_size_tx);
		ft_transfer_request(Start_Transmission_rqst,0);
    }
    else
    {
    	sts = (RESPONSE_BACKUP_DATA_READ_FAIL << 2);
    	log_backup_dwn_rsp(&sts);
    }
}

#endif

void log_read_handler_info(log_storage_handle *ptr)
{
	ptr->start_block_id = log_storage_hdl.start_block_id;
	ptr->end_block_id = log_storage_hdl.end_block_id;
	ptr->current_block_id = log_storage_hdl.current_block_id;
        ptr->first_block_empty = log_storage_hdl.first_block_empty;
        ptr->bkup_erase_cycle = log_storage_hdl.bkup_erase_cycle;
}

#ifndef LINUX_TEMP_PORT
uint8_t log_backup_partition_no(void)
{
	return log_backup_handle.partition_no;
}

#endif


/*
 * Initialize logger
 */
void log_init(void)
{
	/* initialize logger variables*/
#ifndef LINUX_TEMP_PORT
	log_storage_hdl.logger_storage_addr 	= logger_storage_mem_buf;
	log_storage_hdl.write_addr 				= logger_storage_mem_buf;
	log_storage_hdl.tctm_log_store_addr 	= logger_tctm_mem_buf;
#else
	log_storage_hdl.logger_storage_addr 	= sdram_logger_storage_bank1;
	log_storage_hdl.write_addr 				= sdram_logger_storage_bank1;
	log_storage_hdl.tctm_log_store_addr 	= sdram_tctm_storage_bank2;
#endif
	log_storage_hdl.current_block_id 		= 0;
	log_storage_hdl.block_free_bytes[0] 	= LOG_BLOCK_SIZE;
	memset(log_storage_hdl.is_block_empty, 0, LOG_TOTAL_BLOCK_CNT);
	log_storage_hdl.start_block_id 			= 0;
	log_storage_hdl.mem_rotate_started 		= 0;
	log_storage_hdl.first_block_empty       = 1;
	queue_sendfailure_cntr					= 0;
	log_skip_cntr							= 0;
	log_backup_en_dis_cfg 					= 0;
#ifndef LINUX_TEMP_PORT
	log_storage_hdl.bkup_erase_cycle    = 0;
#endif
#if (PERIODIC_LOG_ENB == PERIODIC_LOGGER_SOCKET) || defined(ENABLE_SOC_PRINT)
       os_thread_create(OBC_LOGGER_SOCKET,T_LOG_THREAD_STACK_SIZE,P_OBC_LOGGER_SOCKET,"logger_sim_proc",(app_entry_func_t)logger_skt_simu,NULL,NULL,NULL);
#endif
#if (PERIODIC_LOG_ENB != PERIODIC_LOGGER_OFF)
       os_timer_create(&periodic_logger_out_timer_hdl,"periodic_log_out",PERIODIC,logger_periodic_timeout_cb,NULL);
	   os_delay(100);
	   os_timer_start(periodic_logger_out_timer_hdl,(os_tick_time_t)LOGGER_PERIODIC_OUT_TIME_SEC);
#endif


	   /* Create queue and thread */
	os_queue_create(&log_queue_hdle, 20, sizeof(log_queue_pld), "LOGGER_QUEUE");
    os_thread_create(LOGGER_TRACE, T_LOGGER_TRACE_STACK_SIZE, P_LOGGER_TRACE, "LOGGER_TRACE", log_handler, NULL, NULL, NULL);
#ifdef LOGGER_TEST
    os_timer_create(&logger_test_timer,"logger_test_tmr_evnt",PERIODIC,logger_timeout_expired_cb,NULL);
    os_delay(100);
    os_timer_start(logger_test_timer,(os_tick_time_t)LOGGER_TEST_FUNC_EXEC_TIMER_IN_MS);
#endif
}

void log_level_nvm_read(void)
{
	uint32_t nvm_checksum = 0, calc_chksum = 0;
	uint8_t read_log_filter_cfg[LOG_MODULE_MAX+1];

	/*Read NVM LOG LEVEL CONFIGURATION*/
	nvm_parameter_read(NVM_DATA,NVM_LOGGER_LOG_LEVEL_CFG, read_log_filter_cfg);
	nvm_parameter_read(NVM_DATA,NVM_LOGGER_LOG_LEVEL_CHKSUM, (uint8_t *)&nvm_checksum);
	calc_chksum = calc_checksum_bulkdata(read_log_filter_cfg, (uint32_t) LOG_MODULE_MAX+1);
	if(nvm_checksum == calc_chksum)
	{
	   memcpy(log_level_cfg, read_log_filter_cfg ,LOG_MODULE_MAX+1);
	}
	else
	{
	  //Logger default filter will apply if NVM data is not available
	}

#ifndef LINUX_TEMP_PORT
        log_backup_init();
#endif
}
