/*
 * Copyright 2018 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_common.h"
#include "fsl_usart.h"
#include "fsl_flexcomm.h"

#include "fsl_adapter_uart.h"

#if (defined(HAL_UART_DMA_ENABLE) && (HAL_UART_DMA_ENABLE > 0U))
#include "fsl_component_timer_manager.h"
#include "fsl_usart_dma.h"
#endif /* HAL_UART_DMA_ENABLE */

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#ifndef NDEBUG
#if (defined(DEBUG_CONSOLE_ASSERT_DISABLE) && (DEBUG_CONSOLE_ASSERT_DISABLE > 0U))
#undef assert
#define assert(n)
#endif
#endif

#if (defined(HAL_UART_DMA_ENABLE) && (HAL_UART_DMA_ENABLE > 0U))
/*! @brief uart RX state structure. */
typedef struct _hal_uart_dma_receive_state
{
    uint8_t *volatile buffer;
    volatile uint32_t bufferLength;
    volatile uint32_t bufferSofar;
    volatile uint32_t timeout;
    volatile bool receiveAll;
} hal_uart_dma_receive_state_t;

/*! @brief uart TX state structure. */
typedef struct _hal_uart_dma_send_state
{
    uint8_t *volatile buffer;
    volatile uint32_t bufferLength;
    volatile uint32_t bufferSofar;
    volatile uint32_t timeout;
} hal_uart_dma_send_state_t;

typedef struct _hal_uart_dma_state
{
    struct _hal_uart_dma_state *next;
    uint8_t instance; /* USART instance */
    hal_uart_dma_transfer_callback_t dma_callback;
    void *dma_callback_param;
    usart_dma_handle_t dmaHandle;
    dma_handle_t txDmaHandle;
    dma_handle_t rxDmaHandle;
    hal_uart_dma_receive_state_t dma_rx;
    hal_uart_dma_send_state_t dma_tx;
} hal_uart_dma_state_t;

typedef struct _uart_dma_list
{
    TIMER_MANAGER_HANDLE_DEFINE(timerManagerHandle);
    hal_uart_dma_state_t *dma_list;
    volatile int8_t activeCount;
} hal_uart_dma_list_t;

static hal_uart_dma_list_t s_dmaHandleList;
#endif /* HAL_UART_DMA_ENABLE */

#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))
/*! @brief uart RX state structure. */
typedef struct _hal_uart_receive_state
{
    volatile uint8_t *buffer;
    volatile uint32_t bufferLength;
    volatile uint32_t bufferSofar;
} hal_uart_receive_state_t;

/*! @brief uart TX state structure. */
typedef struct _hal_uart_send_state
{
    volatile uint8_t *buffer;
    volatile uint32_t bufferLength;
    volatile uint32_t bufferSofar;
} hal_uart_send_state_t;
#endif
/*! @brief uart state structure. */
typedef struct _hal_uart_state
{
#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))
    hal_uart_transfer_callback_t callback;
    void *callbackParam;
#if (defined(HAL_UART_TRANSFER_MODE) && (HAL_UART_TRANSFER_MODE > 0U))
    usart_handle_t hardwareHandle;
#endif
    hal_uart_receive_state_t rx;
    hal_uart_send_state_t tx;
#endif
    uint8_t instance;
#if (defined(HAL_UART_DMA_ENABLE) && (HAL_UART_DMA_ENABLE > 0U))
    hal_uart_dma_state_t *dmaHandle;
#endif /* HAL_UART_DMA_ENABLE */
#if (defined(HAL_UART_ADAPTER_LOWPOWER) && (HAL_UART_ADAPTER_LOWPOWER > 0U))
    hal_uart_config_t config;
#endif
} hal_uart_state_t;

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/
static USART_Type *const s_UsartAdapterBase[] = USART_BASE_PTRS;

#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))

#if !(defined(HAL_UART_TRANSFER_MODE) && (HAL_UART_TRANSFER_MODE > 0U))
/* Array of USART IRQ number. */
static const IRQn_Type s_UsartIRQ[] = USART_IRQS;
#endif

#endif

/*******************************************************************************
 * Code
 ******************************************************************************/

#if ((defined(HAL_UART_TRANSFER_MODE) && (HAL_UART_TRANSFER_MODE > 0U)) || \
     (defined(HAL_UART_DMA_ENABLE) && (HAL_UART_DMA_ENABLE > 0U)))
static hal_uart_status_t HAL_UartGetStatus(status_t status)
{
    hal_uart_status_t uartStatus = kStatus_HAL_UartError;
    switch (status)
    {
        case kStatus_Success:
            uartStatus = kStatus_HAL_UartSuccess;
            break;
        case kStatus_USART_TxBusy:
            uartStatus = kStatus_HAL_UartTxBusy;
            break;
        case kStatus_USART_RxBusy:
            uartStatus = kStatus_HAL_UartRxBusy;
            break;
        case kStatus_USART_TxIdle:
            uartStatus = kStatus_HAL_UartTxIdle;
            break;
        case kStatus_USART_RxIdle:
            uartStatus = kStatus_HAL_UartRxIdle;
            break;
        case kStatus_USART_BaudrateNotSupport:
            uartStatus = kStatus_HAL_UartBaudrateNotSupport;
            break;
        case kStatus_USART_NoiseError:
        case kStatus_USART_FramingError:
        case kStatus_USART_ParityError:
            uartStatus = kStatus_HAL_UartProtocolError;
            break;
        default:
            /* This comments for MISRA C-2012 Rule 16.4 */
            break;
    }
    return uartStatus;
}
#else
static hal_uart_status_t HAL_UartGetStatus(status_t status)
{
    if (kStatus_Success == status)
    {
        return kStatus_HAL_UartSuccess;
    }
    else
    {
        return kStatus_HAL_UartError;
    }
}
#endif

#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))

#if (defined(HAL_UART_TRANSFER_MODE) && (HAL_UART_TRANSFER_MODE > 0U))
static void HAL_UartCallback(USART_Type *base, usart_handle_t *handle, status_t status, void *callbackParam)
{
    hal_uart_state_t *uartHandle;
    hal_uart_status_t uartStatus = HAL_UartGetStatus(status);
    assert(callbackParam);

    uartHandle = (hal_uart_state_t *)callbackParam;

    if (kStatus_HAL_UartProtocolError == uartStatus)
    {
        if (0U != uartHandle->hardwareHandle.rxDataSize)
        {
            uartStatus = kStatus_HAL_UartError;
        }
    }

    if (NULL != uartHandle->callback)
    {
        uartHandle->callback(uartHandle, uartStatus, uartHandle->callbackParam);
    }
}

#else
static void HAL_UartInterruptHandle(USART_Type *base, void *handle)
{
    hal_uart_state_t *uartHandle = (hal_uart_state_t *)handle;
    uint32_t status;
    uint8_t instance;

    if (NULL == uartHandle)
    {
        return;
    }
    instance = uartHandle->instance;

    status = USART_GetStatusFlags(s_UsartAdapterBase[instance]);

    /* Receive data register full */
    if ((0U != (USART_FIFOSTAT_RXNOTEMPTY_MASK & status)) &&
        (0U != (USART_GetEnabledInterrupts(s_UsartAdapterBase[instance]) & USART_FIFOINTENSET_RXLVL_MASK)))
    {
        if (NULL != uartHandle->rx.buffer)
        {
            uartHandle->rx.buffer[uartHandle->rx.bufferSofar++] = USART_ReadByte(s_UsartAdapterBase[instance]);
            if (uartHandle->rx.bufferSofar >= uartHandle->rx.bufferLength)
            {
                USART_DisableInterrupts(s_UsartAdapterBase[instance],
                                        USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENCLR_RXERR_MASK);
                uartHandle->rx.buffer = NULL;
                if (NULL != uartHandle->callback)
                {
                    uartHandle->callback(uartHandle, kStatus_HAL_UartRxIdle, uartHandle->callbackParam);
                }
            }
        }
    }

    /* Send data register empty and the interrupt is enabled. */
    if ((0U != (USART_FIFOSTAT_TXNOTFULL_MASK & status)) &&
        (0U != (USART_GetEnabledInterrupts(s_UsartAdapterBase[instance]) & USART_FIFOINTENSET_TXLVL_MASK)))
    {
        if (NULL != uartHandle->tx.buffer)
        {
            USART_WriteByte(s_UsartAdapterBase[instance], uartHandle->tx.buffer[uartHandle->tx.bufferSofar++]);
            if (uartHandle->tx.bufferSofar >= uartHandle->tx.bufferLength)
            {
                USART_DisableInterrupts(s_UsartAdapterBase[instance], USART_FIFOINTENCLR_TXLVL_MASK);
                uartHandle->tx.buffer = NULL;
                if (NULL != uartHandle->callback)
                {
                    uartHandle->callback(uartHandle, kStatus_HAL_UartTxIdle, uartHandle->callbackParam);
                }
            }
        }
    }

#if 1
    USART_ClearStatusFlags(s_UsartAdapterBase[instance], status);
#endif
}

static void HAL_UartInterruptHandle_Wapper(void *base, void *handle)
{
    HAL_UartInterruptHandle((USART_Type *)base, handle);
}
#endif

#endif

static hal_uart_status_t HAL_UartInitCommon(hal_uart_handle_t handle, const hal_uart_config_t *config)
{
    usart_config_t usartConfig;
    status_t status;

    assert(handle);
    assert(config);
    assert(config->instance < (sizeof(s_UsartAdapterBase) / sizeof(USART_Type *)));
    assert(s_UsartAdapterBase[config->instance]);
    assert(HAL_UART_HANDLE_SIZE >= sizeof(hal_uart_state_t));

    USART_GetDefaultConfig(&usartConfig);
    usartConfig.baudRate_Bps = config->baudRate_Bps;

    if ((0U != config->enableRxRTS) || (0U != config->enableTxCTS))
    {
        usartConfig.enableHardwareFlowControl = true;
    }

    if (kHAL_UartParityEven == config->parityMode)
    {
        usartConfig.parityMode = kUSART_ParityEven;
    }
    else if (kHAL_UartParityOdd == config->parityMode)
    {
        usartConfig.parityMode = kUSART_ParityOdd;
    }
    else
    {
        usartConfig.parityMode = kUSART_ParityDisabled;
    }

    if (kHAL_UartTwoStopBit == config->stopBitCount)
    {
        usartConfig.stopBitCount = kUSART_TwoStopBit;
    }
    else
    {
        usartConfig.stopBitCount = kUSART_OneStopBit;
    }
    usartConfig.enableRx    = (bool)config->enableRx;
    usartConfig.enableTx    = (bool)config->enableTx;
    usartConfig.txWatermark = kUSART_TxFifo0;
    usartConfig.rxWatermark = kUSART_RxFifo1;

    status = USART_Init(s_UsartAdapterBase[config->instance], &usartConfig, config->srcClock_Hz);

    if (kStatus_Success != status)
    {
        return HAL_UartGetStatus(status);
    }

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartInit(hal_uart_handle_t handle, const hal_uart_config_t *uart_config)
{
    hal_uart_state_t *uartHandle;
    hal_uart_status_t status;

    /* Init serial port */
    status = HAL_UartInitCommon(handle, uart_config);
    if (kStatus_HAL_UartSuccess != status)
    {
        return status;
    }

    uartHandle           = (hal_uart_state_t *)handle;
    uartHandle->instance = uart_config->instance;
#if (defined(HAL_UART_DMA_ENABLE) && (HAL_UART_DMA_ENABLE > 0U))
    uartHandle->dmaHandle = NULL;
#endif /* HAL_UART_DMA_ENABLE */
#if (defined(HAL_UART_ADAPTER_LOWPOWER) && (HAL_UART_ADAPTER_LOWPOWER > 0U))
    (void)memcpy(&uartHandle->config, uart_config, sizeof(hal_uart_config_t));
#endif

#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))

#if (defined(HAL_UART_TRANSFER_MODE) && (HAL_UART_TRANSFER_MODE > 0U))
    USART_TransferCreateHandle(s_UsartAdapterBase[uart_config->instance], &uartHandle->hardwareHandle,
                               (usart_transfer_callback_t)HAL_UartCallback, handle);
#else
    /* Enable interrupt in NVIC. */
    FLEXCOMM_SetIRQHandler(s_UsartAdapterBase[uart_config->instance], HAL_UartInterruptHandle_Wapper, handle);
    NVIC_SetPriority((IRQn_Type)s_UsartIRQ[uart_config->instance], HAL_UART_ISR_PRIORITY);
    (void)EnableIRQ(s_UsartIRQ[uart_config->instance]);
#endif

#endif

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartDeinit(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;

    assert(handle);

    uartHandle = (hal_uart_state_t *)handle;

    USART_Deinit(s_UsartAdapterBase[uartHandle->instance]);

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartReceiveBlocking(hal_uart_handle_t handle, uint8_t *data, size_t length)
{
    hal_uart_state_t *uartHandle;
    status_t status;
    assert(handle);
    assert(data);
    assert(length);

    uartHandle = (hal_uart_state_t *)handle;

#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))
    if (NULL != uartHandle->rx.buffer)
    {
        return kStatus_HAL_UartRxBusy;
    }
#endif

    status = USART_ReadBlocking(s_UsartAdapterBase[uartHandle->instance], data, length);

    return HAL_UartGetStatus(status);
}

hal_uart_status_t HAL_UartSendBlocking(hal_uart_handle_t handle, const uint8_t *data, size_t length)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(data);
    assert(length);

    uartHandle = (hal_uart_state_t *)handle;

#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))
    if (NULL != uartHandle->tx.buffer)
    {
        return kStatus_HAL_UartTxBusy;
    }
#endif

    (void)USART_WriteBlocking(s_UsartAdapterBase[uartHandle->instance], data, length);

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartEnterLowpower(hal_uart_handle_t handle)
{
    assert(handle);

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartExitLowpower(hal_uart_handle_t handle)
{
#if (defined(HAL_UART_ADAPTER_LOWPOWER) && (HAL_UART_ADAPTER_LOWPOWER > 0U))
    hal_uart_state_t *uartHandle;
    assert(handle);

    uartHandle = (hal_uart_state_t *)handle;

    HAL_UartInit(handle, &uartHandle->config);
#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))
    USART_EnableInterrupts(s_UsartAdapterBase[uartHandle->instance], USART_FIFOINTENSET_RXLVL_MASK);
#endif
#endif
    return kStatus_HAL_UartSuccess;
}

#if (defined(UART_ADAPTER_NON_BLOCKING_MODE) && (UART_ADAPTER_NON_BLOCKING_MODE > 0U))

#if (defined(HAL_UART_TRANSFER_MODE) && (HAL_UART_TRANSFER_MODE > 0U))

hal_uart_status_t HAL_UartTransferInstallCallback(hal_uart_handle_t handle,
                                                  hal_uart_transfer_callback_t callback,
                                                  void *callbackParam)
{
    hal_uart_state_t *uartHandle;

    assert(handle);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    uartHandle->callbackParam = callbackParam;
    uartHandle->callback      = callback;

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartTransferReceiveNonBlocking(hal_uart_handle_t handle, hal_uart_transfer_t *transfer)
{
    hal_uart_state_t *uartHandle;
    status_t status;
    assert(handle);
    assert(transfer);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    status = USART_TransferReceiveNonBlocking(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle,
                                              (usart_transfer_t *)transfer, NULL);

    return HAL_UartGetStatus(status);
}

hal_uart_status_t HAL_UartTransferSendNonBlocking(hal_uart_handle_t handle, hal_uart_transfer_t *transfer)
{
    hal_uart_state_t *uartHandle;
    status_t status;
    assert(handle);
    assert(transfer);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    status = USART_TransferSendNonBlocking(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle,
                                           (usart_transfer_t *)transfer);

    return HAL_UartGetStatus(status);
}

hal_uart_status_t HAL_UartTransferGetReceiveCount(hal_uart_handle_t handle, uint32_t *count)
{
    hal_uart_state_t *uartHandle;
    status_t status;
    assert(handle);
    assert(count);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    status =
        USART_TransferGetReceiveCount(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle, count);

    return HAL_UartGetStatus(status);
}

hal_uart_status_t HAL_UartTransferGetSendCount(hal_uart_handle_t handle, uint32_t *count)
{
    hal_uart_state_t *uartHandle;
    status_t status;
    assert(handle);
    assert(count);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    status = USART_TransferGetSendCount(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle, count);

    return HAL_UartGetStatus(status);
}

hal_uart_status_t HAL_UartTransferAbortReceive(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    USART_TransferAbortReceive(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle);

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartTransferAbortSend(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    USART_TransferAbortSend(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle);

    return kStatus_HAL_UartSuccess;
}

#else

/* None transactional API with non-blocking mode. */
hal_uart_status_t HAL_UartInstallCallback(hal_uart_handle_t handle,
                                          hal_uart_transfer_callback_t callback,
                                          void *callbackParam)
{
    hal_uart_state_t *uartHandle;

    assert(handle);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    uartHandle->callbackParam = callbackParam;
    uartHandle->callback      = callback;

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartReceiveNonBlocking(hal_uart_handle_t handle, uint8_t *data, size_t length)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(data);
    assert(length);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    if (NULL != uartHandle->rx.buffer)
    {
        return kStatus_HAL_UartRxBusy;
    }

    uartHandle->rx.bufferLength = length;
    uartHandle->rx.bufferSofar  = 0;
    uartHandle->rx.buffer       = data;
    USART_EnableInterrupts(s_UsartAdapterBase[uartHandle->instance], USART_FIFOINTENSET_RXLVL_MASK);
    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartSendNonBlocking(hal_uart_handle_t handle, uint8_t *data, size_t length)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(data);
    assert(length);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    if (NULL != uartHandle->tx.buffer)
    {
        return kStatus_HAL_UartTxBusy;
    }
    uartHandle->tx.bufferLength = length;
    uartHandle->tx.bufferSofar  = 0;
    uartHandle->tx.buffer       = (volatile uint8_t *)data;
    USART_EnableInterrupts(s_UsartAdapterBase[uartHandle->instance], USART_FIFOINTENSET_TXLVL_MASK);
    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartGetReceiveCount(hal_uart_handle_t handle, uint32_t *reCount)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(reCount);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    if (NULL != uartHandle->rx.buffer)
    {
        *reCount = uartHandle->rx.bufferSofar;
        return kStatus_HAL_UartSuccess;
    }
    return kStatus_HAL_UartError;
}

hal_uart_status_t HAL_UartGetSendCount(hal_uart_handle_t handle, uint32_t *seCount)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(seCount);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    if (NULL != uartHandle->tx.buffer)
    {
        *seCount = uartHandle->tx.bufferSofar;
        return kStatus_HAL_UartSuccess;
    }
    return kStatus_HAL_UartError;
}

hal_uart_status_t HAL_UartAbortReceive(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    if (NULL != uartHandle->rx.buffer)
    {
        USART_DisableInterrupts(s_UsartAdapterBase[uartHandle->instance],
                                USART_FIFOINTENCLR_RXLVL_MASK | USART_FIFOINTENCLR_RXERR_MASK);
        uartHandle->rx.buffer = NULL;
    }

    return kStatus_HAL_UartSuccess;
}

hal_uart_status_t HAL_UartAbortSend(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

    if (NULL != uartHandle->tx.buffer)
    {
        USART_DisableInterrupts(s_UsartAdapterBase[uartHandle->instance], USART_FIFOINTENCLR_TXLVL_MASK);
        uartHandle->tx.buffer = NULL;
    }

    return kStatus_HAL_UartSuccess;
}

#endif

#if (defined(HAL_UART_TRANSFER_MODE) && (HAL_UART_TRANSFER_MODE > 0U))

void HAL_UartIsrFunction(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(0U != HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

#if 0
    DisableIRQ(s_UsartIRQ[uartHandle->instance]);
#endif
    USART_TransferHandleIRQ(s_UsartAdapterBase[uartHandle->instance], &uartHandle->hardwareHandle);
#if 0
    NVIC_SetPriority((IRQn_Type)s_UsartIRQ[uartHandle->instance], HAL_UART_ISR_PRIORITY);
    EnableIRQ(s_UsartIRQ[uartHandle->instance]);
#endif
}

#else

void HAL_UartIsrFunction(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    assert(handle);
    assert(0U == HAL_UART_TRANSFER_MODE);

    uartHandle = (hal_uart_state_t *)handle;

#if 0
    DisableIRQ(s_UsartIRQ[uartHandle->instance]);
#endif
    HAL_UartInterruptHandle(s_UsartAdapterBase[uartHandle->instance], (void *)uartHandle);
#if 0
    NVIC_SetPriority((IRQn_Type)s_UsartIRQ[uartHandle->instance], HAL_UART_ISR_PRIORITY);
    EnableIRQ(s_UsartIRQ[uartHandle->instance]);
#endif
}

#endif

#endif

#if (defined(HAL_UART_DMA_ENABLE) && (HAL_UART_DMA_ENABLE > 0U))
static void USART_DMACallbacks(USART_Type *base, usart_dma_handle_t *handle, status_t status, void *userData)
{
    hal_uart_dma_state_t *uartDmaHandle;
    hal_uart_status_t uartStatus = HAL_UartGetStatus(status);
    hal_dma_callback_msg_t msg;
    assert(handle);

    uartDmaHandle = (hal_uart_dma_state_t *)userData;

    if (NULL != uartDmaHandle->dma_callback)
    {
        if (kStatus_HAL_UartTxIdle == uartStatus)
        {
            msg.status                   = kStatus_HAL_UartDmaTxIdle;
            msg.data                     = uartDmaHandle->dma_tx.buffer;
            msg.dataSize                 = uartDmaHandle->dma_tx.bufferLength;
            uartDmaHandle->dma_tx.buffer = NULL;
        }
        else if (kStatus_HAL_UartRxIdle == uartStatus)
        {
            msg.status                   = kStatus_HAL_UartDmaRxIdle;
            msg.data                     = uartDmaHandle->dma_rx.buffer;
            msg.dataSize                 = uartDmaHandle->dma_rx.bufferLength;
            uartDmaHandle->dma_rx.buffer = NULL;
        }

        uartDmaHandle->dma_callback(uartDmaHandle, &msg, uartDmaHandle->dma_callback_param);
    }
}

static void TimeoutTimer_Callbcak(void *param)
{
    hal_uart_dma_list_t *uartDmaHandleList;
    hal_uart_dma_state_t *uartDmaHandle;
    hal_dma_callback_msg_t msg;
    uint32_t newReceived = 0U;

    uartDmaHandleList = &s_dmaHandleList;
    uartDmaHandle     = uartDmaHandleList->dma_list;

    while (NULL != uartDmaHandle)
    {
        if ((NULL != uartDmaHandle->dma_rx.buffer) && (false == uartDmaHandle->dma_rx.receiveAll))
        {
            /* HAL_UartDMAGetReceiveCount(uartDmaHandle, &msg.dataSize); */
            USART_TransferGetReceiveCountDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle,
                                             &msg.dataSize);
            newReceived                       = msg.dataSize - uartDmaHandle->dma_rx.bufferSofar;
            uartDmaHandle->dma_rx.bufferSofar = msg.dataSize;

            /* 1, If it is in idle state. */
            if ((0U == newReceived) && (0U < uartDmaHandle->dma_rx.bufferSofar))
            {
                uartDmaHandle->dma_rx.timeout++;
                if (uartDmaHandle->dma_rx.timeout >= HAL_UART_DMA_IDLELINE_TIMEOUT)
                {
                    /* HAL_UartDMAAbortReceive(uartDmaHandle); */
                    USART_TransferAbortReceiveDMA(s_UsartAdapterBase[uartDmaHandle->instance],
                                                  &uartDmaHandle->dmaHandle);
                    msg.data                     = uartDmaHandle->dma_rx.buffer;
                    msg.status                   = kStatus_HAL_UartDmaIdleline;
                    uartDmaHandle->dma_rx.buffer = NULL;
                    uartDmaHandle->dma_callback(uartDmaHandle, &msg, uartDmaHandle->dma_callback_param);
                }
            }
            /* 2, If got new data again. */
            if ((0U < newReceived) && (0U < uartDmaHandle->dma_rx.bufferSofar))
            {
                uartDmaHandle->dma_rx.timeout = 0U;
            }
        }

        uartDmaHandle = uartDmaHandle->next;
    }
}

hal_uart_dma_status_t HAL_UartDMAInit(hal_uart_handle_t handle,
                                      hal_uart_dma_handle_t dmaHandle,
                                      hal_uart_dma_config_t *dmaConfig)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;

    assert(handle);
    assert(dmaHandle);

    /* DMA init process. */
    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = (hal_uart_dma_state_t *)dmaHandle;

    uartHandle->dmaHandle = uartDmaHandle;

    uartDmaHandle->instance = dmaConfig->uart_instance;

    DMA_Type *dmaBases[] = DMA_BASE_PTRS;
    DMA_EnableChannel(dmaBases[dmaConfig->dma_instance], dmaConfig->tx_channel);
    DMA_EnableChannel(dmaBases[dmaConfig->dma_instance], dmaConfig->rx_channel);

    DMA_CreateHandle(&uartDmaHandle->txDmaHandle, dmaBases[dmaConfig->dma_instance], dmaConfig->tx_channel);
    DMA_CreateHandle(&uartDmaHandle->rxDmaHandle, dmaBases[dmaConfig->dma_instance], dmaConfig->rx_channel);

    /* Timeout timer init. */
    if (0U == s_dmaHandleList.activeCount)
    {
        s_dmaHandleList.dma_list = uartDmaHandle;
        uartDmaHandle->next      = NULL;
        s_dmaHandleList.activeCount++;

        timer_status_t timerStatus;
        timerStatus = TM_Open((timer_handle_t)s_dmaHandleList.timerManagerHandle);
        assert(kStatus_TimerSuccess == timerStatus);

        timerStatus =
            TM_InstallCallback((timer_handle_t)s_dmaHandleList.timerManagerHandle, TimeoutTimer_Callbcak, NULL);
        assert(kStatus_TimerSuccess == timerStatus);

        (void)TM_Start((timer_handle_t)s_dmaHandleList.timerManagerHandle, (uint8_t)kTimerModeIntervalTimer, 1);

        (void)timerStatus;
    }
    else
    {
        uartDmaHandle->next      = s_dmaHandleList.dma_list;
        s_dmaHandleList.dma_list = uartDmaHandle;
    }

    return kStatus_HAL_UartDmaSuccess;
}

hal_uart_dma_status_t HAL_UartDMADeinit(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;
    hal_uart_dma_state_t *prev;
    hal_uart_dma_state_t *curr;

    assert(handle);

    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = uartHandle->dmaHandle;

    uartHandle->dmaHandle = NULL;

    assert(uartDmaHandle);

    /* Abort rx/tx */
    /* Here we should not abort before create transfer handle. */
    if (NULL != uartDmaHandle->dmaHandle.txDmaHandle)
    {
        USART_TransferAbortSendDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle);
    }
    if (NULL != uartDmaHandle->dmaHandle.rxDmaHandle)
    {
        USART_TransferAbortReceiveDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle);
    }

    /* Disable rx/tx channels */
    /* Here we should not disable before create transfer handle. */
    if (NULL != uartDmaHandle->dmaHandle.txDmaHandle)
    {
        DMA_DisableChannel(uartDmaHandle->txDmaHandle.base, uartDmaHandle->txDmaHandle.channel);
    }
    if (NULL != uartDmaHandle->dmaHandle.rxDmaHandle)
    {
        DMA_DisableChannel(uartDmaHandle->rxDmaHandle.base, uartDmaHandle->rxDmaHandle.channel);
    }

    /* Remove handle from list */
    prev = NULL;
    curr = s_dmaHandleList.dma_list;
    while (curr != NULL)
    {
        if (curr == uartDmaHandle)
        {
            /* 1, if it is the first one */
            if (prev == NULL)
            {
                s_dmaHandleList.dma_list = curr->next;
            }
            /* 2, if it is the last one */
            else if (curr->next == NULL)
            {
                prev->next = NULL;
            }
            /* 3, if it is in the middle */
            else
            {
                prev->next = curr->next;
            }
            break;
        }

        prev = curr;
        curr = curr->next;
    }

    /* Reset all handle data. */
    (void)memset(uartDmaHandle, 0, sizeof(hal_uart_dma_state_t));

    s_dmaHandleList.activeCount = (s_dmaHandleList.activeCount > 0) ? (s_dmaHandleList.activeCount - 1) : 0;
    if (0 == s_dmaHandleList.activeCount)
    {
        (void)TM_Close((timer_handle_t)s_dmaHandleList.timerManagerHandle);
    }

    return kStatus_HAL_UartDmaSuccess;
}

hal_uart_dma_status_t HAL_UartDMATransferInstallCallback(hal_uart_handle_t handle,
                                                         hal_uart_dma_transfer_callback_t callback,
                                                         void *callbackParam)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;

    assert(handle);

    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = uartHandle->dmaHandle;

    assert(uartDmaHandle);

    uartDmaHandle->dma_callback       = callback;
    uartDmaHandle->dma_callback_param = callbackParam;

    USART_TransferCreateHandleDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle,
                                  USART_DMACallbacks, uartDmaHandle, &uartDmaHandle->txDmaHandle,
                                  &uartDmaHandle->rxDmaHandle);

    return kStatus_HAL_UartDmaSuccess;
}

hal_uart_dma_status_t HAL_UartDMATransferReceive(hal_uart_handle_t handle,
                                                 uint8_t *data,
                                                 size_t length,
                                                 bool receiveAll)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;
    usart_transfer_t xfer;

    assert(handle);
    assert(data);

    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = uartHandle->dmaHandle;

    assert(uartDmaHandle);

    if (NULL == uartDmaHandle->dma_rx.buffer)
    {
        uartDmaHandle->dma_rx.buffer       = data;
        uartDmaHandle->dma_rx.bufferLength = length;
        uartDmaHandle->dma_rx.timeout      = 0U;
        uartDmaHandle->dma_rx.receiveAll   = receiveAll;
    }
    else
    {
        /* Already in reading process. */
        return kStatus_HAL_UartDmaRxBusy;
    }

    xfer.data     = data;
    xfer.dataSize = length;

    USART_TransferReceiveDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle, &xfer);

    return kStatus_HAL_UartDmaSuccess;
}

hal_uart_dma_status_t HAL_UartDMATransferSend(hal_uart_handle_t handle, uint8_t *data, size_t length)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;
    usart_transfer_t xfer;

    assert(handle);
    assert(data);

    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = uartHandle->dmaHandle;

    assert(uartDmaHandle);

    if (NULL == uartDmaHandle->dma_tx.buffer)
    {
        uartDmaHandle->dma_tx.buffer       = data;
        uartDmaHandle->dma_tx.bufferLength = length;
        uartDmaHandle->dma_tx.bufferSofar  = 0U;
        uartDmaHandle->dma_tx.timeout      = 0U;
    }
    else
    {
        /* Already in writing process. */
        return kStatus_HAL_UartDmaTxBusy;
    }

    xfer.data     = data;
    xfer.dataSize = length;

    USART_TransferSendDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle, &xfer);

    return kStatus_HAL_UartDmaSuccess;
}

hal_uart_dma_status_t HAL_UartDMAGetReceiveCount(hal_uart_handle_t handle, uint32_t *reCount)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;

    assert(handle);

    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = uartHandle->dmaHandle;

    assert(uartDmaHandle);

    if (kStatus_Success != USART_TransferGetReceiveCountDMA(s_UsartAdapterBase[uartDmaHandle->instance],
                                                            &uartDmaHandle->dmaHandle, reCount))
    {
        return kStatus_HAL_UartDmaError;
    }

    return kStatus_HAL_UartDmaSuccess;
}

hal_uart_dma_status_t HAL_UartDMAGetSendCount(hal_uart_handle_t handle, uint32_t *seCount)
{
    /* No get send count API */
    return kStatus_HAL_UartDmaError;
}

hal_uart_dma_status_t HAL_UartDMAAbortReceive(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;

    assert(handle);

    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = uartHandle->dmaHandle;

    assert(uartDmaHandle);

    USART_TransferAbortReceiveDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle);

    return kStatus_HAL_UartDmaSuccess;
}

hal_uart_dma_status_t HAL_UartDMAAbortSend(hal_uart_handle_t handle)
{
    hal_uart_state_t *uartHandle;
    hal_uart_dma_state_t *uartDmaHandle;

    assert(handle);

    uartHandle    = (hal_uart_state_t *)handle;
    uartDmaHandle = uartHandle->dmaHandle;

    assert(uartDmaHandle);

    USART_TransferAbortSendDMA(s_UsartAdapterBase[uartDmaHandle->instance], &uartDmaHandle->dmaHandle);

    return kStatus_HAL_UartDmaSuccess;
}
#endif /* HAL_UART_DMA_ENABLE */
