/*==================================================================================================
*   Project              : RTD AUTOSAR 4.4
*   Platform             : CORTEXM
*   Peripheral           : GPIO
*   Dependencies         : none
*
*   Autosar Version      : 4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   Autosar Conf.Variant :
*   SW Version           : 1.0.0
*   Build Version        : S32K1_RTD_1_0_0_HF01_D2109_ASR_REL_4_4_REV_0000_20210907
*
*   (c) Copyright 2020-2021 NXP Semiconductors
*   All Rights Reserved.
*
*   NXP Confidential. This software is owned or controlled by NXP and may only be
*   used strictly in accordance with the applicable license terms. By expressly
*   accepting such terms or by downloading, installing, activating and/or otherwise
*   using the software, you are agreeing that you have read, and that you agree to
*   comply with and are bound by, such license terms. If you do not agree to be
*   bound by the applicable license terms, then you may not retain, install,
*   activate or otherwise use the software.
==================================================================================================*/

#ifdef __cplusplus
extern "C" {
#endif

/**
*   @file Dio_Ipw.c
*
*   @internal
*   @addtogroup DIO_IPW
*   @{
*/

/*=================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
=================================================================================================*/

#include "Dio_Cfg.h"
#include "Dio_Ipw.h"
#include "Gpio_Dio_Ip_Cfg.h"
/*=================================================================================================
                               SOURCE FILE VERSION INFORMATION
=================================================================================================*/
#define DIO_VENDOR_ID_IPW_C                    43
#define DIO_AR_RELEASE_MAJOR_VERSION_IPW_C     4
#define DIO_AR_RELEASE_MINOR_VERSION_IPW_C     4
#define DIO_AR_RELEASE_REVISION_VERSION_IPW_C  0
#define DIO_SW_MAJOR_VERSION_IPW_C             1
#define DIO_SW_MINOR_VERSION_IPW_C             0
#define DIO_SW_PATCH_VERSION_IPW_C             0
/*=================================================================================================
*                                     FILE VERSION CHECKS
=================================================================================================*/
/* Check if Dio_Ipw source file and Dio_Ipw header file are of the same vendor */
#if (DIO_VENDOR_ID_IPW_C != DIO_VENDOR_ID_IPW_H)
    #error "Dio_Ipw.c and Dio_Ipw.h have different vendor ids"
#endif

/* Check if  Dio_Ipw source file and Dio_Ipw header file are of the same Autosar version */
#if ((DIO_AR_RELEASE_MAJOR_VERSION_IPW_C    != DIO_AR_RELEASE_MAJOR_VERSION_IPW_H) || \
     (DIO_AR_RELEASE_MINOR_VERSION_IPW_C    != DIO_AR_RELEASE_MINOR_VERSION_IPW_H) || \
     (DIO_AR_RELEASE_REVISION_VERSION_IPW_C != DIO_AR_RELEASE_REVISION_VERSION_IPW_H) \
    )
    #error "AutoSar Version Numbers of Dio_Ipw.c and Dio_Ipw.h are different"
#endif

/* Check if Dio_Ipw source file and Dio_Ipw header file are of the same Software version */
#if ((DIO_SW_MAJOR_VERSION_IPW_C != DIO_SW_MAJOR_VERSION_IPW_H) || \
     (DIO_SW_MINOR_VERSION_IPW_C != DIO_SW_MINOR_VERSION_IPW_H) || \
     (DIO_SW_PATCH_VERSION_IPW_C != DIO_SW_PATCH_VERSION_IPW_H)    \
    )
    #error "Software Version Numbers of Dio_Ipw.c and Dio_Ipw.h are different"
#endif

/* Check if Dio_Ipw source file and Dio_Cfg header file are of the same vendor */
#if (DIO_VENDOR_ID_IPW_C != DIO_VENDOR_ID_CFG_H)
    #error "Dio_Ipw.c and Dio_Cfg.h have different vendor ids"
#endif

/* Check if  Dio_Ipw source file and Dio_Cfg header file are of the same Autosar version */
#if ((DIO_AR_RELEASE_MAJOR_VERSION_IPW_C    != DIO_AR_RELEASE_MAJOR_VERSION_CFG_H) || \
     (DIO_AR_RELEASE_MINOR_VERSION_IPW_C    != DIO_AR_RELEASE_MINOR_VERSION_CFG_H) || \
     (DIO_AR_RELEASE_REVISION_VERSION_IPW_C != DIO_AR_RELEASE_REVISION_VERSION_CFG_H) \
    )
    #error "AutoSar Version Numbers of Dio_Ipw.c and Dio_Cfg.h are different"
#endif

/* Check if Dio_Ipw source file and Dio_Cfg header file are of the same Software version */
#if ((DIO_SW_MAJOR_VERSION_IPW_C != DIO_SW_MAJOR_VERSION_CFG_H) || \
     (DIO_SW_MINOR_VERSION_IPW_C != DIO_SW_MINOR_VERSION_CFG_H) || \
     (DIO_SW_PATCH_VERSION_IPW_C != DIO_SW_PATCH_VERSION_CFG_H)    \
    )
    #error "Software Version Numbers of Dio_Ipw.c and Dio_Cfg.h are different"
#endif

/* Check if Dio_Ipw source file and Gpio_Dio_Ip_Cfg header file are of the same vendor */
#if (DIO_VENDOR_ID_IPW_C != GPIO_DIO_IP_VENDOR_ID_CFG_H)
    #error "Dio_Ipw.c and Gpio_Dio_Ip_Cfg.h have different vendor ids"
#endif

/* Check if  Dio_Ipw source file and Gpio_Dio_Ip_Cfg header file are of the same Autosar version */
#if ((DIO_AR_RELEASE_MAJOR_VERSION_IPW_C    != GPIO_DIO_IP_AR_RELEASE_MAJOR_VERSION_CFG_H) || \
     (DIO_AR_RELEASE_MINOR_VERSION_IPW_C    != GPIO_DIO_IP_AR_RELEASE_MINOR_VERSION_CFG_H) || \
     (DIO_AR_RELEASE_REVISION_VERSION_IPW_C != GPIO_DIO_IP_AR_RELEASE_REVISION_VERSION_CFG_H) \
    )
    #error "AutoSar Version Numbers of Dio_Ipw.c and Gpio_Dio_Ip_Cfg.h are different"
#endif

/* Check if Dio_Ipw source file and Gpio_Dio_Ip_Cfg header file are of the same Software version */
#if ((DIO_SW_MAJOR_VERSION_IPW_C != GPIO_DIO_IP_SW_MAJOR_VERSION_CFG_H) || \
     (DIO_SW_MINOR_VERSION_IPW_C != GPIO_DIO_IP_SW_MINOR_VERSION_CFG_H) || \
     (DIO_SW_PATCH_VERSION_IPW_C != GPIO_DIO_IP_SW_PATCH_VERSION_CFG_H)    \
    )
    #error "Software Version Numbers of Dio_Ipw.c and Gpio_Dio_Ip_Cfg.h are different"
#endif

/*=================================================================================================
*                          LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
=================================================================================================*/

/*=================================================================================================
*                                       LOCAL MACROS
=================================================================================================*/
#if (STD_ON == DIO_REVERSEPORTBITS)
    #define GPIO_DIO_REVERSE_BITS_SHIFT            ((Dio_PortLevelType)1U)
    #define GPIO_DIO_REVERSE_BITS_MASK             ((Dio_PortLevelType)0x1U)
    #define GPIO_DIO_REVERSE_BITS_NUMBER           ((Dio_PortLevelType)((Dio_PortLevelType)((Dio_PortLevelType)(sizeof(Dio_PortLevelType)) << 0x3U) - 1U))
#endif /* (STD_ON == DIO_REVERSEPORTBITS) */

/*=================================================================================================
*                                      LOCAL CONSTANTS
=================================================================================================*/


/*=================================================================================================
*                                      LOCAL VARIABLES
=================================================================================================*/


/*=================================================================================================
*                                      GLOBAL CONSTANTS
=================================================================================================*/


/*=================================================================================================
*                                      GLOBAL VARIABLES
=================================================================================================*/


/*=================================================================================================
*                                   LOCAL FUNCTION PROTOTYPES
=================================================================================================*/

#define DIO_START_SEC_CODE
#include "Dio_MemMap.h"

#if (STD_ON == DIO_REVERSEPORTBITS)
static Dio_PortLevelType Dio_Ipw_ReverseBits
(
    Dio_PortLevelType Level
);
#endif /* (STD_ON == DIO_REVERSEPORTBITS) */

/*=================================================================================================
*                                       LOCAL FUNCTIONS
=================================================================================================*/

#if (STD_ON == DIO_REVERSEPORTBITS)
/**
* @brief          Reverses bits.
*
* @param[in]      Level       Bits to be reversed.
*
* @return         The reversed bits.
*
* @pre            This function can be used only if @p DIO_REVERSEPORTBITS is
*                 enabled.
*/
static Dio_PortLevelType Dio_Ipw_ReverseBits
(
    Dio_PortLevelType Level
)
{
    /* RevLevel will be reversed bits of Level */
    Dio_PortLevelType TempLevel = Level;
    Dio_PortLevelType RevLevel = TempLevel;
    Dio_PortLevelType NumShifts = GPIO_DIO_REVERSE_BITS_NUMBER; /* number of shifts needed due to trailing 0s */

    for (TempLevel = (Dio_PortLevelType)(TempLevel >> GPIO_DIO_REVERSE_BITS_SHIFT); (Dio_PortLevelType)STD_LOW != TempLevel; TempLevel = (Dio_PortLevelType)(TempLevel >> GPIO_DIO_REVERSE_BITS_SHIFT))
    {
        RevLevel = (Dio_PortLevelType)(RevLevel << GPIO_DIO_REVERSE_BITS_SHIFT);
        RevLevel = (Dio_PortLevelType)(RevLevel | ((Dio_PortLevelType)(TempLevel & GPIO_DIO_REVERSE_BITS_MASK)));
        NumShifts--;
    }

    RevLevel = (Dio_PortLevelType)((uint32)RevLevel << NumShifts); /* Remaining shifts when Level's highest bits are zero */

    return RevLevel;
}
#endif /* (STD_ON == DIO_REVERSEPORTBITS) */

/*=================================================================================================
*                                       GLOBAL FUNCTIONS
=================================================================================================*/

/*===============================================================================================*/
/**
* @brief          Returns the value of the specified DIO channel.
* @details        This function returns the value of the specified DIO channel.
*
* @param[in]      ChannelId   Specifies the required channel id.
*
* @return                     Returns the level of the corresponding pin as
*                             @p STD_HIGH or @p STD_LOW.
* @retval STD_HIGH            The logical level of the corresponding pin is 1.
* @retval STD_LOW             The logical level of the corresponding Pin is 0.
*/
Dio_LevelType Dio_Ipw_ReadChannel
(
    Dio_ChannelType ChannelId
)
{
    Dio_LevelType ChannelLevel = (Dio_LevelType) STD_LOW;
    uint32 u32GpioInstance;
    uint32 u32PinIndex;

    u32GpioInstance = GPIO_DIO_IP_PORT_U32(ChannelId);
    u32PinIndex = GPIO_DIO_IP_CHANNEL_U32(ChannelId);
    const GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[u32GpioInstance];

    ChannelLevel = Gpio_Dio_Ip_ReadPin(GpioBase, u32PinIndex);
    return ChannelLevel;
}

/*===============================================================================================*/
/**
* @brief          Sets the level of a channel.
* @details        If the specified channel is configured as an output channel,
*                 this function shall set the specified level on the
*                 specified channel. If the specified channel is configured
*                 as an input channel, this function shall have no influence
*                 on the physical output and on the result of the next read
*                 service.
*
* @param[in]      ChannelId   Specifies the required channel id.
* @param[in]      Level       Specifies the channel desired level.
*/
void Dio_Ipw_WriteChannel
(
    Dio_ChannelType ChannelId,
    Dio_LevelType Level
)
{
    uint32 u32GpioInstance;
    uint32 u32PinIndex;

    u32GpioInstance = GPIO_DIO_IP_PORT_U32(ChannelId);
    u32PinIndex = GPIO_DIO_IP_CHANNEL_U32(ChannelId);
    GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[u32GpioInstance];

    Gpio_Dio_Ip_WritePin(GpioBase, u32PinIndex, Level);
}

#if (STD_ON == DIO_FLIP_CHANNEL_API)
/*===============================================================================================*/
/**
* @brief          Inverts the level of a channel.
* @details        If the specified channel is configured as an output channel,
*                 this function shall invert the level of the specified
*                 channel. If the specified channel is configured as an
*                 input channel, this function shall have no influence
*                 on the physical output and on the result of the next
*                 read service.
*
* @param[in]      ChannelId   Specifies the required channel id.
*
* @return                     Returns the level of the corresponding pin as
*                             @p STD_HIGH or @p STD_LOW.
* @retval STD_HIGH            The logical level of the corresponding pin is 1.
* @retval STD_LOW             The logical level of the corresponding Pin is 0.
*
* @pre            This function can be used only if @p DIO_FLIP_CHANNEL_API
*                 has been enabled.

*/
Dio_LevelType Dio_Ipw_FlipChannel
(
    Dio_ChannelType ChannelId
)
{
    Dio_LevelType ChannelLevel = (Dio_LevelType)STD_LOW;
    uint32 u32GpioInstance;
    uint32 u32PinIndex;
    uint32 u32PortOutPutLevel;
    u32GpioInstance = GPIO_DIO_IP_PORT_U32(ChannelId);
    u32PinIndex = GPIO_DIO_IP_CHANNEL_U32(ChannelId);
    GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[u32GpioInstance];

    Gpio_Dio_Ip_TogglePins(GpioBase, ((uint32)1U << u32PinIndex));

    u32PortOutPutLevel = Gpio_Dio_Ip_GetPinsOutput(GpioBase);
    ChannelLevel = (Dio_LevelType)((u32PortOutPutLevel & ((uint32)1U << u32PinIndex)) >> u32PinIndex);

    return ChannelLevel;
}
#endif /* (STD_ON == DIO_FLIP_CHANNEL_API) */

/*===============================================================================================*/
/**
* @brief          Returns the level of all channels of specified port.
* @details        This function will return the level of all channels
*                 belonging to the specified port.
*
* @param[in]      PortId      Specifies the required port id.
*
* @return                     Levels of all channels of specified port.
*/
Dio_PortLevelType Dio_Ipw_ReadPort
(
    Dio_PortType PortId
)
{
    Dio_PortLevelType PortLevel = (Dio_PortLevelType)STD_LOW;
    const GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[PortId];

    PortLevel = (Dio_PortLevelType)(Gpio_Dio_Ip_ReadPins(GpioBase));

#if (STD_ON == DIO_READZERO_UNDEFINEDPORTS)
    PortLevel =(Dio_PortLevelType)(PortLevel & Dio_aAvailablePinsForRead[PortId]);
#endif
#if (STD_ON == DIO_REVERSEPORTBITS)
    PortLevel = (Dio_PortLevelType)(Dio_Ipw_ReverseBits(PortLevel));
#endif

    return PortLevel;
}

/*===============================================================================================*/
/**
* @brief          Sets the value of a port.
* @details        This function will set the specified value on the specified
*                 port.
*
* @param[in]      PortId      Specifies the required port id.
* @param[in]      Level       Specifies the required levels for the port pins.
*/
void Dio_Ipw_WritePort
(
    Dio_PortType PortId,
    Dio_PortLevelType Level
)
{
    Dio_PortLevelType CrtLevel = Level;
    GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[PortId];

#if (STD_ON == DIO_REVERSEPORTBITS)
    CrtLevel = (Dio_PortLevelType)(Dio_Ipw_ReverseBits(CrtLevel));
#endif /* STD_ON == DIO_REVERSEPORTBITS */
    Gpio_Dio_Ip_WritePins(GpioBase, CrtLevel);
}

/*===============================================================================================*/
/**
* @brief          This service reads a subset of the adjoining bits of a port.
* @details        This function will read a subset of adjoining bits of a
*                 port (channel group).
*
* @param[in]      pChannelGroupIdPtr Pointer to the channel group.
* @return                     The channel group levels.
*/
Dio_PortLevelType Dio_Ipw_ReadChannelGroup
(
    const Dio_ChannelGroupType * pChannelGroupIdPtr
)
{
    Dio_PortLevelType PortLevel = (Dio_PortLevelType)STD_LOW;
    Dio_PortLevelType pinsValue;
    const GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[pChannelGroupIdPtr->port];

    pinsValue = (Dio_PortLevelType)(Gpio_Dio_Ip_ReadPins(GpioBase));

#if (STD_ON == DIO_REVERSEPORTBITS)
    PortLevel = (Dio_PortLevelType)((pinsValue & (pChannelGroupIdPtr->mask)) << (pChannelGroupIdPtr->u8offset));
    PortLevel = (Dio_PortLevelType)(Dio_Ipw_ReverseBits(PortLevel));
#else
    PortLevel = (Dio_PortLevelType)((pinsValue & (pChannelGroupIdPtr->mask)) >> (pChannelGroupIdPtr->u8offset));
#endif

    return PortLevel;
}

/*===============================================================================================*/
/**
* @brief          Sets a subset of the adjoining bits of a port to the
*                 specified levels.
* @details        This function will set a subset of adjoining bits of a port
*                 (channel group) to the specified levels without changing
*                 the remaining channels of the port and channels that
*                 are configured as input.
*                 This function will do the masking of the channels and will
*                 do the shifting so that the values written by the function
*                 are aligned to the LSB.
*
* @param[in]      pChannelGroupIdPtr Pointer to the channel group.
* @param[in]      Level       Desired levels for the channel group.
*/
void Dio_Ipw_WriteChannelGroup
(
    const Dio_ChannelGroupType * pChannelGroupIdPtr,
    Dio_PortLevelType                 Level
)
{
    Dio_PortLevelType ValueSet;
    Dio_PortLevelType ValueClear;

    GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[pChannelGroupIdPtr->port];

#if (STD_ON == DIO_REVERSEPORTBITS)
    ValueSet = (((Dio_PortLevelType)(Dio_Ipw_ReverseBits(Level)) >> (pChannelGroupIdPtr->u8offset)) & (((Dio_PortLevelType)(pChannelGroupIdPtr->mask) )));
#else
    ValueSet = (((Dio_PortLevelType)(Level) << (pChannelGroupIdPtr->u8offset)) & (((Dio_PortLevelType)(pChannelGroupIdPtr->mask) )));
#endif

    Gpio_Dio_Ip_SetPins(GpioBase, ValueSet);
    ValueClear = (~ValueSet) & pChannelGroupIdPtr->mask;
    Gpio_Dio_Ip_ClearPins(GpioBase, ValueClear);

}

#if ((STD_ON == DIO_MASKEDWRITEPORT_API) || defined(__DOXYGEN__))
/*===============================================================================================*/
/**
* @brief          DIO Mask write port using mask.
* @details        Writes a DIO port with masked value.
*
* @param[in]      PortId      Specifies the required port id.
* @param[in]      Level       Specifies the required levels for the port pins.
* @param[in]      Mask        Specifies the Mask value of the port.
*
* @pre            This function can be used only if @p DIO_MASKEDWRITEPORT_API
*                 has been enabled.
*/

void Dio_Ipw_MaskedWritePort
(
    Dio_PortType PortId,
    Dio_PortLevelType Level,
    Dio_PortLevelType Mask
)
{
    Dio_PortLevelType Value;
    GPIO_Type * GpioBase = (GPIO_Type *)GpioBaseAdresses[PortId];

    Value = ((uint32)Mask) & ((uint32)(Level));
    Gpio_Dio_Ip_SetPins(GpioBase, Value);
    Value = (~Level) & Mask;
    Gpio_Dio_Ip_ClearPins(GpioBase, Value);
}
#endif /* (STD_ON == DIO_MASKEDWRITEPORT_API) || defined(__DOXYGEN__) */

#define DIO_STOP_SEC_CODE

#include "Dio_MemMap.h"


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