in hw/mcu/nxp/src/ext/nxp-kinetis-sdk/drivers/fsl_smartcard_emvsim.c [662:968]
void SMARTCARD_EMVSIM_IRQHandler(EMVSIM_Type *base, smartcard_context_t *context)
{
if (NULL == context)
{
return;
}
/* Check card insertion/removal interrupt occurs, only EMVSIM DIRECT interface driver using enables this interrupt
* to occur */
if (((base->PCSR & EMVSIM_PCSR_SPDIM_MASK) == 0u) && ((base->PCSR & EMVSIM_PCSR_SPDIF_MASK) != 0u))
{
/* Clear card presence interrupt status */
base->PCSR |= EMVSIM_PCSR_SPDIF_MASK;
/* Set PD signal edge behaviour */
if (((emvsim_presence_detect_edge_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDES_MASK) >>
EMVSIM_PCSR_SPDES_SHIFT) == kEMVSIM_DetectOnFallingEdge) &&
((emvsim_presence_detect_status_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDP_MASK) >>
EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsLow))
{ /* Set rising edge interrupt */
base->PCSR |= EMVSIM_PCSR_SPDES_MASK;
}
if (((emvsim_presence_detect_edge_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDES_MASK) >>
EMVSIM_PCSR_SPDES_SHIFT) == kEMVSIM_DetectOnRisingEdge) &&
((emvsim_presence_detect_status_t)(uint32_t)((base->PCSR & EMVSIM_PCSR_SPDP_MASK) >>
EMVSIM_PCSR_SPDP_SHIFT) == kEMVSIM_DetectPinIsHigh))
{ /* Set falling edge interrupt */
base->PCSR &= ~EMVSIM_PCSR_SPDES_MASK;
}
/* Card presence(insertion)/removal detected */
/* Invoke callback if there is one */
if (NULL != context->interfaceCallback)
{
context->interfaceCallback(context, context->interfaceCallbackParam);
}
return;
}
/* Check if timer for initial character (TS) detection has expired */
if (((base->INT_MASK & EMVSIM_INT_MASK_GPCNT0_IM_MASK) >> EMVSIM_INT_MASK_GPCNT0_IM_SHIFT == 0u) &&
((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT0_TO_MASK) != 0u))
{
/* Disable TS and ADT timers by clearing source clock to 0 */
base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK);
context->timersState.initCharTimerExpired = true;
/* Disable and clear GPCNT interrupt */
base->INT_MASK |= EMVSIM_INT_MASK_GPCNT0_IM_MASK;
base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT0_TO_MASK;
/* Down counter trigger, and clear any pending counter status flag */
base->CTRL &= ~EMVSIM_CTRL_RCV_EN_MASK;
base->CTRL |= EMVSIM_CTRL_RCV_EN_MASK;
context->transferState = kSMARTCARD_IdleState;
/* Unblock the caller */
smartcard_emvsim_CompleteReceiveData(base, context);
return;
}
/* Check if timer for ATR duration timer has expired */
if (((base->INT_MASK & EMVSIM_INT_MASK_GPCNT1_IM_MASK) == 0u) &&
((base->TX_STATUS & EMVSIM_TX_STATUS_GPCNT1_TO_MASK) != 0u))
{ /* Disable clock counter by clearing source clock to 0 */
base->CLKCFG &= ~EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK;
/* Disable and clear GPCNT interrupt */
base->INT_MASK |= EMVSIM_INT_MASK_GPCNT1_IM_MASK;
base->TX_STATUS = EMVSIM_TX_STATUS_GPCNT1_TO_MASK;
context->timersState.adtExpired = true;
/* Unblock the caller */
smartcard_emvsim_CompleteReceiveData(base, context);
return;
}
/*
* Check if a parity error was indicated.
* A parity error will cause transmission of NACK if ANACK bit is set in
* CTRL register and PEF bit will not be asserted. When ANACK is not set,
* PEF will be asserted.
*/
if ((base->RX_STATUS & EMVSIM_RX_STATUS_PEF_MASK) != 0u)
{
context->parityError = true;
/* Clear parity error indication */
base->RX_STATUS = EMVSIM_RX_STATUS_PEF_MASK;
}
/* Check if transmit NACK generation threshold was reached */
if ((base->TX_STATUS & EMVSIM_TX_STATUS_TNTE_MASK) != 0u)
{
context->txtCrossed = true;
/* Disable transmit NACK threshold interrupt */
base->INT_MASK |= EMVSIM_INT_MASK_TNACK_IM_MASK;
/* Clear transmit NACK threshold error flag */
base->TX_STATUS = EMVSIM_TX_STATUS_TNTE_MASK;
/* Unblock the caller */
smartcard_emvsim_CompleteSendData(base, context);
return;
}
/* Check if receive NACK generation threshold was reached */
if ((base->RX_STATUS & EMVSIM_RX_STATUS_RTE_MASK) != 0u)
{
context->rxtCrossed = true;
/* Clear receiver NACK threshold interrupt status */
base->RX_STATUS = EMVSIM_RX_STATUS_RTE_MASK;
if (context->xIsBusy)
{ /* Unblock the caller */
smartcard_emvsim_CompleteReceiveData(base, context);
}
}
/* Check if a Character Wait Timer expired */
if (((base->INT_MASK & EMVSIM_INT_MASK_CWT_ERR_IM_MASK) == 0u) &&
((base->RX_STATUS & EMVSIM_RX_STATUS_CWT_ERR_MASK) != 0u))
{ /* Disable Character Wait Timer interrupt */
base->INT_MASK |= EMVSIM_INT_MASK_CWT_ERR_IM_MASK;
/* Reset the counter */
base->CTRL &= ~EMVSIM_CTRL_CWT_EN_MASK;
/* Clear interrupt status */
base->RX_STATUS = EMVSIM_RX_STATUS_CWT_ERR_MASK;
/* Enable CWT timer */
base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK;
context->transferState = kSMARTCARD_IdleState;
if (kSMARTCARD_T0Transport == context->tType)
{ /* Indicate WWT expired */
context->timersState.wwtExpired = true;
}
else
{ /* Indicate CWT expired */
context->timersState.cwtExpired = true;
}
if (context->xIsBusy)
{ /* Terminate and unblock any caller */
smartcard_emvsim_CompleteReceiveData(base, context);
}
}
/* Check if a Block Wait Timer expired */
if (((base->INT_MASK & EMVSIM_INT_MASK_BWT_ERR_IM_MASK) == 0u) &&
((base->RX_STATUS & EMVSIM_RX_STATUS_BWT_ERR_MASK) != 0u))
{ /* Disable Block Wait Timer interrupt */
base->INT_MASK |= EMVSIM_INT_MASK_BWT_ERR_IM_MASK;
/* Clear interrupt status flag */
base->CTRL &= ~EMVSIM_CTRL_BWT_EN_MASK;
/* Clear error */
base->RX_STATUS = EMVSIM_RX_STATUS_BWT_ERR_MASK;
/* Enable BWT timer */
base->CTRL |= EMVSIM_CTRL_BWT_EN_MASK;
if (kSMARTCARD_T0Transport == context->tType)
{ /* Indicate WWT expired */
context->timersState.wwtExpired = true;
}
else
{ /* Indicate BWT expired */
context->timersState.bwtExpired = true;
}
/* Check if Wait Time Extension(WTX) was requested */
if (context->wtxRequested)
{ /* Reset WTX to default */
(void)SMARTCARD_EMVSIM_Control(base, context, kSMARTCARD_ResetWaitTimeMultiplier, 1u);
}
if (context->xIsBusy)
{ /* Terminate and unblock any caller */
smartcard_emvsim_CompleteReceiveData(base, context);
}
}
/* RX_DATA IRQ */
/* Used in T=1 after receive 1st byte - disable BWT and enable CWT interrupt */
if (((base->INT_MASK & EMVSIM_INT_MASK_RX_DATA_IM_MASK) == 0u) &&
((base->RX_STATUS & EMVSIM_RX_STATUS_RX_DATA_MASK) != 0u))
{
if ((context->tType == kSMARTCARD_T1Transport) && (context->xSize > 0u) &&
((base->INT_MASK & EMVSIM_INT_MASK_BWT_ERR_IM_MASK) == 0u))
{
context->timersState.cwtExpired = false;
/* Clear CWT error flag */
base->RX_STATUS = EMVSIM_RX_STATUS_CWT_ERR_MASK;
/* Enable CWT */
base->CTRL |= EMVSIM_CTRL_CWT_EN_MASK;
/* Only the 1st byte has been received, now time to disable BWT interrupt and enable CWT interrupt */
base->INT_MASK = (base->INT_MASK & ~EMVSIM_INT_MASK_CWT_ERR_IM_MASK) | EMVSIM_INT_MASK_BWT_ERR_IM_MASK;
}
/* Disable interrupt when is received new byte */
base->INT_MASK |= EMVSIM_INT_MASK_RX_DATA_IM_MASK;
}
/* RDT IRQ - count of bytes in rx fifo reached the rx threshold value RX_THD[RDT] */
if (((base->INT_MASK & EMVSIM_INT_MASK_RDT_IM_MASK) == 0u) &&
((base->RX_STATUS & EMVSIM_RX_STATUS_RDTF_MASK) != 0u))
{
if (kSMARTCARD_WaitingForTSState == context->transferState)
{
/* Read byte */
(void)(base->RX_BUF);
if ((base->CTRL & EMVSIM_CTRL_ICM_MASK) != 0u)
{ /* ICM mode still enabled, this is due to parity error */
context->transferState = kSMARTCARD_InvalidTSDetecetedState;
}
else
{ /* Received valid TS */
context->transferState = kSMARTCARD_ReceivingState;
/* Get Data Convention form by reading IC bit of EMVSIM_CTRL register */
context->cardParams.convention =
(smartcard_card_convention_t)(uint32_t)((base->CTRL & EMVSIM_CTRL_IC_MASK) >> EMVSIM_CTRL_IC_SHIFT);
}
if (kSMARTCARD_InvalidTSDetecetedState == context->transferState)
{ /* Stop initial character (TS) detection timer, ADT timer and it's interrupt to occur */
base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK);
base->INT_MASK |= EMVSIM_INT_MASK_GPCNT0_IM_MASK;
smartcard_emvsim_CompleteReceiveData(base, context);
}
if (kSMARTCARD_ReceivingState == context->transferState)
{ /* Stop initial character (TS) detection timer and disable ATR duration timer to reset it */
base->CLKCFG &= ~(EMVSIM_CLKCFG_GPCNT0_CLK_SEL_MASK | EMVSIM_CLKCFG_GPCNT1_CLK_SEL_MASK);
/* Start ATR duration counter (restart GPCNT) */
base->CLKCFG |= EMVSIM_CLKCFG_GPCNT1_CLK_SEL(kEMVSIM_GPCTxClock);
/* Start ATR duration counter, Disable counter 0 interrupt and Enable counter 1 interrupt */
base->INT_MASK = (base->INT_MASK & ~EMVSIM_INT_MASK_GPCNT1_IM_MASK) | EMVSIM_INT_MASK_GPCNT0_IM_MASK;
/* Complete receive transfer */
smartcard_emvsim_CompleteReceiveData(base, context);
}
/* Return anyway */
return;
}
while (((base->RX_STATUS & EMVSIM_RX_STATUS_RX_CNT_MASK) != 0u) && ((context->xSize) > 0u))
{
/* Get data and put into receive buffer */
*context->xBuff = (uint8_t)(base->RX_BUF);
++context->xBuff;
--context->xSize;
}
/* Check if the last byte was received */
if (context->xSize == 0u)
{
smartcard_emvsim_CompleteReceiveData(base, context);
}
else
{
/* If the count of remaining bytes to receive is less than depth of fifo, update the value of the receiver
* data threshold */
if (context->xSize < context->rxFifoThreshold)
{
/* Set receiver data threshold value to count of remaining bytes */
uint32_t rx_thd;
rx_thd = (base->RX_THD & ~EMVSIM_RX_THD_RDT_MASK);
rx_thd |= context->xSize;
base->RX_THD = rx_thd;
}
}
}
/* ETC IRQ - all data from fifo is transmitted */
if (((base->INT_MASK & EMVSIM_INT_MASK_ETC_IM_MASK) == 0u) &&
((base->TX_STATUS & EMVSIM_TX_STATUS_ETCF_MASK) != 0u))
{
smartcard_emvsim_CompleteSendData(base, context);
}
/* TDT IRQ - tx fifo is empty */
if (((base->INT_MASK & EMVSIM_INT_MASK_TDT_IM_MASK) == 0u) &&
((base->TX_STATUS & EMVSIM_TX_STATUS_TDTF_MASK) != 0u))
{
if (context->xSize == 0u)
{
smartcard_emvsim_CompleteSendData(base, context);
}
if (context->xSize == 1u)
{
/* Disable TDT interrupt */
base->INT_MASK |= EMVSIM_INT_MASK_TDT_IM_MASK;
/* When the TX_GETU is not zero while sending last byte, the transmitter sends one byte more */
base->TX_GETU = 0;
/* Write data to fifo */
base->TX_BUF = *(context->xBuff);
++context->xBuff;
--context->xSize;
/* Last byte was written to fifo - wait for ETC interrupt */
/* Clear ETC flag and enable ETC interrupt */
base->TX_STATUS |= EMVSIM_TX_STATUS_ETCF_MASK;
base->INT_MASK &= ~EMVSIM_INT_MASK_ETC_IM_MASK;
}
else
{
/* To fifo will be written 2 or more bytes */
size_t getu_tail = (size_t)(base->TX_GETU > 0u);
while (((context->txFifoEntryCount - (uint8_t)((base->TX_STATUS & EMVSIM_TX_STATUS_TX_CNT_MASK) >>
EMVSIM_TX_STATUS_TX_CNT_SHIFT)) > 0u) &&
(context->xSize > getu_tail))
{
/* Write data to fifo */
base->TX_BUF = *(context->xBuff);
++context->xBuff;
--context->xSize;
}
if (context->xSize == 0u)
{
/* Disable TDT interrupt */
base->INT_MASK |= EMVSIM_INT_MASK_TDT_IM_MASK;
/* Clear ETC flag and enable ETC interrupt */
base->TX_STATUS |= EMVSIM_TX_STATUS_ETCF_MASK;
base->INT_MASK &= ~EMVSIM_INT_MASK_ETC_IM_MASK;
}
}
}
SDK_ISR_EXIT_BARRIER;
}