void SMARTCARD_EMVSIM_IRQHandler()

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;
}