/*!
* @file     Adc.c
*
* @version  1.0.0
*
* @brief    AUTOSAR Adc Driver implementations
*
* @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.
*/

#ifdef __cplusplus
extern "C"{
#endif  /* ifdef __cplusplus */

#include "Adc.h"
#include "Adc_Hw.h"  
#include "Reg_eSys.h"

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

#include "Det.h"

/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup ADC_Driver
  * @brief ADC driver modules
  @{
*/

/** @defgroup ADC_Macros
  @{
*/
/*******************************************************************************
                    VENDOR ID & AUTOSAR VERSION INFO
*******************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define ADC_VENDOR_ID                              0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define ADC_AR_RELEASE_MAJOR_VERSION               0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define ADC_AR_RELEASE_MINOR_VERSION               0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define ADC_AR_RELEASE_REVISION_VERSION            0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */ 
#define ADC_SW_MAJOR_VERSION                       0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define ADC_SW_MINOR_VERSION                       0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define ADC_SW_PATCH_VERSION                       0x00U

/**@} end of group ADC_Macros */
/*******************************************************************************
                              GLOBAL VARIABLE
*******************************************************************************/
/** @defgroup ADC_Variable
  @{
*/
#define ADC_START_SEC_VAR_INIT_UNSPECIFIED
#include "Adc_MemMap.h"

/** Status of the ADC module */
static VAR(Adc_UnitStateType, ADC_VAR) g_adcGlobalState = ADC_UNIT_STATE_UNINIT;

/** Pointer variable to the ADC configuration structure */
volatile P2CONST(Adc_ConfigType, ADC_VAR, ADC_APPL_CONST) g_adcConfigPtr = NULL_PTR;

/** Pointer variable of the adc group */
P2CONST(Adc_GroupConfigType, ADC_VAR, ADC_APPL_CONST) g_adcGroupPtr = NULL_PTR;

/** The currently running channel group of the ADC */
Adc_GroupType g_adcActiveGroup = 0xFF;

/**@} end of group ADC_Variable */

#define ADC_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Adc_MemMap.h"

#define ADC_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Adc_MemMap.h"

/** @defgroup ADC_Variable
  @{
*/

/** ADC priority queue variable */
Adc_UnitStatusRecordType g_adcHwPrioQueStatus;

/** Status of each ADC group */
VAR(Adc_GroupStatusRecordType, ADC_VAR) g_adcGroupStatus[ADC_MAXIMUN_GROUPS_SET];

/**@} end of group ADC_Variable */

#define ADC_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Adc_MemMap.h"


#define ADC_START_SEC_VAR_INIT_8
#include "Adc_MemMap.h"

/** @defgroup ADC_Variable
  @{
*/
/** ADC current channel Index */
uint16 g_adcCurrentChannel = 0;
/** Number of Queues */
uint8 g_adcIrqQueueNum = 0;
/** Channel Index Calculation */
uint8 g_adcIrqQueueNumLinear = 0;

/**@} end of group ADC_Variable */

#define ADC_STOP_SEC_VAR_INIT_8
#include "Adc_MemMap.h"

/*******************************************************************************
                              GLOBAL FUNCTION
*******************************************************************************/
#if (STD_ON == ADC_ENABLE_INTERRUPT)
#if ((STD_ON == ADC_PRIORITY_IMPLEMENTATION))
static void Adc_PriorityQueueConfig(Adc_GroupType Group)
{
    const Adc_GroupConfigType* group = &g_adcConfigPtr->addGroupCfg[Group];
    uint8 pos = 0;
    uint8 i = 0;

    while ((pos < g_adcHwPrioQueStatus.queueCount) && 
           (g_adcHwPrioQueStatus.groupPriority.priorityQueue[pos] >= group->adcGroupPriority))
    {
        pos++;
    }
    
    if((uint8)0 != g_adcHwPrioQueStatus.queueCount)
    {
        for (i = g_adcHwPrioQueStatus.queueCount; i > pos; i--)
        {
            g_adcHwPrioQueStatus.groupPriority.priorityQueue[i] = g_adcHwPrioQueStatus.groupPriority.priorityQueue[i - (uint8)1];
            g_adcHwPrioQueStatus.groupPriority.groupQueue[i] = g_adcHwPrioQueStatus.groupPriority.groupQueue[i - (uint8)1];
        }
    }
    else
    {
        /* nothing */
    }
    
    g_adcHwPrioQueStatus.groupPriority.priorityQueue[pos] = group->adcGroupPriority;
    g_adcHwPrioQueStatus.groupPriority.groupQueue[pos] = group->groupID;
    
    
    g_adcHwPrioQueStatus.queueCount++;
}
#endif
#endif
/**@} end of group ADC_Fuctions */

#define ADC_START_SEC_CODE
#include "Adc_MemMap.h"

/** @defgroup ADC_Fuctions
  @{
*/

/*!
* @brief        Initializes the ADC hardware units and driver
*
* @param[in]    ConfigPtr   Pointer to configuration set in Variant PB
*                           (Variant PC requires a NULL_PTR).
* @return       None
*
* @note         Service ID[hex]: 0x00
* @note         Synchronous
* @note         Non reentrant function
*
*/
void Adc_Init(P2CONST(Adc_ConfigType, AUTOMATIC, ADC_APPL_CONST) ConfigPtr)
{
    uint8 tempAdc = 0;

#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    if (ADC_UNIT_STATE_UNINIT != g_adcGlobalState)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_INIT, ADC_E_ALREADY_INITIALIZED);
    }
    else if (NULL_PTR == ConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_INIT, ADC_E_PARAM_POINTER);
    }
    else
    {
#endif
        tempAdc = ConfigPtr->adcSelect;
        g_adcConfigPtr = ConfigPtr;
        g_adcGroupPtr = g_adcGroupConfig;
        
        Adc_Hw_clearCtrlReg(tempAdc);
        Adc_Hw_EnableADC(tempAdc,ENABLE);
        
        Adc_Hw_ClockModeConfig(tempAdc,ConfigPtr->adcClockSel);
        Adc_Hw_CataResolutionConfig(tempAdc,ConfigPtr->dataResolution);
        
        Adc_Hw_DisableADC(tempAdc,ENABLE);
        
        if ((uint32_t)0x0 == Adc_Hw_ReadCalibrationFactor(tempAdc))
        {
            
        }
        else
        {
            if (ConfigPtr->selectTranMode == ADC_TRANS_MODE_INTERRUPT)
            {
#if (STD_ON == ADC_ENABLE_INTERRUPT)
#if (STD_ON == ADC_LIMIT_VALUE_DETECTION_ENABLE)
                Adc_Hw_OperationInterrupt(tempAdc,ADC_INT_AWD,ENABLE);
#endif
                Adc_Hw_OperationInterrupt(tempAdc,ADC_INT_EOC,ENABLE);
#endif
            }
            else
            {
#if (ADC_DMA_TRANSFER_MODE == STD_ON)
                Adc_Hw_OperationDma(tempAdc,ENABLE);
                Adc_Hw_EnableDmaLoopMode(tempAdc,ENABLE);
#endif
            }
            Adc_Hw_clearCtrlReg(tempAdc);
            
            g_adcHwPrioQueStatus.queueCount = 0;
            
            g_adcGlobalState = ADC_UNIT_STATE_IDLE;
            
            Adc_Hw_EnableADC(tempAdc,ENABLE);
        }
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
}


#if (STD_ON == ADC_DEINIT_API)
/*!
* @brief            This function is used to clear the existing configuration 
*                   information of the ADC module. After clearing, the state 
*                   of the entire module is restored to the state when it was 
*                   powered on.
* 
* @param[in]        None
*
*/
void Adc_DeInit(void)
{
    uint8 tempAdc = 0;
    uint8 tempState = E_OK;
    uint8 tempVal = 0;
    
    if (NULL_PTR == g_adcConfigPtr)
    {
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_START_GROUP_CONVERSION, ADC_E_UNINIT);
#endif
        tempState = E_NOT_OK;
    }    
    else
    {
	tempAdc = g_adcConfigPtr->adcSelect;

        for (tempVal = 0; tempVal < (uint8)ADC_MAXIMUN_GROUPS_SET; tempVal++)
        {
            if ((g_adcGroupStatus[tempVal].groupStatus != ADC_IDLE) ||
                (g_adcGroupStatus[tempVal].groupStatus != ADC_STREAM_COMPLETED))
            {
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
                (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                                SID_ADC_DEINIT, ADC_E_BUSY);
#endif
		tempState = E_NOT_OK;
            }
            else
            {
                /* nothing */
            }
        }
    }
    
    if (tempState == E_OK)
    {
        Adc_Hw_WriteInterruptFlag(tempAdc,ADC_INT_FLAG_EOC);
#if (STD_ON == ADC_ENABLE_INTERRUPT)
#if (STD_ON == ADC_LIMIT_VALUE_DETECTION_ENABLE)
        Adc_Hw_OperationInterrupt(tempAdc,ADC_INT_AWD,DISABLE);
#endif
        Adc_Hw_OperationInterrupt(tempAdc,ADC_INT_EOC,DISABLE);
#endif
        Adc_Hw_EnableDelayConversion(tempAdc,DISABLE);
        Adc_Hw_DisableADC(tempAdc,ENABLE);
        Adc_Hw_SelectMode(tempAdc,ADC_CONV_MODE_ONESHOT);
        Adc_Hw_CataResolutionConfig(tempAdc,ADC_RESOLUTION_12B);
        Adc_Hw_ClockModeConfig(tempAdc,ADC_CLOCK_MODE_ASYNCLK);
        Adc_Hw_SelectSamplingTime(tempAdc,ADC_SAMPLE_TIME_1_5);
        
        g_adcGlobalState = ADC_UNIT_STATE_UNINIT;
        
    #if (STD_ON == ADC_DMA_TRANSFER_MODE)
        Adc_Hw_OperationDma(tempAdc,DISABLE);
        Adc_Hw_EnableDmaLoopMode(tempAdc,DISABLE);
        Pdl_DeInit();
    #endif
    }
    else
    {
        /* nothing */
    }
}
#endif


#if (STD_ON == ADC_START_STOP_GROUP_API)
/*!
* @brief          This function is used to start the channel conversion whose trigger source is software.
*
* @param[in]      Group    Group ID.
*
*/
void Adc_StartGroupConversion(Adc_GroupType Group)
{
#if (STD_ON == ADC_ENABLE_INTERRUPT) || (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    const Adc_GroupConfigType* group = NULL_PTR;
#if (STD_ON == ADC_PRIORITY_IMPLEMENTATION)
    uint8 newPriority = 0;
    uint16 currPriority = 0;
    uint16 tempGroupQueue = 0;
    boolean currNonPreemptable = 0;
#endif
#endif
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_START_GROUP_CONVERSION, ADC_E_UNINIT);
    }
    else
    {
#endif
#if (STD_ON == ADC_ENABLE_INTERRUPT) || (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
        group = &g_adcConfigPtr->addGroupCfg[Group];
#endif
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
    if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_START_GROUP_CONVERSION, ADC_E_PARAM_GROUP);
    }
    else if ((NULL_PTR == group) || (ADC_TRIGG_SRC_HW == group->selTrigger))
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_START_GROUP_CONVERSION, ADC_E_WRONG_TRIGG_SRC);
    }
    else if (NULL_PTR == group->adcGroupResultBuffer[Group])
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_START_GROUP_CONVERSION, ADC_E_BUFFER_UNINIT);
    }
#if ((STD_ON == ADC_PRIORITY_IMPLEMENTATION) && (STD_ON == ADC_QUEUE_IMPLEMENTATION))
    else if ((g_adcGroupStatus[Group].groupStatus != ADC_IDLE) &&
             (g_adcGroupStatus[Group].groupStatus != ADC_STREAM_COMPLETED))
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_STOP_GROUP_CONVERSION, ADC_E_BUSY);
    }
#endif
    else
    {
#endif

#if (STD_ON == ADC_ENABLE_INTERRUPT)
        if ((uint8)0 == g_adcHwPrioQueStatus.queueCount)
        {
            g_adcGroupStatus[Group].groupStatus = ADC_BUSY;
#if (STD_ON == ADC_PRIORITY_IMPLEMENTATION)
            Adc_PriorityQueueConfig(Group);
#else
            g_adcHwPrioQueStatus.groupPriority.groupQueue[g_adcHwPrioQueStatus.queueCount] = group->groupID;
            g_adcHwPrioQueStatus.queueCount++;
#endif
            Adc_Hw_StartGroupConversion(Group);
            
            if (ADC_CONV_MODE_ONESHOT == g_adcGroupPtr[Group].converMode)
            {
                Adc_RemoveQueueMem(Group);
            }
            else
            {
                /* nothing */
            }
        }
        else
        {
#if (STD_ON == ADC_PRIORITY_IMPLEMENTATION)
            newPriority = group->adcGroupPriority;
            currPriority = g_adcHwPrioQueStatus.groupPriority.priorityQueue[0];
            tempGroupQueue = g_adcHwPrioQueStatus.groupPriority.groupQueue[0];
            currNonPreemptable = g_adcConfigPtr->addGroupCfg[tempGroupQueue].enableNonPreemptable;
            
            if ((newPriority > currPriority) &&(currNonPreemptable != (boolean)TRUE))
            {
                Adc_Hw_StopGroupConversion(g_adcHwPrioQueStatus.groupPriority.groupQueue[0]);
                
                g_adcGroupStatus[Group].groupStatus = ADC_BUSY;
                
                Adc_PriorityQueueConfig(Group);
                Adc_Hw_StartGroupConversion(Group);
                
                if (ADC_CONV_MODE_ONESHOT == g_adcGroupPtr[Group].converMode)
                {
                    Adc_RemoveQueueMem(Group);
                }
                else
                {
                    /* nothing */
                }
            }
            else
            {
                g_adcGroupStatus[Group].groupStatus = ADC_BUSY;
                Adc_PriorityQueueConfig(Group);
            }
#else
#if (STD_ON == ADC_QUEUE_IMPLEMENTATION)
            g_adcHwPrioQueStatus.groupPriority.groupQueue[g_adcHwPrioQueStatus.queueCount] = group->groupID;
            g_adcHwPrioQueStatus.queueCount++;
#endif
#endif
        }
#else
    g_adcGroupStatus[Group].groupStatus = ADC_BUSY;
    Adc_Hw_StartGroupConversion(Group);
#endif


        
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
}


/*!
* @brief          This function is used to stop the channel conversion whose trigger source is software.
* 
* @param[in]      Group    Group ID.
*
*/
void Adc_StopGroupConversion(Adc_GroupType Group)
{
#if (STD_ON == ADC_ENABLE_INTERRUPT) || (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    const Adc_GroupConfigType* group = NULL_PTR;
#endif
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_STOP_GROUP_CONVERSION, ADC_E_UNINIT);
    }
    else
    {
#endif
#if (STD_ON == ADC_ENABLE_INTERRUPT) || (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
        group = &g_adcConfigPtr->addGroupCfg[Group];
#endif
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }

    if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_STOP_GROUP_CONVERSION, ADC_E_PARAM_GROUP);
    }
    else if ((NULL_PTR == group) || (ADC_TRIGG_SRC_HW == group->selTrigger))
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_STOP_GROUP_CONVERSION, ADC_E_WRONG_TRIGG_SRC);
    }
    else if (ADC_IDLE == g_adcGroupStatus[Group].groupStatus)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_STOP_GROUP_CONVERSION, ADC_E_IDLE);
    }
    else
    {
#endif

#if (STD_ON == ADC_ENABLE_INTERRUPT)
#if (STD_ON == ADC_QUEUE_IMPLEMENTATION)
        if (group->groupID == g_adcHwPrioQueStatus.groupPriority.groupQueue[0])
        {
            Adc_RemoveQueueMem(Group);
            if ((ADC_ACCESS_MODE_STREAMING == group->accessModeCfg.accessMode) &&
                (ADC_STREAM_BUFFER_CIRCULAR == group->accessModeCfg.streamMode))
            {
                Adc_Hw_StopGroupConversion(Group);
            }
            else
            {
                /* nothing */
            }
            if ((uint8)0 == g_adcHwPrioQueStatus.queueCount)
            {
                /* nothing */
            }
            else
            {
                g_adcGroupStatus[g_adcHwPrioQueStatus.groupPriority.groupQueue[0]].groupStatus = ADC_BUSY;
                Adc_Hw_StartGroupConversion(g_adcHwPrioQueStatus.groupPriority.groupQueue[0]);
            }
        }
        else
        {
            Adc_RemoveQueueMem(Group);
        }
#else
        Adc_RemoveQueueMem(Group);
        Adc_Hw_StopGroupConversion(Group);
#endif
        g_adcGroupStatus[Group].groupStatus = ADC_IDLE;
#else
    Adc_Hw_StopGroupConversion(Group);
    g_adcGroupStatus[Group].groupStatus = ADC_IDLE;
#endif

#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
}

#endif


/*!
* @brief          This function is used to gain the number of valid samples per channel.
* 
* @param[in]      groupId            group ID.
* @param[out]     PtrToSamplePtr     Pointer to result buffer pointer.
* 
* @return         Adc_StreamNumSampleType   Number of valid samples per channel.
*/
Adc_StreamNumSampleType Adc_GetStreamLastPointer(Adc_GroupType Group, 
                                                 Adc_ValueGroupType** PtrToSamplePtr)
{
    Adc_StreamNumSampleType adcStreamNumSample = 0U;
    Adc_StreamNumSampleType adcResultIndex = 0U;
    const Adc_GroupConfigType* group = NULL_PTR;

#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_GET_STREAM_LAST_POINTER, ADC_E_UNINIT);
        
        *PtrToSamplePtr = (Adc_ValueGroupType *)NULL_PTR;
    }
    else
    {
#endif
        group = &g_adcConfigPtr->addGroupCfg[Group];
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }

    if (NULL_PTR == group)
    {
        /* nothing */
    }
    else if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_GET_STREAM_LAST_POINTER, ADC_E_PARAM_GROUP);
        
        *PtrToSamplePtr = (Adc_ValueGroupType *)NULL_PTR;
    }
    else if (ADC_IDLE == g_adcGroupStatus[Group].groupStatus)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_GET_STREAM_LAST_POINTER, ADC_E_IDLE);
    }
    else
    {
#endif
        if (ADC_BUSY != g_adcGroupStatus[Group].groupStatus)
        {
            adcStreamNumSample = group->accessModeCfg.streamNumSamples;
            adcResultIndex = group->accessModeCfg.streamNumSamples - (Adc_StreamNumSampleType)1;
            
            *PtrToSamplePtr = &group->adcGroupResultBuffer[Group][adcResultIndex];
        }
        else
        {
            /* nothing */
        }
        
        if ((ADC_BUSY == g_adcGroupStatus[Group].groupStatus))
        {
            *PtrToSamplePtr = (Adc_ValueGroupType *)NULL_PTR;
            adcStreamNumSample = 0;
        }
        else if ((ADC_STREAM_COMPLETED == g_adcGroupStatus[Group].groupStatus))
        {
            if ((group->converMode == ADC_CONV_MODE_CONTINUOUS) &&
                (group->accessModeCfg.accessMode == ADC_ACCESS_MODE_STREAMING) &&
                (group->accessModeCfg.streamMode == ADC_STREAM_BUFFER_CIRCULAR))
            {
                g_adcGroupStatus[Group].groupStatus = ADC_BUSY;
            }
            else if ((group->converMode == ADC_CONV_MODE_ONESHOT) ||
                    ((ADC_CONV_MODE_CONTINUOUS == group->converMode) &&
                     (ADC_ACCESS_MODE_STREAMING == group->accessModeCfg.accessMode) &&
                     (ADC_STREAM_BUFFER_LINEAR == group->accessModeCfg.streamMode)) ||
                    ((ADC_CONV_MODE_CONTINUOUS == group->converMode) &&
                     (ADC_ACCESS_MODE_SINGLE == group->accessModeCfg.accessMode)))
            {
                g_adcGroupStatus[Group].groupStatus = ADC_IDLE;
            }
            else
            {
                /* nothing */
            }
        }
        else if ((ADC_COMPLETED == g_adcGroupStatus[Group].groupStatus))
        {
            g_adcGroupStatus[Group].groupStatus = ADC_BUSY;
        }
        else
        {
            /* nothing */
        }
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
    
    return adcStreamNumSample;
}


/*!
* @brief        Initializes ADC driver with the group specific result buffer
*               start address where the conversion results will be stored.
* @details      The application has to ensure that the application buffer, where
*               DataBufferPtr points to, can hold all the conversion results of
*               the specified group. The initialization with Adc_SetupResultBuffer
*               is required after reset, before a group conversion can be started.
*
* @param[in]    Group           Group id
* @param[in]    DataBufferPtr   Pointer to result data buffer
*
* @return       Std_ReturnType  Standard return type
* @retval       E_OK:           Result buffer pointer initialized correctly
* @retval       E_NOT_OK:       Operation failed or development error occurred
*
* @note         Service ID[hex]: 0x0C
* @note         Synchronous
* @note         Reentrant function
*
*/
Std_ReturnType Adc_SetupResultBuffer(Adc_GroupType Group,
                                     Adc_ValueGroupType * DataBufferPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) result = (Std_ReturnType)E_NOT_OK;
    P2CONST(Adc_GroupConfigType, AUTOMATIC, ADC_APPL_CONST) groupPtr = NULL_PTR;
    
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_SETUP_RESULT_BUFFER, ADC_E_UNINIT);
    }
    else if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_SETUP_RESULT_BUFFER, ADC_E_PARAM_GROUP);
    }
    else if (NULL_PTR == DataBufferPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_SETUP_RESULT_BUFFER, ADC_E_PARAM_POINTER);
    }
    else if (ADC_IDLE != g_adcGroupStatus[Group].groupStatus)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_SETUP_RESULT_BUFFER, ADC_E_BUSY);
    }
    else
    {
#endif
        groupPtr = &g_adcConfigPtr->addGroupCfg[Group];
        groupPtr->adcGroupResultBuffer[Group] = DataBufferPtr;
#if (ADC_ENABLE_INTERRUPT == STD_ON)
#if (ADC_DMA_TRANSFER_MODE == STD_ON)
        if (g_adcConfigPtr->selectTranMode == ADC_TRANS_MODE_DMA)
        {
            Adc_Hw_DmaConfig(Group);
            Pdl_TopDmaChDataNumSet(DMA_HW_CH1, groupPtr->channelCount);
            Pdl_TopDmaMAddrRefresh(DMA_HW_CH1, (uint32_t)Adc_DmaBuf_Pointer[Group]);
            
            Pdl_TopDmaChEn(DMA_HW_CH1);
        }
#endif
#endif
        result = (Std_ReturnType)E_OK;
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
    return result;
}


#if (ADC_HARDWARE_TRIG_API == STD_ON)
/*!
* @brief          This function is used to enable the hardware trigger for the conversion group.
*
* @param[in]      groupId     group ID.
* 
*/
void Adc_EnableHardwareTrigger(Adc_GroupType Group)
{
    uint8 tempAdc = 0;
    const Adc_GroupConfigType* group = NULL_PTR;
    uint8 tempNum = 0;

#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_HARDWARE_TRIGGER, ADC_E_UNINIT);
    }
    else
    {
#endif
        group = &g_adcConfigPtr->addGroupCfg[Group];
        tempAdc = g_adcConfigPtr->adcSelect;
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }

    if (NULL_PTR == group)
    {
        /* nothing */
    }
    else if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_HARDWARE_TRIGGER, ADC_E_PARAM_GROUP);
    }
    else if (ADC_TRIGG_SRC_SW == group->selTrigger)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_HARDWARE_TRIGGER, ADC_E_WRONG_TRIGG_SRC);
    }
    else if (ADC_CONV_MODE_CONTINUOUS == group->converMode)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_HARDWARE_TRIGGER, ADC_E_WRONG_CONV_MODE);
    }
    else if (NULL_PTR == group->adcGroupResultBuffer[Group])
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_HARDWARE_TRIGGER, ADC_E_BUFFER_UNINIT);
    }
#if ((STD_OFF == ADC_PRIORITY_IMPLEMENTATION) && (STD_OFF == ADC_QUEUE_IMPLEMENTATION))
    else if (g_adcGroupStatus[Group].groupStatus != ADC_IDLE)
    {
        Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_HARDWARE_TRIGGER, ADC_E_BUSY);
    }
#endif
    else
    {
#endif
        Adc_Hw_SelectTRGOSignal(group->hwUnitId,group->TrgoSel);
        
        g_adcGroupStatus[Group].groupStatus = ADC_BUSY;
        
        Adc_Hw_TriggerSelect(tempAdc,ADC_TRIGG_SRC_HW,group->selHwTriggerSignal);
        Adc_Hw_TriggerEvent(tempAdc,group->triggerEvent);
        Adc_Hw_EnableBackDirection(tempAdc,group->enableBack);
        
        Adc_Hw_SelectMode(tempAdc,ADC_CONV_MODE_ONESHOT);
        Adc_Hw_EnableDelayConversion(tempAdc,ENABLE);
        
        Adc_Hw_SelectSamplingTime(tempAdc,group->channelCfg[0].sampleTime);
        
        for (tempNum = 0; tempNum < group->channelCount; tempNum++)
        {
            Adc_Hw_SelectChannel(tempAdc,group->channelCfg[tempNum].adcHwChannel,ENABLE);
        }
        
        g_adcActiveGroup = Group;
        Adc_Hw_EnableConversion(tempAdc,ENABLE);
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
}


/*!
* @brief          This function is used to disable the hardware trigger for the conversion group.
*
* @param[in]      groupId     group ID.
* 
*/
void Adc_DisableHardwareTrigger(Adc_GroupType Group)
{
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    const Adc_GroupConfigType* group = NULL_PTR;
  
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_HARDWARE_TRIGGER, ADC_E_UNINIT);
    }
    else
    {
        group = &g_adcConfigPtr->addGroupCfg[Group];
    }

    if (NULL_PTR == group)
    {
        /* nothing */
    }
    else if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_HARDWARE_TRIGGER, ADC_E_PARAM_GROUP);
    }
    else if (ADC_TRIGG_SRC_SW == group->selTrigger)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_HARDWARE_TRIGGER, ADC_E_WRONG_TRIGG_SRC);
    }
    else if (ADC_IDLE == g_adcGroupStatus[Group].groupStatus)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_HARDWARE_TRIGGER, ADC_E_IDLE);
    }
    else if (ADC_CONV_MODE_CONTINUOUS == group->converMode)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_HARDWARE_TRIGGER, ADC_E_WRONG_CONV_MODE);
    }
    else
    {
#endif
        Adc_Hw_StopGroupConversion(Group);
        g_adcGroupStatus[Group].groupStatus = ADC_IDLE;
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
}
#endif


#if (STD_ON == ADC_GROUP_NOTIFICATION_API)
/*!
* @brief          This function is used to enable the notification.
* 
* @param[in]      groupId     group ID.
* 
*/
void Adc_EnableGroupNotification(Adc_GroupType Group)
{
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    const Adc_GroupConfigType* group = NULL_PTR;
  
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_GROUP_NOTIFICATION, ADC_E_UNINIT);
    }
    else
    {
        group = &g_adcConfigPtr->addGroupCfg[Group];
    }
    if (NULL_PTR == group)
    {
        /* nothing */
    }
    else if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_GROUP_NOTIFICATION, ADC_E_PARAM_GROUP);
    }
    else if (NULL_PTR == group->adcGroupNotification)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_ENABLE_GROUP_NOTIFICATION, ADC_E_NOTIF_CAPABILITY);
    }
    else
    {
#endif
        g_adcGroupStatus[Group].notificationStatus = ADC_GROUP_NOTIFICATION_ENABLED;
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
}


/*!
* @brief          This function is used to disable the notification.
* 
* @param[in]      groupId     group ID.
*
*/
void Adc_DisableGroupNotification(Adc_GroupType Group)
{
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    const Adc_GroupConfigType* group = NULL_PTR;
  
    if (NULL_PTR == g_adcConfigPtr)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_GROUP_NOTIFICATION, ADC_E_UNINIT);
    }
    else
    {
        group = &g_adcConfigPtr->addGroupCfg[Group];
    }

    if (NULL_PTR == group)
    {
        /* nothing */
    }
    else if (Group >= g_adcConfig.groupMaxNum)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_GROUP_NOTIFICATION, ADC_E_PARAM_GROUP);
    }
    else if (NULL_PTR == group->adcGroupNotification)
    {
        (void)Det_ReportError((uint16)ADC_H_MODULE_ID, ADC_INSTANCE_ID,
                            SID_ADC_DISABLE_GROUP_NOTIFICATION, ADC_E_NOTIF_CAPABILITY);
    }
    else
    {
#endif
        g_adcGroupStatus[Group].notificationStatus = ADC_GROUP_NOTIFICATION_DISABLED;
#if (STD_ON == ADC_DEV_ERR_DETECT_ENABLE)
    }
#endif
}
#endif


#if (ADC_VERSINFO_API == STD_ON)
/*!
* @brief         This function is used to return the ADC module version information
*
* @param[in]     VersionInfo:  A pointer to the variable where version information is stored.
*
* @retval        void
*
*/
FUNC(void, MCU_CODE) Adc_GetVersionInfo(P2VAR(Std_VersionInfoType, AUTOMATIC, ADC_APPL_DATA) VersionInfo)
{
    if(NULL_PTR != VersionInfo)
    {
        (VersionInfo)->vendorID = (uint16)ADC_CFG_H_VENDOR_ID;
        (VersionInfo)->moduleID = (uint8)ADC_CFG_H_MODULE_ID;
        (VersionInfo)->sw_major_version = (uint8)ADC_CFG_H_SW_MAJOR_VERSION;
        (VersionInfo)->sw_minor_version = (uint8)ADC_CFG_H_SW_MINOR_VERSION;
        (VersionInfo)->sw_patch_version = (uint8)ADC_CFG_H_SW_PATCH_VERSION;
    }
    else
    {
#if (ADC_DEV_ERR_DETECT_ENABLE == STD_ON)
        (void)Det_ReportError((uint16)ADC_CFG_H_MODULE_ID, ADC_INSTANCE_ID,
                        SID_ADC_GET_VERSION_INFO, ADC_E_PARAM_POINTER);
#endif
    }
}
#endif


void Adc_RemoveQueueMem(Adc_GroupType Group)
{
    const uint8 groupID = g_adcConfigPtr->addGroupCfg[Group].groupID;
    uint8 idx = 0xFF;
    uint8 i = 0;
    
    for(i = 0; i < (uint8)g_adcHwPrioQueStatus.queueCount; i++)
    {
        if (g_adcHwPrioQueStatus.groupPriority.groupQueue[i] == groupID)
        {
            idx = i;
        }
        else
        {
            /* nothing */
        }
    }
    
    if(idx == (uint8)0xFF)
    {
        /* nothing */
    }
    else
    {
        for(i = idx; i < (g_adcHwPrioQueStatus.queueCount - (uint8)1); i++)
        {
#if (STD_ON == ADC_PRIORITY_IMPLEMENTATION)
            g_adcHwPrioQueStatus.groupPriority.priorityQueue[i] = g_adcHwPrioQueStatus.groupPriority.priorityQueue[i + (uint8)1];
#endif
            g_adcHwPrioQueStatus.groupPriority.groupQueue[i] = g_adcHwPrioQueStatus.groupPriority.groupQueue[i + (uint8)1];
        }

#if (STD_ON == ADC_PRIORITY_IMPLEMENTATION)
        g_adcHwPrioQueStatus.groupPriority.priorityQueue[g_adcHwPrioQueStatus.queueCount - (uint8)1] = 0;
#endif
        g_adcHwPrioQueStatus.groupPriority.groupQueue[g_adcHwPrioQueStatus.queueCount - (uint8)1] = 0;
        
        g_adcHwPrioQueStatus.queueCount--;
    }
}


#if (STD_ON == ADC_DMA_TRANSFER_MODE)
FUNC(void, GPT_CODE) Adc_DmaChannel1CompletionNotificaiton(void)
{
    uint8 tempAdc = g_adcConfigPtr->adcSelect;
    uint16 tempGroup = g_adcActiveGroup;
    
    if (ADC_STATUS_REG->EOSEQFLG)
    {
        if (ADC_ACCESS_MODE_SINGLE == g_adcGroupPtr[tempGroup].accessModeCfg.accessMode)
        {
            
            for (g_adcCurrentChannel = 0; g_adcCurrentChannel < g_adcGroupPtr[tempGroup].channelCount; g_adcCurrentChannel++)
            {
                g_adcGroupPtr[tempGroup].adcGroupResultBuffer[tempGroup][g_adcCurrentChannel] 
                                                = Adc_DmaBuf_Pointer[tempGroup][g_adcCurrentChannel];
            }
            if (g_adcCurrentChannel == g_adcConfigPtr->addGroupCfg[tempGroup].channelCount)
            {
                if (g_adcGroupStatus[tempGroup].notificationStatus == ADC_GROUP_NOTIFICATION_ENABLED &&
                    g_adcGroupPtr[tempGroup].adcGroupNotification != NULL_PTR)
                {
                    g_adcGroupPtr[tempGroup].adcGroupNotification();
                }
                g_adcGroupStatus[tempGroup].groupStatus = ADC_STREAM_COMPLETED;
                
                g_adcCurrentChannel = 0;
                Adc_RemoveQueueMem(tempGroup);
                Adc_Hw_StopGroupConversion(tempGroup);
                
                if (0 == g_adcHwPrioQueStatus.queueCount)
                {
                    /* nothing */
                }
                else
                {
                    g_adcGroupStatus[g_adcHwPrioQueStatus.groupPriority.groupQueue[0]].groupStatus = ADC_IDLE;
                    Adc_Hw_StartGroupConversion(g_adcHwPrioQueStatus.groupPriority.groupQueue[0]);
                }
            }
        }
        else if (ADC_ACCESS_MODE_STREAMING == g_adcGroupPtr[tempGroup].accessModeCfg.accessMode &&
                 ADC_STREAM_BUFFER_LINEAR == g_adcGroupPtr[tempGroup].accessModeCfg.streamMode)
        {
            if (Adc_Hw_GetChannelNum(tempAdc))
            {
                for (uint8 tempVal = 0; tempVal < g_adcGroupPtr[tempGroup].channelCount; tempVal++)
                {
                    g_adcGroupPtr[tempGroup].adcGroupResultBuffer[tempGroup][g_adcCurrentChannel + g_adcIrqQueueNumLinear] = 
                                                                        Adc_DmaBuf_Pointer[tempGroup][tempVal];
                    g_adcCurrentChannel = g_adcCurrentChannel + g_adcGroupPtr[tempGroup].accessModeCfg.streamNumSamples;
                }

                g_adcGroupStatus[tempGroup].groupStatus = ADC_COMPLETED;
            }
            
            if (g_adcIrqQueueNumLinear == (g_adcGroupPtr[tempGroup].accessModeCfg.streamNumSamples - 1) && 
                g_adcCurrentChannel == g_adcGroupPtr[tempGroup].accessModeCfg.streamNumSamples *
                                       g_adcGroupPtr[tempGroup].channelCount)
            {
                g_adcIrqQueueNumLinear = 0;
                
                if (g_adcGroupStatus[tempGroup].notificationStatus == ADC_GROUP_NOTIFICATION_ENABLED &&
                    g_adcGroupPtr[tempGroup].adcGroupNotification != NULL_PTR)
                {
                    g_adcGroupPtr[tempGroup].adcGroupNotification();
                }
                g_adcGroupStatus[tempGroup].groupStatus = ADC_STREAM_COMPLETED;
                
                Adc_RemoveQueueMem(tempGroup);
                Adc_Hw_StopGroupConversion(tempGroup);
                
                if (0 == g_adcHwPrioQueStatus.queueCount)
                {
                    /* nothing */
                }
                else
                {
                    g_adcGroupStatus[g_adcHwPrioQueStatus.groupPriority.groupQueue[0]].groupStatus = ADC_IDLE;
                    Adc_Hw_StartGroupConversion(g_adcHwPrioQueStatus.groupPriority.groupQueue[0]);
                }
            }
            if (g_adcCurrentChannel == g_adcGroupPtr[tempGroup].accessModeCfg.streamNumSamples *
                                       g_adcGroupPtr[tempGroup].channelCount)
            {
                g_adcIrqQueueNumLinear++;
                g_adcCurrentChannel = 0;
                
                if (g_adcGroupStatus[tempGroup].groupStatus == ADC_COMPLETED &&
                    g_adcIrqQueueNumLinear == (g_adcGroupPtr[tempGroup].accessModeCfg.streamNumSamples - 1))
                {
                    Adc_Hw_EnableConversion(tempAdc,ENABLE);
                }
            }
            
        }
        else if (ADC_ACCESS_MODE_STREAMING == g_adcGroupPtr[tempGroup].accessModeCfg.accessMode &&
                 ADC_STREAM_BUFFER_CIRCULAR == g_adcGroupPtr[tempGroup].accessModeCfg.streamMode)
        {
            for (uint8 tempVal = 0; tempVal < g_adcGroupPtr[tempGroup].channelCount; tempVal++)
            {
                g_adcGroupPtr[tempGroup].adcGroupResultBuffer[tempGroup][g_adcCurrentChannel + g_adcIrqQueueNum] = 
                                                                    Adc_DmaBuf_Pointer[tempGroup][tempVal];
                g_adcCurrentChannel = g_adcCurrentChannel + g_adcGroupPtr[g_adcActiveGroup].accessModeCfg.streamNumSamples;
            }
            
            if (g_adcCurrentChannel == g_adcGroupPtr[g_adcActiveGroup].accessModeCfg.streamNumSamples * 
                                       g_adcGroupPtr[g_adcActiveGroup].channelCount)
            {
                g_adcIrqQueueNum++;
                g_adcCurrentChannel = 0;
                
                if (g_adcIrqQueueNum == g_adcGroupPtr[tempGroup].accessModeCfg.streamNumSamples)
                {
                    g_adcIrqQueueNum = 0;
                    
                    if (g_adcGroupStatus[tempGroup].notificationStatus == ADC_GROUP_NOTIFICATION_ENABLED &&
                        g_adcGroupPtr[tempGroup].adcGroupNotification != NULL_PTR)
                    {
                        g_adcGroupPtr[tempGroup].adcGroupNotification();
                    }
                    g_adcGroupStatus[tempGroup].groupStatus = ADC_COMPLETED;
                }
            }
        }
    }
}
#endif

/**@} end of group ADC_Fuctions */

#define ADC_STOP_SEC_CODE
#include "Adc_MemMap.h"

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

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