/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaMasterIRQHandler
 * Description   : Interrupt handler for SPI master mode.
 * This handler is used when the extraByte flag is set to retrieve the received last byte.
 *
 *END**************************************************************************/
void SPI_DRV_DmaMasterIRQHandler(uint32_t instance)
{
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
    /* instantiate local variable of type spi_master_state_t and point to global state */
    spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance];

    SPI_Type *base = g_spiBase[instance];

    /* If the SPI module contains a FIFO (and if it is enabled), check the FIFO empty flag */
    if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base)))
    {
        if (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 0)
        {
            /* If there is a receive buffer, copy the final byte from the SPI data register
             *  to the receive buffer
             */
            if (spiDmaState->receiveBuffer)
            {
                spiDmaState->receiveBuffer[spiDmaState->transferByteCnt-2] =
                                                              SPI_HAL_ReadDataLow(base);
            }
            /* Else, read out the data register and throw away the bytes read */
            else
            {
                /* Read and throw away the lower data buffer to clear it out */
                s_rxBuffIfNull = SPI_HAL_ReadDataLow(base);
            }
            /* Read and throw away the upper data buffer to clear it out */
            s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base);

            SPI_DRV_DmaMasterCompleteTransfer(instance);
        }
    }
    else /* Check the read pending flag */
    {
        if (SPI_HAL_IsReadBuffFullPending(base) == 1)
        {
            /* If there is a receive buffer, copy the final byte from the SPI data register
             *  to the receive buffer
             */
            if (spiDmaState->receiveBuffer)
            {
                spiDmaState->receiveBuffer[spiDmaState->transferByteCnt-2] =
                                                              SPI_HAL_ReadDataLow(base);
            }
            /* Else, read out the data register and throw away the bytes read */
            else
            {
                /* Read and throw away the lower data buffer to clear it out */
                s_rxBuffIfNull = SPI_HAL_ReadDataLow(base);
            }
            /* Read and throw away the upper data buffer to clear it out */
            s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base);
            SPI_DRV_DmaMasterCompleteTransfer(instance);
        }
    }
#endif /* FSL_FEATURE_SPI_16BIT_TRANSFERS */
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaMasterAbortTransfer
 * Description   : Terminates an asynchronous transfer early with DMA support.
 *
 * During an async transfer, the user has the option to terminate the transfer early if the transfer
 * is still in progress.
 *
 *END**************************************************************************/
spi_status_t SPI_DRV_DmaMasterAbortTransfer(uint32_t instance)
{
    /* instantiate local variable of type spi_dma_master_state_t and point to global state */
    spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance];

    /* Check if a transfer is running.*/
    if (!spiDmaState->isTransferInProgress)
    {
        return kStatus_SPI_NoTransferInProgress;
    }

    /* Stop the running transfer.*/
    SPI_DRV_DmaMasterCompleteTransfer(instance);

    return kStatus_SPI_Success;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaMasterCallback
 * Description   : This function is called when the DMA generates an interrupt.
 * The DMA generates an interrupt when the channel is "done", meaning that the
 * expected number of bytes have been transferred.  When the interrupt occurs,
 * the DMA will jump to this callback as it was registered in the DMA register
 * callback service function.  The user will defined their own callback function
 * to take whatever action they deem necessary for handling the end of a transfer.
 * For example, the user may simply want their callback function to set a global
 * flag to indicate that the transfer is complete.  The user defined callback
 * is passed in through the "param" parameter.
 * The parameter chanStatus is currently not used.
 *
 *END**************************************************************************/
void SPI_DRV_DmaMasterCallback(void *param, dma_channel_status_t chanStatus)
{
    uint32_t instance = (uint32_t)(param);

    /* instantiate local variable of type spi_master_state_t and point to global state */
    spi_dma_master_state_t * spiDmaState = (spi_dma_master_state_t *)g_spiStatePtr[instance];

    SPI_Type *base = g_spiBase[instance];

    /* If the extraByte flag was set, need to enable the TX empty interrupt to get the last byte */
    if (spiDmaState->extraByte)
    {
        SPI_HAL_SetTxDmaCmd(base, false);

        /* If the TX buffer is already empty then it may not generate an interrupt so soon
         * after the TX DMA is disabled, therefore read the RX data and put into RX buffer.
         */
        if (SPI_HAL_GetIntStatusFlag(base, kSpiTxBufferEmptyFlag))
        {
#if FSL_FEATURE_SPI_16BIT_TRANSFERS
            /* If the SPI module contains a FIFO (and if it is enabled), check the FIFO empty flag */
            if ((g_spiFifoSize[instance] != 0) && (SPI_HAL_GetFifoCmd(base)))
            {
                /* Wait till the rx buffer has data */
                while (SPI_HAL_GetFifoStatusFlag(base, kSpiRxFifoEmpty) == 1) {}

            }
            else /* Check the read pending flag */
            {
                /* Wait till the rx buffer has data */
                while (SPI_HAL_IsReadBuffFullPending(base) == 0) {}
            }

            /* If there is a receive buffer, copy the final byte from the SPI data register
             *  to the receive buffer
             */
            if (spiDmaState->receiveBuffer)
            {
                spiDmaState->receiveBuffer[spiDmaState->transferByteCnt-2] =
                                                              SPI_HAL_ReadDataLow(base);
            }
            /* Else, read out the data register and throw away the bytes read */
            else
            {
                /* Read and throw away the lower data buffer to clear it out */
                s_rxBuffIfNull = SPI_HAL_ReadDataLow(base);
            }
            /* Read and throw away the upper data buffer to clear it out */
            s_rxBuffIfNull = SPI_HAL_ReadDataHigh(base);
            SPI_DRV_DmaMasterCompleteTransfer(instance);
#endif
        }
        else
        {
            /* Else, if the TX buffer is not empty, enable the interrupt and handle the
             * receive in the ISR
             */
            SPI_HAL_SetIntMode(base, kSpiTxEmptyInt, true);
        }
    }
    else /* If no extra byte is needing to be receive, complete the transfer */
    {
        SPI_DRV_DmaMasterCompleteTransfer(instance);
    }
}
/*FUNCTION**********************************************************************
 *
 * Function Name : SPI_DRV_DmaMasterCallback
 * Description   : This function is called when the DMA generates an interrupt.
 * The DMA generates an interrupt when the channel is "done", meaning that the
 * expected number of bytes have been transferred.  When the interrupt occurs,
 * the DMA will jump to this callback as it was registered in the DMA register
 * callback service function.  The user will defined their own callback function
 * to take whatever action they deem necessary for handling the end of a transfer.
 * For example, the user may simply want their callback function to set a global
 * flag to indicate that the transfer is complete.  The user defined callback
 * is passed in through the "param" parameter.
 * The parameter chanStatus is currently not used.
 *
 *END**************************************************************************/
void SPI_DRV_DmaMasterCallback(void *param, dma_channel_status_t chanStatus)
{
    uint32_t instance = (uint32_t)(param);

    SPI_DRV_DmaMasterCompleteTransfer(instance);
}