/**
* @file    CddI2c.c
*==================================================================================================
*   Project              : YTMicro AUTOSAR 4.4.0 MCAL
*   Platform             : ARM
*   Peripheral           : CddI2c
*   Dependencies         : none
*
*   Autosar Version      : V4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   SW Version           : V1.3.2
*
*   (c) Copyright 2020-2023 Yuntu Microelectronics co.,ltd.
*   All Rights Reserved.
==================================================================================================*/

#include "Compiler.h"
#ifdef __cplusplus
extern "C"
{
#endif

/*==================================================================================================
                                              INCLUDE FILES
==================================================================================================*/
#include "CddI2c.h"
#include "CddI2c_Lld.h"
#include "OsIf.h"
#include "SchM_CddI2c.h"
#include "Det.h"
/*==================================================================================================
                                      SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define CDDI2C_VENDOR_ID_C                      (180)
#define CDDI2C_AR_RELEASE_MAJOR_VERSION_C       (4)
#define CDDI2C_AR_RELEASE_MINOR_VERSION_C       (4)
#define CDDI2C_AR_RELEASE_REVISION_VERSION_C    (0)
#define CDDI2C_SW_MAJOR_VERSION_C               (1)
#define CDDI2C_SW_MINOR_VERSION_C               (3)
#define CDDI2C_SW_PATCH_VERSION_C               (2)
/*==================================================================================================
                                            FILE VERSION CHECKS
==================================================================================================*/
/* Check if source file and CDDI2C header file are of the same vendor */
#if (CDDI2C_VENDOR_ID_C != CDDI2C_VENDOR_ID)
#error "CddI2c.c and CddI2c.h have different vendor ids"
#endif

/* Check if source file and CDDI2C header file are of the same Autosar version */
#if ((CDDI2C_AR_RELEASE_MAJOR_VERSION_C != CDDI2C_AR_RELEASE_MAJOR_VERSION) || \
     (CDDI2C_AR_RELEASE_MINOR_VERSION_C != CDDI2C_AR_RELEASE_MINOR_VERSION) || \
     (CDDI2C_AR_RELEASE_REVISION_VERSION_C != CDDI2C_AR_RELEASE_REVISION_VERSION))
#error "AutoSar Version Numbers of CddI2c.c and CddI2c.h are different"
#endif

/* Check if source file and CDDI2C header file are of the same Software version */
#if ((CDDI2C_SW_MAJOR_VERSION_C != CDDI2C_SW_MAJOR_VERSION) || \
     (CDDI2C_SW_MINOR_VERSION_C != CDDI2C_SW_MINOR_VERSION) || \
     (CDDI2C_SW_PATCH_VERSION_C != CDDI2C_SW_PATCH_VERSION))
#error "Software Version Numbers of CddI2c.c and CddI2c.h are different"
#endif

/*==================================================================================================
                                                GLOBAL VARIABLES
==================================================================================================*/
#define CDDI2C_START_SEC_VAR_INIT_UNSPECIFIED
#include "CddI2c_MemMap.h"

/**
* @brief          I2C Channel status array.
* @details        The status of the I2C channels.
*/
CDDI2C_VAR volatile CddI2c_StatusType CddI2c_ChannelStatus[CDDI2C_HW_MAX_MODULES] = CDDI2C_CHN_INIT_STATUS;

#define CDDI2C_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "CddI2c_MemMap.h"

#define CDDI2C_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "CddI2c_MemMap.h"
/**
* @brief          Global configuration pointer.
* @details        Pointer to the configuration structure.
*/
CDDI2C_VAR static const CddI2c_HwChannelConfigType *CddI2c_ChnConfigPtr[CDDI2C_HW_MAX_MODULES];

#define CDDI2C_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "CddI2c_MemMap.h"

/*==================================================================================================
                                                EXTERNAL VARIABLES
==================================================================================================*/
#if (CDDI2C_PRECOMPILE_SUPPORT == STD_ON)
extern const CddI2c_ConfigType CddI2c_PreCompileConfig;
#endif

/*==================================================================================================
                                                LOCAL VARIABLES
==================================================================================================*/
/*==================================================================================================
                                                LOCAL CONSTANTS
==================================================================================================*/
/*==================================================================================================
                                                LOCAL MACROS
==================================================================================================*/
/*==================================================================================================
                                                LOCAL FUNCTIONS
==================================================================================================*/

#define CDDI2C_START_SEC_CODE
#include "CddI2c_MemMap.h"

/**
* @brief   This function checks parameters for initialization of I2c driver.
*
* @param[in]     Config       Specifies the pointer to the configuration set
* @return        Std_ReturnType
* @retval        E_OK:     No error
* @retval        E_NOT_OK: Error
*
*/
CDDI2C_FUNC LOCAL_INLINE Std_ReturnType CddI2c_ErrorCheckInit(uint8 Channel, const CddI2c_HwChannelConfigType *Config)
{
    Std_ReturnType CheckStatus = E_OK;
    /* Check Config for not being a null pointer */
    if (NULL_PTR == Config)
    {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
        /* Invalid pointer */
        (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                              (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_PARAM_POINTER);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
        CheckStatus = E_NOT_OK;
    }
    else
    {
        /*Check the hw number is valid or not*/
        if (Config->I2cHwUnit >= CDDI2C_HW_MAX_MODULES)
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
            /* Invalid pointer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
            CheckStatus = E_NOT_OK;
        }
        /*Check the hw Channel is init or not*/
        else if (I2C_CHN_UNINIT != CddI2c_ChannelStatus[Channel])
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
            /* Invalid pointer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_REPEATED_INIT);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
            CheckStatus = E_NOT_OK;
        }
        else
        {
            /*Do Nothing*/
        }
    }
    return CheckStatus;
}

/**
* @brief   This function checks parameters for start listening of I2c slave driver.
*
* @param[in]     Config       Specifies the pointer to the configuration set
* @return        Std_ReturnType
* @retval        E_OK:     No error
* @retval        E_NOT_OK: Error
*
*/
CDDI2C_FUNC LOCAL_INLINE Std_ReturnType CddI2c_ErrorCheckStartListening(uint8 Channel, const CddI2c_HwChannelConfigType *Config)
{
    Std_ReturnType CheckStatus = E_OK;
    /* Check Config for not being a null pointer */
    if (NULL_PTR == Config)
    {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
        /* Invalid pointer */
        (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                              (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_PARAM_POINTER);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
        CheckStatus = E_NOT_OK;
    }
    else
    {
        /*Check the hw number is valid or not*/
        if (Config->I2cHwUnit >= CDDI2C_HW_MAX_MODULES)
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
            /* Invalid pointer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
            CheckStatus = E_NOT_OK;
        }
        /*Check the hw Channel is init or not*/
        else if (I2C_CHN_UNINIT == CddI2c_ChannelStatus[Channel])
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
            /* Invalid pointer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_REPEATED_INIT);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
            CheckStatus = E_NOT_OK;
        }
        else
        {
            /*Do Nothing*/
        }
    }
    return CheckStatus;
}

/**
* @brief   This function checks parameters for master transfer function of I2c driver.
*
* @param[in]     Channel       Specifies the index of Channel
* @param[in]     RequestPtr     Specifies the pointer to user transmit request
* @param[in]     I2cApiId      Specifies what api call this function
* @return        Std_ReturnType
* @retval        E_OK: No error
* @retval        E_NOT_OK: Error
*
*/
CDDI2C_FUNC LOCAL_INLINE Std_ReturnType CddI2c_MasterErrorCheckTransfer(uint8 Channel,
        const CddI2c_RequestType *RequestPtr,
        uint8 I2cApiId)
{
    Std_ReturnType CheckStatus = (Std_ReturnType)E_NOT_OK;
    /* Check for invalid Channel */
    if (Channel >= CDDI2C_HW_MAX_MODULES)
    {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
        /* Invalid Channel */
        /* Report error to development error tracer */
        (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                              I2cApiId, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
    }
    else
    {
        if (I2C_CHN_UNINIT == CddI2c_ChannelStatus[Channel])
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /*Channel uninit, report error to development error*/
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_UNINIT);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
        }
        else
        {
            CheckStatus = E_OK;
        }
    }
    if (E_OK == CheckStatus)
    {
        /* Check RequestPtr for not being a null pointer */
        if (NULL_PTR == RequestPtr)
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /* Invalid pointer */
            /* Report error to development error tracer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_PARAM_POINTER);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
            CheckStatus = (Std_ReturnType)E_NOT_OK;
        }
        else if (((0U == RequestPtr->BufferSize) || (NULL_PTR == RequestPtr->DataBuffer)) && (I2C_SEND_DATA == RequestPtr->DataDirection))
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /* Invalid pointer */
            /* Report error to development error tracer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_SEND_DATA_INVALID);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
            CheckStatus = (Std_ReturnType)E_NOT_OK;
        }
        else if (((0U == RequestPtr->BufferSize) || (256U < RequestPtr->BufferSize) ||
                  (NULL_PTR == RequestPtr->DataBuffer)) && (I2C_RECEIVE_DATA == RequestPtr->DataDirection))
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /* Invalid pointer */
            /* Report error to development error tracer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_RX_DATA_BUFFER_INVALID);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
            CheckStatus = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            CheckStatus = (Std_ReturnType)E_OK;
        }
    }
    else
    {
        /*Do Nothing*/
    }
    if (E_OK == CheckStatus)
    {
        /* Check whether the I2C Channel is a master or master/slave Channel  */
        if (I2C_SLAVE_MODE == CddI2c_ChnConfigPtr[Channel]->TransferModeConfig)
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /* Invalid mode */
            /* Report error to development error tracer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
            CheckStatus = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            CheckStatus = (Std_ReturnType)E_OK;
        }
    }
    else
    {
        /*Do Nothing*/
    }
    return CheckStatus;
}

/**
* @brief   This function checks parameters for slave transfer function of I2c driver.
*
* @param[in]     Channel       Specifies the index of Channel
* @param[in]     DataBufferPtr Specifies the pointer to user transmit request
* @param[in]     I2cApiId      Specifies what api call this function
* @return        Std_ReturnType
* @retval        E_OK: No error
* @retval        E_NOT_OK: Error
*
*/
CDDI2C_FUNC LOCAL_INLINE Std_ReturnType CddI2c_SlaveErrorCheckTransfer(uint8 Channel,
        const uint8 *DataBufferPtr,
        uint8 I2cApiId)
{
    Std_ReturnType CheckStatus = (Std_ReturnType)E_NOT_OK;
    /* Check for invalid Channel */
    if (Channel >= CDDI2C_HW_MAX_MODULES)
    {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
        /* Invalid Channel */
        /* Report error to development error tracer */
        (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                              I2cApiId, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
    }
    else
    {
        if (I2C_CHN_UNINIT == CddI2c_ChannelStatus[Channel])
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /*Channel uninit, report error to development error*/
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_UNINIT);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
        }
        else
        {
            CheckStatus = E_OK;
        }
    }
    if (E_OK == CheckStatus)
    {
        /* Check DataBufferPtr for not being a null pointer */
        if (NULL_PTR == DataBufferPtr)
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /* Invalid pointer */
            /* Report error to development error tracer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_PARAM_POINTER);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
            CheckStatus = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            CheckStatus = (Std_ReturnType)E_OK;
        }
    }
    else
    {
        /*Do Nothing*/
    }
    if (E_OK == CheckStatus)
    {
        /* Check whether the I2C Channel is a master or master/slave Channel  */
        if (I2C_MASTER_MODE == CddI2c_ChnConfigPtr[Channel]->TransferModeConfig)
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /* Invalid mode */
            /* Report error to development error tracer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  I2cApiId, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
            CheckStatus = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            CheckStatus = (Std_ReturnType)E_OK;
        }
    }
    else
    {
        /*Do Nothing*/
    }
    return CheckStatus;
}

/**
 * @brief   This function checks what IP is used and initiate the module in master or slave mode.
 *
 * @param[in]     Config     Specifies the pointer to I2c Channel configuration
 * @return         Std_ReturnType
 * @retval         E_OK       The hw Channel is initialized successfully
 * @retval         E_NOT_OK   The hw Channel is not initialized successfully
*/

CDDI2C_FUNC static Std_ReturnType CddI2c_InitHWChannel(const CddI2c_HwChannelConfigType *Config)
{
    Std_ReturnType RetValue = E_OK;
    I2C_StatusType TempStatus = I2C_SUCCESS_STATUS;
    if (I2C_SLAVE_MODE != Config->TransferModeConfig)
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        TempStatus = (I2C_StatusType)OsIf_Trusted_Call_Return2param(I2C_Lld_MasterInit, Config->I2cHwUnit, Config->HwChannelConfig.Master);
#else
        TempStatus = I2C_Lld_MasterInit(Config->I2cHwUnit, Config->HwChannelConfig.Master);
#endif
    }
    else
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        TempStatus = (I2C_StatusType)OsIf_Trusted_Call_Return2param(I2C_Lld_SlaveInit, Config->I2cHwUnit, Config->HwChannelConfig.Slave);
#else
        TempStatus = I2C_Lld_SlaveInit(Config->I2cHwUnit, Config->HwChannelConfig.Slave);
#endif
    }
    if (TempStatus != I2C_SUCCESS_STATUS)
    {
        RetValue = E_NOT_OK;
    }
    else
    {
        /*Do Nothing*/
    }
    return RetValue;
}

/**
 * @brief   This function checks what IP is used and de-initiate the i2c module.
 * @param[in] ConfigPtr Specifies the pointer to hardware Channel configuration
 * @return  void
*/
CDDI2C_FUNC static void CddI2c_DeInitHWChannel(const CddI2c_HwChannelConfigType *ConfigPtr)
{
    if (I2C_SLAVE_MODE != ConfigPtr->TransferModeConfig)
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        OsIf_Trusted_Call1param(I2C_Lld_MasterDeinit, ConfigPtr->I2cHwUnit);
#else
        (void) I2C_Lld_MasterDeinit(ConfigPtr->I2cHwUnit);
#endif
    }
    else
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        OsIf_Trusted_Call1param(I2C_Lld_SlaveDeinit, ConfigPtr->I2cHwUnit);
#else
        (void) I2C_Lld_SlaveDeinit(ConfigPtr->I2cHwUnit);
#endif
    }
}

/**
 * @brief   Conversion hw status to CddI2c_StatusType.
 * @details This function converts the hardware status to CddI2c_StatusType.
 * @param[in] Channel - The Channel number.
 * @param[in] Status - The hardware status.
 * @return CddI2c_StatusType
*/
CDDI2C_FUNC static CddI2c_StatusType CddI2c_ConvertStatus(const uint8 Channel,
        const I2C_StatusType Status)
{
    CddI2c_StatusType RetStatus = I2C_CHN_UNINIT;
    switch (Status)
    {
        case I2C_SUCCESS_STATUS: /* I2C_SUCCESS_STATUS */
        {
            if (I2C_CHN_IDLE == CddI2c_ChannelStatus[Channel])
            {
                RetStatus = I2C_CHN_IDLE;
            }
            else
            {
                RetStatus = I2C_CHN_COMPLETED;
                CddI2c_ChannelStatus[Channel] = I2C_CHN_COMPLETED;
            }
            break;
        }
        case I2C_CHN_BUSY_STATUS: /* I2C_CHN_BUSY_STATUS */
        {
            if (I2C_CHN_TX == CddI2c_ChannelStatus[Channel])
            {
                RetStatus = I2C_CHN_TX;
            }
            else
            {
                RetStatus = I2C_CHN_RX;
            }
            break;
        }
        case I2C_BUS_BUSY_STATUS: /* I2C_BUS_BUSY_STATUS */
        {
            if (I2C_CHN_TX == CddI2c_ChannelStatus[Channel])
            {
                RetStatus = I2C_CHN_TX;
            }
            else
            {
                RetStatus = I2C_CHN_RX;
            }
            break;
        }
        default:
        {
            RetStatus = I2C_CHN_ERROR_PRESENT;
            CddI2c_ChannelStatus[Channel] = I2C_CHN_ERROR_PRESENT;
            break;
        }
    }
    return RetStatus;
}

/**
 * @brief   Returns the current status of the i2c module Channel.
 * @param[in]   Channel     The Channel to be checked.
 * @param[in]   ConfigType  The configuration of the Channel.
 * @return  CddI2c_StatusType
 * @retval  I2C_CHN_UNINIT          The Channel is not initialized.
 * @retval  I2C_CHN_IDLE            The Channel is idle.
 * @retval  I2C_CHN_TX              The Channel is transmitting.
 * @retval  I2C_CHN_RX              The Channel is receiving.
 * @retval  I2C_CHN_COMPLETED       The Channel is completed.
 * @retval  I2C_CHN_ERROR_PRESENT   The Channel is error present.
*/
CDDI2C_FUNC static CddI2c_StatusType CddI2c_GetHWStatus(const uint8 Channel,
        const CddI2c_HwChannelConfigType *ConfigType)
{
    I2C_StatusType RetStatus = I2C_SUCCESS_STATUS;
    CddI2c_StatusType RetTemp = I2C_CHN_IDLE;
    uint8 Instance = CddI2c_ChnConfigPtr[Channel]->I2cHwUnit;
    if (I2C_SLAVE_MODE != ConfigType->TransferModeConfig)
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        RetStatus = (I2C_StatusType)OsIf_Trusted_Call_Return2param(I2C_Lld_MasterGetTransferStatus, Instance, NULL_PTR);
#else
        RetStatus = I2C_Lld_MasterGetTransferStatus(Instance, NULL_PTR);
#endif
    }
    else
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        RetStatus = (I2C_StatusType)OsIf_Trusted_Call_Return2param(I2C_Lld_SlaveGetTransferStatus, Instance, NULL_PTR);
#else
        RetStatus = I2C_Lld_SlaveGetTransferStatus(Instance, NULL_PTR);
#endif
    }
    /* Convert RetStatus */
    RetTemp =  CddI2c_ConvertStatus(Channel, RetStatus);
    return RetTemp;
}

/**
 * @brief   This function starts an asynchronous receive or send transfer.
 * @param[in]  Channel - The Channel to be used for the transfer.
 * @param[in]   Request - The request to be processed.
 * @return  Std_ReturnType
 * @retval  E_OK - The request was accepted.
 * @retval  E_NOT_OK - The request was not accepted.
*/
CDDI2C_FUNC static Std_ReturnType CddI2c_AsyncTransfer(uint8 Channel, const CddI2c_RequestType *Request)
{
    I2C_StatusType TmpReturn;
    Std_ReturnType RetTemp;
    uint8 Instance = CddI2c_ChnConfigPtr[Channel]->I2cHwUnit;
    /* Set slave address */
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
    OsIf_Trusted_Call3params(I2C_Lld_MasterSetSlaveAddr, Instance, Request->SlaveAddress, Request->BitsSlaveAddressIs10);
#else
    I2C_Lld_MasterSetSlaveAddr(Instance, Request->SlaveAddress, Request->BitsSlaveAddressIs10);
#endif
    /* Enable/disable high speed mode */
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
    OsIf_Trusted_Call2params(I2C_Lld_MasterSetHighSpeedMode, Instance, Request->HighSpeedMode);
#else
    I2C_Lld_MasterSetHighSpeedMode(Instance, Request->HighSpeedMode);
#endif
    if (I2C_SEND_DATA == Request->DataDirection)
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        TmpReturn = (I2C_StatusType)OsIf_Trusted_Call_Return4param(I2C_Lld_MasterSendData, Instance, Request->DataBuffer, \
                    Request->BufferSize, \
                    ((Request->RepeatedStart == FALSE) ? 1U : 0U));
#else
        TmpReturn = I2C_Lld_MasterSendData(Instance, Request->DataBuffer, \
                                           Request->BufferSize, \
                                           ((FALSE == Request->RepeatedStart) ? 1U : 0U));
#endif
    }
    else
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        TmpReturn = (I2C_StatusType)OsIf_Trusted_Call_Return4param(I2C_Lld_MasterReceiveData, Instance, Request->DataBuffer, \
                    Request->BufferSize, \
                    ((Request->RepeatedStart == FALSE) ? 1U : 0U));
#else
        TmpReturn = I2C_Lld_MasterReceiveData(Instance, Request->DataBuffer, \
                                              Request->BufferSize, \
                                              ((FALSE == Request->RepeatedStart) ? 1U : 0U));
#endif
    }
    if (I2C_CHN_BUSY_STATUS != TmpReturn)
    {
        RetTemp = E_NOT_OK;
    }
    else
    {
        RetTemp = E_OK;
    }
    return RetTemp;
}

/**
 * @brief   This function starts a synchronous receive or send transfer.
 * @param[in]   Channel - The Channel to be used.
 * @param[in]   Request - The request to be processed.
 * @return  Std_ReturnType
 * @retval  E_OK - The request was successfully.
 * @retval  E_NOT_OK - The request was not successfully.
*/
CDDI2C_FUNC static Std_ReturnType CddI2c_SyncHWTransfer(uint8 Channel, const CddI2c_RequestType *Request)
{
    I2C_StatusType TmpReturn;
    Std_ReturnType ReValue = E_OK;
    uint8 Instance = CddI2c_ChnConfigPtr[Channel]->I2cHwUnit;
    /* Set slave address */
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
    OsIf_Trusted_Call3params(I2C_Lld_MasterSetSlaveAddr, Instance, Request->SlaveAddress, Request->BitsSlaveAddressIs10);
#else
    I2C_Lld_MasterSetSlaveAddr(Instance, Request->SlaveAddress, Request->BitsSlaveAddressIs10);
#endif
    /* Enable/disable high speed mode */
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
    OsIf_Trusted_Call2params(I2C_Lld_MasterSetHighSpeedMode, Instance, Request->HighSpeedMode);
#else
    I2C_Lld_MasterSetHighSpeedMode(Instance, Request->HighSpeedMode);
#endif
    if (I2C_SEND_DATA == Request->DataDirection)
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        TmpReturn = (I2C_StatusType)OsIf_Trusted_Call_Return4param(I2C_Lld_MasterSendDataBlocking, Instance, Request->DataBuffer, \
                    Request->BufferSize, \
                    ((Request->RepeatedStart == FALSE) ? 1U : 0U));
#else
        TmpReturn = I2C_Lld_MasterSendDataBlocking(Instance, Request->DataBuffer, \
                    Request->BufferSize, \
                    ((FALSE == Request->RepeatedStart) ? 1U : 0U));
#endif
    }
    else
    {
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
        TmpReturn = (I2C_StatusType)OsIf_Trusted_Call_Return4param(I2C_Lld_MasterRxDataBlocking, Instance, Request->DataBuffer, \
                    Request->BufferSize, \
                    ((Request->RepeatedStart == FALSE) ? 1U : 0U));
#else
        TmpReturn = I2C_Lld_MasterRxDataBlocking(Instance, Request->DataBuffer, \
                    Request->BufferSize, \
                    ((FALSE == Request->RepeatedStart) ? 1U : 0U));
#endif
    }
    if (I2C_SUCCESS_STATUS != TmpReturn)
    {
        ReValue = E_NOT_OK;
    }
    else
    {
        /*Do Nothing*/
    }
    return ReValue;
}
/*==================================================================================================
                                                GLOBAL FUNCTIONS
==================================================================================================*/

CDDI2C_FUNC void CddI2c_Init(const CddI2c_ConfigType *Config)
{
    Std_ReturnType CheckStatus;
    const CddI2c_ConfigType *CddI2cConfigPtr = NULL_PTR;
#if (CDDI2C_PRECOMPILE_SUPPORT == STD_ON)
    CddI2cConfigPtr = &CddI2c_PreCompileConfig;
#else
    CddI2cConfigPtr = Config;
#endif
    /* Check Config for not being a null pointer */
    if (NULL_PTR == CddI2cConfigPtr)
    {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
        /* Invalid pointer */
        (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                              (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_PARAM_POINTER);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
    }
    else
    {
        for (uint8 Channel = (uint8)0U; Channel < CddI2cConfigPtr->I2cInitChnAmount; ++Channel)
        {
            if (Channel >= CDDI2C_HW_MAX_MODULES)
            {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON )
                /* Invalid pointer */
                (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                      (uint8)CDDI2C_SID_INIT, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /*(CDDI2C_DEV_ERROR_DETECT == STD_ON ) */
            }
            else
            {
                /*Check configure data */
                CheckStatus = CddI2c_ErrorCheckInit(Channel, &CddI2cConfigPtr->I2cChnConfig[Channel]);
                if ((Std_ReturnType)E_OK == CheckStatus)
                {
                    /*set the config ptr point to config data*/
                    CddI2c_ChnConfigPtr[Channel] = &CddI2cConfigPtr->I2cChnConfig[Channel];
                    /* initialization Channel */
                    CheckStatus = CddI2c_InitHWChannel(CddI2c_ChnConfigPtr[Channel]);
                    if (E_NOT_OK == CheckStatus)
                    {
                        /*hw Channel init failed, set the struct to UNINIT*/
                        CddI2c_ChannelStatus[Channel] = I2C_CHN_UNINIT;
                        (void)Det_ReportRuntimeError(CDDI2C_MODULE_ID, CDDI2C_INSTANCE_ID,
                                                     CDDI2C_SID_INIT, CDDI2C_E_PARAM_UNAVAILABLE);
                    }
                    else
                    {
                        /*Set the Channel status to IDLE*/
                        CddI2c_ChannelStatus[Channel] = I2C_CHN_IDLE;
                    }
                }
                else
                {
                    /*Do Nothing*/
                }
            }
        }
    }
}

CDDI2C_FUNC void CddI2c_DeInit(void)
{
    uint8 Channel = 0;
    Std_ReturnType ChannelState = E_NOT_OK;
    /* Check whether the I2C driver is in I2C_UNINIT state */
    SchM_Enter_CddI2c_CDDI2C_EXCLUSIVE_AREA_01();
    for (Channel = 0; Channel < CDDI2C_HW_MAX_MODULES; ++Channel)
    {
        if (I2C_CHN_UNINIT != CddI2c_ChannelStatus[Channel])
        {
            ChannelState = E_OK;
        }
        else
        {
            /*Do Nothing*/
        }
    }
    SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_01();
    if (E_NOT_OK == ChannelState)
    {
#if (CDDI2C_DEV_ERROR_DETECT  == STD_ON)
        /* I2C driver isn't initialized */
        (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                              (uint8)CDDI2C_SID_DEINIT, (uint8)CDDI2C_E_UNINIT);
#endif /* (CDDI2C_DEV_ERROR_DETECT == STD_ON) */
    }
    else
    {
        for (Channel = 0U; Channel < CDDI2C_HW_MAX_MODULES; ++Channel)
        {
            if (NULL_PTR != CddI2c_ChnConfigPtr[Channel])
            {
                /* deinit Channel */
                CddI2c_DeInitHWChannel(CddI2c_ChnConfigPtr[Channel]);
                /* Set Channel status to I2C_CHN_UNINIT */
                SchM_Enter_CddI2c_CDDI2C_EXCLUSIVE_AREA_02();
                CddI2c_ChannelStatus[Channel] = I2C_CHN_UNINIT;
                /*reset the configure pointer to NULL*/
                CddI2c_ChnConfigPtr[Channel] = NULL_PTR;
                SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_02();
            }
            else
            {
                /*Do Nothing*/
            }
        }
    }
}

CDDI2C_FUNC Std_ReturnType CddI2c_SyncModeTransfer(uint8 Channel, const CddI2c_RequestType *RequestPtr)
{
    Std_ReturnType TempReturn = (Std_ReturnType)E_NOT_OK;
    Std_ReturnType CheckStatus;
    CddI2c_StatusType TempChannelStatus;
    SchM_Enter_CddI2c_CDDI2C_EXCLUSIVE_AREA_03();
    CheckStatus = CddI2c_MasterErrorCheckTransfer(Channel, RequestPtr, (uint8)CDDI2C_SID_SYNC_MODE_TRANSFER);
    if ((Std_ReturnType)E_OK == CheckStatus)
    {
        /* Check whether the I2C Channel is in busy state */
        TempChannelStatus = CddI2c_GetHWStatus(Channel,
                                               CddI2c_ChnConfigPtr[Channel]);
        if ((I2C_CHN_TX != TempChannelStatus) && (I2C_CHN_RX != TempChannelStatus))
        {
            if (I2C_SEND_DATA == RequestPtr->DataDirection)
            {
                CddI2c_ChannelStatus[Channel] = I2C_CHN_TX;
            }
            else
            {
                CddI2c_ChannelStatus[Channel] = I2C_CHN_RX;
            }
            SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_03();
            TempReturn = CddI2c_SyncHWTransfer(Channel, RequestPtr);
            if (E_OK == TempReturn)
            {
                CddI2c_ChannelStatus[Channel] = I2C_CHN_COMPLETED;
            }
            else
            {
                CddI2c_ChannelStatus[Channel] = I2C_CHN_ERROR_PRESENT;
            }
        }
        else
        {
            TempReturn = E_NOT_OK;
            SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_03();
        }
    }
    else
    {
        SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_03();
        TempReturn = E_NOT_OK;
    }
    return TempReturn;
}

CDDI2C_FUNC Std_ReturnType CddI2c_AsyncModeTransfer(uint8 Channel, const CddI2c_RequestType *RequestPtr)
{
    Std_ReturnType TempReturn = (Std_ReturnType)E_NOT_OK;
    Std_ReturnType CheckStatus;
    CddI2c_StatusType TempChannelStatus;
    SchM_Enter_CddI2c_CDDI2C_EXCLUSIVE_AREA_04();
    CheckStatus = CddI2c_MasterErrorCheckTransfer(Channel, RequestPtr, (uint8)CDDI2C_SID_ASYNC_MODE_TRANSFER);
    if ((Std_ReturnType)E_OK == CheckStatus)
    {
        /* Check whether the I2C Channel is in busy state */
        TempChannelStatus = CddI2c_GetHWStatus(Channel,
                                               CddI2c_ChnConfigPtr[Channel]);
        if ((I2C_CHN_TX != TempChannelStatus) && (I2C_CHN_RX != TempChannelStatus))
        {
            if (RequestPtr->DataDirection == I2C_SEND_DATA)
            {
                CddI2c_ChannelStatus[Channel] = I2C_CHN_TX;
            }
            else
            {
                CddI2c_ChannelStatus[Channel] = I2C_CHN_RX;
            }
            SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_04();
            TempReturn = CddI2c_AsyncTransfer(Channel, RequestPtr);
        }
        else
        {
            SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_04();
        }
    }
    else
    {
        SchM_Exit_CddI2c_CDDI2C_EXCLUSIVE_AREA_04();
    }
    return TempReturn;
}

CDDI2C_FUNC Std_ReturnType CddI2c_PrepareSlaveBuffer(uint8 Channel, uint8 *DataBufferPtr, uint16 BufferSize, boolean SlaveSend)
{
    Std_ReturnType TempReturn = (Std_ReturnType)E_NOT_OK;
    Std_ReturnType CheckStatus;
    CddI2c_StatusType TempChannelStatus;
    CheckStatus = CddI2c_SlaveErrorCheckTransfer(Channel, DataBufferPtr, (uint8)CDDI2C_SID_PREPARE_SLAVE_BUFFER);
    if ((Std_ReturnType)E_OK == CheckStatus)
    {
        /* Check whether the I2C Channel is in busy state */
        TempChannelStatus = CddI2c_GetHWStatus(Channel,
                                               CddI2c_ChnConfigPtr[Channel]);
        if ((I2C_CHN_TX != TempChannelStatus) && (I2C_CHN_RX != TempChannelStatus))
        {
            if (TRUE == SlaveSend)
            {
                TempReturn =  I2C_Lld_SlaveSetTxBuffer(CddI2c_ChnConfigPtr[Channel]->I2cHwUnit, DataBufferPtr, BufferSize);
            }
            else
            {
                TempReturn =  I2C_Lld_SlaveSetRxBuffer(CddI2c_ChnConfigPtr[Channel]->I2cHwUnit, DataBufferPtr, BufferSize);
            }
        }
        else
        {
            /*Do noting*/
        }
    }
    return TempReturn;
}

CDDI2C_FUNC Std_ReturnType  CddI2c_StartListening(uint8 Channel)
{
    Std_ReturnType TempStatus;
    I2C_StatusType TempReturn = I2C_PARAM_ERROR_STATUS;
    /*Check configure data */
    TempStatus = CddI2c_ErrorCheckStartListening(Channel, CddI2c_ChnConfigPtr[Channel]);
    if ((Std_ReturnType)E_OK == TempStatus)
    {
        if (CddI2c_ChnConfigPtr[Channel]->TransferModeConfig != I2C_SLAVE_MODE)
        {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
            /* Report error to development error tracer */
            (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                                  (uint8)CDDI2C_SID_START_LISTENING, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
            TempStatus = E_NOT_OK;
        }
        else if (TRUE == CddI2c_ChnConfigPtr[Channel]->HwChannelConfig.Slave->SlaveListening)
        {
            TempStatus = E_NOT_OK;
        }
        else
        {
            CddI2c_ChannelStatus[Channel] = I2C_CHN_IDLE;
#ifdef CDDI2C_ENABLE_USER_MODE_SUPPORT
            TempReturn = (I2C_StatusType)OsIf_Trusted_Call_Return1param(I2C_Lld_StartListening, CddI2c_ChnConfigPtr[Channel]->I2cHwUnit);
#else
            TempReturn = I2C_Lld_StartListening(CddI2c_ChnConfigPtr[Channel]->I2cHwUnit);
#endif
            if (TempReturn != I2C_SUCCESS_STATUS)
            {
                TempStatus = E_NOT_OK;
            }
            else
            {
                TempStatus = E_OK;
            }
        }
    }
    else
    {
        /*Do Nothing*/
    }
    return TempStatus;
}

CDDI2C_FUNC CddI2c_StatusType CddI2c_GetTransferStatus(uint8 Channel)
{
    CddI2c_StatusType ChannelStatus = I2C_CHN_UNINIT;
    if (Channel >= CDDI2C_HW_MAX_MODULES)
    {
#if (CDDI2C_DEV_ERROR_DETECT == STD_ON)
        /* Invalid Channel */
        /* Report error to development error tracer */
        (void)Det_ReportError((uint16)CDDI2C_MODULE_ID, (uint8)CDDI2C_INSTANCE_ID,
                              (uint8)CDDI2C_SID_GET_TRANSFER_STATUS, (uint8)CDDI2C_E_INVALID_CHANNEL);
#endif /* (I2C_DEV_ERROR_DETECT == STD_ON) */
    }
    else
    {
        ChannelStatus = CddI2c_GetHWStatus(Channel, CddI2c_ChnConfigPtr[Channel]);
    }
    return ChannelStatus;
}

#define CDDI2C_STOP_SEC_CODE
#include "CddI2c_MemMap.h"

#ifdef __cplusplus
}
#endif

/* End of file CddI2c.c */

