#include "sec_apdu.h"
#include "sec_EseStatus.h"
#include "sec_spi_info.h"
#include "lib_ver.h"
#include "tz_debug.h"
#include "sec_mw.h"
#include "tz_utils.h"
#include "tz_platform.h"

#define DELAY_TIME_FOR_SPI_RELEASE_IN_MILLI  100
#define MAX_BUFFER_SIZE 258

#ifdef USE_QSEE
#include <qsee_heap.h>
#ifdef USE_ISPI_API
#include <qsee_env.h>
#include <CSPI.h>
#include <ISPI.h>
Object gSpiSingleton;
#endif
#endif

#ifdef USE_BLOWFISH
#include <tee_spi.h>
#include <tee_internal_api.h>
TEES_SPIHandler handler;
#endif

#ifdef USE_TRUSTY_UNISOC
#endif

#ifdef COMMON_VENDOR
uint8_t chip_vendor = 0;
#endif

uint8_t increased_wtx_max_time = 0;

int is_secure_spi_opened = FALSE;

void channelMasking (uint8_t channelId, p_secEse_7816_cpdu_t pCmd) {
    if (channelId < 4) {
        pCmd->cla = (pCmd->cla & 0xfc) | channelId;
    } else {
        LOGE("channelId is not valid");
    }
}

void set_increased_wtx_max_time(uint8_t time) {
    increased_wtx_max_time = time;
    LOGI("set_increased_wtx_max_time = %d", increased_wtx_max_time);
}

#ifdef USE_QSEE

int eSEGpioOpen() {
    int retval = 0;
#ifdef GPIO_CONTROL
    unsigned char data[4] = "open";
    ese_oem_req_t cmd;
    unsigned int output;
    cmd.cmd_id = ESE_OPEN_DATA;
    cmd.data = data;

    retval = qsee_oem_process_cmd((unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&output, sizeof(unsigned int));
    LOGI("eSEGpioOpen qsee_oem_process_cmd retval = %d", retval);
#endif

#ifdef CS_CONTROL
#ifdef TLMM_CONTROL
    uint32_t gpio_key_miso;
    uint32_t gpio_key_mosi;
    uint32_t gpio_key_clk;
    uint32_t gpio_key_cs;

    qsee_tlmm_config_t my_config;

    my_config.drive = QSEE_GPIO_6MA;
    my_config.pull = QSEE_GPIO_PULL_DOWN;
    my_config.direction = QSEE_GPIO_OUTPUT;

    LOGI("eSEGpioOpen");
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_MISO, &gpio_key_miso) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_miso Failed");
        retval = -1;
    }
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_MOSI, &gpio_key_mosi) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_mosi Failed");
        retval = -1;
    }
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_CLK, &gpio_key_clk) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_clk Failed");
        retval = -1;
    }
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_CS, &gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_cs Failed");
        retval = -1;
    }
    if (retval == 0) {
        if (qsee_tlmm_config_gpio_id(gpio_key_miso, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_miso Failed");
            retval = -1;
        }
        if (qsee_tlmm_config_gpio_id(gpio_key_mosi, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_mosi Failed");
            retval = -1;
        }
        if (qsee_tlmm_config_gpio_id(gpio_key_clk, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_clk Failed");
            retval = -1;
        }
        if (qsee_tlmm_config_gpio_id(gpio_key_cs, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_cs Failed");
            retval = -1;
        }

        if (qsee_tlmm_select_gpio_id_mode(gpio_key_miso, QSEE_GPIO_MODE_PRIMARY) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_miso Failed");
            retval = -1;
        }
        if (qsee_tlmm_select_gpio_id_mode(gpio_key_mosi, QSEE_GPIO_MODE_PRIMARY) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_mosi Failed");
            retval = -1;
        }
        if (qsee_tlmm_select_gpio_id_mode(gpio_key_clk, QSEE_GPIO_MODE_PRIMARY) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_clk Failed");
            retval = -1;
        }
        if (qsee_tlmm_select_gpio_id_mode(gpio_key_cs, QSEE_GPIO_MODE_PRIMARY) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_cs Failed");
            retval = -1;
        }
    }

    if (qsee_tlmm_release_gpio_id(gpio_key_miso) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_miso Failed");
        retval = -1;
    }
    if (qsee_tlmm_release_gpio_id(gpio_key_mosi) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_mosi Failed");
        retval = -1;
    }
    if (qsee_tlmm_release_gpio_id(gpio_key_clk) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_clk Failed");
        retval = -1;
    }
    if (qsee_tlmm_release_gpio_id(gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_cs Failed");
        retval = -1;
    }
#endif
#endif

    return retval;
}


int eSEGpioClose() {
    int retval = 0;
#ifdef GPIO_CONTROL
    unsigned char data[5] = "close";
    ese_oem_req_t cmd;
    unsigned int output;
    cmd.cmd_id = ESE_CLOSE_DATA;
    cmd.data = data;

    retval = qsee_oem_process_cmd((unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&output, sizeof(unsigned int));
    LOGI("eSEGpioClose qsee_oem_process_cmd retval = %d", retval);
#endif
#ifdef TLMM_CONTROL
    uint32_t gpio_key_miso;
    uint32_t gpio_key_mosi;
    uint32_t gpio_key_clk;
    uint32_t gpio_key_cs;

    qsee_tlmm_config_t my_config;

    my_config.drive = QSEE_GPIO_6MA;
    my_config.pull = QSEE_GPIO_PULL_DOWN;
    my_config.direction = QSEE_GPIO_OUTPUT;

    LOGI("eSEGpioClose");
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_MISO, &gpio_key_miso) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_miso Failed");
        retval = -1;
    }
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_MOSI, &gpio_key_mosi) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_mosi Failed");
        retval = -1;
    }
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_CLK, &gpio_key_clk) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_clk Failed");
        retval = -1;
    }
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_CS, &gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_cs Failed");
        retval = -1;
    }
    if (retval == 0) {
        if (qsee_tlmm_config_gpio_id(gpio_key_miso, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_miso Failed");
            retval = -1;
        }
        if (qsee_tlmm_config_gpio_id(gpio_key_mosi, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_mosi Failed");
            retval = -1;
        }
        if (qsee_tlmm_config_gpio_id(gpio_key_clk, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_clk Failed");
            retval = -1;
        }
        if (qsee_tlmm_config_gpio_id(gpio_key_cs, &my_config) != 0) {
            LOGE("qsee_tlmm_config_gpio_id: gpio_key_cs Failed");
            retval = -1;
        }

        if (qsee_tlmm_select_gpio_id_mode(gpio_key_miso, QSEE_GPIO_MODE_GENERAL) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_miso Failed");
            retval = -1;
        }
        if (qsee_tlmm_select_gpio_id_mode(gpio_key_mosi, QSEE_GPIO_MODE_GENERAL) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_mosi Failed");
            retval = -1;
        }
        if (qsee_tlmm_select_gpio_id_mode(gpio_key_clk, QSEE_GPIO_MODE_GENERAL) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_clk Failed");
            retval = -1;
        }
        if (qsee_tlmm_select_gpio_id_mode(gpio_key_cs, QSEE_GPIO_MODE_GENERAL) != 0) {
            LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_cs Failed");
            retval = -1;
        }

        if (qsee_tlmm_gpio_id_out(gpio_key_miso, QSEE_GPIO_LOW) != 0) {
            LOGE("qsee_tlmm_gpio_id_out output-LOW: Failed");
            retval = -1;
        }
        if (qsee_tlmm_gpio_id_out(gpio_key_mosi, QSEE_GPIO_LOW) != 0) {
            LOGE("qsee_tlmm_gpio_id_out output-LOW: Failed");
            retval = -1;
        }
        if (qsee_tlmm_gpio_id_out(gpio_key_clk, QSEE_GPIO_LOW) != 0) {
            LOGE("qsee_tlmm_gpio_id_out output-LOW: Failed");
            retval = -1;
        }
        if (qsee_tlmm_gpio_id_out(gpio_key_cs, QSEE_GPIO_LOW) != 0) {
            LOGE("qsee_tlmm_gpio_id_out output-LOW: Failed");
            retval = -1;
        }
    }
    if (qsee_tlmm_release_gpio_id(gpio_key_miso) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_miso Failed");
        retval = -1;
    }
    if (qsee_tlmm_release_gpio_id(gpio_key_mosi) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_mosi Failed");
        retval = -1;
    }
    if (qsee_tlmm_release_gpio_id(gpio_key_clk) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_clk Failed");
        retval = -1;
    }
    if (qsee_tlmm_release_gpio_id(gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_cs Failed");
        retval = -1;
    }
#endif
    return retval;
}

#ifdef CS_CONTROL
int eSEGpioCSEnable() {
    int retval = 0;

#ifdef TLMM_CONTROL
    uint32_t gpio_key_cs;
    qsee_tlmm_config_t my_config;

    my_config.drive = QSEE_GPIO_6MA;
    my_config.pull = QSEE_GPIO_PULL_DOWN;
    my_config.direction = QSEE_GPIO_OUTPUT;

    //LOGD("eSEGpioCSEnable");
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_CS, &gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_cs Failed");
        return -1;
    }

    if (qsee_tlmm_config_gpio_id(gpio_key_cs, &my_config) != 0) {
        LOGE("qsee_tlmm_config_gpio_id: gpio_key_cs Failed");
        return -1;
    }

    if (qsee_tlmm_select_gpio_id_mode(gpio_key_cs, QSEE_GPIO_MODE_GENERAL) != 0) {
        LOGE("qsee_tlmm_select_gpio_id_mode to generic IO: gpio_key_cs Failed");
        return -1;
    }

    if (qsee_tlmm_gpio_id_out(gpio_key_cs, QSEE_GPIO_LOW) != 0) {
      LOGE("qsee_tlmm_gpio_id_out output-LOW: Failed");
      return -1;
    }

    if (qsee_tlmm_release_gpio_id(gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_cs Failed");
        return -1;
    }
#endif

    return retval;
}

int eSEGpioCSDisable() {
    int retval = 0;

#ifdef TLMM_CONTROL
    uint32_t gpio_key_cs;

    //LOGD("eSEGpioCSDisable");
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_CS, &gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_get_gpio_id: gpio_key_cs Failed");
        return -1;
    }
    if (qsee_tlmm_gpio_id_out(gpio_key_cs, QSEE_GPIO_HIGH) != 0) {
      LOGE("qsee_tlmm_gpio_id_out output-LOW: Failed");
      return -1;
    }

    if (qsee_tlmm_release_gpio_id(gpio_key_cs) != 0) {
        LOGE("qsee_tlmm_release_gpio_id: gpio_key_cs Failed");
        return -1;
    }
#endif

    return retval;
}
#endif

int spiOpen() {
    int retval = 0;
    qsee_spi_device_id_t deviceId  = ESE_SPI_DEVICE_ID;

    LOGI("Library version : %s", LIB_VER);

#ifdef COMMON_VENDOR
    if (chip_vendor == 0) {
        LOGE("spiOpen is not supported, use spiOpenWithChipVendor API");
        return RESULT_NOT_SUPPORTED;
    }
#endif

#ifdef USE_ALWAYS_POWER_ON
    sleepProcess(DELAY_TIME_FOR_SPI_RELEASE_IN_MILLI);
#endif

    eSEGpioOpen();

#ifdef USE_ISPI_API
#ifdef COMMON_VENDOR
    if (chip_vendor == CHIP_VENDOR_NXP_JCOP40) {
        retval = qsee_spi_open(deviceId);
    } else {
        LOGI("Use ISPI APIs");
        gSpiSingleton = qsee_open_singleton(CSPI_UID);
        if (Object_isNull(gSpiSingleton)) {
            LOGE("qsee_open_singleton is failed");
            return RESULT_SPI_OPEN_FAILED;
        }
        retval = ISPI_open(gSpiSingleton, deviceId);
    }
#else
    LOGI("Use ISPI APIs");
    gSpiSingleton = qsee_open_singleton(CSPI_UID);
    if (Object_isNull(gSpiSingleton)) {
        LOGE("qsee_open_singleton is failed");
        return RESULT_SPI_OPEN_FAILED;
    }
    retval = ISPI_open(gSpiSingleton, deviceId);
#endif
#else
    retval = qsee_spi_open(deviceId);
#endif

    if (0 != retval) {
        LOGE("qsee_spi_open: retval = %d", retval);
        return retval;
    } else {
        LOGI("spiOpen success");
        is_secure_spi_opened = TRUE;
    }

    if (ESESTATUS_SUCCESS != iso7816_init()) {
        LOGE("iso7816_init fail");
        return RESULT_SPI_INIT_FAILED;
    }

    return retval;
}

#ifdef USE_ALWAYS_POWER_ON
int eSECsHigh() {
    int retval = 0;

    uint32_t gpio_key_cs;

    LOGI("eSECsHigh");
    if (qsee_tlmm_get_gpio_id(BLSP_SPI_CS, &gpio_key_cs) != 0) {
    	LOGI("qsee_tlmm_get_gpio_id: gpio_key_cs Failed or not supported");
    	return -1;
    }

    if (qsee_tlmm_gpio_id_out(gpio_key_cs, QSEE_GPIO_HIGH) != 0) {
    	LOGE("qsee_tlmm_gpio_id_out output-HIGH: Failed");
    	retval = -1;
    }

    if (qsee_tlmm_release_gpio_id(gpio_key_cs) != 0) {
    	LOGE("qsee_tlmm_release_gpio_id: gpio_key_cs Failed");
    	retval = -1;
    }

    return retval;

}
#endif

int spiClose() {
    int retval = 0;
    qsee_spi_device_id_t deviceId = ESE_SPI_DEVICE_ID;

    LOGI("Library version : %s", LIB_VER);

    iso7816_deinit();

    if (0 != (retval = qsee_spi_close(deviceId))) {
        LOGE("qsee_spi_close: retval = %d", retval);
    } else {
        LOGI("spiClose success");
        is_secure_spi_opened = FALSE;
    }

#ifdef USE_ALWAYS_POWER_ON
    eSECsHigh();
#endif

#ifndef NOT_CONTROL_GPIO_CLOSE
    eSEGpioClose();
#endif

#ifdef USE_ALWAYS_POWER_ON
    sleepProcess(DELAY_TIME_FOR_SPI_RELEASE_IN_MILLI);
#endif

    return retval;
}
#endif

#ifdef USE_MOBICORE

#if defined(EXYNOS_7420) || defined(EXYNOS_3250)
void setSpiConfiguration_sec(spi_config_t* spi_config) {
    spi_config->delay_usecs = 100;
    spi_config->speed_hz = SPI_MAX_FREQ;
    spi_config->bits_per_word = 0;
    spi_config->dma_mode = 0;
}
#else
void setSpiConfiguration_sec(spi_config_t* spi_config) {
    spi_config->delay_usecs = 100;
    spi_config->speed_hz = SPI_MAX_FREQ;
    spi_config->bits_per_word = 0;
    spi_config->dma_mode = 0;
    spi_config->spi_mode = SPI_TX_MODE_0; // secdrv_hw_hal.h
}
#endif

int spiOpen() {
    int retval = 0;
    uint32_t deviceId  = ESE_SPI_DEVICE_ID;
    spi_config_t spi_config;

#ifdef COMMON_VENDOR
    if (chip_vendor == 0) {
        LOGE("spiOpen is not supported, use spiOpenWithChipVendor API");
        return RESULT_NOT_SUPPORTED;
    }
#endif

    setSpiConfiguration_sec(&spi_config);

    LOGD("spi deviceId = %d",ESE_SPI_DEVICE_ID);
    LOGD("spi_config.delay_usecs = %d",spi_config.delay_usecs);
    LOGD("spi_config.speed_hz = %d",spi_config.speed_hz);
    LOGD("spi_config.bits_per_word = %d",spi_config.bits_per_word);
    LOGD("spi_config.dma_mode = %d",spi_config.dma_mode);
#if !defined(EXYNOS_7420) && !defined(EXYNOS_3250)
    LOGD("spi_config.spi_mode = %d",spi_config.spi_mode);
#endif


    if (0 != (retval = tlApiSecSPIInit(deviceId,&spi_config))) {
        LOGE("tlApiSecSPIInit: retval = 0x%x", retval);
        return retval;
    } else {
        LOGI("spiOpen success");
        is_secure_spi_opened = TRUE;
    }

    if (ESESTATUS_SUCCESS != iso7816_init()) {
        LOGE("iso7816_init fail");
        return RESULT_SPI_INIT_FAILED;
    }

    return retval;
}

int spiClose() {
    int retval = 0;
    uint32_t deviceId = ESE_SPI_DEVICE_ID;

    if (is_secure_spi_opened == TRUE) {
        iso7816_deinit();

        if (0 != (retval = tlApiSecSPIExit(deviceId))) {
            LOGE("tlApiSecSPIExit: retval = %d", retval);
            return retval;
        } else {
            LOGI("spiClose success");
            is_secure_spi_opened = FALSE;
        }
    } else {
        LOGI("Skip spiClose, spi is not opened");
    }
    return retval;
}
#endif

#ifdef USE_BLOWFISH
int spiOpen() {
    uint32_t deviceId = ESE_SPI_DEVICE_ID;
    TEE_Result res = TEE_SUCCESS;

#ifdef COMMON_VENDOR
    if (chip_vendor == 0) {
        LOGE("spiOpen is not supported, use spiOpenWithChipVendor API");
        return RESULT_NOT_SUPPORTED;
    }
#endif

    res = TEES_SPIInit(deviceId, NULL, &handler);
    if (res != TEE_SUCCESS) {
        LOGE("Failed to initalize SPI, tee_err: %#x", res);
        handler = NULL;
        return res;
    }

    if (ESESTATUS_SUCCESS != iso7816_init()) {
        LOGE("iso7816_init fail");
        return RESULT_SPI_INIT_FAILED;
    }

    return res;
}

int spiClose() {
    iso7816_deinit();

    if (NULL != handler) {
        if (TEES_SPIExit(handler)) {
            LOGE("Failed to close SPI device");
        }

        handler = NULL;
    } else {
        LOGE("do not SPIExit() because TEE isn't initialized");
    }

    return 0;
}
#endif

#ifdef USE_TRUSTY_UNISOC
int spiOpen() {
    int res = 0;
#ifdef COMMON_VENDOR
    if (chip_vendor == 0) {
        LOGE("spiOpen is not supported, use spiOpenWithChipVendor API");
        return RESULT_NOT_SUPPORTED;
    }
#endif

    return res;
}

int spiClose() {
    iso7816_deinit();
    return 0;
}
#endif


#ifdef COMMON_VENDOR
int spiOpenWithChipVendor(uint8_t chipVendor) {
    switch (chipVendor) {
        case CHIP_VENDOR_NXP_JCOP40:
            LOGI("eSE chip vendor: NXP(JCOP40 or over)");
            break;
        case CHIP_VENDOR_THALES_UT20:
            LOGI("eSE chip vendor: Thales(UT20 to UT50)");
            break;
        case CHIP_VENDOR_THALES_UT51:
            LOGI("eSE chip vendor: Thales(UT51)");
            break;
        case CHIP_VENDOR_THALES_UT60:
            LOGI("eSE chip vendor: Thales(UT60 or over)");
            break;
        default:
            LOGE("Not supported eSE chip vendor : %d", chipVendor);
            return RESULT_NOT_SUPPORTED;
    }

    chip_vendor = chipVendor;
    return spiOpen();
}
#endif

ESESTATUS secEseOpen(uint8_t* channelId) {
    ESESTATUS status = ESESTATUS_SUCCESS;
    //int result = -1;
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;
    uint8_t rpduData[MAX_BUFFER_SIZE]= {0,};

    LOGD("start secEseOpen");
    LOGI("Library version : %s", LIB_VER);

    memset(&cpdu, 0x00, sizeof(secEse_7816_cpdu_t));
    memset(&rpdu, 0x00, sizeof(secEse_7816_rpdu_t));
    cpdu.cla = 0x00;
    cpdu.ins = 0x70;
    cpdu.p1 = 0x00;
    cpdu.p2 = 0x00;
    cpdu.cpdu_type = 0x00;
    cpdu.lc = 0x00;
    cpdu.le_type = 0x01;
    cpdu.le = 0x01;
    cpdu.pdata = NULL;

    rpdu.pdata = rpduData;
    rpdu.len = cpdu.le;

    status = iso7816_transceive(&cpdu, &rpdu);

    if ((status == ESESTATUS_SUCCESS) && ((rpdu.sw1 != 0x90) || (rpdu.sw2 != 0x00))) {
        LOGD("secEseOpen Abnormal Status Word");
        status = (rpdu.sw1 << 8)|(rpdu.sw2) ;
    } else if (status == ESESTATUS_SUCCESS && rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00){
        if (rpdu.len != 1) {
            LOGD("secEseOpen invalid channel ID length");
            status = ESESTATUS_INVALID_CHANNLE_ID;
        } else {
            *channelId = rpdu.pdata[0];
            if (*channelId > 3){
                LOGD("secEseOpen invalid channel ID");
                status = ESESTATUS_INVALID_CHANNLE_ID;
            }
            LOGD("secEseOpen Channel %02x is opened", *channelId);
        }
    }
    LOGD("secEseOpen result is %04x", status);
    LOGD("end secEseOpen");

    return status;
}

ESESTATUS secEseClose(uint8_t channelId) {
    ESESTATUS status = ESESTATUS_SUCCESS;
    //int result = -1;
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;
    uint8_t rpduData[MAX_BUFFER_SIZE] = {0,};

    LOGD("start secEseClose");
    LOGI("Library version : %s", LIB_VER);

    if (channelId > 3 /*|| usedChannel[channelId] == 0*/) {
        LOGE("Invalid channelId");
        return ESESTATUS_INVALID_CHANNLE_ID;
    }

    memset(&cpdu,0x00,sizeof(secEse_7816_cpdu_t));
    memset(&rpdu,0x00,sizeof(secEse_7816_rpdu_t));
    cpdu.cla = 0x00;
    cpdu.ins = 0x70;
    cpdu.p1 = 0x80;
    cpdu.p2 = channelId;
    cpdu.cpdu_type = 0x00;
    cpdu.lc = 0x00;
    cpdu.le_type = 0x00;
    cpdu.pdata = NULL;

    rpdu.pdata = rpduData;
    rpdu.len = cpdu.le;

    status = iso7816_transceive(&cpdu, &rpdu);

    if ((status == ESESTATUS_SUCCESS) && ((rpdu.sw1 != 0x90) || (rpdu.sw2 != 0x00))) {
        LOGD("secEseClose Abnormal Status Word");
        status = (rpdu.sw1 << 8)|(rpdu.sw2);
    }
    //usedChannel[channelId] = 0;
    LOGD("secEseClose result is %04x", status);
    LOGD("end secEseClose");
    return status;
}

ESESTATUS secEseSelect(uint8_t channelId, uint8_t *aid, uint8_t offset, uint8_t length, p_secEse_7816_rpdu_t pRsp) {
    ESESTATUS status = ESESTATUS_SUCCESS;
    secEse_7816_cpdu_t cpdu;

    if (channelId > 3 /*|| usedChannel[channelId] == 0*/) {
        LOGE("Invalid channelId");
        return ESESTATUS_INVALID_CHANNLE_ID;
    }

    if (offset != 0){ // offset parameter is deprecated. but API declaration can't be changed because of compatibility.
        LOGE("Invalid offset %d", offset);
        return ESESTATUS_INVALID_OFFSET;
    }

    cpdu.cla = 0x00;
    cpdu.ins = 0xA4;
    cpdu.p1 = 0x04;
    cpdu.p2 = 0x00;
    cpdu.lc = length;
    cpdu.cpdu_type = 0x00;
    cpdu.pdata = aid + offset;
    cpdu.le = 0x00;
    cpdu.le_type = 0x01;

    status = secEseTransmit(channelId, &cpdu, pRsp);
    LOGD("secEseSelect status is %04x", status);

    return status;
}

ESESTATUS secEseTransmit(uint8_t channelId, p_secEse_7816_cpdu_t pCmd, p_secEse_7816_rpdu_t pRsp) {
    ESESTATUS result = ESESTATUS_SUCCESS;

    LOGI("Library version : %s", LIB_VER);

    if (channelId > 3 /*|| usedChannel[channelId] == 0*/) {
        LOGE("Invalid channelId");
        return ESESTATUS_INVALID_CHANNLE_ID;
    } else if ((pCmd->cla & 0x80) == 0x00 && (pCmd->cla & 0x60) != 0x20) {
        if (pCmd->ins == 0x70) {
            LOGE("Invalid prameter. MANAGE CHANNEL command not allowed");
            return ESESTATUS_INVALID_INS;
        }
    }
    channelMasking(channelId, pCmd);

    result = iso7816_transceive(pCmd, pRsp);
    LOGD("secEseTransmit result is %04x", result);

    return result;
}

ESESTATUS secEseAPDUTransmit(uint8_t channelId, uint8_t* pApdu, uint16_t apduLen, p_secEse_7816_rpdu_t pRsp) {
    ESESTATUS result = ESESTATUS_SUCCESS;

    LOGI("Library version : %s", LIB_VER);

    if (channelId > 3 /*|| usedChannel[channelId] == 0*/) {
        LOGE("Invalid channelId");
        return ESESTATUS_INVALID_CHANNLE_ID;
    }

    pApdu[0] = (pApdu[0] & 0xfc) | channelId;

    result = iso7816_apdu_transceive(apduLen, pApdu, pRsp);
    LOGD("secEseAPDUTransmit result is %04x", result);

    return result;
}

/* initProcess function should be exist even though this function always return ESESTATUS_SUCCESS.
because samsungPay TA is using this API */
ESESTATUS initProcess(){
    return ESESTATUS_SUCCESS;
}

