#include <err.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

#include "darknet.h"
#include "activations.h"
#include "cost_layer.h"

#include "main.h"

#include "libs_tlc/include/QSEEComAPI/QSEEComAPI.h"

/* TEE resources */

struct QSEECom_handle *l_QSEEComHandle = NULL;
tci_message_t *send_msg;
tci_message_t *resp_msg;
uint32_t len = sizeof(tci_message_t);

/*
TEEC_Context ctx;
TEEC_Session sess;
TEEC_SharedMemory workspaceSM;
*/
float *net_input_back;
float *net_delta_back;
float *net_output_back;
int sysCount = 0;
char state;
int debug_plot_bool = 0;

void debug_plot(char *filename, int num, float *tobeplot, int length)
{
    struct stat st = {0};
    if (stat("/media/debug_plot", &st) == -1) {
            mkdir("/media/debug_plot", 0700);
    }

    FILE * fp;
    int i;

    char strnum[10];
    sprintf(strnum, "%d", num);

    /* open the file for writing*/
    char *s1 = "/media/debug_plot/";
    //char *s1 = "";
    char *s2 = ".txt";

    char *result = malloc(strlen(s1) + strlen(filename) + strlen(strnum) + strlen(s2) + 1); // +1 for the null-terminator

    // in real code you would check for errors in malloc here
    strcpy(result, s1);
    strcat(result, filename);
    strcat(result, strnum);
    strcat(result, s2);

    fp = fopen(result,"w");

    /* write lines of text into the file stream*/
    for(i = 0; i < length; i++){
        fprintf(fp, "%f\n",tobeplot[i]);
    }

    /* close the file*/
    fclose (fp);
    free(result);
}


void summary_array(char *print_name, float *arr, int n)
{

    float sum=0, min, max, idxzero=0;

    for(int i=0; i<n; i++)
    {
        sum = sum + arr[i];
        if (i == 0){
            min = arr[i];
            max = arr[i];
        }
        if (arr[i] < min){
            min = arr[i];
        }
        if (arr[i] > max){
            max = arr[i];
        }
        if (arr[i] == 0){
           idxzero++;
        }
    }

    float mean=0;
    mean = sum / n;
    printf("%s || mean = %f; min=%f; max=%f; number of zeros=%f \n", print_name, mean, min, max, idxzero);
}


void make_network_CA(int n, float learning_rate, float momentum, float decay, int time_steps, int notruth, int batch, int subdivisions, int random, int adam, float B1, float B2, float eps, int h, int w, int c, int inputs, int max_crop, int min_crop, float max_ratio, float min_ratio, int center, float clip, float angle, float aspect, float saturation, float exposure, float hue, int burn_in, float power, int max_batches)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = MAKE_NETWORK_CMD;
    int *passint = send_msg->payload.make_network_cmd.passint;

    passint[0] = n;
    passint[1] = time_steps;
    passint[2] = notruth;
    passint[3] = batch;
    passint[4] = subdivisions;
    passint[5] = random;
    passint[6] = adam;
    passint[7] = h;
    passint[8] = w;
    passint[9] = c;
    passint[10] = inputs;
    passint[11] = max_crop;
    passint[12] = min_crop;
    passint[13] = center;
    passint[14] = burn_in;
    passint[15] = max_batches;

    float *passfloat = send_msg->payload.make_network_cmd.passfloat;
    passfloat[0] = learning_rate;
    passfloat[1] = momentum;
    passfloat[2] = decay;
    passfloat[3] = B1;
    passfloat[4] = B2;
    passfloat[5] = eps;
    passfloat[6] = max_ratio;
    passfloat[7] = min_ratio;
    passfloat[8] = clip;
    passfloat[9] = angle;
    passfloat[10] = aspect;
    passfloat[11] = saturation;
    passfloat[12] = exposure;
    passfloat[13] = hue;
    passfloat[14] = power;


    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: Send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: Send command success with ret = %d\n", __func__, ret);
    }
}

void make_convolutional_layer_CA(int batch, int h, int w, int c, int n, int groups, int size, int stride, int padding, ACTIVATION activation, int batch_normalize, int binary, int xnor, int adam, int flipped, float dot)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = MAKE_CONV_CMD;

    int *passint = send_msg->payload.make_conv_cmd.passint;
    passint[0] = batch;
    passint[1] = h;
    passint[2] = w;
    passint[3] = c;
    passint[4] = n;
    passint[5] = groups;
    passint[6] = size;
    passint[7] = stride;
    passint[8] = padding;
    passint[9] = batch_normalize;
    passint[10] = binary;
    passint[11] = xnor;
    passint[12] = adam;
    passint[13] = flipped;

    send_msg->payload.make_conv_cmd.passflo = dot;
    char *acti = get_activation_string(activation);

    memcpy(send_msg->payload.make_conv_cmd.acti.buf, acti, strlen(acti));
    send_msg->payload.make_conv_cmd.acti.len = strlen(acti) + 1;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: Send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: Send command success with ret = %d\n", __func__, ret);
    }

}

void make_maxpool_layer_CA(int batch, int h, int w, int c, int size, int stride, int padding)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = MAKE_MAX_CMD;

    int *passint = send_msg->payload.make_max_cmd.passint;
    passint[0] = batch;
    passint[1] = h;
    passint[2] = w;
    passint[3] = c;
    passint[4] = size;
    passint[5] = stride;
    passint[6] = padding;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: Send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: Send command success with ret = %d\n", __func__, ret);
    }

}

void make_dropout_layer_CA(int batch, int inputs, float probability, int w, int h, int c, float *net_prev_output, float *net_prev_delta)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = MAKE_DROP_CMD;

    int *passint = send_msg->payload.make_drop_cmd.passint;
    passint[0] = batch;
    passint[1] = inputs;
    passint[2] = w;
    passint[3] = h;
    passint[4] = c;
    float passflo[1];
    passflo[0] = probability;

    if(debug_plot_bool == 1){
        debug_plot("net_prev_output", sysCount, net_prev_output, inputs*batch);
        debug_plot("net_prev_delta", sysCount, net_prev_delta, inputs*batch);
    }

    /* TODO: input only? will TA operate on this buffer directly */
    memcpy(send_msg->payload.make_drop_cmd.net_prev_output.buf, net_prev_output, sizeof(float)*inputs*batch);
    send_msg->payload.make_drop_cmd.net_prev_output.len = sizeof(float)*inputs*batch;
    memcpy(send_msg->payload.make_drop_cmd.net_prev_delta.buf, net_prev_delta, sizeof(float)*inputs*batch);
    send_msg->payload.make_drop_cmd.net_prev_delta.len = sizeof(float)*inputs*batch;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}



void make_connected_layer_CA(int batch, int inputs, int outputs, ACTIVATION activation, int batch_normalize, int adam)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = MAKE_CONNECTED_CMD;

    int *passarg = send_msg->payload.make_connected_cmd.passarg;
    passarg[0] = batch;
    passarg[1] = inputs;
    passarg[2] = outputs;
    passarg[3] = batch_normalize;
    passarg[4] = adam;

    char *actv = get_activation_string(activation);
    memcpy(send_msg->payload.make_connected_cmd.actv.buf, actv, strlen(actv));
    send_msg->payload.make_connected_cmd.actv.len = strlen(actv) + 1;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}

void make_softmax_layer_CA(int batch, int inputs, int groups, float temperature, int w, int h, int c, int spatial, int noloss)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = MAKE_SOFTMAX_CMD;

    int *passint = send_msg->payload.make_softmax_cmd.passint;
    passint[0] = batch;
    passint[1] = inputs;
    passint[2] = groups;
    passint[3] = w;
    passint[4] = h;
    passint[5] = c;
    passint[6] = spatial;
    passint[7] = noloss;
    send_msg->payload.make_softmax_cmd.passflo = temperature;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}

void make_cost_layer_CA(int batch, int inputs, COST_TYPE cost_type, float scale, float ratio, float noobject_scale, float thresh)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = MAKE_COST_CMD;

    int *passint = send_msg->payload.make_cost_cmd.passint;
    float *passflo = send_msg->payload.make_cost_cmd.passflo;
    char *passcost;

    passint[0] = batch;
    passint[1] = inputs;
    passflo[0] = scale;
    passflo[1] = ratio;
    passflo[2] = noobject_scale;
    passflo[3] = thresh;

    passcost = get_cost_string(cost_type);
    memcpy(send_msg->payload.make_cost_cmd.passcost.buf, passcost, strlen(passcost));
    send_msg->payload.make_cost_cmd.passcost.len = strlen(passcost) + 1;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}

void transfer_weights_CA(float *vec, int length, int layer_i, char type, int additional)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = TRANS_WEI_CMD;

    memcpy(send_msg->payload.trans_wei_cmd.vec.buf, vec, sizeof(float) * length);
    send_msg->payload.trans_wei_cmd.vec.len = sizeof(float) * length;

    int *passint = send_msg->payload.trans_wei_cmd.passint;
    passint[0] = length;
    passint[1] = layer_i;
    passint[2] = additional;

    send_msg->payload.trans_wei_cmd.type = type;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }

}

void save_weights_CA(float *vec, int length, int layer_i, char type)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = SAVE_WEI_CMD;

    int *passint = send_msg->payload.save_wei_cmd.passint;
    passint[0] = length;
    passint[1] = layer_i;

    send_msg->payload.save_wei_cmd.type = type;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }

    for(int z=0; z<length; z++){
         vec[z] = ((float *) resp_msg->payload.save_wei_resp.weights_back.buf)[z];
    }

}


void forward_network_CA(float *net_input, int l_inputs, int net_batch, int net_train)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = FORWARD_CMD;

    float *params0 = (float *) send_msg->payload.forward_cmd.net_input.buf;  
    for(int z=0; z<l_inputs*net_batch; z++){
        params0[z] = net_input[z];
    }
    send_msg->payload.forward_cmd.net_input.len = sizeof(float) * l_inputs*net_batch;
    send_msg->payload.forward_cmd.net_train = net_train;

    /////////  debug_plot  /////////
    if(debug_plot_bool == 1){
        debug_plot("forward_net_input_", sysCount, params0, l_inputs*net_batch);
    }

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}


void forward_network_back_CA(float *l_output, int net_inputs, int net_batch)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = FORWARD_BACK_CMD;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }

    for(int z=0; z<net_inputs * net_batch; z++){
            l_output[z] = ((float *) resp_msg->payload.forward_back_resp.net_input_back.buf)[z];
    }

   /////////  debug_plot  /////////
   if(debug_plot_bool == 1){
       debug_plot("forward_net_back_input_", sysCount, (float *) send_msg->payload.forward_back_cmd.net_input_back.buf, net_inputs*net_batch);
   }
}




void backward_network_CA(float *net_input, int l_inputs, int net_batch, int net_train)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = BACKWARD_CMD;

    float *params0 = (float *) send_msg->payload.backward_cmd.net_input.buf;  

    for(int z=0; z<l_inputs*net_batch; z++){
            params0[z] = net_input[z];
            //params1[z] = net_delta[z];
    }
    send_msg->payload.backward_cmd.net_input.len = sizeof(float)*l_inputs*net_batch;
    send_msg->payload.backward_cmd.net_train = net_train;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
    /////////  debug_plot  /////////
    if(debug_plot_bool == 1){
            debug_plot("backward_net_input_", sysCount, params0, l_inputs*net_batch);
            //debug_plot("backward_net_delta_", sysCount, params1, l_inputs*net_batch); // zero, removing!
    }
}


void backward_network_CA_addidion(float *l_output, float *l_delta, int net_inputs, int net_batch)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = BACKWARD_ADD_CMD;

    send_msg->payload.backward_add_cmd.net_input_back.len = sizeof(float) * net_inputs * net_batch;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }

    for(int z=0; z<net_inputs * net_batch; z++){
            l_output[z] = ((float *) resp_msg->payload.backward_add_resp.net_input_back.buf)[z];
            l_delta[z] = ((float *) resp_msg->payload.backward_add_resp.net_delta_back.buf)[z];
    }

    /////////  debug_plot  /////////
    if(debug_plot_bool == 1){
            debug_plot("backward_net_add_input_", sysCount, (float *) resp_msg->payload.backward_add_resp.net_input_back.buf, net_inputs*net_batch);
            debug_plot("backward_net_add_delta_", sysCount, (float *) resp_msg->payload.backward_add_resp.net_delta_back.buf, net_inputs*net_batch);
    }
}



void backward_network_back_CA(float *net_input, int l_inputs, int net_batch, float *net_delta)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = BACKWARD_BACK_CMD;

    float *params0 = (float *) send_msg->payload.backward_back_cmd.net_input.buf;
    float *params1 = (float *) send_msg->payload.backward_back_cmd.net_delta.buf;

    for(int z=0; z<l_inputs*net_batch; z++){
        params0[z] = net_input[z];
        params1[z] = net_delta[z];
    }
    send_msg->payload.backward_back_cmd.net_input.len = sizeof(float)*l_inputs*net_batch;
    send_msg->payload.backward_back_cmd.net_delta.len = sizeof(float)*l_inputs*net_batch;


     /////////  debug_plot  /////////
    if(debug_plot_bool == 1){
        debug_plot("backward_net_back_input_", sysCount, params0, l_inputs*net_batch);
        debug_plot("backward_net_back_delta_", sysCount, params1, l_inputs*net_batch);
    }

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}



void backward_network_back_CA_addidion(float *l_output, float *l_delta, int net_inputs, int net_batch)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = BACKWARD_BACK_ADD_CMD;
    send_msg->payload.backward_back_add_cmd.net_input_back.len = sizeof(float) * net_inputs * net_batch;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }

    for(int z=0; z<net_inputs * net_batch; z++){
            l_output[z] = ((float *) resp_msg->payload.backward_back_add_resp.net_input_back.buf)[z];
            //l_pp2.delta[z] = net_delta_back[z];
            l_delta[z] = 0.0f;
    }

   /////////  debug_plot  /////////
   if(debug_plot_bool == 1){
       debug_plot("backward_add_back_net_input_", sysCount, (float *) resp_msg->payload.backward_back_add_resp.net_input_back.buf, net_inputs*net_batch);
       //debug_plot("backward_add_back_net_delta_", sysCount, net_delta_back, net_inputs*net_batch); //zeros, removing!!
   }
}

void update_network_CA(update_args a)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = BACKWARD_BACK_CMD;

    int *passint = (int *) send_msg->payload.update_cmd.passint;
    passint[0] = a.batch;
    passint[1] = a.adam;
    passint[2] = a.t;

    float *passflo = (float *) send_msg->payload.update_cmd.passflo;
    passflo[0] = a.learning_rate;
    passflo[1] = a.momentum;
    passflo[2] = a.decay;
    passflo[3] = a.B1;
    passflo[4] = a.B2;
    passflo[5] = a.eps;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}



void net_truth_CA(float *net_truth, int net_truths, int net_batch)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = NET_TRUTH_CMD;

    float *params0 = (float *) send_msg->payload.net_truth_cmd.net_truth.buf;
    for(int z=0; z<net_truths*net_batch; z++){
        params0[z] = net_truth[z];
    }
    send_msg->payload.net_truth_cmd.net_truth.len = sizeof(float)*net_truths*net_batch;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }

     /////////  debug_plot  /////////
    if(debug_plot_bool == 1){
            debug_plot("backward_net_truth_", sysCount, (float *) send_msg->payload.net_truth_cmd.net_truth.buf, net_truths*net_batch);
    }
}

void calc_network_loss_CA(int n, int batch)
{
    sysCount++;
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = CALC_LOSS_CMD;

    int *params0 = send_msg->payload.calc_loss_cmd.passint;
    params0[0] = n;
    params0[1] = batch;

    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }
}

void net_output_return_CA(int net_outputs, int net_batch)
{
    uint32_t ret = 0;
    memset(send_msg, 0, sizeof(tci_message_t));
    memset(resp_msg, 0, sizeof(tci_message_t));
    
    send_msg->header.id = OUTPUT_RETURN_CMD;
    send_msg->payload.output_return_cmd.net_output_back.len = sizeof(float) * net_outputs * net_batch;
    
    ret = QSEECom_send_cmd(l_QSEEComHandle, send_msg, len, resp_msg, len);
    if (ret) {
            printf("%s: send command failed with ret = %d\n", __func__, ret);
            return;
    } else {
            printf("%s: send command success with ret = %d\n", __func__, ret);
    }

    if (net_output_back == NULL)
            net_output_back = malloc(sizeof(float) * net_outputs * net_batch);
    memcpy(net_output_back, resp_msg->payload.output_return_resp.net_output_back.buf, sizeof(float) * net_outputs * net_batch);

}


void prepare_tee_session()
{
    static char appname[10] = "pebble";
    struct qseecom_app_info app_info;
    uint32_t ret = 0;

    send_msg = malloc(sizeof(tci_message_t));
    resp_msg = malloc(sizeof(tci_message_t));

    if (len & QSEECOM_ALIGN_MASK)
            len = QSEECOM_ALIGN(len);

    ret = QSEECom_start_app(&l_QSEEComHandle, "/vendor/firmware_mnt/image",
                    appname, 3 * sizeof(tci_message_t));
    if (ret) {
            printf("%s: Loading app -%s failed\n", __func__, appname);
            return;
    } else {
            printf("Loading app -%s succeded\n", appname);
    }

    ret = QSEECom_set_bandwidth(l_QSEEComHandle, true);
    if (ret) {
            printf("%s: Set Bandwith True Failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: Set Bandwith True succeded\n", __func__);
    }

    ret = QSEECom_get_app_info(l_QSEEComHandle, &app_info);
    if (ret) {
            printf("%s: Fail to get app_info\n", __func__);
            //return -1;
    }
}

void terminate_tee_session()
{
    uint32_t ret = 0;

    ret = QSEECom_set_bandwidth(l_QSEEComHandle, false);
    if (ret) {
            printf("%s: Set Bandwith False Failed with ret = %d\n", __func__, ret);
    } else {
            printf("%s: Set Bandwith False succeded\n", __func__);
    }

    ret = QSEECom_shutdown_app(&l_QSEEComHandle);
    if (ret) {
            printf("%s: Shutdown app failed with ret = %d\n", __func__, ret);
    } else {
            free(send_msg);
            free(resp_msg);
            printf("shutdown app: pass\n");
    }
}



int main(int argc, char **argv)
{

    printf("Prepare session with the TA\n");
    prepare_tee_session();

    printf("Begin darknet\n");
    darknet_main(argc, argv);

    terminate_tee_session();
    return 0;
}
