/*!
* @file     Usart_Irq.c
*
* @version  1.0.0
*
* @brief    The source file of the usart irq driver.
*
* @attention
*
* Project Name      : AUTOSAR MCAL
*
* Platform          : Arm
*
* Autosar Standard  : Classic Platform 4.4.0
*
* Compiled Version  : G32A10xx_MCAL_1_0_0_01-Otc-25
*
* Copyright (C) 2026 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the Geehy Semiconductor Software License Agreement for the governing permissions
* and limitations under the License.
*/

#include "Std_Types.h"
#include "Mcu_RcmTypes.h"
#include "CDD_Usart_Cfg.h"
#include "Usart_Irq.h"
#include "Usart_Reg.h"

#if (STD_ON == USART1_IRQ_ENABLE) || (STD_ON == USART2_IRQ_ENABLE)
#include "CDD_Usart.h"
#include "Usart_Hw.h"
#endif

#if (STD_ON == USART_DMA_SUPPORT)
#include "CDD_Pdl.h"
#endif

/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup USART_Driver
  * @brief USART driver modules
  @{
*/

/** @defgroup USART_Macros
  @{
*/
/*******************************************************************************
                    VENDOR ID & AUTOSAR VERSION INFO
*******************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define USART_IRQ_VENDOR_ID                              0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define USART_IRQ_AR_RELEASE_MAJOR_VERSION               0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define USART_IRQ_AR_RELEASE_MINOR_VERSION               0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define USART_IRQ_AR_RELEASE_REVISION_VERSION            0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */ 
#define USART_IRQ_SW_MAJOR_VERSION                       0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define USART_IRQ_SW_MINOR_VERSION                       0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define USART_IRQ_SW_PATCH_VERSION                       0x00U

/**@} end of group USART_Macros */
/*******************************************************************************
                              GLOBAL VARIABLE
*******************************************************************************/
/*******************************************************************************
                         LOCAL FUNCTION PROTOTYPES
*******************************************************************************/
/** @defgroup USART_Fuctions
  @{
*/

#if (STD_ON == USART1_IRQ_ENABLE) || (STD_ON == USART2_IRQ_ENABLE)
static FUNC(void, USART_CODE) Usart_Irq_TransmitHandler(Usart_StateType * uartStatus);
static FUNC(void, USART_CODE) Usart_Irq_TxCompleteHandler(Usart_StateType * uartStatus);
static FUNC(void, USART_CODE) Usart_Irq_ReceiveHandler(Usart_StateType * uartStatus);
static FUNC(void, USART_CODE) Usart_Irq_ErrorIrqHandler(Usart_StateType * uartStatus);
static FUNC(void, USART_CODE) Usart_Irq_InterruptHandlerFunction(Usart_UsartIdType usartId);
#endif

/*******************************************************************************
                              GLOBAL FUNCTION
*******************************************************************************/
/*!
* @brief        This function handles USART1 interrupt Handler
*
* @param        None
*
*/
#if (STD_ON == USART1_IRQ_ENABLE)
FUNC(void, USART_CODE) USART1_IRQHandler(void)
{
    Usart_Irq_InterruptHandlerFunction(USART1_ID);
}
#endif

/*!
* @brief        This function handles USART2 interrupt Handler
*
* @param        None
*
*/
#if (STD_ON == USART2_IRQ_ENABLE)
FUNC(void, USART_CODE) USART2_IRQHandler(void)
{
    Usart_Irq_InterruptHandlerFunction(USART2_ID);
}
#endif



#if (STD_ON == USART1_IRQ_ENABLE) || (STD_ON == USART2_IRQ_ENABLE)
/*!
* @brief       Main interrupt handler for USART events
*
* @param       usartId         USART channel ID triggering the interrupt
*
* @note        Handles error conditions first
* @note        Prioritizes RX over TX operations
* @note        Manages RX buffer not empty/TX buffer empty/transmission complete flags
*/
static FUNC(void, USART_CODE) Usart_Irq_InterruptHandlerFunction(Usart_UsartIdType usartId)
{
    /* Retrieve the pointer to the USART1 state structure */
    Usart_StateType * tempUartStatus = &g_lpuartStatus[usartId];

    /* Handle any existing error flags (e.g., overrun, framing, parity) */
    Usart_Irq_ErrorIrqHandler(tempUartStatus);

    /* RX: only when driver RX is active and RXBNE interrupt is enabled */
    if (((uint8)0 != tempUartStatus->rxBusy)
        && ((uint8)SET == Usart_Hw_ReadIntFlag(tempUartStatus->usartId, USART_INT_FLAG_RXBNE)))
    {
        Usart_Irq_ReceiveHandler(tempUartStatus);
    }
    else
    {
        /* nothing */
    }

    /* TX: only when driver TX is active and TXBE interrupt is enabled */
    if (((uint8)0 != tempUartStatus->txBusy)
        && ((uint8)SET == Usart_Hw_ReadIntFlag(tempUartStatus->usartId, USART_INT_FLAG_TXBE)))
    {
        Usart_Irq_TransmitHandler(tempUartStatus);
    }
    else
    {
        /* nothing */
    }

    /* TX complete: only when driver TX is active and TXC interrupt is enabled */
    if (((uint8)0 != tempUartStatus->txBusy)
        && ((uint8)SET == Usart_Hw_ReadIntFlag(tempUartStatus->usartId, USART_INT_FLAG_TXC)))
    {
        Usart_Irq_TxCompleteHandler(tempUartStatus);
    }
    else
    {
        /* nothing */
    }
}


/*!
* @brief       Stops interrupt-driven reception
*
* @param       uartStatus      Pointer to USART state structure
*
* @note        Disables RX direction and associated interrupts
* @note        Clears RX busy flag
* @note        Performs final data read before disabling
*/
static FUNC(void, USART_CODE) Usart_Irq_StopRxInt(Usart_StateType * uartStatus)
{
    (void)Usart_Hw_RxData(uartStatus->usartId);
    
    Usart_Hw_OperationDirectionMode(uartStatus->usartId,USART_MODE_RX,DISABLE);
  
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_ERRIE,DISABLE);
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_PEIE,DISABLE);
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_RXTOIE,DISABLE);
    
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_RXBNEIE,DISABLE);

    Usart_Hw_ClearStatusFlag(uartStatus->usartId, (uint32)USART_FLAG_RXTOF);
    
    uartStatus->rxBusy = FALSE;
    uartStatus->rxLen = 0U;
    uartStatus->rxBuffer = (uint16 *)0;
}


/*!
* @brief       Stops DMA-driven reception
*
* @param       uartStatus      Pointer to USART state structure
*
* @note        Disables RX direction and DMA requests
* @note        Conditionally disables DMA notifications/channel if supported
* @note        Clears RX busy flag
*/
static FUNC(void, USART_CODE) Usart_Irq_StopRxDma(Usart_StateType * uartStatus)
{
    (void)Usart_Hw_RxData(uartStatus->usartId);

    Usart_Hw_OperationDirectionMode(uartStatus->usartId,USART_MODE_RX,DISABLE);
    Usart_Hw_OperationDma(uartStatus->usartId,USART_DMA_REQUEST_RX,DISABLE);

#if (STD_ON == USART_DMA_SUPPORT)
    Pdl_TopDmaNotifiDis(uartStatus->rxDmaChannel, PDL_DMA_TRAN_COMPLETED);
    Pdl_TopDmaNotifiDis(uartStatus->rxDmaChannel, PDL_DMA_TRAN_HALF_COMPLETED);
    Pdl_TopDmaNotifiDis(uartStatus->rxDmaChannel, PDL_DMA_TRAN_ERROR);
    Pdl_TopDmaChDis(uartStatus->rxDmaChannel);
#endif
    uartStatus->rxBusy = FALSE;
    uartStatus->rxLen = 0U;
    uartStatus->rxBuffer = (uint16 *)0;
}

/*!
* @brief        This function handles USART error interrupt Handler
*
* @param        uartStatus      Pointer to USART state structure
*
*/
static FUNC(void, USART_CODE) Usart_Irq_ErrorIrqHandler(Usart_StateType * uartStatus)
{
    Usart_UsartIdType usartId = uartStatus->usartId;

    /* Only process errors while an RX transfer is active */
    if ((uint8)0 == uartStatus->rxBusy)
    {
        /* nothing */
    }
    /* Parity error: flag set and PEIE enabled */
    else if ((uint8)SET == Usart_Hw_ReadIntFlag(usartId, USART_INT_FLAG_PE))
    {
        uartStatus->rxStatus = STATUS_USART_PARITY_ERROR;

        if (uartStatus->transferType == USART_USE_DMA)
        {
            Usart_Irq_StopRxDma(uartStatus);
        }
        else
        {
            Usart_Irq_StopRxInt(uartStatus);
        }
    }
    /* Framing error: flag set and ERRIE enabled */
    else if ((uint8)SET == Usart_Hw_ReadIntFlag(usartId, USART_INT_FLAG_FE))
    {
        uartStatus->rxStatus = STATUS_USART_FRAMING_ERROR;
      
        if (uartStatus->transferType == USART_USE_DMA)
        {
            Usart_Irq_StopRxDma(uartStatus);
        }
        else
        {
            Usart_Irq_StopRxInt(uartStatus);
        }
    }
    /* Noise error: flag set and ERRIE enabled */
    else if ((uint8)SET == Usart_Hw_ReadIntFlag(usartId, USART_INT_FLAG_NE))
    {
        uartStatus->rxStatus = STATUS_USART_NOISE_ERROR;
      
        if (uartStatus->transferType == USART_USE_DMA)
        {
            Usart_Irq_StopRxDma(uartStatus);
        }
        else
        {
            Usart_Irq_StopRxInt(uartStatus);
        }
    }
    /* Overrun error: flag set and ERRIE enabled */
    else if ((uint8)SET == Usart_Hw_ReadIntFlag(usartId, USART_INT_FLAG_OVRE))
    {
        uartStatus->rxStatus = STATUS_USART_RX_OVERRUN;
      
        if (uartStatus->transferType == USART_USE_DMA)
        {
            Usart_Irq_StopRxDma(uartStatus);
        }
        else
        {
            Usart_Irq_StopRxInt(uartStatus);
        }
    }
    /* Receive timeout: flag set and RXTOIE enabled */
    else if ((uint8)SET == Usart_Hw_ReadIntFlag(usartId, USART_INT_FLAG_RXTOF))
    {
        uartStatus->rxStatus = STATUS_USART_TIMEOUT;
      
        if (uartStatus->transferType == USART_USE_DMA)
        {
            Usart_Irq_StopRxDma(uartStatus);
        }
        else
        {
            Usart_Irq_StopRxInt(uartStatus);
        }
    }
    else
    {
        /* nothing */
    }
}


/*!
* @brief       Handles received data during interrupt processing
*
* @param       uartStatus      Pointer to USART state structure
*
* @note        Applies parity masking based on word length
* @note        Manages receive buffer pointers and counters
* @note        Automatically disables RX when transfer completes
* @note        Updates RX status upon completion
*/
static FUNC(void, USART_CODE) Usart_Irq_ReceiveHandler(Usart_StateType * uartStatus)
{
    uint16 * tempVal = uartStatus->rxBuffer;
    
    /* Read one data word from the USART hardware data register and store it */
    *tempVal = Usart_Hw_RxData(uartStatus->usartId);
    
    /* If parity is configured, apply a mask to keep only the valid bits
       depending on the word length (e.g., 7-bit or 8-bit format) */
    if (g_lpuartStatus[uartStatus->usartId].parity != USART_PARITY_NONE)
    {
        if (uartStatus->wordLength == USART_WORD_LEN_9B)
        {
            *tempVal = *tempVal & (uint16)0xFF;
        }
        else if (uartStatus->wordLength == USART_WORD_LEN_8B)
        {
            *tempVal = *tempVal & (uint16)0xEF;
        }
        else
        {
            /* nothing */
        }
    }
    else if (uartStatus->wordLength == USART_WORD_LEN_8B)
    {
        *tempVal = *tempVal & (uint16)0xFFU;
    }
    else
    {
        /* nothing */
    }
    
    /* Decrement the remaining receive length and move to the next buffer position */
    uartStatus->rxLen = uartStatus->rxLen - 1U;
    ++uartStatus->rxBuffer;
    
    /* If there is no more data to receive (rxLen == 0), stop RX and clear state */
    if (uartStatus->rxLen == 0U)
    {
        if (uartStatus->rxStatus == STATUS_USART_BUSY)
        {
            uartStatus->rxStatus = STATUS_USART_SUCCESS;
        }
        else
        {
            /* nothing */
        }

        Usart_Irq_StopRxInt(uartStatus);
    }
    else
    {
        /* nothing */
    }
}


/*!
* @brief       Handles data transmission during interrupt processing
*
* @param       uartStatus      Pointer to USART state structure
*
* @note        Manages buffer pointers and length counters
* @note        Adjusts pointer arithmetic based on word length and parity
* @note        Automatically switches interrupt modes when transfer completes
*/
static FUNC(void, USART_CODE) Usart_Irq_TransmitHandler(Usart_StateType * uartStatus)
{
    /* If there is no data to transmit, return immediately. */
    if (uartStatus->txLen <= 0U)
    {
        /* nothing */
    }
    else
    {
        /* Send one data unit from txBuffer to the USART hardware data register. */
        Usart_Hw_TxData(uartStatus->usartId, uartStatus->txBuffer);
        
        if (uartStatus->modeSelect == USART_HALF_DUPLEX)
        {
            if (*uartStatus->txBuffer != Usart_Hw_RxData(uartStatus->usartId))
            {
                uartStatus->txStatus = STATUS_USART_ERROR;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {
            /* nothing */
        }

        if (g_lpuartStatus[uartStatus->usartId].parity == USART_PARITY_NONE)
        {
            if (uartStatus->wordLength == USART_WORD_LEN_9B)
            {
                uartStatus->txBuffer = &uartStatus->txBuffer[2];
                uartStatus->txLen -= 2U;
            }
            else if (uartStatus->wordLength == USART_WORD_LEN_8B)
            {
                uartStatus->txLen = uartStatus->txLen - 1U;
                ++uartStatus->txBuffer;
            }
            else
            {
                /* nothing */
            }
        }
        else
        {
            uartStatus->txLen = uartStatus->txLen - 1U;
            ++uartStatus->txBuffer;
        }

        
        /* If all data has been transmitted (txLen == 0), disable or enable certain interrupts as needed. */
        if (uartStatus->txLen == 0U)
        {
            Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_TXBEIE,DISABLE);
            Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_TXCIE,ENABLE);
        }
        else
        {
            /* nothing */
        }
    }
}


/*!
* @brief       Stops interrupt-driven transmission
*
* @param       uartStatus      Pointer to USART state structure
*
* @note        Disables TX direction and associated interrupts
* @note        Updates transmission status flags
* @note        Clears TX busy flag
*/
static FUNC(void, USART_CODE) Usart_Irq_StopTxInt(Usart_StateType * uartStatus)
{
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_TXBEIE,DISABLE);
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_TXCIE,DISABLE);
    Usart_Hw_OperationDirectionMode(uartStatus->usartId,USART_MODE_TX,DISABLE);
    Usart_Hw_ClearStatusFlag(uartStatus->usartId, (uint32)USART_FLAG_TXC);

    if (uartStatus->txStatus == STATUS_USART_BUSY)
    {
        uartStatus->txStatus = STATUS_USART_SUCCESS;
    }
    else
    {
        /* nothing */
    }
    
    uartStatus->txBusy = FALSE;
    uartStatus->txLen = 0U;
    uartStatus->txBuffer = (const uint8 *)0;
}


/*!
* @brief       Stops DMA-driven transmission
*
* @param       uartStatus      Pointer to USART state structure
*
* @note        Disables TX direction and DMA requests
* @note        Conditionally disables DMA notifications/channel if supported
* @note        Updates transmission status and clears busy flag
*/
static FUNC(void, USART_CODE) Usart_Irq_StopTxDma(Usart_StateType * uartStatus)
{
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_TXBEIE,DISABLE);
    Usart_Hw_OperationInterrupt(uartStatus->usartId,USART_INT_TXCIE,DISABLE);
    Usart_Hw_OperationDirectionMode(uartStatus->usartId,USART_MODE_TX,DISABLE);
    Usart_Hw_OperationDma(uartStatus->usartId,USART_DMA_REQUEST_TX,DISABLE);
    Usart_Hw_ClearStatusFlag(uartStatus->usartId, (uint32)USART_FLAG_TXC);

#if (STD_ON == USART_DMA_SUPPORT)
    Pdl_TopDmaNotifiDis(uartStatus->txDmaChannel, PDL_DMA_TRAN_COMPLETED);
    Pdl_TopDmaNotifiDis(uartStatus->txDmaChannel, PDL_DMA_TRAN_HALF_COMPLETED);
    Pdl_TopDmaNotifiDis(uartStatus->txDmaChannel, PDL_DMA_TRAN_ERROR);
    Pdl_TopDmaChDis(uartStatus->txDmaChannel);
#endif

    if (uartStatus->txStatus == STATUS_USART_BUSY)
    {
        uartStatus->txStatus = STATUS_USART_SUCCESS;
    }
    else
    {
        /* nothing */
    }

    uartStatus->txBusy = FALSE;
    uartStatus->txLen = 0U;
    uartStatus->txBuffer = (const uint8 *)0;
}


/*!
* @brief       Handles transmission complete interrupt
*
* @param       uartStatus      Pointer to USART state structure
*
* @note        Delegates to appropriate stop function based on transfer type
* @note        Verifies all data has been transmitted before stopping
*/
static FUNC(void, USART_CODE) Usart_Irq_TxCompleteHandler(Usart_StateType * uartStatus)
{
    if (uartStatus->txLen != 0U)
    {
        /* nothing */
    }
    else
    {
        if (uartStatus->transferType == USART_USE_DMA)
        {
            Usart_Irq_StopTxDma(uartStatus);
        }
        else
        {
            Usart_Irq_StopTxInt(uartStatus);
        }
    }
}
#endif

/**@} end of group USART_Fuctions */

#ifdef __cplusplus
}
#endif  /* ifdef __cplusplus */

/**@} end of group USART_Driver */
/**@} end of group G32A10xx_StdPeriphDriver */
