#include "es_sample_app.h"
#include "es_intf_ctrl_msg.h"
#include "es_info.h"
/*
 * added for FT
 */
#include "file_transfer.h"
#include "ft_sample_app_upload.h"
#include "ft_sample_app_dwnld.h"
#include <string.h>

/******** Automation Framework Start *********/

s_ps_autom_user_input ps_autom_user_input;
int ps_autom_i = 3;

/******** Automation Framework Start *********/

typedef struct ft_tctm_pld_tx
{
	uint8_t *payload_ptr;
	uint16_t payload_len;
	uint16_t tc_tm_id;
	uint8_t send_request;
    uint16_t dest_node;
}ft_tctm_payload_tx;

ft_tctm_payload_tx ft_pld_tx;
uint16_t set_ftds_debug;


uint16 rsp_enc_id = 0;
uint16 ps_evnt_trig = 0;
s_sock_info icd_soc_inf;
uint16 tc_id_var = 0;
FILE *inf;
int sockfd; // connfd;

uint32 xband_data[50] = {0};
uint16 xband_data_len = 0;
extern char tty_rsp[1000];


void ft_destination_set(uint16_t set);

int8 obc_ps_xband_rsp_enc(uint8** data, uint16* len,uint8* buff_data,uint16 buf_len);
int main(int argc, char **argv)
{
    ps_autom_user_input.ps_autom_arg_cnt = argc;
    printf("Number of Arguments: %d \n",ps_autom_user_input.ps_autom_arg_cnt);
    //Enable Line buffering for stdout
    setvbuf(stdout, NULL, _IOLBF, 0);
    int i=1;
    for(; i<argc;i++)
    {
	    long int ps_autom_str_len = strlen(argv[i]);
	    //printf("Argument no: %d Input String: %s Input String Length: %d \n",i,argv[i],ps_autom_str_len);
	    ps_autom_user_input.ps_autom_argv[i] = malloc(ps_autom_str_len+2);
	    ps_autom_user_input.ps_autom_argv_valid[i] = 1;
	    memcpy(ps_autom_user_input.ps_autom_argv[i],argv[i],ps_autom_str_len+1);
	    printf("Argument no: %d String: %ls \n",i,ps_autom_user_input.ps_autom_argv[i]);
    }

    ps_server_param params;
    int8 status = 0;
    uint32 icd;
    pthread_t r_id;
    pthread_t s_id;
    pthread_t re_id;

    /*
     * added for FT
     */
    pthread_t ft_thread;
    //pthread_t ft_user_input;

    s_ipcc_terminator ipcc_term;

    //////////////////////////////////////////
    //Read socket information from file
    /////////////////////////////////////////
    inf = fopen("es_soc_cfg.txt", "r");

    if (inf == NULL) {
        printf("Error to open the file\n");
        exit(1);
    }

    fread(&icd_soc_inf, sizeof(s_sock_info),1, inf);
    printf("ES ICD socket address is %s %u \n",icd_soc_inf.ip_addr,atoi(icd_soc_inf.port_num));

    fclose(inf);

    params.port = atoi(icd_soc_inf.port_num);
    params.addr = inet_addr(icd_soc_inf.ip_addr);
    params.ipcc_frame = (s_ipcc_frame *) malloc(sizeof(s_ipcc_frame));
    params.ipcc_frame->cmac_hmac = (uint8 *) malloc(SHA256_HASH_SIZE);
    params.ipcc_frame->ipcc_data = (uint8 *) malloc(1024);

    for(icd = 0; icd < 255; icd++)
    {
        ipcc_term_add_ipcc_func(&ipcc_term, 25, ps_print_data);
    }

    pthread_create(&r_id, NULL, ps_rcv_socket_server_thread, &params);
    pthread_create(&s_id, NULL, ps_get_icd_cmd_id_thread, NULL);
    pthread_create(&s_id, NULL, ps_evnt_trig_thread, NULL);
    pthread_create(&re_id, NULL, ps_rsp_enc_socket_server_thread, NULL);

    /*
     * added for FT
     */
   // pthread_create(&ft_user_input, NULL, app1234_thread, NULL);
    pthread_create(&ft_thread, NULL, ft_handler, NULL);


    pthread_join(r_id, NULL);

    /*
     *  added for FT
     */
    pthread_join(ft_thread, NULL);
  //  pthread_join(ft_user_input, NULL);
    return status;
}

int ps_print_data( s_ipcc_frame * ipcc_frame)
{
    s_ipcc_crypt_params param;
    uint8 key[] = {0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
                   0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

    uint8 iv[16] = {0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

    s_ipcc_ctrl ctrl_param;
    uint16 ipcc_len = 0;
    uint16 seq_no = 0;
    int loop = 0;
    //printf("ES APP: Triggered print data function \n");
    if( NULL != ipcc_frame && NULL != ipcc_frame->ipcc_data)
    {
        ipcc_term_extract_seq_no(ipcc_frame, &seq_no);
        validate_seq_num(seq_no);
        ipcc_term_extract_ipcc_ctrl(ipcc_frame, &ctrl_param);
        ipcc_term_extract_ipcc_len(ipcc_frame, &ipcc_len);
        if(ctrl_param.encrypt)
        {
            //printf("ES APP: Received Data is encrypted \n");
            memcpy(param.iv, iv, 16);
            param.key_size = 256;
            param.key = (unsigned char *)malloc(param.key_size);
            memcpy(param.key, key, param.key_size);
            param.encrypt_mode = IPCC_CRYPT_AES_CFB8;
            ipcc_orig_decrypt_data(&param,
                                (const unsigned char *)ipcc_frame->ipcc_data,ipcc_len,
                                (unsigned char *)ipcc_frame->ipcc_data);
			#ifdef PRINT_BUF_ON
            printf("ES APP: Decrypted data: ");
            for(loop = 0; loop < ipcc_len; loop++)
                printf("%x ", ipcc_frame->ipcc_data[loop]);
            printf("\n");
			#endif
            ps_icm_crrn_id_dec((const unsigned char*)ipcc_frame->ipcc_data, ipcc_len);
        }
        else
        {
            printf("ES APP: Received Data is unencrypted \n");
            printf("ES APP: Data is %d\n", *ipcc_frame->ipcc_data++);
            printf("ES APP: ipcc_seqno is %d \n", ipcc_frame->seq_no);
            printf("ES APP: Data is \n");
            for(loop = 0; loop < ipcc_len; loop++)
                printf("%x ", ipcc_frame->ipcc_data[loop]);
            printf("\n");
            ps_icm_crrn_id_dec((const unsigned char*)ipcc_frame->ipcc_data, ipcc_len);
        }
    }
    return 0;
}


uint8_t ft_payload_transmitter(uint16 tc_tm_id, uint16_t src_dst_id, uint8_t *payload_ptr, uint16_t payload_len)
{
	uint8_t ret_busy_sts = 0;
	uint16_t u16cnt;
	if(payload_ptr != NULL)
	{
		if(ft_pld_tx.send_request != 1)
		{
			ft_pld_tx.payload_ptr = malloc(payload_len);
			if(ft_pld_tx.payload_ptr != NULL)
			{
				for(u16cnt = 0; u16cnt< payload_len; u16cnt++)
				{
					ft_pld_tx.payload_ptr[u16cnt] = payload_ptr[u16cnt];
				}
				ft_pld_tx.tc_tm_id = tc_tm_id;
				ft_pld_tx.payload_len = payload_len;
				ft_pld_tx.send_request = 1;
				ret_busy_sts = 1;
			}
            ft_destination_set(src_dst_id);
		}
	}
	return ret_busy_sts;
}


void ft_destination_set(uint16_t set)
{
    ft_pld_tx.dest_node = set;
//    printf("FTM Node set %x\n",ft_pld_tx.dest_node);
}


/*
 *
 * func added for FT
 */
void ft_ps_set_enc_id()
{
    /** commenting for now in ES */
	//rsp_enc_id = OBC_PS_TC_TM_MSG_CMD;
}

void *ps_rsp_enc_socket_server_thread(void *params)
{
    uint8 *data = NULL;
    uint16 data_len;
    uint8 shut_rsp = ICM_PS_SHUT_INIT;
#if 0

    uint8 num_app;
    uint8* buf_ptr;
    uint16 app_id_buff_len;
    uint8 num_elem;
    uint8* app_id_qos_pwd_ptr;
    uint16 app_id_qos_pwd_len;
    uint8 num_hw,hw_num_elem;
    uint8 *hw_id_ptr,*hw_id_qos_pwd_ptr;
    uint16 buff_len;
    uint32 tm_tty_rsp;
#endif

    while(1)
    {
        usleep(1000);
#if 0
        if(ft_pld_tx.send_request == 1)
        {

        	printf("TM ready to send %d \n",ft_pld_tx.tc_tm_id);
            tc_id_var = ft_pld_tx.tc_tm_id;
            rsp_enc_id = OBC_PS_FTP_MSG_CMD;
          //  ft_pld_tx.send_request = 0;
        }
#endif

        if(rsp_enc_id)
        {
            switch(rsp_enc_id)
            {
                case OBC_ES_PWR_OFF_CMD:
                    {
                        obc_es_pwr_off_rsp_enc(&data, &data_len, shut_rsp);
                        es_socket_send(data,data_len);
                        free(data);
                        break;
                    }
#if 0
                case OBC_PS_PWR_OFF_CMD:
                    {
                        obc_ps_pwr_off_rsp_enc(&data, &data_len, shut_rsp);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_PLD_HW_PWR_OFF_CMD:
                    {
                        obc_ps_pld_hw_pwr_off_rsp_enc(&data, &data_len, 0);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_VM_PWR_OFF_CMD:
                    {
                        obc_ps_vm_pwr_off_rsp_enc(&data, &data_len, 0);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_VM_PWR_ON_CMD:
                    {
                        obc_ps_vm_pwr_on_rsp_enc(&data, &data_len, 0);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_TEMP_INFO:
                    {
                        uint8_t ps_temp;
                        getTemperature(&ps_temp);
                        obc_ps_get_temp_info_rsp_enc(&data, &data_len,ps_temp);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_TIME_INFO:
                    {
                        ps_get_time_s ps_get_time;
                        uint32_t ps_uptime,ps_epoch_time;
                        printCPUUptime(&ps_uptime);
                        printEpochTime(&ps_epoch_time);
                        ps_get_time.uptime=ps_uptime;
                        ps_get_time.epoch_time=ps_epoch_time;
                        obc_ps_get_time_info_rsp_enc(&data, &data_len,&ps_get_time);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }

                case OBC_PS_CHIP_INFO:
                    {
                        
                        ps_get_chip_info_s ps_get_chip_info;
                        getProcessorInfo(&ps_get_chip_info);
                        ps_get_feature_s ps_get_features;
                        getCPUFeatures(&ps_get_features);
                        obc_ps_get_chip_info_rsp_enc(&data, &data_len,&ps_get_chip_info,&ps_get_features);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_EXT_MEM:
                    {

                        ps_get_ext_mem_s ps_get_ext_mem;
                        printMemoryInfo(&ps_get_ext_mem);
                        obc_ps_get_ext_mem_rsp_enc(&data, &data_len,&ps_get_ext_mem);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }

                case OBC_PS_TC_TM_MSG_CMD:
                    {
                        icm_tm_pld_info_s tm_pld_info;
                        tm_pld_info.src_id = TM_SRC_PS;
                        tm_pld_info.dst_id = TM_DST_GS;

                        /* This function can be invoked directly by the application
                         * under its own thread context by providing the filled in
                         * structure information. Otherwise, if the application wants
                         * to send it by a separate thread, then global variable (rsp_enc_id)
                         * can be updated and triggered as shown in this example */

                        switch(tc_id_var)
                        {

                            case TM_TTY_START:
                                {
                                    tm_tty_rsp = 0;
                                    tm_pld_info.tm_id = TM_TTY_START;
                                    tm_pld_info.tm_pld_len = 4;
                                    tm_pld_info.tm_pld_buff = (uint8*)malloc(tm_pld_info.tm_pld_len);
                                    memcpy(tm_pld_info.tm_pld_buff, &tm_tty_rsp, tm_pld_info.tm_pld_len);

                                    obc_ps_tc_tm_msg_rsp_enc (&data,&data_len,&tm_pld_info);
                                    ps_socket_send(data,data_len);
                                    free(data);
                                }
                                break;

                            case TM_TTY_DEBUG:
                                {
                                    tm_pld_info.tm_id = TM_TTY_DEBUG;
                                    tm_pld_info.tm_pld_len = strlen(tty_rsp);
                                    tm_pld_info.tm_pld_buff = (uint8*)tty_rsp;

                                    obc_ps_tc_tm_msg_rsp_enc (&data,&data_len,&tm_pld_info);
                                    ps_socket_send(data,data_len);
                                    free(data);
                                }
                                break;

                            case TM_TTY_END:
                                {
                                    tm_tty_rsp = 0;
                                    tm_pld_info.tm_id = TM_TTY_END;
                                    tm_pld_info.tm_pld_len = 4;
                                    tm_pld_info.tm_pld_buff = (uint8*)malloc(tm_pld_info.tm_pld_len);
                                    memcpy(tm_pld_info.tm_pld_buff, &tm_tty_rsp, tm_pld_info.tm_pld_len);

                                    obc_ps_tc_tm_msg_rsp_enc (&data,&data_len,&tm_pld_info);
                                    ps_socket_send(data,data_len);
                                    free(data);
                                }
                                break;

                            case TM_XBAND:
                                {
                                    printf("X-Band command received ");
                                }
                                break;

                            default:
                                printf("Invalid TC ID received\n");
                                break;
                        }

                        break;
                    }
                case OBC_PS_FTP_MSG_CMD:
                    {
                        icm_tm_pld_info_s tm_pld_info;
                        tm_pld_info.src_id = TM_SRC_PS;
                        tm_pld_info.dst_id = TM_DST_GS;

                        /* This function can be invoked directly by the application
                         * under its own thread context by providing the filled in
                         * structure information. Otherwise, if the application wants
                         * to send it by a separate thread, then global variable (rsp_enc_id)
                         * can be updated and triggered as shown in this example */

                        switch(tc_id_var)
                        {

                            case TM_FTCI:
                            case TM_FTFCI:
                            case TM_FTDS:
                            case TM_FTSR:
                            case TM_FTDR:
                                {
                                    tm_pld_info.tm_id = ft_pld_tx.tc_tm_id;
                                    tm_pld_info.tm_pld_len = ft_pld_tx.payload_len;
                                    tm_pld_info.tm_pld_buff = ft_pld_tx.payload_ptr;
                                    printf("Send FT Tx :%d\n",tm_pld_info.tm_id);

                                    obc_ps_tc_tm_msg_rsp_enc (&data,&data_len,&tm_pld_info);
                                    ps_socket_send(data,data_len);
                                    free(data);
                                    free(ft_pld_tx.payload_ptr);
                                    ft_pld_tx.send_request = 0;
                                }
                                break;

                            default:
                                printf("Invalid TC ID received\n");
                                break;
                        }

                        break;
                    }
                case OBC_PS_KEEP_ALIVE_REQ:
                    {
                        obc_ps_keep_alive_rsp_enc(&data, &data_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_GS_PASS_NTF:
                    {
                        obc_ps_gs_pass_ntf_rsp_enc(&data, &data_len, 0);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_RADIO_PWR_ON_NTF:
                    {
                        obc_ps_radio_pwr_on_ntf_rsp_enc(&data, &data_len, 0);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_RADIO_PWR_OFF_NTF:
                    {
                        obc_ps_radio_pwr_off_ntf_rsp_enc(&data, &data_len, 0);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_OBC_FIRM_UPDT_NTF:
                    {
                        obc_ps_obc_frim_updt_ntf_rsp_enc(&data, &data_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_OBC_RST_RECV_UPDT_NTF:
                    {
                        obc_ps_obc_rst_recv_updt_ntf_rsp_enc(&data, &data_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_STAGED_TC_CMD:
                    {
                        obc_ps_staged_tc_cmd_rsp_enc(&data, &data_len);
                        ps_socket_send(data,data_len);
                        free(data);
                    }
                    break;
                case OBC_PS_OBC_HW_ERR_RECOV_NTF:
                    {
                        obc_ps_obc_hw_err_recv_ntf_rsp_enc(&data, &data_len,0);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_PS_APP_ID_LIST_REQ:
                    {
                        num_app = 5;
                        //Frame structure - Number of APP + 2 Byte APP ID + 2 Byte Peer APP ID + ....
                        app_id_buff_len = (1+(2+2)*num_app);
                        buf_ptr = malloc(app_id_buff_len);
                        *buf_ptr = num_app;
                        obc_ps_ps_app_id_list_req_rsp_enc(&data, &data_len,buf_ptr,app_id_buff_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_PS_APP_PRI_LIST_REQ:
                    {
                        num_elem = 5;
                        //Frame structure - Number of APP + 2 Byte APP ID + 1 Byte APP ID QoS + 1 Byte APP ID PWD + ....
                        app_id_qos_pwd_len = (1+(2+1+1)*num_elem);
                        app_id_qos_pwd_ptr = malloc(app_id_qos_pwd_len);
                        *app_id_qos_pwd_ptr = num_elem;
                        obc_ps_ps_app_pri_list_rsp_enc(&data, &data_len,app_id_qos_pwd_ptr,app_id_qos_pwd_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_PS_HW_ID_LIST_REQ:
                    {
                        num_hw = 5;
                        //Frame structure - Number of HW + 2 Byte HW ID + ....
                        buff_len = (1+(2*num_hw));
                        hw_id_ptr = malloc(buff_len);
                        *hw_id_ptr = num_hw;
                        obc_ps_ps_hw_id_list_rsp_enc(&data, &data_len,hw_id_ptr,buff_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_PS_HW_PRI_LIST_REQ:
                    {
                        hw_num_elem = 5;
                        //Frame structure - Number of APP + 2 Byte APP ID + 1 Byte APP ID QoS + 1 Byte APP ID PWD + ....
                        buff_len = (1+(2+1+1)*hw_num_elem);
                        hw_id_qos_pwd_ptr = malloc(buff_len);
                        *hw_id_qos_pwd_ptr = hw_num_elem;
                        obc_ps_ps_hw_pri_list_rsp_enc(&data, &data_len,hw_id_qos_pwd_ptr,buff_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
                case OBC_PS_XBAND_CMD:
                    {
                        obc_ps_xband_rsp_enc(&data, &data_len,(uint8 *)xband_data,xband_data_len);
                        printf("\nX-Band command buffer length: %d\n",xband_data_len);
                        ps_socket_send(data,data_len);
                        free(data);
                        break;
                    }
#endif
                default:
                    {
                        icm_default_rsp_enc_hdlr();
                    }
            }
            rsp_enc_id = 0;
            tc_id_var = 0;
        }
    }
}

void *ps_evnt_trig_thread(void *params)
{
    uint16 cmd_id;
    while(1)
    {
        usleep(1000);
        if(ps_evnt_trig)
        {
            cmd_id = ps_evnt_trig;
            ps_evnt_trig = 0;
            ps_encode_icd_cmd(cmd_id);
        }
    }
}

void *ps_get_icd_cmd_id_thread(void *params)
{
    volatile uint16 cmd_id;
    icm_data_dec_hdlr_map();
    while(1)
    {
        sleep(1);
        printf("Enter Test Type ID \n");
        printf("Test Type ID 1 - Send ICD to OBC\n");
        printf("Test Type ID 3 - Select File Transfer\n");

	if(ps_autom_i < ps_autom_user_input.ps_autom_arg_cnt && ps_autom_user_input.ps_autom_argv_valid[2])
	{
	    cmd_id = atoi((char *)ps_autom_user_input.ps_autom_argv[2]);
	}
	else
	{
	    scanf(" %hu",&cmd_id);
	}
	printf("Entered Test Type is: %hu\n",cmd_id);

        if(1 == cmd_id)
        {
            printf("Enter command ID to encode and send. Possible ICM to send from PS to OBC [%d:%d]\n",ES_OBC_TRGT_POINT_REQ,(ICM_CRRN_ID_MAX-1));
	    if(ps_autom_i < ps_autom_user_input.ps_autom_arg_cnt && ps_autom_user_input.ps_autom_argv_valid[ps_autom_i])
	    {
	        cmd_id = atoi((char *)ps_autom_user_input.ps_autom_argv[ps_autom_i]);
	    }
	    else
	    {
	        scanf(" %hu",&cmd_id);
	    }
	    printf("Entered Telecommand ID to send from PS to OBC : %hu \n",cmd_id);
            ps_encode_icd_cmd(cmd_id);
            if(ps_autom_i < ps_autom_user_input.ps_autom_arg_cnt)
            {
                ps_autom_i++;
                sleep(atoi((char *)ps_autom_user_input.ps_autom_argv[1]));
            }
        }
        else if(3 == cmd_id)
        {
            printf("File Transfer Initiated...\n\n");


            printf("Enter FTDS interval time in ms between \"1 to 2000\"\n");
            scanf("%hu",&set_ftds_debug);
            ft_set_ftds_delay(set_ftds_debug);

            ft_pld_tx.send_request = 0;
            ft_register_pld_trasnmitter_cblk(ft_payload_transmitter);
            app1234_thread();
        }
        else
        {
            printf("Invalid Type ID. Please try again\n");
        }
    }
}

void ps_encode_icd_cmd(uint16 cmd_id)
{
    uint8 *data = NULL;
    uint16 data_len;
    icm_trgt_pt_req_s tpr;
#if 0
    uint8 *buf_ptr = NULL;
    uint16 *app_id_info_ptr, *hw_id_info_ptr = NULL;
    uint16 app_info_buff_len, hw_info_buff_len;
    uint8 node_state;
    uint16 hw_id;
    uint16 num_app, num_hw = 0;
    icm_reg_orbt_trig_s rot;
    icm_reg_grnd_stn_ps_ntf_s rgspn;
    s_ssd_err_info ssd_err_info;
    ps_shutdown_ntf psd;
    schd_ps_pwr_on_req spor;
    radio_rx_enbl_dsbl rxed;
#endif
    switch(cmd_id)
    {
        case ES_OBC_TRGT_POINT_REQ:
            {
                tpr.lat = 10;
                tpr.longit = 10;
                tpr.alt = 10;
                tpr.pld_hw_id = ICM_PLD_HW_ID_AICRAFT;
                tpr.act_tmr_min = 5;
                tpr.act_tmr_sec = 10;
                tpr.act_tmr_ms = 2000;
                es_obc_trgt_point_req_enc(&data, &data_len, &tpr);
                es_socket_send(data,data_len);
                free(data);
                break;
            }

#if 0
        case PS_OBC_REG_ORBIT_TRIG_CMD:
            {
                rot.lat = -90;
                rot.longit = 11;
                rot.alt = 11;
                rot.pld_hw_id = ICM_PLD_HW_ID_TRANSCELESTIAL;
                rot.alrt_tmr_min = 5;
                rot.alrt_tmr_sec = 10;
                rot.alrt_tmr_ms = 2000;
                ps_obc_reg_orbit_trig_cmd_enc(&data, &data_len, &rot);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_GET_CURR_TIME_REQ:
            {
                ps_obc_get_curr_time_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }

        case PS_OBC_GNSS_LOC_REQ:
            {
                ps_obc_gnss_loc_req_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_KEEP_ALIVE_REQ:
            {
                ps_obc_keep_alive_req_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_SCHD_PS_PWR_ON_REQ:
            {
                spor.timer_seconds = 0;
                spor.timer_minutes = 0;
                spor.timer_hours = 0;
                spor.timer_days = 0;
                ps_obc_schd_ps_pwr_on_req_enc(&data, &data_len,&spor);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_RADIO_PWR_ON_REQ:
            {
                ps_obc_radio_pwr_on_req_enc(&data, &data_len, ICM_RD_COMM_SBAND);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_OBC_APP_ID_LIST_REQ:
            {
                ps_obc_obc_app_id_list_req_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_OBC_HW_ID_LIST_REQ:
            {
                ps_obc_obc_hw_id_list_req_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_OBC_APP_QoS_PRI_LIST_REQ:
            {
                ps_obc_obc_app_qos_pri_list_req_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_RADIO_PWR_OFF_CMD:
            {
                ps_obc_radio_pwr_off_cmd_enc(&data, &data_len, ICM_RD_COMM_SBAND);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_RADIO_RX_ENBL_DSBL_CMD:
            {
                rxed.radio_mod_id = ICM_RD_COMM_SBAND;
                rxed.radio_rx_enable_disable = 0;
                ps_obc_radio_rx_enbl_dsbl_cmd_enc(&data, &data_len, &rxed);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_REG_GRND_STN_PASS_NTF_CMD:
            {
                rgspn.pld_hw_id = ICM_PLD_HW_ID_TRANSCELESTIAL;
                rgspn.grnd_stn_id = 3;
                rgspn.alrt_tmr_min = 5;
                rgspn.alrt_tmr_sec = 10;
                rgspn.alrt_tmr_ms = 2000;
                rgspn.purpose = 1;
                ps_obc_reg_grnd_stn_pass_ntf_cmd_enc(&data, &data_len, &rgspn);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_RADIO_TX_ENBL_DSBL_CMD:
            {
                ps_obc_radio_tx_enbl_dsbl_cmd_enc(&data, &data_len, ICM_RD_COMM_SBAND, 0);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_STATE_UPDT_NTF:
            {
                node_state = ICM_NODE_STE_PWR_SAVE;
                ps_obc_ste_updt_ntf_enc(&data, &data_len, node_state);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PWR_ON_HNDSK_NTF:
            {
                ps_obc_pwr_on_hndsh_ntf_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_KEEP_ALIVE_NTF:
            {
                ps_obc_keep_alive_ntf_enc(&data, &data_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_RADIO_DATA_TX_CPLT_NTF:
            {
                ps_obc_radio_data_tx_cplt_ntf_enc(&data, &data_len, ICM_RD_COMM_SBAND);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_SSD_ERR_NTF:
            {
                ssd_err_info.err_type = BAD_SECTOR;
                ssd_err_info.sect_id = 100;
                ps_obc_ssd_err_ntf_enc(&data, &data_len, &ssd_err_info);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PS_FIRM_UPDT_NTF:
            {
                ps_obc_ps_firmware_updt_ntf_enc(&data, &data_len, PS_FM_UPDT_CPLT);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PLD_HW_FIRM_UPDT_NTF:
            {
                ps_obc_pld_hw_firmware_updt_ntf_enc(&data, &data_len, PLD_HW_FM_UPDT_CPLT, 1);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_VM_FIRM_UPDT_NTF:
            {
                ps_obc_vm_firmware_updt_ntf_enc(&data, &data_len, VM_FM_UPDT_CPLT, 2);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PS_RST_RECV_UPDT_NTF:
            {
                ps_obc_ps_rst_rcv_ntf_enc(&data, &data_len, PS_RST_RCV_CPLT, PS_WDT_RST);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PS_APP_ID_LIST_NTF:
            {
                num_app = 5;
                //Frame structure - Number of APP + 2 Byte APP ID + 2 Byte Peer APP ID + ....
                app_info_buff_len = (1+(2+2)*num_app);
                buf_ptr = malloc(app_info_buff_len);
                *buf_ptr = num_app;
                app_id_info_ptr = (uint16*)(buf_ptr+1);
                //Refer HW_ID_Mapping XL sheet for information on HW ID list and APP ID list encoding
                //TBD - ICD document need to be updated on the APP ID size information
                *app_id_info_ptr++ = 0x88;
                *app_id_info_ptr++ = 0x2001;
                *app_id_info_ptr++ = 0x89;
                *app_id_info_ptr++ = 0x2002;
                *app_id_info_ptr++ = 0x8a;
                *app_id_info_ptr++ = 0x2003;
                *app_id_info_ptr++ = 0x8b;
                *app_id_info_ptr++ = 0x2004;
                *app_id_info_ptr++ = 0x8c;
                *app_id_info_ptr++ = 0x2005;
                ps_obc_ps_app_id_list_ntf_enc(&data, &data_len, buf_ptr, app_info_buff_len);
                ps_socket_send(data,data_len);
                free(data);

                /* Trigger next set of events */
                ps_evnt_trig = PS_OBC_PS_HW_ID_LIST_NTF;

                break;
            }
        case PS_OBC_PS_HW_ID_LIST_NTF:
            {
                num_hw = 5;
                //Frame structure - Number of HW + 2 Byte HW ID + 2 Byte HW ID + ....
                hw_info_buff_len = (1+(2*num_hw));
                buf_ptr = malloc(hw_info_buff_len);
                *buf_ptr = num_hw;
                hw_id_info_ptr = (uint16*)(buf_ptr+1);
                //Refer HW_ID_Mapping XL sheet for information on HW ID list and APP ID list encoding
                //TBD - ICD document need to be updated on the HW ID size information
                *hw_id_info_ptr++ = 0x4001;
                *hw_id_info_ptr++ = 0x4002;
                *hw_id_info_ptr++ = 0x4003;
                *hw_id_info_ptr++ = 0x4004;
                *hw_id_info_ptr++ = 0x4005;
                ps_obc_ps_hw_id_list_ntf_enc(&data, &data_len, buf_ptr, hw_info_buff_len);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PS_HW_ERR_RECOV_NTF:
            {
                hw_id = 0x4001;
                ps_obc_ps_hw_err_recov_ntf_enc(&data, &data_len, hw_id);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PS_SHUTDOWN_NTF:
            {
                psd.shutdown_timer_value_minutes = 0;
                psd.shutdown_timer_seconds = 0;
                psd.shutdown_timer_milliseconds = 0;
                ps_obc_ps_shutdown_ntf_enc(&data, &data_len, &psd);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PS_HW_PWR_ON_CMD:
            {
                hw_id = 0x4001;
                ps_obc_ps_hw_pwr_on_cmd_enc(&data, &data_len, hw_id);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
        case PS_OBC_PS_HW_PWR_OFF_CMD:
            {
                hw_id = 0x4001;
                ps_obc_ps_hw_pwr_off_cmd_enc(&data, &data_len, hw_id);
                ps_socket_send(data,data_len);
                free(data);
                break;
            }
#endif
        default :
            {
                printf("Encoder not enabled for entered command ID. Please retry\n");
            }
    }
}

void *ps_rcv_socket_server_thread (void * params)
{
    ps_server_param *param = (ps_server_param *)params;
    ps_app_socket_server_init(param->addr, param->port, param->ipcc_frame);
    return 0;
}
void ps_app_socket_server_init(uint32 addr, uint32 port, s_ipcc_frame *ipcc_orig)
{

    int32_t status,bytesize;
    struct sockaddr_in servaddr; // cli;
    uint8 buffer[1024];

        // socket create and verification
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd == -1) {
            printf("socket creation failed...\n");
            status = sockfd;
        }
        else
        {
            bzero(&servaddr, sizeof(servaddr));

            // assign IP, PORT
            servaddr.sin_family = AF_INET;
            servaddr.sin_addr.s_addr = addr;
            servaddr.sin_port = htons(port);

            printf(" connecting to server ..");
            // connect the client socket to server socket
            while (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
            {
                usleep(1000);
                //printf(".");
                /* wait for server */
                //printf("SOCKET: connected to the server..\n");
            }
            while(1)
            {
                usleep(100);
                
                memset(buffer,0,2000);
                bytesize = recv(sockfd, buffer, 2000,MSG_DONTWAIT);//MSG_WAITALL
                if(bytesize==0)
                {
                    printf("[Socket ICD] Successfully closing socket\n");
                    close(sockfd);
                }
                else if(bytesize>0)
                {
                    printf("[Socket ICD] Successfully Received data of size %d\n",bytesize);
#ifdef PRINT_BUF_ON					
                    printf("Received data stream: ");
                    int i = 0;
                    for (i = 0; i< bytesize; i++)
                    {
                        printf("%x ",buffer[i]);
                    }
                    printf("\n");
#endif
                    status=ipcc_unpack_trigger((const unsigned char *)buffer,
                            ipcc_orig, bytesize);
                    if(status < 0)
                    {
                        printf("IPCC unpacking error\n");
                        //            pthread_exit(NULL);
                    }

                }
            }
        }
}
void validate_seq_num(uint16 actual_seq_no)
{
    static uint16 expected_seq_no = 1;
    uint32 missing_frames , i = 0;
    if(expected_seq_no != actual_seq_no)
    {
      if(actual_seq_no > expected_seq_no)
      {
          missing_frames = actual_seq_no - expected_seq_no;
          for (i=0; i<missing_frames; i++)
          {
              //printf(" Warning !!! Missing frame. Sequence number : %d \n",expected_seq_no);
              expected_seq_no++;
          }
      }
      else
      {
           printf(" Warning !!! Received the same packet again : %d \n",actual_seq_no);
      }

    }
    expected_seq_no++;
}

int es_socket_send(uint8 *data, uint16 data_len)
{
    s_ipcc_frame *ipcc_orig_app;
    uint8 *dst;
    uint16 ipcc_len = data_len;
    int32 size = 0,status;
    uint32 loop = 0;

    /* Encryption related params */
    s_ipcc_crypt_params param;
    uint8 key[] = {0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
                   0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                   0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

    uint8 iv[16] = {0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};

    memcpy(param.iv, iv, 16);
    param.key_size = 256;
    param.key = (unsigned char *)malloc(param.key_size);
    memcpy(param.key, key, param.key_size);
    param.encrypt_mode = IPCC_CRYPT_AES_CFB8;
    ipcc_orig_select_encryption(&param);

    /* Send buffer and frame memory allocations */
    ipcc_orig_app = (s_ipcc_frame *) malloc(sizeof(s_ipcc_frame));
    dst = (unsigned char *) malloc(sizeof(s_ipcc_frame)+ipcc_len);

    ipcc_orig_init(ipcc_orig_app);
    //ipcc_orig_reset_seq_no();
    ipcc_orig_select_encryption(&param);
    ipcc_orig_cfg_sof(ipcc_orig_app, 0xA5);
    ipcc_orig_cfg_ipcc_ctrl(ipcc_orig_app, 0x20);
    ipcc_orig_cfg_qos(ipcc_orig_app, 1);
    ipcc_orig_cfg_sa_id(ipcc_orig_app, 1);
    ipcc_orig_cfg_da_id(ipcc_orig_app, 13);
    ipcc_orig_cfg_ipcc_id(ipcc_orig_app, 25);

    ipcc_orig_cfg_ipcc_len(ipcc_orig_app, ipcc_len);
    ipcc_orig_cfg_ipcc_data (ipcc_orig_app, data);
#ifdef PRINT_BUF_ON
    printf("ICM Encoded byte stream: ");
    for(loop = 0; loop < ipcc_len; loop++)
        printf("%x ", data[loop]);
    printf("\n");
#endif
    ipcc_orig_app->cmac_hmac = (uint8_t *) malloc(SHA256_HASH_SIZE);
    bzero(dst, size);
    size = ipcc_pack(dst, ipcc_orig_app);
    status = write(sockfd, dst, size);
    int i = 0;
	#ifdef PRINT_BUF_ON
    printf("ICD encoded data stream: ");
    for (i = 0; i< size; i++)
    {
        printf("%x ",dst[i]);
    }
    printf("\n");
	#endif
    if(status<0)
    {
        printf("[SOCKET ICD] Failure in transferring data %d\n",status);
    }
    else
    {
        printf("[SOCKET ICD] Successfully transferred data of size %d\n",status);
    }
 //   size = tcp_send(addr, port, dst, size);

    return 0;
}

