chen
2024-11-08 cc432b761c884a0bd8e9d83db0a4e26109fc08b1
keil/include/components/se/src/T1.c
对比新文件
@@ -0,0 +1,1670 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "T1.h"
#include "phdriver.h"
#include "se_api.h"
#include "mk_misc.h"
#include "mk_trace.h"
static uint8_t gp_data_tx[270];
static uint8_t gp_data_tx_bck[270];
uint8_t gp_data_rx[270];
static T1_params g_T1_params;
static uint8_t g_all_data_buf[1024];
atr_info g_atr = {
    .len = 0x13,
    .vendor_ID = {0x00},
    .dll_IC = 0x01,
    .bgt = {0x00, 0x01},
    .bwt = {0x03, 0xE8},
    .max_freq = {0x4E, 0x20},
    .checksum = 0x00,
    .default_IFSC = 0xFE,
    .num_channels = 0x01,
    .max_IFSC = {0x00, 0xFF},
    .capbilities = {0x00, 0x14}, // Extended frame length feature doesn't support
};
uint32_t g_recv_total_len = 0;
static uint8_t t1_calculate_LRC(uint8_t *p_data, uint16_t offset, uint16_t len);
static uint16_t t1_calculate_CRC(uint8_t *p_data, uint16_t offset, uint16_t len);
static void t1_set_epilogue(uint8_t *p_data, uint16_t offset, uint16_t len);
static ESESTATUS t1_read(uint16_t *p_data_len);
static uint8_t set_info_len(uint8_t *p_data, uint16_t info_len);
static uint16_t get_info_len(uint8_t *p_data);
static ESESTATUS decode_ATR(uint8_t *p_data, bool is_CIP);
static void free_tx_part_mem(void);
static void reset_for_resync_rsp(void);
static ESESTATUS do_T1_recovery_at_decode_Iframe(void);
static ESESTATUS do_T1_recovery_at_decode_Sframe(void);
static ESESTATUS do_T1_recovery_at_decode_Rframe(void);
static ESESTATUS t1_recv_data_store_in_list(uint8_t *p_data, uint16_t data_len, uint16_t total_len);
static void t1_recv_data_list_destroy(void);
static void reset_ATR(void);
/******************************************************************************
 * @Function     Transmit_receive_process
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS Transmit_receive_process(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    g_ese_ctx.is_read_done = false;
    g_recv_total_len = 0;
    while (STATE_IDEL != g_ese_ctx.next_T1_state)
    {
        switch (g_ese_ctx.p_T1_params->tx_frame_type)
        {
            case IFRAME:
            {
                status = t1_send_Iframe();
                break;
            }
            case RFRAME:
            {
                status = t1_send_Rframe();
                break;
            }
            case SFRAME:
            {
                status = t1_send_Sframe();
                break;
            }
            case FRAME_TYPE_INVALID_MAX:
            case FRAME_TYPE_INVALID_MIN:
            {
                status = ESESTATUS_INVALID_PARAMETER;
                LOG_INFO(TRACE_MODULE_SE, "%s : invalid T1 frame type: %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_frame_type);
            }
        }
        if (ESESTATUS_SUCCESS == status)
        {
#ifdef DBG_LEVEL_STACK
            gDumpStackFlag = false;
#endif
            g_ese_ctx.p_T1_params->blk_retry_cnt = 0;
            status = response_process();
            // Do not need handle the status value
        }
        else
        {
            if (((ESESTATUS_PH_IO != status) && (ESESTATUS_MEM_EXCEPTION != status)) || (g_ese_ctx.p_T1_params->blk_retry_cnt >= g_ese_ctx.max_blk_retry_cnt))
            {
                LOG_INFO(TRACE_MODULE_SE, "%s: send frame failed, frameType = %d, status = %d, retryCnt = %d\r\n", __FUNCTION__,
                         g_ese_ctx.p_T1_params->tx_frame_type, status, g_ese_ctx.max_blk_retry_cnt);
                g_ese_ctx.next_T1_state = STATE_IDEL;
                break;
            }
            else
            {
                // resend
                g_ese_ctx.p_T1_params->blk_retry_cnt++;
            }
        }
    }
    return status;
}
/******************************************************************************
 * @Function     response_process
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS response_process(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    uint16_t data_len = 0;
    // LOG_INFO(TRACE_MODULE_SE, "%s: enter\r\n", __FUNCTION__);
    status = t1_read(&data_len);
    if (ESESTATUS_SUCCESS == status)
    {
        status = t1_chk_epilogue(gp_data_rx, 0, data_len);
        if (status == ESESTATUS_SUCCESS)
        {
            status = t1_decode_frame(data_len);
            if (ESESTATUS_SUCCESS == status)
            {
            }
        }
        else
        {
            do_T1_recovery_at_undecode();
        }
    }
    else if (ESESTATUS_FATAL_ERROR == status)
    {
        g_ese_ctx.next_T1_state = STATE_IDEL;
    }
    else
    {
        do_T1_recovery_at_undecode();
    }
    return status;
}
/******************************************************************************
 * @Function         t1_send_Sframe
 * @Returns          On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
#endif
ESESTATUS t1_send_Sframe(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    int ret = -1;
    uint8_t frame_len = 0;
    if (SFRAME_TYPE_INVALID == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
    {
        LOG_INFO(TRACE_MODULE_SE, "%s : invalid S-block frame type: %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type);
        return ESESTATUS_INVALID_PARAMETER;
    }
    else
    {
        frame_len = get_header_len(true);
    }
    // memset(gp_data_tx, 0, sizeof(gp_data_tx));
    switch (g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
    {
        case RESYNC_REQ:
        {
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | RESYNC_REQ);
            break;
        }
        case IFS_REQ:
        {
            uint8_t len_offset = 0, info_len = 0x02;
            frame_len += info_len;
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | IFS_REQ);
            len_offset = set_info_len(gp_data_tx, info_len);
            gp_data_tx[len_offset + 1] = (uint8_t)(g_ese_ctx.max_IFSD >> 8);
            gp_data_tx[len_offset + 2] = (uint8_t)(g_ese_ctx.max_IFSD & 0xFF);
            break;
        }
        case IFS_RSP:
        {
            uint8_t len_offset = 0, info_len = 0;
            info_len = (uint8_t)get_info_len(gp_data_rx);
            frame_len += info_len;
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | IFS_REQ);
            len_offset = set_info_len(gp_data_tx, info_len);
            memcpy(&gp_data_tx[len_offset + 1], &gp_data_rx[len_offset + 1], info_len);
            break;
        }
        case ABORT_REQ:
        {
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | ABORT_REQ);
            break;
        }
        case WTX_RSP:
        {
            uint8_t len_offset = 0, info_len = 1;
            frame_len += info_len;
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | WTX_RSP);
            len_offset = set_info_len(gp_data_tx, info_len);
            gp_data_tx[len_offset + 1] = g_ese_ctx.p_T1_params->wtx_info;
            break;
        }
        case CIP_REQ:
        {
            /* Note:T1 CIP_REQ for ATR, the frame's INFO length should be 1 byte,
             */
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | CIP_REQ);
            break;
        }
        case PROP_END_APDU_REQ:
        {
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | PROP_END_APDU_REQ);
            break;
        }
        case HARD_RESET_REQ:
        {
            break;
        }
        case ATR_REQ:
        {
            gp_data_tx[T1_PCB_OFFSET] = (T1_S_BLOCK_REQ_MASK | ATR_REQ);
            break;
        }
        default:
        {
            LOG_INFO(TRACE_MODULE_SE, "%s : invalid S-block frame type: %X\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type);
            break;
        }
    }
    gp_data_tx[T1_NAD_OFFSET] = NAD_D2C;
    // caculate LRC or CRC and set it to pFramebuff
    t1_set_epilogue(gp_data_tx, 0, frame_len);
    ret = phdriver_write(gp_data_tx, frame_len);
    if (-1 == ret)
    {
        status = ESESTATUS_PH_IO;
        LOG_INFO(TRACE_MODULE_SE, "write fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret);
    }
    return status;
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
/******************************************************************************
 * @Function         t1_send_Iframe
 * @Returns          On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_send_Iframe(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    int ret = -1;
    uint16_t frame_len = 0;
    uint8_t *p_frame_buf = NULL;
    uint16_t len_offset = 0;
    uint16_t send_len = 0;
    uint16_t tx_data_offset = 0;
    if (g_ese_ctx.p_T1_params->recovery_cnt > g_ese_ctx.max_recovery_cnt)
    {
        LOG_INFO(TRACE_MODULE_SE, "%s fatal error, recovery_cnt = %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->recovery_cnt);
        status = ESESTATUS_FATAL_ERROR;
        goto cleanup;
    }
    else if ((g_ese_ctx.p_T1_params->p_data_tx_part != NULL))
    {
        // LOG_INFO(TRACE_MODULE_SE, "%s retry_send_part, tx_len_part = %u\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_len_part);
        p_frame_buf = g_ese_ctx.p_T1_params->p_data_tx_part;
        frame_len = g_ese_ctx.p_T1_params->tx_len_part;
        goto retry_send_part;
    }
    tx_data_offset = g_ese_ctx.p_T1_params->tx_data_offset;
    frame_len = (g_ese_ctx.is_T1_ext_hdr_len ? T1_EXT_HEADER_LEN : T1_HEADER_LEN) + ((LRC == g_atr.checksum) ? T1_LRC_LEN : T1_CRC_LEN);
    if ((g_ese_ctx.p_T1_params->tx_len - tx_data_offset) > g_ese_ctx.max_IFSC)
    {
        g_ese_ctx.p_T1_params->is_device_chaining = true;
        send_len = g_ese_ctx.max_IFSC;
        tx_data_offset += g_ese_ctx.max_IFSC;
    }
    else
    {
        g_ese_ctx.p_T1_params->is_device_chaining = false;
        send_len = g_ese_ctx.p_T1_params->tx_len - tx_data_offset;
        tx_data_offset += send_len;
    }
    frame_len += send_len;
    // memset(gp_data_tx, 0, sizeof(gp_data_tx));
    p_frame_buf = gp_data_tx;
    p_frame_buf[T1_NAD_OFFSET] = NAD_D2C;
    len_offset = set_info_len(p_frame_buf, send_len);
    memcpy((p_frame_buf + len_offset + 1), (g_ese_ctx.p_T1_params->p_data_tx + g_ese_ctx.p_T1_params->tx_data_offset), send_len);
    g_ese_ctx.p_T1_params->tx_data_offset = tx_data_offset;
    // memset(gp_data_tx_bck, 0, sizeof(gp_data_tx_bck));
    memcpy(gp_data_tx_bck, p_frame_buf, frame_len);
    g_ese_ctx.p_T1_params->p_data_tx_part = gp_data_tx_bck;
    g_ese_ctx.p_T1_params->tx_len_part = frame_len;
retry_send_part:
    p_frame_buf[T1_PCB_OFFSET] = 0x00;
    if (g_ese_ctx.p_T1_params->is_device_chaining)
    {
        p_frame_buf[T1_PCB_OFFSET] |= T1_CHAINING_MASK;
    }
    p_frame_buf[T1_PCB_OFFSET] |= (g_ese_ctx.seq_num_device << 6);
    t1_set_epilogue(p_frame_buf, 0, frame_len);
    ret = phdriver_write(p_frame_buf, frame_len);
    if (-1 == ret)
    {
        status = ESESTATUS_PH_IO;
        LOG_INFO(TRACE_MODULE_SE, "write fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret);
    }
cleanup:
    if (S_ABORT_RSP == g_ese_ctx.next_T1_state)
    {
        g_ese_ctx.next_T1_state = STATE_IDEL;
        free_tx_part_mem();
    }
    return status;
}
/******************************************************************************
 * @Function         t1_send_Rframe
 * @Returns          On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_send_Rframe(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    int ret = -1;
    uint8_t frame_len = 0;
    uint8_t *p_frame_buff = gp_data_tx;
    if (RNACK_INVALID_ERROR == g_ese_ctx.p_T1_params->tx_sub_Rframe_type)
    {
        LOG_INFO(TRACE_MODULE_SE, "%s : invalid R-block frame type: %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type);
        return ESESTATUS_INVALID_PARAMETER;
    }
    else
    {
        frame_len = get_header_len(true);
    }
    // memset(gp_data_tx, 0, sizeof(gp_data_tx));
    // pFramebuff = gp_data_tx;
    if (RNACK_PARITY_ERROR == g_ese_ctx.p_T1_params->tx_sub_Rframe_type)
    {
        p_frame_buff[1] = 0x81;
    }
    else if (RNACK_OTHER_ERROR == g_ese_ctx.p_T1_params->tx_sub_Rframe_type)
    {
        p_frame_buff[1] = 0x82;
    }
    else
    { // if (RACK == g_ese_ctx.p_T1_params->subRFrameType) {
        p_frame_buff[1] = 0x80;
    }
    p_frame_buff[1] |= (g_ese_ctx.seq_num_card << 4);
    p_frame_buff[T1_NAD_OFFSET] = NAD_D2C;
    // caculate LRC or CRC and set it to pFramebuff
    t1_set_epilogue(p_frame_buff, 0, frame_len);
    ret = phdriver_write(p_frame_buff, frame_len);
    if (-1 == ret)
    {
        status = ESESTATUS_PH_IO;
        LOG_INFO(TRACE_MODULE_SE, "write fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret);
    }
    else
    {
        // LOG_INFO(TRACE_MODULE_SE, "\nTx", 2, pFramebuff, frameLen);
        // LOG_INFO(TRACE_MODULE_SE, "\n");
    }
    if (NULL == p_frame_buff)
    {
        LOG_INFO(TRACE_MODULE_SE, "%s failed, frame buffer malloc memory failed\r\n", __FUNCTION__);
        status = ESESTATUS_MEM_EXCEPTION;
    }
    return status;
}
/******************************************************************************
 * @Function     t1_calculate_LRC
 * @Param        p_data - data to compute the LRC over.
 *               offset - calculate start offset.
 *               len    - data length, not include the epilogue byte.
 * @Returns      On success return the LRC of the data.
 ******************************************************************************/
static uint8_t t1_calculate_LRC(uint8_t *p_data, uint16_t offset, uint16_t len)
{
    uint8_t LRC = 0;
    uint16_t i = 0;
    for (i = offset; i < len; i++)
    {
        LRC = LRC ^ p_data[i];
    }
    return LRC;
}
/******************************************************************************
 * @Function     t1_calculate_CRC
 * @Param        p_data - data to compute the CRC over.
 *               offset - calculate start offset.
 *               len    - data length, not include the epilogue bytes..
 * @Returns      On success return the CRC of the data.
 ******************************************************************************/
static uint16_t t1_calculate_CRC(uint8_t *p_data, uint16_t offset, uint16_t len)
{
    uint16_t crc;
    crc = (uint16_t)CRC_PRESET;
    int i, j;
    for (i = offset; i < len; i++)
    {
        crc = crc ^ ((unsigned short)p_data[i]);
        for (j = 0; j < 8; j++)
        {
            if ((crc & 0x0001) == 0x0001)
            {
                crc = (crc >> 1) ^ CRC_POLYNOMIAL;
            }
            else
            {
                crc = crc >> 1;
            }
        }
    }
    crc = ~crc;
    return crc;
}
/******************************************************************************
 * @Function     t1_set_epilogue
 * @Param        p_data - data to compute the LRC or CRC over.
 *               offset - calculate start offset.
 *               len    - data length, include the epilogue byte(s).
 ******************************************************************************/
static void t1_set_epilogue(uint8_t *p_data, uint16_t offset, uint16_t len)
{
    if ((LRC == g_atr.checksum) ||
        (CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
        /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/
        || (CIP_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
        /*|| (ATR_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/)
    {
        // LRC
        p_data[len - 1] = t1_calculate_LRC(p_data, offset, len - 1);
    }
    else
    {
        const uint16_t CRC = t1_calculate_CRC(p_data, offset, len - 2);
        p_data[len - 2] = (uint8_t)(CRC >> 8);
        p_data[len - 1] = (uint8_t)CRC;
    }
}
/******************************************************************************
 * @Function     t1_chk_epilogue
 * @Param        p_data  - data to compute the LRC or CRC over.
 *               offset - calculate start offset.
 *               len    - data length, include the epilogue byte(s).
 * @Returns      ESESTATUS_SUCCESS if caculate result is equal to response's epilogue,
 *               else ESESTATUS_PARITY_ERROR.
 ******************************************************************************/
ESESTATUS t1_chk_epilogue(uint8_t *p_data, uint16_t offset, uint16_t len)
{
    ESESTATUS status = ESESTATUS_PARITY_ERROR;
    /* Note:T1 CIP_REQ for ATR, the frame's INFO length should be 1 byte,
     *      do not support 2 bytes length.
     *      And epiLogue field should use LRC (1 byte).
     */
    if ((LRC == g_atr.checksum) ||
        (CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
        /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/
        || (CIP_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
        /*|| (ATR_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/)
    {
        // LRC
        const uint8_t LRC = t1_calculate_LRC(p_data, offset, len - 1);
        if (LRC == p_data[len - 1])
        {
            status = ESESTATUS_SUCCESS;
        }
    }
    else
    {
        uint16_t rspCRC = (uint16_t)(((uint16_t)p_data[len - 2]) << 8);
        rspCRC |= p_data[len - 1];
        const uint16_t CRC = t1_calculate_CRC(p_data, offset, len - 2);
        if (CRC == rspCRC)
        {
            status = ESESTATUS_SUCCESS;
        }
    }
    return status;
}
/******************************************************************************
 * @Function     t1_read
 * @Param        p_data_len - point to data length.
 * @Returns      On success return ESESTATUS_SUCCESS, else ESESTATUS_xxx.
 ******************************************************************************/
static ESESTATUS t1_read(uint16_t *p_data_len)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    int ret = -1;
    const uint32_t sof_max_cnt = g_ese_ctx.max_read_retry_cnt;
    uint32_t sof_cnt = 0;
    uint16_t total_cnt = 0, num_Bytes_to_read = 0, read_index = 0;
#ifdef USE_SPI_SPLIT_READ
    const uint8_t hdrLen = get_header_len(false) + 1;
#else
    const uint8_t hdrLen = g_ese_ctx.max_IFSD;
#endif
#ifdef DBG_LEVEL_STACK
    if (gDumpStackFlag)
    {
        dumpCallstack();
    }
    gDumpStackFlag = true;
#endif
    // memset(gp_data_rx, 0x00, sizeof(gp_data_rx));
    do
    {
        sys_timer_delay_ms(1); // 10
        ret = phdriver_read(gp_data_rx, 1);
        if ((ret < 0) || (NAD_C2DT != gp_data_rx[0]))
        {
            sof_cnt++;
            continue;
        }
        else
        {
            phdriver_read(gp_data_rx + 1, (hdrLen - 1));
            if (g_ese_ctx.is_T1_ext_hdr_len)
            {
                num_Bytes_to_read = (uint16_t)(((uint16_t)gp_data_rx[T1_FRAME_LEN_OFFSET]) << 8);
                num_Bytes_to_read |= gp_data_rx[T1_FRAME_LEN_OFFSET2];
                if (CRC == g_atr.checksum)
                {
                    num_Bytes_to_read += 1;
                }
            }
            else
            {
                num_Bytes_to_read = gp_data_rx[T1_FRAME_LEN_OFFSET];
            }
            read_index = hdrLen;
            total_cnt += hdrLen;
            // LOG_INFO(TRACE_MODULE_SE, "_spi_read() [HDR] read data right!! \r\n");
            break;
        }
    } while (sof_cnt < sof_max_cnt);
    /*SOF Read timeout happened, go for frame retransmission*/
    if (sof_cnt == sof_max_cnt)
    {
        if (ret >= 0)
        {
            ret = -1;
            status = ESESTATUS_PH_IOR_INVALID_DATA;
        }
        else
        {
            status = ESESTATUS_PH_IO;
        }
        // LOG_INFO(TRACE_MODULE_SE, "_spi_read() [HDR] execption, ret = %d, sofCnt = %X\r\n", ret, sofCnt);
    }
#ifdef USE_SPI_SPLIT_READ
    if (ret < 0)
    {
        if ((-1 == ret) && (4 == errno))
        {
            // Interrupted system call, is NFC_DLD_FLUSH
            status = ESESTATUS_FATAL_ERROR;
        }
    }
    else
    {
        if (0 != num_Bytes_to_read)
        {
            ret = phdriver_read(&gp_data_rx[read_index], num_Bytes_to_read);
            if (ret < 0)
            {
                status = ESESTATUS_PH_IO;
                LOG_INFO(TRACE_MODULE_SE, "%s _spi_read() [payload] execption, ret = %x, errno = %d\r\n", __FUNCTION__, ret, errno);
            }
            else
            {
                // LOG_INFO(TRACE_MODULE_SE, " _spi_read() [payload] right!!!!!!!!!!!!!!\r\n");
                total_cnt += num_Bytes_to_read;
            }
        }
    }
#endif
    if (ESESTATUS_SUCCESS != status)
    {
        *p_data_len = 0;
        // LOG_INFO(TRACE_MODULE_SE, "RxFail\r\n");
        // LOG_INFO(TRACE_MODULE_SE, "read fail: %s, errno = %d, ret = %d\r\n", __FUNCTION__, errno, ret);
    }
    else
    {
        *p_data_len = total_cnt;
        // LOG_INFO(TRACE_MODULE_SE, "Rx\r\n");
    }
    return status;
}
/******************************************************************************
 * @Function     t1_decode_frame
 * @Param        data_len - data length.
 * @Returns      On success return ESESTATUS_SUCCESS, else ESESTATUS_xxx.
 ******************************************************************************/
ESESTATUS t1_decode_frame(uint16_t data_len)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    uint8_t pcb = gp_data_rx[T1_PCB_OFFSET];
    T1_pcb_bits *p_pcb_bits;
    if (g_ese_ctx.p_T1_params)
    {
        p_pcb_bits = &g_ese_ctx.p_T1_params->last_rx_pcb_bits;
    }
    else
    {
        LOG_INFO(TRACE_MODULE_SE, "p_T1_params is NULL\r\n");
        return ESESTATUS_INVALID_PCB;
    }
    // memset(p_pcb_bits, 0x00, sizeof(T1_pcb_bits));
    memcpy(p_pcb_bits, &pcb, sizeof(uint8_t));
    uint16_t infoLen = get_info_len(gp_data_rx);
    uint8_t dataOffset = get_header_len(false);
    if (0x00 == p_pcb_bits->msb)
    {
        // I-FRAME decoded
        g_ese_ctx.p_T1_params->last_rx_frame_type = IFRAME;
        g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = SFRAME_TYPE_INVALID;
        g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_INVALID_ERROR;
        g_ese_ctx.p_T1_params->wtx_cnt = 0;
        if (g_ese_ctx.is_seq_num_dr && (p_pcb_bits->bit7 != g_ese_ctx.seq_num_card))
        {
            g_ese_ctx.seq_num_card ^= 0x01;
        }
        g_ese_ctx.is_seq_num_dr = false;
        if (p_pcb_bits->bit7 == g_ese_ctx.seq_num_card)
        {
            g_ese_ctx.p_T1_params->recovery_cnt = 0;
            g_ese_ctx.p_T1_params->resync_CIP_req_cnt = 0;
            g_ese_ctx.is_resync_recovery_flag = false;
            if (p_pcb_bits->bit6)
            {
                g_ese_ctx.p_T1_params->is_card_chaining = true;
                g_ese_ctx.seq_num_card = (g_ese_ctx.seq_num_card ^ 0x01);
                status = t1_recv_data_store_in_list(&gp_data_rx[dataOffset], infoLen, data_len);
                if (ESESTATUS_SUCCESS != status)
                {
                    LOG_INFO(TRACE_MODULE_SE, "%s, t1_recv_data_store_in_list failed, terminate transmission, status = %d\r\n", __FUNCTION__, status);
                    g_ese_ctx.next_T1_state = STATE_IDEL;
                    free_tx_part_mem();
                }
                else
                {
                    // Card response chaining and successfully, then request the next segments data.
                    g_ese_ctx.next_T1_state = R_ACK;
                    g_ese_ctx.p_T1_params->tx_frame_type = RFRAME;
                    g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RACK;
                }
            }
            else
            {
                g_ese_ctx.p_T1_params->is_card_chaining = false;
                status = t1_recv_data_store_in_list(&gp_data_rx[dataOffset], infoLen, data_len);
                if (ESESTATUS_SUCCESS != status)
                {
                    LOG_INFO(TRACE_MODULE_SE, "%s, t1_recv_data_store_in_list failed, terminate transmission, status = %d\r\n", __FUNCTION__, status);
                }
                else
                {
                    // Not chaining, and response success.
                }
                g_ese_ctx.seq_num_device = (g_ese_ctx.seq_num_device ^ 0x01);
                g_ese_ctx.seq_num_card = (g_ese_ctx.seq_num_card ^ 0x01);
                g_ese_ctx.next_T1_state = STATE_IDEL;
                free_tx_part_mem();
            }
        }
        else
        {
            LOG_INFO(TRACE_MODULE_SE, "%s, received invalid seqNum = %02X, seq_num_card = %02X\r\n", __FUNCTION__, p_pcb_bits->bit7, g_ese_ctx.seq_num_card);
            status = do_T1_recovery_at_decode_Iframe();
        }
    }
    else if ((0x01 == p_pcb_bits->msb) && (0x00 == p_pcb_bits->bit7))
    {
        // R-FRAME decoded
        g_ese_ctx.p_T1_params->last_rx_frame_type = RFRAME;
        g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = SFRAME_TYPE_INVALID;
        if ((0x00 == p_pcb_bits->lsb) && (0x00 == p_pcb_bits->bit2))
        {
            g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RACK;
            if ((NULL != g_ese_ctx.p_T1_params->p_data_tx) && g_ese_ctx.p_T1_params->is_device_chaining)
            {
                if (g_ese_ctx.seq_num_device != p_pcb_bits->bit5)
                {
                    // Device chaining, valid card request the next segments of device data to send.
                    // seq_num_device should changed, but the seq_num_card unchanged until received card I-block.
                    g_ese_ctx.seq_num_device = p_pcb_bits->bit5;
                    g_ese_ctx.next_T1_state = I_BLK;
                    g_ese_ctx.p_T1_params->tx_frame_type = IFRAME;
                    g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_INVALID_ERROR;
                    free_tx_part_mem();
                }
                else
                {
                    status = do_T1_recovery_at_decode_Rframe();
                }
            }
            else if (NULL != g_ese_ctx.p_T1_params->p_data_tx)
            {
                status = ESESTATUS_INVALID_PARAMETER;
                LOG_INFO(TRACE_MODULE_SE, "%s: Device initiates unchaining I-block cannot receive RACK, terminate transmit.\r\n", __FUNCTION__);
                // terminate transmit
                g_ese_ctx.next_T1_state = STATE_IDEL;
            }
            else
            {
                g_ese_ctx.next_T1_state = STATE_IDEL;
            }
        }
        else
        {
            g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = SFRAME_TYPE_INVALID;
            if ((0x01 == p_pcb_bits->lsb) && (0x00 == p_pcb_bits->bit2))
            {
                g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_PARITY_ERROR;
                status = ESESTATUS_PARITY_ERROR;
            }
            else if ((0x00 == p_pcb_bits->lsb) && (0x01 == p_pcb_bits->bit2))
            {
                // Other error
                g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_OTHER_ERROR;
                status = ESESTATUS_UNKNOWN_ERROR;
            }
            else
            {
                g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_INVALID_ERROR;
                status = ESESTATUS_UNKNOWN_ERROR;
            }
            // LOG_INFO(TRACE_MODULE_SE, "%s: PCB = 0x%02X, recovery_cnt = %d, max_recovery_cnt = %d\r\n", __FUNCTION__, pcb,
            // g_ese_ctx.p_T1_params->recovery_cnt,
            // g_ese_ctx.max_recovery_cnt);
            do_T1_recovery_at_decode_Rframe();
        }
    }
    else if ((0x01 == p_pcb_bits->msb) && (0x01 == p_pcb_bits->bit7))
    {
        g_ese_ctx.p_T1_params->last_rx_frame_type = SFRAME;
        g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type = RNACK_INVALID_ERROR;
        LOG_INFO(TRACE_MODULE_SE, "%s S-Frame Received\r\n", __FUNCTION__);
        uint8_t subFrameType = pcb & T1_S_BLOCK_SUB_TYPE_MASK;
        if (RESYNC_RSP != subFrameType)
        {
            g_ese_ctx.is_resync_recovery_flag = false;
        }
        switch (subFrameType)
        {
            case RESYNC_RSP:
            {
                g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = RESYNC_RSP;
                status = do_T1_recovery_at_decode_Sframe();
                break;
            }
            case IFS_REQ:
            {
                uint16_t IFSC = 0;
                if (2 == infoLen)
                {
                    IFSC = (uint16_t)(((uint16_t)gp_data_rx[dataOffset]) << 8);
                    IFSC |= gp_data_rx[dataOffset + 1];
                    LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %04X\r\n", __FUNCTION__, IFSC);
                }
                else if (1 == infoLen)
                {
                    IFSC = (uint16_t)gp_data_rx[dataOffset];
                    LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %02X\r\n", __FUNCTION__, IFSC);
                }
                else
                {
                    LOG_INFO(TRACE_MODULE_SE, "%s Invalid IFS_RSP Received\r\n", __FUNCTION__);
                }
                g_ese_ctx.max_IFSC = IFSC;
                g_ese_ctx.next_T1_state = S_IFS_RSP;
                g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Sframe_type = IFS_RSP;
                break;
            }
            case IFS_RSP:
            {
                g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type = IFS_RSP;
                uint16_t IFSD = 0;
                uint8_t offset = get_header_len(false);
                if (2 == infoLen)
                {
                    IFSD = (uint16_t)(((uint16_t)gp_data_rx[offset]) << 8);
                    IFSD |= gp_data_rx[offset + 1];
                    LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %04X\r\n", __FUNCTION__, IFSD);
                }
                else if (1 == infoLen)
                {
                    IFSD = (uint16_t)gp_data_rx[offset];
                    LOG_INFO(TRACE_MODULE_SE, "%s IFS_RSP Received, IFSD = %02X\r\n", __FUNCTION__, IFSD);
                }
                else
                {
                    LOG_INFO(TRACE_MODULE_SE, "%s Invalid IFS_RSP Received\r\n", __FUNCTION__);
                }
                if (g_ese_ctx.max_IFSD != IFSD)
                {
                    LOG_INFO(TRACE_MODULE_SE, "%s : invalid IFS receive paylod, receivedIFSD = %X, sentIFSD = %X\r\n", __FUNCTION__, IFSD, g_ese_ctx.max_IFSD);
                }
                status = do_T1_recovery_at_decode_Sframe();
                break;
            }
            case ABORT_REQ:
            case ABORT_RSP:
            {
                // Rule 9: only chaining cmd or rsp will send (receive) ABORT_REQ
                if (g_ese_ctx.p_T1_params->is_card_chaining || g_ese_ctx.p_T1_params->is_device_chaining)
                {
                    t1_recv_data_list_destroy();
                }
                g_ese_ctx.next_T1_state = STATE_IDEL;
                break;
            }
            case WTX_REQ:
            {
                if (g_ese_ctx.p_T1_params->wtx_cnt <= g_ese_ctx.max_wtx_cnt)
                {
                    g_ese_ctx.p_T1_params->wtx_cnt++;
                    g_ese_ctx.p_T1_params->wtx_info = gp_data_rx[get_header_len(false)];
                    g_ese_ctx.next_T1_state = S_WTX_RSP;
                    g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
                    g_ese_ctx.p_T1_params->tx_sub_Sframe_type = WTX_RSP;
                }
                else
                {
                    LOG_INFO(TRACE_MODULE_SE, "%s : failed, WTX_REQ counter larger than maxWtxCnt\r\n", __FUNCTION__);
                    status = ESESTATUS_FAILED;
                    g_ese_ctx.next_T1_state = STATE_IDEL;
                }
                break;
            }
            case CIP_RSP:
            {
                status = decode_ATR(gp_data_rx, true);
                reset_for_resync_rsp();
                g_ese_ctx.next_T1_state = STATE_IDEL;
                break;
            }
            case PROP_END_APDU_RSP:
            {
                status = ESESTATUS_SUCCESS;
                g_ese_ctx.next_T1_state = STATE_IDEL;
                break;
            }
            case HARD_RESET_RSP:
            {
                status = ESESTATUS_SUCCESS;
                g_ese_ctx.next_T1_state = STATE_IDEL;
                break;
            }
            case ATR_RSP:
            {
                status = decode_ATR(gp_data_rx, false);
                g_ese_ctx.next_T1_state = STATE_IDEL;
                break;
            }
            default:
            {
                status = ESESTATUS_SUCCESS;
                g_ese_ctx.next_T1_state = STATE_IDEL;
                LOG_INFO(TRACE_MODULE_SE, "%s : invalid S-block frame type: %X\r\n", __FUNCTION__, subFrameType);
            }
        }
    }
    else
    {
        // LOG_ERROR(TRACE_MODULE_SE, "[RX]Nothing\r\n");
        LOG_INFO(TRACE_MODULE_SE, "%s Wrong-Frame Received, PCB = %X\r\n", __FUNCTION__, pcb);
        status = ESESTATUS_INVALID_PCB;
    }
    return status;
}
/** Contains the Prologue and (or not) Epilogue field length **/
uint8_t get_header_len(bool contains_epilogue)
{
    uint8_t len = 0;
    bool is_T1_ext_hdr_len = g_ese_ctx.is_T1_ext_hdr_len;
    uint8_t checksum = g_atr.checksum;
    if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && ((CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
                                                             /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/))
    {
        is_T1_ext_hdr_len = false;
        checksum = 0;
    }
    len = (is_T1_ext_hdr_len ? T1_EXT_HEADER_LEN : T1_HEADER_LEN);
    if (contains_epilogue)
    {
        len += ((checksum == 0) ? T1_LRC_LEN : T1_CRC_LEN);
    }
    return len;
}
static uint8_t set_info_len(uint8_t *p_data, uint16_t info_len)
{
    uint8_t len_offset = 0;
    bool is_T1_ext_hdr_len = g_ese_ctx.is_T1_ext_hdr_len;
    if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && ((CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
                                                             /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/))
    {
        is_T1_ext_hdr_len = false;
    }
    if (is_T1_ext_hdr_len)
    {
        p_data[T1_FRAME_LEN_OFFSET] = (uint8_t)(info_len >> 8);
        p_data[T1_FRAME_LEN_OFFSET2] = (uint8_t)(info_len & 0xFF);
        len_offset = T1_FRAME_LEN_OFFSET2;
    }
    else
    {
        p_data[T1_FRAME_LEN_OFFSET] = (uint8_t)(info_len & 0xFF);
        len_offset = T1_FRAME_LEN_OFFSET;
    }
    return len_offset;
}
static uint16_t get_info_len(uint8_t *p_data)
{
    uint16_t info_len = 0;
    bool is_T1_ext_hdr_len = g_ese_ctx.is_T1_ext_hdr_len;
    if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && ((CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)
                                                             /*|| (ATR_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)*/))
    {
        is_T1_ext_hdr_len = false;
    }
    if (is_T1_ext_hdr_len)
    {
        info_len = (uint16_t)(((uint16_t)p_data[T1_FRAME_LEN_OFFSET]) << 8);
        info_len |= p_data[T1_FRAME_LEN_OFFSET2];
    }
    else
    {
        info_len = p_data[T1_FRAME_LEN_OFFSET];
    }
    return info_len;
}
/******************************************************************************
 * @Function     decode_ATR
 * @Param        p_data  - received data and its must be PCB = 0xE4 or 0xE7.
 *               is_CIP  - true if received data's PCB = 0xE4.
 * @Return       ESESTATUS_SUCCESS if decode ATR success, else ESESTATUS_INVALID_T1_LEN.
 ******************************************************************************/
static ESESTATUS decode_ATR(uint8_t *p_data, bool is_CIP)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    uint16_t info_len = get_info_len(p_data);
    uint8_t *p_start = &p_data[T1_FRAME_LEN_OFFSET];
    if (!is_CIP && g_ese_ctx.is_T1_ext_hdr_len)
    {
        // Currently, ATR length is 0x13, exttended frame length high byte should be 0x00
        p_start++;
    }
    if (sizeof(atr_info) == (info_len + 1))
    {
        memcpy(&g_atr.len, p_start, sizeof(atr_info));
    }
    else if (0 == p_data[T1_FRAME_LEN_OFFSET])
    {
        // Do nothing, keep befor ATR value.
        reset_ATR();
    }
    else
    {
        LOG_INFO(TRACE_MODULE_SE, "%s : invalid ATR response AtrInfoLen = %02X\r\n", __FUNCTION__, (uint8_t)sizeof(atr_info));
        status = ESESTATUS_INVALID_T1_LEN;
    }
    if (ESESTATUS_SUCCESS == status)
    {
        g_ese_ctx.max_IFSC = (uint16_t)(((uint16_t)g_atr.max_IFSC[0]) << 8);
        g_ese_ctx.max_IFSC |= g_atr.max_IFSC[1];
        g_ese_ctx.is_T1_ext_hdr_len = (g_atr.capbilities[1] & 0x08) != 0;
    }
    return status;
}
/******************************************************************************
 * @Function     init_Iframe_from_cmd_apdu
 * @Param        p_cmd_apdu - 7816-4 APDU that shall be sent.
 *               cmd_len - Length of the apduCmd to be sent.
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS init_Iframe_from_cmd_apdu(uint8_t *p_cmd_apdu, uint16_t cmd_len)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    g_ese_ctx.p_T1_params = &g_T1_params;
    g_ese_ctx.p_T1_params->is_device_chaining = (cmd_len > g_ese_ctx.max_IFSC ? true : false);
    g_ese_ctx.next_T1_state = I_BLK;
    g_ese_ctx.p_T1_params->tx_frame_type = IFRAME;
    g_ese_ctx.p_T1_params->p_data_tx = p_cmd_apdu;
    g_ese_ctx.p_T1_params->tx_len = cmd_len;
    g_ese_ctx.p_T1_params->tx_data_offset = 0;
    g_ese_ctx.p_T1_params->tx_len_part = 0;
    g_ese_ctx.p_T1_params->p_data_tx_part = NULL;
    g_ese_ctx.p_T1_params->resync_CIP_req_cnt = 0;
    return status;
}
/******************************************************************************
 * @Function     deinit_Iframe_from_cmd_apdu
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
void deinit_Iframe_from_cmd_apdu(void)
{
    if (NULL != g_ese_ctx.p_T1_params)
    {
        g_ese_ctx.p_T1_params->p_data_tx = NULL;
        if (NULL != g_ese_ctx.p_T1_params->p_data_tx_part)
        {
            g_ese_ctx.p_T1_params->p_data_tx_part = NULL;
        }
        g_ese_ctx.p_T1_params = NULL;
    }
}
/******************************************************************************
 * @Function     free_tx_part_mem
 ******************************************************************************/
static void free_tx_part_mem(void)
{
    if (NULL != g_ese_ctx.p_T1_params)
    {
        if (NULL != g_ese_ctx.p_T1_params->p_data_tx_part)
        {
            g_ese_ctx.p_T1_params->p_data_tx_part = NULL;
        }
    }
}
/******************************************************************************
 * @Function     reset_for_resync_rsp
 ******************************************************************************/
static void reset_for_resync_rsp(void)
{
    g_ese_ctx.seq_num_card = 0;
    g_ese_ctx.seq_num_device = 0;
    g_ese_ctx.p_T1_params->recovery_cnt = 0;
    g_ese_ctx.p_T1_params->resync_CIP_req_cnt = 0;
    g_ese_ctx.p_T1_params->wtx_cnt = 0;
    g_ese_ctx.p_T1_params->tx_data_offset = 0;
    if (g_ese_ctx.p_T1_params->is_card_chaining)
    {
        t1_recv_data_list_destroy();
    }
    g_ese_ctx.p_T1_params->is_device_chaining = false;
    g_ese_ctx.p_T1_params->is_card_chaining = false;
}
/******************************************************************************
 * @Function     do_T1_recovery_at_undecode
 * @Returns      On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR.
 ******************************************************************************/
ESESTATUS do_T1_recovery_at_undecode(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    if (g_ese_ctx.p_T1_params->recovery_cnt < g_ese_ctx.max_recovery_cnt)
    {
        g_ese_ctx.p_T1_params->recovery_cnt++;
        if ((SFRAME != g_ese_ctx.p_T1_params->tx_frame_type) || (WTX_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type))
        {
            g_ese_ctx.next_T1_state = R_PARITY_ERR;
            g_ese_ctx.p_T1_params->tx_frame_type = RFRAME;
            g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_PARITY_ERROR;
            // Should use the N(S), that is g_ese_ctx.seq_num_device
        }
    }
    else
    {
        if (((SFRAME != g_ese_ctx.p_T1_params->tx_frame_type) || (WTX_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type)) && !g_ese_ctx.is_resync_recovery_flag)
        {
            g_ese_ctx.is_resync_recovery_flag = true;
            // Do case 4
            g_ese_ctx.next_T1_state = S_RESYNC_REQ;
            g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
            g_ese_ctx.p_T1_params->tx_sub_Sframe_type = RESYNC_REQ;
        }
        else if (g_ese_ctx.is_resync_recovery_flag)
        {
            if (g_ese_ctx.p_T1_params->resync_CIP_req_cnt < g_ese_ctx.max_recovery_cnt)
            {
                g_ese_ctx.p_T1_params->resync_CIP_req_cnt++;
                // Do case 5
                g_ese_ctx.next_T1_state = S_CIP_REQ;
                g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ;
            }
            else
            {
                status = ESESTATUS_FATAL_ERROR;
                g_ese_ctx.next_T1_state = STATE_IDEL;
            }
        }
        else
        {
            // Chip hard reset if warm reset failed.
            if ((SFRAME == g_ese_ctx.p_T1_params->tx_frame_type) && (CIP_REQ == g_ese_ctx.p_T1_params->tx_sub_Sframe_type))
            {
                LOG_INFO(TRACE_MODULE_SE, "%s: warm reset failed, TODO need chip hard reset to recover\r\n", __FUNCTION__);
                // need to chip hard reset
                status = ESESTATUS_FATAL_ERROR;
                g_ese_ctx.next_T1_state = STATE_IDEL;
            }
            else
            {
                LOG_INFO(TRACE_MODULE_SE, "%s: S(... REQ) failed, warm reset to recover lastTxFrameType = %d, lastTxSFrameType = %d\r\n", __FUNCTION__,
                         g_ese_ctx.p_T1_params->tx_frame_type, g_ese_ctx.p_T1_params->tx_sub_Sframe_type);
                g_ese_ctx.next_T1_state = S_CIP_REQ;
                g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ;
            }
        }
    }
    return status;
}
/******************************************************************************
 * @Function     do_T1_recovery_at_decode_Iframe
 * @Returns      On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR.
 ******************************************************************************/
static ESESTATUS do_T1_recovery_at_decode_Iframe(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    T1_frame_types last_rx_frame_type = g_ese_ctx.p_T1_params->last_rx_frame_type;
    T1_pcb_bits *p_pcb_bits = &g_ese_ctx.p_T1_params->last_rx_pcb_bits;
    if (IFRAME == last_rx_frame_type)
    {
        if (g_ese_ctx.p_T1_params->recovery_cnt < g_ese_ctx.max_recovery_cnt)
        {
            g_ese_ctx.p_T1_params->recovery_cnt++;
            if (p_pcb_bits->bit7 != g_ese_ctx.seq_num_card)
            {
                g_ese_ctx.next_T1_state = R_OTHER_ERR;
                g_ese_ctx.p_T1_params->tx_frame_type = RFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_OTHER_ERROR;
            }
            else
            {
                // Cannot be occured this case
                LOG_INFO(TRACE_MODULE_SE,
                         "%s: an I-block received, seqNum exception, terminate transmission. lastTxSeqNum = %d, lastRxExpectedNum = %d, lastRxSeqNum = %d\r\n",
                         __FUNCTION__, g_ese_ctx.seq_num_device, g_ese_ctx.seq_num_card, p_pcb_bits->bit7);
                g_ese_ctx.next_T1_state = STATE_IDEL;
                g_ese_ctx.is_resync_recovery_flag = false;
                status = ESESTATUS_INVALID_PARAMETER;
                free_tx_part_mem();
            }
        }
        else
        {
            // Should transmit RESYNC_REQ to recover.
            LOG_INFO(TRACE_MODULE_SE, "%s: lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = %d RESYNC_REQ should be sent to recover\r\n",
                     __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt);
            // RESYNC_REQ only send once, recovery_cnt should not be reset to zero.
            g_ese_ctx.is_resync_recovery_flag = true;
            g_ese_ctx.next_T1_state = S_RESYNC_REQ;
            g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
            g_ese_ctx.p_T1_params->tx_sub_Sframe_type = RESYNC_REQ;
        }
    }
    else
    {
        status = ESESTATUS_INVALID_PARAMETER;
        LOG_INFO(TRACE_MODULE_SE,
                 "%s: should be called when received an invalid IFrame, but non-IFrame received, lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = "
                 "%d\r\n",
                 __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt);
        g_ese_ctx.next_T1_state = STATE_IDEL;
        free_tx_part_mem();
    }
    return status;
}
/******************************************************************************
 * @Function     do_T1_recovery_at_decode_Sframe
 * @Returns      On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR.
 ******************************************************************************/
static ESESTATUS do_T1_recovery_at_decode_Sframe(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    T1_frame_types last_rx_frame_type = g_ese_ctx.p_T1_params->last_rx_frame_type;
    Sframe_types last_rx_sub_Sframe_type = g_ese_ctx.p_T1_params->last_rx_sub_Sframe_type;
    if ((SFRAME == last_rx_frame_type) && (NULL != g_ese_ctx.p_T1_params->p_data_tx))
    {
        // recovery_cnt will be ignored for RESYNC_RSP and IFS_RSP
        if (RESYNC_RSP == last_rx_sub_Sframe_type)
        {
            reset_for_resync_rsp();
            g_ese_ctx.next_T1_state = I_BLK;
            g_ese_ctx.p_T1_params->tx_frame_type = IFRAME;
            g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID;
            g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_INVALID_ERROR;
        }
        else if (IFS_RSP == last_rx_sub_Sframe_type)
        {
            if (g_ese_ctx.p_T1_params->is_card_chaining)
            {
                g_ese_ctx.next_T1_state = R_ACK;
                g_ese_ctx.p_T1_params->tx_frame_type = RFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID;
                g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RACK;
            }
            else if (g_ese_ctx.p_T1_params->is_device_chaining)
            {
                g_ese_ctx.next_T1_state = I_BLK;
                g_ese_ctx.p_T1_params->tx_frame_type = IFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID;
                g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_INVALID_ERROR;
            }
            else
            {
                LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block I-block is unchaining, terminate transmit when received IFS_RSP\r\n", __FUNCTION__);
                // terminate transmit
                g_ese_ctx.next_T1_state = STATE_IDEL;
            }
        }
        else
        {
            LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is an I-block, lastTxFrameType = %d, but device received R-block, cannot be occurred.\r\n",
                     __FUNCTION__, last_rx_sub_Sframe_type);
            // terminate transmit
            g_ese_ctx.next_T1_state = STATE_IDEL;
        }
    }
    else
    {
        status = ESESTATUS_INVALID_PARAMETER;
        LOG_INFO(TRACE_MODULE_SE,
                 "%s: should be called when received an SFrame, but non-SFrame received, lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = %d\r\n",
                 __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt);
        g_ese_ctx.next_T1_state = STATE_IDEL;
    }
    return status;
}
/******************************************************************************
 * @Function     do_T1_recovery_at_decode_Rframe
 * @Returns      On success return ESESTATUS_SUCCESS, else ESESTATUS_FATAL_ERROR.
 ******************************************************************************/
static ESESTATUS do_T1_recovery_at_decode_Rframe(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    T1_frame_types last_rx_frame_type = g_ese_ctx.p_T1_params->last_rx_frame_type;
    Rframe_types last_rx_sub_Rframe_type = g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type;
    if (RFRAME == last_rx_frame_type)
    {
        if (g_ese_ctx.p_T1_params->recovery_cnt < g_ese_ctx.max_recovery_cnt)
        {
            g_ese_ctx.p_T1_params->recovery_cnt++;
            if ((NULL != g_ese_ctx.p_T1_params->p_data_tx))
            {
                // device initiates block is an I-block
                if (IFRAME == g_ese_ctx.p_T1_params->tx_frame_type)
                {
                    if (RACK == last_rx_sub_Rframe_type)
                    {
                        g_ese_ctx.next_T1_state = R_OTHER_ERR;
                        g_ese_ctx.p_T1_params->tx_frame_type = RFRAME;
                        g_ese_ctx.p_T1_params->tx_sub_Rframe_type = RNACK_OTHER_ERROR;
                        g_ese_ctx.p_T1_params->tx_sub_Sframe_type = SFRAME_TYPE_INVALID;
                        LOG_INFO(TRACE_MODULE_SE, "%s: RACK for RNACK_OTHER_ERROR\r\n", __FUNCTION__);
                    }
                    else if (RNACK_PARITY_ERROR == last_rx_sub_Rframe_type)
                    {
                        g_ese_ctx.next_T1_state = I_BLK;
                        g_ese_ctx.p_T1_params->tx_frame_type = IFRAME;
                        // LOG_INFO(TRACE_MODULE_SE, "%s: RNACK_PARITY_ERROR, resend IFRAME\r\n", __FUNCTION__);
                    }
                    else if (RNACK_OTHER_ERROR == last_rx_sub_Rframe_type)
                    {
                        g_ese_ctx.seq_num_device ^= 0x01;
                        g_ese_ctx.is_seq_num_dr = true;
                        g_ese_ctx.next_T1_state = I_BLK;
                        g_ese_ctx.p_T1_params->tx_frame_type = IFRAME;
                        // LOG_INFO(TRACE_MODULE_SE, "%s: RNACK_OTHER_ERROR, resend IFRAME\r\n", __FUNCTION__);
                    }
                    else
                    {
                        g_ese_ctx.next_T1_state = STATE_IDEL;
                        g_ese_ctx.is_resync_recovery_flag = false;
                        LOG_INFO(
                            TRACE_MODULE_SE,
                            "%s: lastSendIFrame, lastRecvRFrame recovery failed, unkonwn  lastRFrameType = %d, recovery_cnt = %d, max_recovery_cnt = %d\r\n",
                            __FUNCTION__, g_ese_ctx.p_T1_params->last_rx_sub_Rframe_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt);
                    }
                }
                else if (SFRAME == g_ese_ctx.p_T1_params->tx_frame_type)
                {
                    if ((WTX_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) || (IFS_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type) ||
                        (ABORT_RSP == g_ese_ctx.p_T1_params->tx_sub_Sframe_type))
                    {
                        LOG_INFO(TRACE_MODULE_SE,
                                 "%s: device initiates block is an I-block, lastTxSubSFrameType = %d, but device received R-block, cannot be occurred.\r\n",
                                 __FUNCTION__, g_ese_ctx.p_T1_params->tx_sub_Sframe_type);
                        // terminate transmit
                        g_ese_ctx.next_T1_state = STATE_IDEL;
                        g_ese_ctx.is_resync_recovery_flag = false;
                    }
                    else
                    {
                        LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is I-block, lastTxSubSFrameType = %d, recovery_cnt = %d\r\n", __FUNCTION__,
                                 g_ese_ctx.p_T1_params->tx_sub_Sframe_type, g_ese_ctx.p_T1_params->recovery_cnt);
                    }
                }
                else if (RFRAME == g_ese_ctx.p_T1_params->tx_frame_type)
                {
                    LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is I-block, lastTxSubRFrameType = %d, recovery_cnt = %d\r\n", __FUNCTION__,
                             g_ese_ctx.p_T1_params->tx_sub_Rframe_type, g_ese_ctx.p_T1_params->recovery_cnt);
                }
                else
                {
                    // unknown R-block type, terminate transmit
                    g_ese_ctx.next_T1_state = STATE_IDEL;
                    g_ese_ctx.is_resync_recovery_flag = false;
                    LOG_INFO(TRACE_MODULE_SE, "%s: lastSend unknown frame type, recovery_cnt = %d\r\n", __FUNCTION__, g_ese_ctx.p_T1_params->recovery_cnt);
                }
            }
            else if (SFRAME == g_ese_ctx.p_T1_params->tx_frame_type)
            {
                LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block is S-block, lastTxSubSFrameType = %d, recovery_cnt = %d\r\n", __FUNCTION__,
                         g_ese_ctx.p_T1_params->tx_sub_Sframe_type, g_ese_ctx.p_T1_params->recovery_cnt);
            }
            else
            {
                LOG_INFO(TRACE_MODULE_SE, "%s: device initiates block cannot be an R-block, lastTxFrameType = %d\r\n", __FUNCTION__,
                         g_ese_ctx.p_T1_params->tx_frame_type);
                g_ese_ctx.next_T1_state = STATE_IDEL;
                g_ese_ctx.is_resync_recovery_flag = false;
            }
        }
        else
        {
            if (!g_ese_ctx.is_resync_recovery_flag && (NULL != g_ese_ctx.p_T1_params->p_data_tx))
            {
                g_ese_ctx.is_resync_recovery_flag = true;
                g_ese_ctx.next_T1_state = S_RESYNC_REQ;
                g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Sframe_type = RESYNC_REQ;
            }
            else if (g_ese_ctx.is_resync_recovery_flag && (NULL != g_ese_ctx.p_T1_params->p_data_tx))
            {
                free_tx_part_mem();
                g_ese_ctx.is_resync_recovery_flag = false;
                g_ese_ctx.next_T1_state = S_CIP_REQ;
                g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
                g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ;
            }
            else
            {
                status = ESESTATUS_INVALID_PARAMETER;
                LOG_INFO(TRACE_MODULE_SE,
                         "%s: should be called when received an RFrame, but non-RFrame received, lastRecvFrameType = %d, recovery_cnt = %d, max_recovery_cnt = "
                         "%d\r\n",
                         __FUNCTION__, last_rx_frame_type, g_ese_ctx.p_T1_params->recovery_cnt, g_ese_ctx.max_recovery_cnt);
                // terminate transmit
                g_ese_ctx.next_T1_state = STATE_IDEL;
            }
        }
    }
    return status;
}
/******************************************************************************
 * @Function     t1_recv_data_store_in_list
 * @Param        p_data    - 7816-4 APDU response that shall be stored.
 *               data_len  - Length of the APDU response.
 *               total_len - T=1 total length, contains prologue and epilogue.
 * @Returns      On Success ESESTATUS_SUCCESS else ESESTATUS error.
 ******************************************************************************/
static ESESTATUS t1_recv_data_store_in_list(uint8_t *p_data, uint16_t data_len, uint16_t total_len)
{
    if ((0 == data_len) || (data_len != (total_len - get_header_len(true))))
    {
        // Other error, do nothing
        return ESESTATUS_INVALID_T1_LEN;
    }
    // if (g_recv_total_len == 0)
    // {
    //     memset(g_all_data_buf, 0, sizeof(g_all_data_buf));
    // }
    memcpy(g_all_data_buf + g_recv_total_len, p_data, data_len);
    g_recv_total_len += data_len;
    return ESESTATUS_SUCCESS;
}
/******************************************************************************
 * @Function     t1_recv_data_list_destroy
 ******************************************************************************/
static void t1_recv_data_list_destroy(void)
{
    g_recv_total_len = 0;
}
static void reset_ATR(void)
{
    atr_info atr = {
        .len = 0x13,
        .vendor_ID = {0x00},
        .dll_IC = 0x01,
        .bgt = {0x00, 0x01},
        .bwt = {0x03, 0xE8},
        .max_freq = {0x4E, 0x20},
        .checksum = 0x00,
        .default_IFSC = 0xFE,
        .num_channels = 0x01,
        .max_IFSC = {0x00, 0xFF},
        .capbilities = {0x00, 0x14}, // Extended frame length feature doesn't support
    };
    g_atr = atr;
}
/******************************************************************************
 * @Function     t1_transmit_receive_apdu
 * @Param        p_cmd_apdu - 7816-4 APDU that shall be sent.
 *               cmd_len - Length of the apduCmd to be sent.
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_transmit_receive_apdu(uint8_t *p_cmd_apdu, uint16_t cmd_len)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    // LOG_INFO(TRACE_MODULE_SE, "%s: Enter\r\n", __FUNCTION__);
    status = init_Iframe_from_cmd_apdu(p_cmd_apdu, cmd_len);
    if (ESESTATUS_SUCCESS != status)
    {
        goto cleanup;
    }
    status = Transmit_receive_process();
    if (ESESTATUS_SUCCESS != status)
    {
        LOG_INFO(TRACE_MODULE_SE, "%s: t1_transmit_receive_apdu failed, status = %d\r\n", __FUNCTION__, status);
    }
cleanup:
    deinit_Iframe_from_cmd_apdu();
    return status;
}
/******************************************************************************
 * @Function     t1_CIP_req
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_CIP_req(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    // LOG_INFO(TRACE_MODULE_SE, "t1CIPReq() enter\r\n");
    g_ese_ctx.p_T1_params = &g_T1_params;
    g_ese_ctx.p_T1_params->is_device_chaining = false;
    g_ese_ctx.next_T1_state = S_CIP_REQ;
    g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
    g_ese_ctx.p_T1_params->tx_sub_Sframe_type = CIP_REQ;
    status = Transmit_receive_process();
    g_ese_ctx.p_T1_params = NULL;
    return status;
}
/******************************************************************************
 * @Function     t1_ATR_req
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_ATR_req(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    g_ese_ctx.p_T1_params = &g_T1_params;
    g_ese_ctx.p_T1_params->is_device_chaining = false;
    g_ese_ctx.next_T1_state = S_ATR_REQ;
    g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
    g_ese_ctx.p_T1_params->tx_sub_Sframe_type = ATR_REQ;
    status = Transmit_receive_process();
    g_ese_ctx.p_T1_params = NULL;
    return status;
}
/******************************************************************************
 * @Function     t1_IFSD_req
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_IFSD_req(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    g_ese_ctx.p_T1_params = &g_T1_params;
    g_ese_ctx.p_T1_params->is_device_chaining = false;
    g_ese_ctx.next_T1_state = S_IFS_REQ;
    g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
    g_ese_ctx.p_T1_params->tx_sub_Sframe_type = IFS_REQ;
    status = Transmit_receive_process();
    g_ese_ctx.p_T1_params = NULL;
    return status;
}
/******************************************************************************
 * @Function     t1_prop_end_apdu_req
 * @Returns      On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_prop_end_apdu_req(void)
{
    ESESTATUS status = ESESTATUS_SUCCESS;
    g_ese_ctx.p_T1_params = &g_T1_params;
    g_ese_ctx.p_T1_params->is_device_chaining = false;
    g_ese_ctx.next_T1_state = S_PROP_END_APDU_REQ;
    g_ese_ctx.p_T1_params->tx_frame_type = SFRAME;
    g_ese_ctx.p_T1_params->tx_sub_Sframe_type = PROP_END_APDU_REQ;
    status = Transmit_receive_process();
    g_ese_ctx.p_T1_params = NULL;
    return status;
}
/******************************************************************************
 * Function     t1_receive_data_and_get
 * @Param        pp_Data - a pointer address to the received data.
 *               data_len - a pointer to the length of the received data.
 * Returns       On success return ESESTATUS_SUCCESS or else ESESTATUS error.
 ******************************************************************************/
ESESTATUS t1_receive_data_and_get(uint8_t **pp_Data, uint16_t *data_len)
{
    *data_len = (uint16_t)g_recv_total_len;
    *pp_Data = g_all_data_buf;
    return ESESTATUS_SUCCESS;
}