/* ======================================================================
 *   Copyright (c) 2022 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */

/**
 *  \file     Port.c
 *
 */
/*  ----------------------------------------------------------------------------
 *  FILE DESCRIPTION
 *  ----------------------------------------------------------------------------
 *         File:  Port.c
 *      Project:  AM263 MCAL Driver
 *       Module:  PortDriver
 *    Generator:  -
 *
 *  Description:  This module implements a driver in ANSI C programming language 
 *                to centralize the configuration of ports and pins which are  
 *                used by more than one driver module.
 *                With this driver you can:
 *                - Configure all port pins
 *                - Initialize the configuration
 *                - Refresh the configuration (EMC purposes)
 *                - Switch the port pin configuration during runtime*/
 /*****************************************************************************/

#define PORT_SOURCE (1)

/* ========================================================================== */
/*                          Include Files                                  */
/* ========================================================================== */
#include "string.h"
#include "Std_Types.h"

/* Requirements : SWS_Port_00080, SWS_Port_00131 */
#include "Port.h"
#include "Port_priv.h"

#if (PORT_CFG_DEV_ERROR_DETECT == STD_ON)
/* Requirements : SWS_Port_00080, SWS_Port_00131 */
#include "Det.h"
#endif
#include "Os.h"

/* Requirements : SWS_Port_00080, SWS_Port_00131 */
#include "SchM_Port.h"

#define PORT_START_SEC_CODE
#include "Port_MemMap.h"
#include "hw_types.h"
#define PORT_STOP_SEC_CODE
#include "Port_MemMap.h"
/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

/* AUTOSAR version information check has to match definition in header file */
#if ((PORT_AR_RELEASE_MAJOR_VERSION != (0x04U)) || \
    (PORT_AR_RELEASE_MINOR_VERSION != (0x03U)) ||  \
    (PORT_AR_RELEASE_REVISION_VERSION != (0x01U)))
   #error "Port: AUTOSAR Version Numbers of Port Driver are different"
#endif

/* Vendor specific version */
#if ((PORT_SW_MAJOR_VERSION != (0U)) || (PORT_SW_MINOR_VERSION != (9U)))
   #error \
    "Vendor specific version numbers of Port.c and Port.h are inconsistent"
#endif

/* Versions of all included header files shall be checked, configuration is
 * just an example */
#if ((PORT_CFG_MAJOR_VERSION != (0U)) || (PORT_CFG_MINOR_VERSION != (9U)))
   #error "Version numbers of Port.c and Port_Cfg.h are inconsistent!"
#endif

/* ========================================================================== */
/*                          Function Declarations                             */
/* ========================================================================== */

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
LOCAL_INLINE void Port_reportDetError(uint8 apiId, uint8 errorId);
static boolean Port_ValidateSetPinMode(
    Port_PinModeType    Mode,
    const
    Port_PinConfigType *pinConfig,
    uint8              *errorIdPtr);
static boolean Port_ValidateSetPinDirection(
    const Port_PinConfigType *pinConfig,
    Port_PinModeType          curMode,
    uint8                    *errorIdPtr);
LOCAL_INLINE uint32 Port_GetDioRegId(Port_PinModeType mode);
#endif  /* #if (STD_ON == PORT_CFG_DEV_ERROR_DETECT) */

#if ((STD_ON == PORT_CFG_SET_PIN_MODE_API) ||          \
    (STD_ON == PORT_CFG_REFRESH_PORT_DIRECTION_API) || \
    (STD_ON == PORT_CFG_SET_PIN_DIRECTION_API))
LOCAL_INLINE boolean Port_IsDioMode(Port_PinModeType mode);
static void Port_ConfigDioPinDirection(
    const uint32 gpioPortAddr,
    uint32       dioChannelId,
    Port_PinDirectionType direction,
	Port_EdgeTrig  TriEdge,
	boolean TriggerEn);
#endif

#if ((STD_ON == PORT_CFG_SET_PIN_DIRECTION_API) || \
    (STD_ON == PORT_CFG_REFRESH_PORT_DIRECTION_API))
static Port_PinModeType Port_GetCurrentPinMode(
    P2CONST(Port_PinConfigType, AUTO, PORT_APPL_DATA)padCfg);
#endif

#if ((STD_ON == PORT_CFG_SET_PIN_MODE_API) || \
    (STD_ON == PORT_CFG_SET_PIN_DIRECTION_API))
static void Port_ConfigDioPin(const uint32           gpioPortAddr,
                              uint32                 dioChannelId,
                              Port_PinDirectionType  direction,
                              Port_PinLevelValueType level,
							  Port_EdgeTrig  TriEdge,
							  boolean TriggerEn);
static const Port_PinConfigType *
Port_MapPinIdToPinConfig(Port_PinType             PinId,
                         const Port_PinConfigType modeCfg[],
                         uint16                   numPins);
static void Port_ConfigPadAndDioPin(const Port_PinConfigType *pinConfig,
                                    Port_PinModeType          curMode,
                                    Port_PinDirectionType     Direction);
static void Port_SetPinConfigPadAndDioPin(const Port_PinConfigType *pinConfig,
                                          Port_PinModeType          Mode);
#endif

static void Port_DioInit(void);
static void Port_InitPadList(
    P2CONST(Port_PinConfigType, AUTO, PORT_APPL_DATA)padList,
    uint16 elements);
static uint32 Port_GetMuxMode(
    Port_PinModeType Port_PinMode,
    const Port_PinModeConfigType *
    modeCfg,
    uint32           Port_NumPortModes);
void Port_MapConfigToReg(
    P2CONST(Port_PinConfigType, AUTO, PORT_APPL_DATA)padConfig,
    P2VAR(Port_PadRegSettingType, AUTO, PORT_APPL_DATA)padRegSetting,
    Port_PinModeType pinMode);

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

#define PORT_START_SEC_VAR_INIT_UNSPECIFIED
#include "Port_MemMap.h"

/** \brief PORT driver object */
static VAR(Port_ConfigType, PORT_VAR_ZERO_INIT) gPortDrvObj;

#define PORT_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Port_MemMap.h"

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
/* Global Init Done flag */
static boolean gPortInitDone = FALSE;
#endif

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */
#define PORT_START_SEC_CODE
#include "Port_MemMap.h"

/* Design : PORT_DesignId_004 */
/* Requirements : SWS_Port_00140, SWS_Port_00001, SWS_Port_00004,
 *                SWS_Port_00005, SWS_Port_00079, SWS_Port_00081,
 *                SWS_Port_00082, SWS_Port_00213, SWS_Port_00042,
 *                SWS_Port_00113, SWS_Port_00214, SWS_Port_00043,
 *                SWS_Port_00002, SWS_Port_00003, SWS_Port_00055,
 *                SWS_Port_00121
 */
FUNC(void, PORT_CODE) Port_Init(P2CONST(Port_ConfigType, AUTOMATIC,
                                        PORT_PBCFG) ConfigPtr)
{

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    /* Call of Errorhook if parameter refers to NULL */
    if (NULL_PTR == ConfigPtr)
    {
        /* Requirements : SWS_Port_00051 */
        Port_reportDetError(PORT_SID_INIT, PORT_E_INIT_FAILED);
    }
    else
#endif /*(STD_ON == PORT_CFG_DEV_ERROR_DETECT)*/
    {
        /* Requirements : SWS_Port_00041 */
        /* Copy Config */
        (void) memcpy(&gPortDrvObj, ConfigPtr, sizeof (Port_ConfigType));

        Port_DioInit();

        /* Set all registers to configured values */
        Port_InitPadList(gPortDrvObj.PinConfig_pt,
                     gPortDrvObj.NumberOfPortPins);

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
        /* Set Init Done flag */
        gPortInitDone = TRUE;
#endif
    }

    return;
}


/* Requirements : SWS_Port_00137 */
#if (STD_ON == PORT_CFG_SET_PIN_DIRECTION_API)

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
static boolean Port_ValidateSetPinDirection(
    const Port_PinConfigType *pinConfig,
    Port_PinModeType          curMode,
    uint8                    *errorIdPtr)
{
    boolean retVal = FALSE;

    if ((pinConfig != NULL) && (curMode != PORT_PIN_MODE_INVALID))
    {
        if (pinConfig->Port_DirectionChangeable == (boolean) TRUE)
        {
            retVal = (boolean) TRUE;
        }
        else
        {
            retVal      = (boolean) FALSE;
            *errorIdPtr = PORT_E_DIRECTION_UNCHANGEABLE;
        }
    }
    else
    {
        *errorIdPtr = PORT_E_PARAM_PIN;
        retVal      = (boolean) FALSE;
    }
    return (retVal);
}

#endif /*PORT_CFG_DEV_ERROR_DETECT */

static void Port_ConfigPadAndDioPin(const Port_PinConfigType *pinConfig,
                                    Port_PinModeType          curMode,
                                    Port_PinDirectionType     Direction)
{
    uint32 gpioRegAddr = 0U;

    if (Port_IsDioMode(curMode) == (boolean) TRUE)
    {
        gpioRegAddr = Port_GetGPIOPortAddr(pinConfig->Port_PinDioRegId);
        Port_ConfigDioPin(gpioRegAddr,
                          pinConfig->Port_PinDioChannelId,
                          Direction,
                          pinConfig->Port_PinLevelValue,
						  pinConfig->Port_PinSelectEdgeTrigger,
					      pinConfig->Port_PinSetEdgeTrigger) ;
    }

    Port_ConfigurePad(pinConfig, curMode);

    return;
}

/* Design : PORT_DesignId_005 */
/* Requirements : SWS_Port_00141, SWS_Port_00063, SWS_Port_00054 */

FUNC(void, PORT_CODE) Port_SetPinDirection(Port_PinType Pin,
                                           Port_PinDirectionType Direction)
{
    const Port_PinConfigType *pinConfig;
    Port_PinModeType          curMode = 0U;
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    boolean validConfig = FALSE;
    uint8   errId;
#endif

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    /* Check if module has been initialzied. */
    if ((boolean) FALSE == gPortInitDone)
    {
        /* Report error to an Errorhook function. */
        /* Requirements : SWS_Port_00051 */
        Port_reportDetError(PORT_SID_SET_PIN_DIR, PORT_E_UNINIT);
    }
    else
#endif
    {
        pinConfig = Port_MapPinIdToPinConfig(
            Pin,
            gPortDrvObj.PinConfig_pt,
            gPortDrvObj.
            NumberOfPortPins);
        if (pinConfig != NULL)
        {
            curMode = Port_GetCurrentPinMode(pinConfig);
        }
        else
        {
            curMode = PORT_PIN_MODE_INVALID;
        }
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
        errId       = 0U;
        validConfig = Port_ValidateSetPinDirection(pinConfig, curMode, &errId);
        if (validConfig == (boolean) FALSE)
        {
            /* Requirements : SWS_Port_00051 */
            Port_reportDetError(PORT_SID_SET_PIN_DIR, errId);
        }
        else
#endif
        {
			
            SchM_Enter_Port_PORT_EXCLUSIVE_AREA_0();
            Port_ConfigPadAndDioPin(pinConfig, curMode, Direction);
            SchM_Exit_Port_PORT_EXCLUSIVE_AREA_0();
        }
    }
    return;
}
#endif /* #if (STD_ON == PORT_CFG_SET_PIN_DIRECTION_API) */


/* Design : PORT_DesignId_006 */
#if (STD_ON == PORT_CFG_REFRESH_PORT_DIRECTION_API)
/* Requirements : SWS_Port_00142, SWS_Port_00066, SWS_Port_00060
 *                SWS_Port_00061 */
FUNC(void, PORT_CODE) Port_RefreshPortDirection(void)
{
    uint16 idx = 0U;
    const Port_PinConfigType *pinConfig;
    Port_PinModeType curMode = 0U;
    uint32 gpioPortAddr = 0U;

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    /* Check if module has been initialized. */
    if ((boolean) FALSE == gPortInitDone)
    {
        /* Report error to an Errorhook function. */
        /* Requirements : SWS_Port_00051 */
        Port_reportDetError(PORT_SID_REFRESH_PORT_DIR, PORT_E_UNINIT);
    }
    else
#endif
    {
        for (idx = 0U; idx < gPortDrvObj.NumberOfPortPins; idx++)
        {
            /* Set all registers to configured values */
            pinConfig = &gPortDrvObj.PinConfig_pt[idx];
            /* If direction is not changeable,pin direction must be refreshed*/
            if (pinConfig->Port_DirectionChangeable == (boolean) FALSE)
            {
                curMode = Port_GetCurrentPinMode(pinConfig);
                if (curMode != PORT_PIN_MODE_INVALID)
                {
                    if (Port_IsDioMode(curMode) == (boolean) TRUE)
                    {
                        gpioPortAddr = Port_GetGPIOPortAddr(
                            pinConfig->Port_PinDioRegId);
                        Port_ConfigDioPinDirection(
                            gpioPortAddr,
                            pinConfig->Port_PinDioChannelId,
                            pinConfig->Port_PinDirection,
							pinConfig->Port_PinSelectEdgeTrigger,
							pinConfig->Port_PinSetEdgeTrigger);
                    }
                    Port_ConfigurePad(pinConfig,
                                      curMode);
                }
            }
        }
    }
}
#endif  /*(STD_ON == PORT_CFG_REFRESH_PORT_DIRECTION_API)*/

#if (STD_ON == PORT_CFG_SET_PIN_MODE_API)

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
static boolean Port_ValidateSetPinMode(
    Port_PinModeType    Mode,
    const
    Port_PinConfigType *pinConfig,
    uint8              *errorIdPtr)
{
    boolean retVal = (boolean)FALSE;
    uint32  idx = 0U;
    uint32  dioRegId = 0U;

    if (pinConfig->Port_PinModeChangeable == (boolean) TRUE)
    {
        for (idx = 0U; idx < pinConfig->Port_NumPortModes; idx++)
        {
            if (pinConfig->Port_PinMode[idx].mode == Mode)
            {
                retVal = (boolean) TRUE;
                break;
            }
        }
        if (idx == pinConfig->Port_NumPortModes)
        {
            retVal      = (boolean) FALSE;
            *errorIdPtr = PORT_E_PARAM_INVALID_MODE;
        }
        else
        {
            if (Port_IsDioMode(Mode) == (boolean) TRUE)
            {
                dioRegId = Port_GetDioRegId(Mode);
                if ((pinConfig->Port_PinDioRegId != PORT_DIO_INVALID_CH_ID)
                    &&
                    (dioRegId == pinConfig->Port_PinDioRegId))
                {
                    retVal = (boolean) TRUE;
                }
                else
                {
                    retVal      = (boolean) FALSE;
                    *errorIdPtr = PORT_E_PARAM_INVALID_MODE;
                }
            }
        }
    }
    else
    {
        retVal      = (boolean) FALSE;
        *errorIdPtr = PORT_E_MODE_UNCHANGEABLE;
    }

    return (retVal);
}

#endif /*PORT_CFG_DEV_ERROR_DETECT */

static void Port_SetPinConfigPadAndDioPin(const Port_PinConfigType *pinConfig,
                                          Port_PinModeType          Mode)
{
    uint32 gpioPortAddr = 0U;
    if (Port_IsDioMode(Mode) == (boolean) TRUE)
    {
        gpioPortAddr = Port_GetGPIOPortAddr(pinConfig->Port_PinDioRegId);
        Port_ConfigDioPin(gpioPortAddr,
                          pinConfig->Port_PinDioChannelId,
                          pinConfig->Port_PinDirection,
                          pinConfig->Port_PinLevelValue,
						  pinConfig->Port_PinSelectEdgeTrigger,
					      pinConfig->Port_PinSetEdgeTrigger);
    }
    Port_ConfigurePad(pinConfig, Mode);

    return;
}

/* Design : PORT_DesignId_007 */
/* Requirements : SWS_Port_00145, SWS_Port_00077, SWS_Port_00087,
 *                SWS_Port_00125, SWS_Port_00128, SWS_Port_00223 */
FUNC(void, PORT_CODE) Port_SetPinMode(Port_PinType Pin, Port_PinModeType Mode)
{
    const Port_PinConfigType *pinConfig;
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    boolean validConfig = (boolean)FALSE;
    uint8   errId;
#endif

#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    /* Check if module has been initialzied. */
    if ((boolean) FALSE == gPortInitDone)
    {
        /* Report error to an Errorhook function. */
        /* Requirements : SWS_Port_00051 */
        Port_reportDetError(PORT_SID_SET_PIN_MODE, PORT_E_UNINIT);
    }
    else
#endif
    {
        pinConfig = Port_MapPinIdToPinConfig(Pin,
            gPortDrvObj.PinConfig_pt,
            gPortDrvObj.
            NumberOfPortPins);
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
        errId       = (uint8) 0U;
        if (pinConfig == NULL_PTR)
        {
            /* Requirements : SWS_Port_00051 */
            Port_reportDetError(PORT_SID_SET_PIN_MODE, PORT_E_PARAM_PIN);
        }
        else
#endif
        {
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
            validConfig = Port_ValidateSetPinMode(Mode, pinConfig, &errId);
            if (((boolean) FALSE) == validConfig)
            {
                /* Requirements : SWS_Port_00051 */
                Port_reportDetError(PORT_SID_SET_PIN_MODE, errId);
            }
            else
#endif
            {
                SchM_Enter_Port_PORT_EXCLUSIVE_AREA_0();
                /* Klockworks_INSPECTED: ABV.STACK
                 *  "Reason - Array index taken from configurator, range is 
															in bounds of array*/
                Port_SetPinConfigPadAndDioPin(pinConfig, Mode);
                SchM_Exit_Port_PORT_EXCLUSIVE_AREA_0();
            }
        }
    }
}
#endif /*(STD_ON == PORT_CFG_SET_PIN_MODE_API)*/



/* Design : PORT_DesignId_008 */
/* Requirements : SWS_Port_00225 */
#if (STD_ON == PORT_CFG_VERSION_INFO_API)
/* Requirements : SWS_Port_00143 */
FUNC(void, PORT_CODE) Port_GetVersionInfo(
    P2VAR(Std_VersionInfoType, AUTOMATIC, PORT_APPL_DATA) versioninfo)
{
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    /*  Check parameter for NULL_PTR.  */
    if (NULL_PTR == versioninfo)
    {
        /* Requirements : SWS_Port_00051 */
        Port_reportDetError(PORT_SID_GET_VERSION_INFO, PORT_E_PARAM_POINTER);
    }
    else
#endif
    {
        /* Fill the version info */
        versioninfo->vendorID         = PORT_VENDOR_ID;
        versioninfo->moduleID         = PORT_MODULE_ID;
        versioninfo->sw_major_version = (uint8) PORT_SW_MAJOR_VERSION;
        versioninfo->sw_minor_version = (uint8) PORT_SW_MINOR_VERSION;
        versioninfo->sw_patch_version = (uint8) PORT_SW_PATCH_VERSION;
    }

    return;
}
#endif  /*(STD_ON == PORT_CFG_VERSION_INFO_API)*/



#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
LOCAL_INLINE uint32 Port_GetDioRegId(Port_PinModeType mode)
{
    uint32 dioRegId = 0U ;

    switch (mode)
    {
        case PORT_PIN_MODE_GPIOAB:
           dioRegId = 0U;
           break;
        case PORT_PIN_MODE_GPIOCD:
            dioRegId = 1U;
           break;
        case PORT_PIN_MODE_GPIOEF:
            dioRegId = 2U;
           break;
        case PORT_PIN_MODE_GPIOGH:
            dioRegId = 3U;
           break;

        case PORT_PIN_MODE_GPIOI:
            dioRegId = 4U;
           break;
        default:
            /*Do nothing*/
             break;
    }

    return dioRegId;
}

#endif /*PORT_CFG_DEV_ERROR_DETECT */

static void Port_DioConfigDir(void)
{
    const Port_PinConfigType *pinConfig;
    uint32 idx = 0U;
    uint32 gpioPortAddr = 0U;

    for (idx = 0U; idx < gPortDrvObj.NumberOfPortPins; idx++)
        {
            /* Set all registers to configured values */
            pinConfig = &gPortDrvObj.PinConfig_pt[idx];
            /* If direction is not changeable,pin direction must be refreshed*/
            if (Port_IsDioMode(pinConfig->Port_PinInitialMode) == (boolean) TRUE)
            {
                gpioPortAddr = Port_GetGPIOPortAddr(
                    pinConfig->Port_PinDioRegId);

                Port_ConfigDioPin(gpioPortAddr,
                      pinConfig->Port_PinDioChannelId,
                      pinConfig->Port_PinDirection,
                      pinConfig->Port_PinLevelValue,
					  pinConfig->Port_PinSelectEdgeTrigger,
					  pinConfig->Port_PinSetEdgeTrigger);
            }

        }

}

static void Port_DioInit(void)
{
    uint32 idx = 0U;
    uint32 gpioPortAddr = 0U;
	uint32 ChannelId = 0U;
	uint32 Bankintr = 0U;
    Port_IntrSettingType gpioIntr;
    gpioIntr.gpioIntBank=0u;
	Port_EdgeTrig gpioEdge = 0U;
	
    Port_GPIOInit(((gpioBASE_t*)SOC_GIO_REG_BASE));
	
    for (idx = 0U; idx < gPortDrvObj.NumberOfGPIORegs; idx++)
        {

            gpioPortAddr = Port_GetGPIOPortAddr(
                    gPortDrvObj.DioConfig_pt[idx].Port_DioRegId);
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
                if (PORT_DIO_INVALID_BASE_ADDR == gpioPortAddr)
                {
                    Port_reportDetError((uint8) PORT_SID_INIT,
                                        (uint8) PORT_E_INIT_FAILED);
                }
                else
#endif      /*(STD_ON == PORT_CFG_DEV_ERROR_DETECT)*/
                {

                    Port_GPIOPortInit((gpioPORT_t *) gpioPortAddr);
					
                }
				
				Bankintr = gPortDrvObj.DioConfig_pt[idx].Port_DioRegId;
				Bankintr += Bankintr;
                gpioIntr.gpioIntBank |= (uint32)(gPortDrvObj.DioConfig_pt[idx].
											Port_BankInterruptEnable)<<Bankintr;
                gpioIntr.channelId   = (uint32)(gPortDrvObj.PinConfig_pt[idx].
														  Port_PinDioChannelId);
			
    Port_GPIOIntConfigure(((gpioBASE_t*) SOC_GIO_REG_BASE), 
											 (Port_IntrSettingType *)&gpioIntr);
    Port_DioConfigDir();
	
}
}

/*
 * \brief Function to program all the pad. Get called at boot-up time
 *
 *
 * \param[in]   pad_array - List of pad to be configured at boot time
 *
 * \return              none
 *
 */

static void Port_InitPadList(
    P2CONST(Port_PinConfigType, AUTO, PORT_APPL_DATA)padList,
    uint16 elements)
{
    uint16 idx = 0U;

    for (idx = 0U; idx < elements; ++idx)
    {
        Port_ConfigurePad(&padList[idx],
                          padList[idx].Port_PinInitialMode);
    }
}

static uint32 Port_GetMuxMode(
    Port_PinModeType Port_PinMode,
    const Port_PinModeConfigType *
    modeCfg,
    uint32           Port_NumPortModes)
{
    uint32 muxmode = 0U;
    uint32 idx = 0U;

    for (idx = 0U; idx < Port_NumPortModes; idx++)
    {
        if (Port_PinMode == modeCfg[idx].mode)
        {
            muxmode = modeCfg[idx].muxmode;
            break;
        }
    }
    if (idx == Port_NumPortModes)
    {
        muxmode = PORT_PAD_REGSETTING_DEFAULT;
    }

    return (muxmode);
}

/*
 * \brief Function to program all the pad. Get called at boot-up time
 *
 *
 * \param[in]   pad_array - List of pad to be configured at boot time
 *
 * \return              none
 *
 */
void Port_MapConfigToReg(
    P2CONST(Port_PinConfigType, AUTO, PORT_APPL_DATA)padConfig,
    P2VAR(Port_PadRegSettingType, AUTO, PORT_APPL_DATA)padRegSetting,
    Port_PinModeType pinMode)
{
    const uint32 pull_typeselect_map[3] =
    {
        [PORT_PIN_PULLTYPE_DEFAULT]  = PORT_PAD_REGSETTING_DEFAULT,
        [PORT_PIN_PULLTYPE_PULLDOWN] = PULLDOWN_EN,
        [PORT_PIN_PULLTYPE_PULLUP]  = PULLUP_EN
    };

    const uint32 pull_inhibit_map[3] =
    {
        [PORT_PIN_PULL_INHIBIT_DEFAULT]  = PORT_PAD_REGSETTING_DEFAULT,
        [PORT_PIN_PULL_INHIBIT_ENABLE] = PORT_PAD_REGSETTING_PULLINHIBIT_ENABLE,
        [PORT_PIN_PULL_INHIBIT_DISABLE] = PORT_PAD_REGSETTING_PULLINHIBIT_DISABLE,

    };

    const uint32 slewcontrol_map[3] =
    {
            [PORT_PIN_SLEWCONTROL_DEFAULT] =  PORT_PAD_REGSETTING_DEFAULT,
        [PORT_PIN_SLEWCONTROL_SLOW_SLEW] =
            PORT_PAD_REGSETTING_SLEWCONTROL_SLOW_SLEW,
        [PORT_PIN_SLEWCONTROL_FAST_SLEW] =
            PORT_PAD_REGSETTING_SLEWCONTROL_FAST_SLEW,
    };

    padRegSetting->muxmode = Port_GetMuxMode(
        pinMode,
        padConfig->Port_PinMode,
        padConfig->Port_NumPortModes);

    padRegSetting->pin_reg_offset = padConfig->Port_RegOffsetAddr;

    padRegSetting->pulludenable =
        pull_typeselect_map[padConfig->Port_PullTypeSelect];
    padRegSetting->pullinhibit=
        pull_inhibit_map[padConfig->Port_PullInhibitEnable];
    padRegSetting->oe_n_override_ctrl=padConfig->Port_OutputOverride_Ctrl;
    padRegSetting->slewcontrol =
        slewcontrol_map[padConfig->Port_SlewControl];
    padRegSetting->ie_n_override_ctrl = padConfig->Port_InputOverride_Ctrl;
}

#if ((STD_ON == PORT_CFG_SET_PIN_MODE_API) ||          \
    (STD_ON == PORT_CFG_REFRESH_PORT_DIRECTION_API) || \
    (STD_ON == PORT_CFG_SET_PIN_DIRECTION_API))

static void Port_ConfigDioPinDirection(
    const uint32 gpioPortAddr,
    uint32       dioChannelId,
    Port_PinDirectionType direction,
	Port_EdgeTrig  TriEdge,
	boolean TriggerEn)
{

    if (direction == PORT_PIN_OUT)
    {

        Port_SetDirection((gpioPORT_t *)gpioPortAddr, dioChannelId, 1);
    }
    else
    {

        Port_SetDirection((gpioPORT_t *)gpioPortAddr, dioChannelId, 0);
    
        Port_GPIOEdgTrigConfigure((gpioPORT_t *) gpioPortAddr,dioChannelId,
															 TriEdge,TriggerEn);
    }
}

#endif


static void Port_ConfigDioPin(const uint32           gpioPortAddr,
                              uint32                 dioChannelId,
                              Port_PinDirectionType  direction,
                              Port_PinLevelValueType level,
							  Port_EdgeTrig  TriEdge,
							  boolean TriggerEn)
{

    if (direction == PORT_PIN_OUT)
    {
        /* For output pin set output latch level and then enable OE */
        /* Requirements : SWS_Dio_00109 */
        if (level == PORT_PIN_LEVEL_HIGH)
        {

            Port_GPIOSetBit((gpioPORT_t*)gpioPortAddr, dioChannelId, 1);
        }
        else
        {

            Port_GPIOSetBit((gpioPORT_t*)gpioPortAddr, dioChannelId, 0);
        }
    }
    Port_ConfigDioPinDirection(gpioPortAddr, dioChannelId, direction,TriEdge,
																	 TriggerEn);
}

#if ((STD_ON == PORT_CFG_SET_PIN_MODE_API) || \
    (STD_ON == PORT_CFG_SET_PIN_DIRECTION_API))

static const Port_PinConfigType *
Port_MapPinIdToPinConfig(Port_PinType             PinId,
                         const Port_PinConfigType modeCfg[],
                         uint16                   numPins)
{
    uint16 idx = 0U;
    const Port_PinConfigType *pinCfg = NULL_PTR;

    for (idx = 0U; idx < numPins; idx++)
    {
        if (modeCfg[idx].Port_PinId == PinId)
        {
            pinCfg = &modeCfg[idx];
            break;
        }
    }

    if (idx == numPins)
    {
        pinCfg = NULL;
    }

    return pinCfg;
}
#endif

#if ((STD_ON == PORT_CFG_SET_PIN_DIRECTION_API) || \
    (STD_ON == PORT_CFG_REFRESH_PORT_DIRECTION_API))

static Port_PinModeType Port_GetCurrentPinMode(
    P2CONST(Port_PinConfigType, AUTO, PORT_APPL_DATA)padCfg)
{
    uint32 idx = 0U;
    Port_PinModeType pinMode = PORT_PIN_MODE_INVALID;

    uint32 muxmode_val = Port_ReadMuxMode(padCfg->Port_RegOffsetAddr);

    for (idx = 0U; idx < padCfg->Port_NumPortModes; idx++)
    {
        if (padCfg->Port_PinMode[idx].muxmode == muxmode_val)
        {
            pinMode = padCfg->Port_PinMode[idx].mode;
            break;
        }
    }
    if (idx == padCfg->Port_NumPortModes)
    {
        pinMode = PORT_PIN_MODE_INVALID;
    }
    return pinMode;
}


#endif


#if ((STD_ON == PORT_CFG_SET_PIN_MODE_API) ||          \
    (STD_ON == PORT_CFG_REFRESH_PORT_DIRECTION_API) || \
    (STD_ON == PORT_CFG_SET_PIN_DIRECTION_API))
LOCAL_INLINE boolean Port_IsDioMode(Port_PinModeType mode)
{
    boolean isDioMode;

    switch (mode)
    {
        case PORT_PIN_MODE_GPIOAB:
        case PORT_PIN_MODE_GPIOCD:
        case PORT_PIN_MODE_GPIOEF:
        case PORT_PIN_MODE_GPIOGH:
        case PORT_PIN_MODE_GPIOI:
        
            isDioMode = (boolean) TRUE;
            break;
        default:
            isDioMode = (boolean) FALSE;
            break;
    }
    return isDioMode;
}

#endif



/*
 * \brief Function to program all the pad. Get called at boot-up time
 *
 *
 * \param[in]   pad_array - List of pad to be configured at boot time
 *
 * \return              none
 *
 */

void Port_ConfigurePad(
    P2CONST(Port_PinConfigType, AUTO, PORT_APPL_DATA)padCfg,
    Port_PinModeType pinMode)
{
    Port_PadRegSettingType padRegConfig;

    Port_MapConfigToReg(padCfg, &padRegConfig,
                        pinMode);
    Port_ConfigurePadCore(SOC_IOMUX_REG_BASE, &padRegConfig);
}

/**
 * \brief API used only for UT.Not to be used by application
 */

FUNC(void, PORT_CODE) Port_DeInit(void)
{
#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
    /* Reset Init Done flag */
    gPortInitDone = (boolean) FALSE;
#endif
}


#if (STD_ON == PORT_CFG_DEV_ERROR_DETECT)
LOCAL_INLINE void Port_reportDetError(uint8 apiId, uint8 errorId)
{
    (void) Det_ReportError(PORT_MODULE_ID, 0, apiId, errorId);
    return;
}

#endif  /* #if (STD_ON == PORT_CFG_DEV_ERROR_DETECT) */


#define PORT_STOP_SEC_CODE
#include "Port_MemMap.h"

