/*!
* @file     Dio_Hw.c
*
* @version  1.0.0
*
* @brief    AUTOSAR Dio 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
    
#include "Dio.h"
#include "Dio_Hw.h"
#include "Dio_Reg.h"

/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup DIO_Driver
  * @brief DIO driver modules
  @{
*/

/** @defgroup DIO_Macros
  @{
*/
/*******************************************************************************
                    VENDOR ID & AUTOSAR VERSION INFO
*******************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define DIO_HW_VENDOR_ID                              0x00C1U
/* Module ID of this module, as defined in the BSW Module List. */
#define DIO_HW_MODULE_ID                              0x0065U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define DIO_HW_AR_RELEASE_MAJOR_VERSION               0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define DIO_HW_AR_RELEASE_MINOR_VERSION               0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define DIO_HW_AR_RELEASE_REVISION_VERSION            0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */ 
#define DIO_HW_SW_MAJOR_VERSION                       0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define DIO_HW_SW_MINOR_VERSION                       0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define DIO_HW_SW_PATCH_VERSION                       0x00U

/**@} end of group DIO_Macros */
/*******************************************************************************
                            GLOBAL VARIABLE
*******************************************************************************/
#define DIO_START_SEC_CONST_UNSPECIFIED
#include "Dio_MemMap.h"

/** @defgroup DIO_Variable
  @{
*/

/** The base address array of the GPIO */
CONST(uint32, DIO_CONST) DIO_BASEADDR_ARR[6] = {
    GPIOA_BASEADDR,
    GPIOB_BASEADDR,
    GPIOC_BASEADDR,
    GPIOD_BASEADDR,
    ((uint32)0x48001000),
    GPIOF_BASEADDR
};

/**@} end of group DIO_Variable */

#define DIO_STOP_SEC_CONST_UNSPECIFIED
#include "Dio_MemMap.h"
/*******************************************************************************
                            GLOBAL FUNCTIONS
*******************************************************************************/
#define DIO_START_SEC_CODE
#include "Dio_MemMap.h"

/** @defgroup DIO_Fuctions
  @{
*/

/*!
* @brief       Reads the specified input port pin
*
* @param       ChannelId       channel id that will be flip. 
*
* @retval      The input port pin value
*
* @note        None
*/
FUNC(Dio_LevelType, DIO_CODE) Dio_Hw_ReadChannel(CONST(Dio_ChannelType, AUTOMATIC) ChannelId)
{
    VAR(Dio_LevelType, AUTOMATIC) channelLevel = DIO_STD_LOW;
    
    uint8 localPortId = (uint8)GPIO_GET_PORT_ID(ChannelId);
    uint8 channelId = (uint8)GPIO_GET_CHANNEL_ID(ChannelId);
    
    const volatile uint32 regGpioInput = REG_READ32(GPIO_IDATA_REG_ADDR(localPortId));

    if ((uint32)0 == (uint32)((regGpioInput & PIN_MASK(ChannelId)) >> channelId))
    {
        channelLevel = DIO_STD_LOW;
    }
    else
    {
        channelLevel = DIO_STD_HIGH;
    }
    
    return channelLevel;
}


/*!
* @brief       Writes the specified level to an output channel
*
* @param       ChannelId       Target channel ID to write
* @param       Level           Output level (HIGH/LOW) to set
*
* @retval      None
*
* @note        None
*/
FUNC(void, DIO_CODE) Dio_Hw_WriteChannel(CONST(Dio_ChannelType, AUTOMATIC) ChannelId, 
                                         CONST(Dio_LevelType, AUTOMATIC) Level)
{
    uint8 localPortId = (uint8)GPIO_GET_PORT_ID(ChannelId);
    uint8 channelId = (uint8)GPIO_GET_CHANNEL_ID(ChannelId);
    
    if (DIO_STD_LOW == Level)
    {
        REG_BIT_CLEAR32(GPIO_ODATA_REG_ADDR(localPortId),(uint32)0x1U << channelId);
    }
    else
    {
        REG_BIT_SET32(GPIO_ODATA_REG_ADDR(localPortId),(uint32)0x1U << channelId);
    }
}



/*!
* @brief       Toggles the current level of the specified channel
*
* @param       ChannelId       Target channel ID to toggle
*
* @retval      New level after toggle operation
*
* @note        None
*/
FUNC(Dio_LevelType, DIO_CODE) Dio_Hw_FlipChannel(CONST(Dio_ChannelType, AUTOMATIC) ChannelId)
{
    VAR(Dio_LevelType, AUTOMATIC) channelLevel = DIO_STD_LOW;
    
    uint8 localPortId = (uint8)GPIO_GET_PORT_ID(ChannelId);
    uint8 channelId = (uint8)GPIO_GET_CHANNEL_ID(ChannelId);
    
    if ((uint32)0 != REG_BIT_GET32(GPIO_ODATA_REG_ADDR(localPortId),(uint32)0x1U << channelId))
    {
        REG_BIT_CLEAR32(GPIO_ODATA_REG_ADDR(localPortId),(uint32)0x1U << channelId);
        channelLevel = DIO_STD_LOW;
    }
    else
    {
        REG_BIT_SET32(GPIO_ODATA_REG_ADDR(localPortId),(uint32)0x1U << channelId);
        channelLevel = DIO_STD_HIGH;
    }
    
    return channelLevel;
}




/*!
* @brief       Reads the current level of an entire port
*
* @param       PortId          Target port ID to read
*
* @retval      Current input levels of the port
*
* @note        None
*/
FUNC(Dio_PortLevelType, DIO_CODE) Dio_Hw_ReadPort(CONST(Dio_PortLevelType, AUTOMATIC) PortId)
{
    VAR(Dio_PortLevelType, AUTOMATIC) portLevel = 0;
    
    portLevel = REG_READ32(GPIO_IDATA_REG_ADDR(PortId));

    return portLevel;
}



/*!
* @brief       Writes the specified level to an entire port
*
* @param       portId          Target port ID to write
* @param       Level           Output levels to set for the port
*
* @retval      None
*
* @note        None
*/
FUNC(void, DIO_CODE) Dio_Hw_WritePort(CONST(Dio_PortType, AUTOMATIC) portId, 
                                      CONST(Dio_PortLevelType, AUTOMATIC) Level)
{
    REG_WRITE32(GPIO_ODATA_REG_ADDR(portId),Level);
}




/*!
* @brief       Reads a specific channel group within a port
*
* @param       ChannelGroupIdPtr Pointer to channel group configuration
*
* @retval      Current levels of the channel group
*
* @note        Uses mask and offset to extract specific bits
*/
FUNC(Dio_PortLevelType, DIO_CODE) Dio_Hw_ReadChannelGroup(P2CONST(Dio_ChannelGroupType, AUTOMATIC, DIO_APPL_CONST) ChannelGroupIdPtr)
{
    VAR(Dio_PortLevelType, AUTOMATIC) portLevel = 0;
    
    portLevel = (REG_READ32(GPIO_IDATA_REG_ADDR(ChannelGroupIdPtr->port)) & ChannelGroupIdPtr->mask) >> ChannelGroupIdPtr->offset;
    
    return portLevel;
}



/*!
* @brief       Writes to a specific channel group within a port
*
* @param       ChannelGroupIdPtr Pointer to channel group configuration
* @param       Level           Levels to write to the channel group
*
* @retval      None
*
* @note        Applies mask and offset during write operation
*/
FUNC(void, DIO_CODE) Dio_Hw_WriteChannelGroup(P2CONST(Dio_ChannelGroupType, AUTOMATIC, DIO_APPL_CONST) ChannelGroupIdPtr,
                                              CONST(Dio_PortLevelType, AUTOMATIC) Level)
{
    REG_BIT_SET32(GPIO_ODATA_REG_ADDR(ChannelGroupIdPtr->port),(Level << ChannelGroupIdPtr->offset) & ChannelGroupIdPtr->mask);
}

/**@} end of group DIO_Fuctions */

#define DIO_STOP_SEC_CODE
#include "Dio_MemMap.h"

#ifdef __cplusplus
}
#endif

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