|
#include <errno.h>
|
#include <string.h>
|
#include <stdlib.h>
|
|
#include "phdriver.h"
|
#include "se_api.h"
|
#include "mk_misc.h"
|
#include "mk_trace.h"
|
|
/******************************************************************************
|
* @Function t1_read_no_wait
|
* @Param p_data_len - point to data length.
|
* @Returns On success return ESESTATUS_SUCCESS, else ESESTATUS_xxx.
|
******************************************************************************/
|
static ESESTATUS t1_read_no_wait(uint16_t *p_data_len)
|
{
|
ESESTATUS status = ESESTATUS_SUCCESS;
|
int ret = -1;
|
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));
|
|
// sys_timer_delay_ms(1); // 10
|
|
ret = phdriver_read(gp_data_rx, 1);
|
|
if ((ret < 0) || (NAD_C2DT != gp_data_rx[0]))
|
{
|
return ESESTATUS_NO_DATA_TO_RECEIVE;
|
}
|
else
|
{
|
ret = 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];
|
|
// CRC has 2 bytes, so the second read len is INF len + 1
|
if (CRC == g_atr.checksum)
|
{
|
num_bytes_to_read += 1;
|
}
|
}
|
else
|
{
|
// LRC has 1 bytes, so the second read len is INF len
|
num_bytes_to_read = gp_data_rx[T1_FRAME_LEN_OFFSET];
|
}
|
read_index = hdrLen;
|
total_cnt += hdrLen;
|
}
|
|
#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
|
{
|
status = ESESTATUS_FAILED;
|
}
|
}
|
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;
|
}
|
else
|
{
|
total_cnt += num_bytes_to_read;
|
}
|
}
|
}
|
#endif
|
|
if (ESESTATUS_SUCCESS != status)
|
{
|
*p_data_len = 0;
|
}
|
else
|
{
|
*p_data_len = total_cnt;
|
}
|
|
return status;
|
}
|
|
/******************************************************************************
|
* @Function response_no_wait_process
|
* @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error.
|
******************************************************************************/
|
static ESESTATUS response_no_wait_process(void)
|
{
|
ESESTATUS status = ESESTATUS_SUCCESS;
|
uint16_t data_len = 0;
|
|
status = t1_read_no_wait(&data_len);
|
if (status == ESESTATUS_NO_DATA_TO_RECEIVE)
|
{
|
return ESESTATUS_NO_DATA_TO_RECEIVE;
|
}
|
|
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
|
{
|
status = do_T1_recovery_at_undecode();
|
}
|
}
|
else if (ESESTATUS_FATAL_ERROR == status)
|
{
|
g_ese_ctx.next_T1_state = STATE_IDEL;
|
}
|
else
|
{
|
status = do_T1_recovery_at_undecode();
|
}
|
|
return status;
|
}
|
|
/******************************************************************************
|
* @Function transmit_only_process
|
* @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error.
|
******************************************************************************/
|
static ESESTATUS transmit_only_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(); // just send
|
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)
|
{
|
if ((g_ese_ctx.p_T1_params->is_device_chaining == true) && (g_ese_ctx.next_T1_state != STATE_IDEL))
|
{
|
#ifdef DBG_LEVEL_STACK
|
gDumpStackFlag = false;
|
#endif
|
g_ese_ctx.p_T1_params->blk_retry_cnt = 0;
|
status = response_process();
|
// status = response_no_wait_process();
|
}
|
else
|
{
|
break;
|
}
|
}
|
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 receive_only_process
|
* @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error.
|
******************************************************************************/
|
static ESESTATUS receive_only_process(void)
|
{
|
ESESTATUS status = ESESTATUS_SUCCESS;
|
#ifdef DBG_LEVEL_STACK
|
gDumpStackFlag = false;
|
#endif
|
g_ese_ctx.p_T1_params->blk_retry_cnt = 0;
|
status = response_no_wait_process();
|
|
while ((status != ESESTATUS_NO_DATA_TO_RECEIVE) && (g_ese_ctx.next_T1_state != STATE_IDEL))
|
{
|
if (g_ese_ctx.p_T1_params->last_rx_frame_type == IFRAME)
|
{
|
if ((g_ese_ctx.p_T1_params->is_card_chaining == true) && (g_ese_ctx.next_T1_state == R_ACK))
|
{
|
status = Transmit_receive_process();
|
// status = transmit_only_process();
|
}
|
break;
|
}
|
else // if (g_ese_ctx.p_T1_params->last_rx_frame_type == RFRAME)
|
{
|
transmit_only_process();
|
status = response_no_wait_process();
|
}
|
}
|
|
return status;
|
}
|
|
/******************************************************************************
|
* @Function t1_transmit_only_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_only_apdu(uint8_t *p_cmd_apdu, uint16_t cmd_len)
|
{
|
ESESTATUS status = ESESTATUS_SUCCESS;
|
status = init_Iframe_from_cmd_apdu(p_cmd_apdu, cmd_len);
|
if (ESESTATUS_SUCCESS != status)
|
{
|
goto cleanup;
|
}
|
|
status = transmit_only_process();
|
|
if (ESESTATUS_SUCCESS != status)
|
{
|
LOG_INFO(TRACE_MODULE_SE, "%s: failed, status = %d\r\n", __FUNCTION__, status);
|
}
|
else
|
{
|
// if success,after receiving the resp,execu deinit_Iframe_from_cmd_apdu
|
return status;
|
}
|
|
cleanup:
|
deinit_Iframe_from_cmd_apdu();
|
return status;
|
}
|
|
/******************************************************************************
|
* @Function t1_receive_only_apdu
|
* @Returns On success return ESESTATUS_SUCCESS or else ESESTATUS error.
|
******************************************************************************/
|
ESESTATUS t1_receive_only_apdu(void)
|
{
|
ESESTATUS status = ESESTATUS_SUCCESS;
|
|
status = receive_only_process(); // response_no_wait_process();
|
|
if (ESESTATUS_NO_DATA_TO_RECEIVE == status)
|
{
|
return ESESTATUS_NO_DATA_TO_RECEIVE;
|
}
|
|
if (ESESTATUS_SUCCESS != status)
|
{
|
LOG_INFO(TRACE_MODULE_SE, "%s: failed, status = %d\r\n", __FUNCTION__, status);
|
}
|
|
deinit_Iframe_from_cmd_apdu();
|
return status;
|
}
|