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

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

#include "Reg_eSys.h"
#include "Std_Types.h"
#include "Port.h"
#include "Port_Hw.h"
#include "Port_Cfg.h"

#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
#include "Det.h"
#endif

/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup PORT_Driver
  * @brief PORT driver modules
  @{
*/

/** @defgroup PORT_Macros
  @{
*/
/*******************************************************************************
                    VENDOR ID & AUTOSAR VERSION INFO
*******************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define PORT_VENDOR_ID                              0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define PORT_AR_RELEASE_MAJOR_VERSION               0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define PORT_AR_RELEASE_MINOR_VERSION               0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define PORT_AR_RELEASE_REVISION_VERSION            0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */ 
#define PORT_SW_MAJOR_VERSION                       0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define PORT_SW_MINOR_VERSION                       0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define PORT_SW_PATCH_VERSION                       0x00U

/**@} end of group PORT_Macros */
/*******************************************************************************
                            GLOBAL VARIABLE
*******************************************************************************/
#define PORT_START_SEC_VAR_INIT_32
#include "Port_MemMap.h"

/** @defgroup PORT_Variable
  @{
*/

/** Global variable configured for port */
static P2CONST(Port_ConfigType, PORT_VAR, PORT_APPL_CONST) g_PortPointCfg = NULL_PTR;

/**@} end of group PORT_Variable */

#define PORT_STOP_SEC_VAR_INIT_32
#include "Port_MemMap.h"
/*******************************************************************************
                            GLOBAL FUNCTIONS
*******************************************************************************/
#define PORT_START_SEC_CODE
#include "Port_MemMap.h"

/** @defgroup PORT_Fuctions
  @{
*/

/*!
* @brief         This function is used to initialize the port driver module.
*
* @param[in]     ConfigPtr     Pointer to structure containing
*                              initialization parameters.
*
* @retval        void
*
* @note          Non Reentrant.
*/
FUNC(void, MCU_CODE) Port_Init(const Port_ConfigType* ConfigPtr)
{
    uint8 num = 0;

#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    if (NULL_PTR == ConfigPtr)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_INIT_SID, PORT_E_INIT_FAILED);
    }
    else
    {
#endif
        g_PortPointCfg = ConfigPtr;
        
        for (num = 0; num < g_PortPointCfg->pinMaxValue; num++)
        {
#if (STD_ON == PORT_DEBUG_IO)
            if ((g_PortPointCfg->pinNum[num].portId == PORT_GPIO_A) &&
                (g_PortPointCfg->pinNum[num].portPinId == GPIO_PIN_13) &&
                (g_PortPointCfg->pinNum[num].pinMode.portPinMode != PA13_SWDIO))
            {
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
                (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                                PORT_INIT_SID, PORT_E_DEBUG_IO_CFG);
#endif
                Port_Hw_AFConfig(PORT_GPIO_A,GPIO_PIN_13,PA13_SWDIO);
            }
            else if ((g_PortPointCfg->pinNum[num].portId == PORT_GPIO_A) &&
                     (g_PortPointCfg->pinNum[num].portPinId == GPIO_PIN_14) &&
                     (g_PortPointCfg->pinNum[num].pinMode.portPinMode != PA14_SWCLK))
            {
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
                (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                                PORT_INIT_SID, PORT_E_DEBUG_IO_CFG);
#endif
                Port_Hw_AFConfig(PORT_GPIO_A,GPIO_PIN_14,PA14_SWCLK);
            }
            else
            {
#endif
                if ((g_PortPointCfg->pinNum[num].pinMode.portPinMode != GPIO_MODE_IN) &&
                    (g_PortPointCfg->pinNum[num].pinMode.portPinMode != GPIO_MODE_OUT))
                {
                    Port_Hw_AFConfig(g_PortPointCfg->pinNum[num].portId,
                                     g_PortPointCfg->pinNum[num].portPinId,
                                     g_PortPointCfg->pinNum[num].pinMode.portPinMode);
                }
                else if ((g_PortPointCfg->pinNum[num].pinMode.portPinMode != GPIO_MODE_IN) &&
                         (g_PortPointCfg->pinNum[num].pinMode.portPinMode != GPIO_MODE_AN))
                {
                    /* Output mode configuration */
                    Port_Hw_ConfigPinOutputMode(g_PortPointCfg->pinNum[num].portId,
                                                g_PortPointCfg->pinNum[num].portPinId,
                                                g_PortPointCfg->pinNum[num].pinMode.outputMode);
                    
                    if (g_PortPointCfg->pinNum[num].pinMode.portPinMode == GPIO_MODE_OUT)
                    {
                        Port_Hw_ConfigPinOData(g_PortPointCfg->pinNum[num].portId,
                                               g_PortPointCfg->pinNum[num].portPinId,
                                               g_PortPointCfg->pinNum[num].pinMode.defaultLevel);
                    }
                    else
                    {
                        /* nothing */
                    }
                }
                else
                {
                    /* nothing */
                }
                
                /* speed */
                Port_Hw_ConfigPinSpeed(g_PortPointCfg->pinNum[num].portId,
                                       g_PortPointCfg->pinNum[num].portPinId,
                                       g_PortPointCfg->pinNum[num].pinMode.speedSelect);
                
                
                /* input/output mode */
                Port_Hw_ConfigPinMode(g_PortPointCfg->pinNum[num].portId,
                                      g_PortPointCfg->pinNum[num].portPinId,
                                      g_PortPointCfg->pinNum[num].pinMode.portPinMode);
                
                /* Pull-up Pull down resistor configuration */
                Port_Hw_ConfigPull(g_PortPointCfg->pinNum[num].portId,
                                   g_PortPointCfg->pinNum[num].portPinId,
                                   g_PortPointCfg->pinNum[num].pinMode.pullValue);
#if (STD_ON == PORT_DEBUG_IO)
            }
#endif
        }
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    }
#endif
}


#if (PORT_SET_PINDIRECTION_API == STD_ON)
/*!
* @brief         This function is used to Sets the port pin direction.
*
* @param[in]     Pin        Pin ID number.
* @param[in]     Direction  Port Pin direction.
*
* @retval        void
*
* @note          Non Reentrant.
*/
FUNC(void, MCU_CODE) Port_SetPinDirection(Port_PinType Pin, Port_PinDirectionType Direction)
{
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    if (NULL_PTR == g_PortPointCfg)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_SETPINDIRECTION_SID, PORT_E_UNINIT);
    }
    else if (Pin >= g_PortPointCfg->pinMaxValue)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_SETPINDIRECTION_SID, PORT_E_PARAM_PIN);
    }
    else if (g_PortPointCfg->pinNum[Pin].pinDirLock == PIN_YES_LOCK)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_SETPINDIRECTION_SID, PORT_E_DIRECTION_UNCHANGEABLE);
    }
    else
    {
#endif
        Port_Hw_ConfigPinDir(g_PortPointCfg->pinNum[Pin].portId,
                             g_PortPointCfg->pinNum[Pin].portPinId,
                             Direction);
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    }
#endif
}
#endif


/*!
* @brief         This function is used to Refreshes port direction.
*
* @retval        void
*
* @note          Non Reentrant.
*/
FUNC(void, MCU_CODE) Port_RefreshPortDirection(void)
{
    uint8 num = 0;

#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    if (NULL_PTR == g_PortPointCfg)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_REFRESHPINDIRECTION_SID, PORT_E_UNINIT);
    }
    else
    {
#endif
        for (num = 0; num < g_PortPointCfg->pinMaxValue; num++)
        {
            if ((g_PortPointCfg->pinNum[num].pinDirLock != PIN_YES_LOCK) &&
                ((g_PortPointCfg->pinNum[num].pinMode.portPinMode == GPIO_MODE_IN) ||
                 (g_PortPointCfg->pinNum[num].pinMode.portPinMode == GPIO_MODE_OUT)))
            {
                Port_Hw_ConfigPinMode(g_PortPointCfg->pinNum[num].portId,
                                      g_PortPointCfg->pinNum[num].portPinId,
                                      g_PortPointCfg->pinNum[num].pinMode.portPinMode);
            }
            else
            {
                /* nothing */
            }
        }
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    }
#endif
}


#if (PORT_VERINFO_API == STD_ON)
/*!
* @brief        The function used to get the version information of Port module.
*
* @param[in]    VersionInfo     Pointer of the memory addr which use to store the version 
*                               information of this module.
* @retval       void
*
* @note   
*/
FUNC(void, MCU_CODE) Port_GetVersionInfo(P2VAR(Std_VersionInfoType, AUTOMATIC, MCU_APPL_DATA) VersionInfo)
{
    if(NULL_PTR != VersionInfo)
    {
        (VersionInfo)->vendorID = (uint16)PORT_VENDOR_ID;
        (VersionInfo)->moduleID = (uint8)PORT_CFG_H_MODULE_ID;
        (VersionInfo)->sw_major_version = (uint8)PORT_AR_RELEASE_MAJOR_VERSION;
        (VersionInfo)->sw_minor_version = (uint8)PORT_AR_RELEASE_MINOR_VERSION;
        (VersionInfo)->sw_patch_version = (uint8)PORT_AR_RELEASE_REVISION_VERSION;
    }
    else
    {
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_GETVERSIONINFO_SID, PORT_E_PARAM_POINTER);
#endif
    }
}
#endif


#if (PORT_SET_PINMODE_API == STD_ON)
/*!
* @brief         This function is used to Sets the port pin mode.
*
* @param[in]     Pin        Pin ID number.
* @param[in]     Mode       New Port Pin mode to be set on port pin.
*
* @retval        void
*
* @note          Non Reentrant.
*/
FUNC(void, MCU_CODE) Port_SetPinMode(Port_PinType Pin, Port_PinModeType Mode)
{
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    if (NULL_PTR == g_PortPointCfg)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_SETPINMODE_SID, PORT_E_UNINIT);
    }
    else if (Pin >= g_PortPointCfg->pinMaxValue)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_SETPINMODE_SID, PORT_E_PARAM_PIN);
    }
    else if (g_PortPointCfg->pinNum[Pin].pinModeLock == PIN_YES_LOCK)
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_SETPINMODE_SID, PORT_E_MODE_UNCHANGEABLE);
    }
    else if ((Mode == GPIO_MODE_IN)  || (Mode == GPIO_MODE_OUT) || (Mode == GPIO_MODE_AF0) ||
             (Mode == GPIO_MODE_AF1) || (Mode == GPIO_MODE_AF2) || (Mode == GPIO_MODE_AF3) ||
             (Mode == GPIO_MODE_AF4) || (Mode == GPIO_MODE_AF5) || (Mode == GPIO_MODE_AF6) ||
             (Mode == GPIO_MODE_AF7) || (Mode == GPIO_MODE_AF_RETAIN) || (Mode == GPIO_MODE_AN))
    {
#endif
        Port_Hw_ConfigPinMode(g_PortPointCfg->pinNum[Pin].portId,
                              g_PortPointCfg->pinNum[Pin].portPinId,
                              Mode);
#if (PORT_DEV_ERR_DETECT_ENABLE == STD_ON)
    }
    else
    {
        (void)Det_ReportError((uint16)PORT_CFG_H_MODULE_ID, PORT_INSTANCE_ID,
                        PORT_SETPINMODE_SID, PORT_E_PARAM_INVALID_MODE);
    }
#endif
}
#endif

/**@} end of group PORT_Fuctions */

#define PORT_STOP_SEC_CODE
#include "Port_MemMap.h"

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

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