/*==================================================================================================
*   Project              : RTD AUTOSAR 4.4
*   Platform             : CORTEXM
*   Peripheral           : DMA,CACHE,TRGMUX,LCU,EMIOS,FLEXIO
*   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        : S32K3_RTD_1_0_0_HF02_D2112_ASR_REL_4_4_REV_0000_20211222
*
*   (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.
==================================================================================================*/

/**
*   @file    Emios_Mcl_Ip.c
*
*   @version 1.0.0
*
*   @brief   AUTOSAR Mcl - Emios Common driver source file.
*   @details
*
*   @addtogroup EMIOS_IP_DRIVER EMIOS IP Driver
*   @{
*/

#ifdef __cplusplus
extern "C"{
#endif

/*==================================================================================================
*                                         INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
#include "Emios_Mcl_Ip.h"

/*==================================================================================================
*                               SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define EMIOS_MCL_IP_VENDOR_ID_C                       43
#define EMIOS_MCL_IP_AR_RELEASE_MAJOR_VERSION_C        4
#define EMIOS_MCL_IP_AR_RELEASE_MINOR_VERSION_C        4
#define EMIOS_MCL_IP_AR_RELEASE_REVISION_VERSION_C     0
#define EMIOS_MCL_IP_SW_MAJOR_VERSION_C                1
#define EMIOS_MCL_IP_SW_MINOR_VERSION_C                0
#define EMIOS_MCL_IP_SW_PATCH_VERSION_C                0
/*==================================================================================================
*                                      FILE VERSION CHECKS
==================================================================================================*/
#if (EMIOS_MCL_IP_VENDOR_ID_C != EMIOS_MCL_IP_VENDOR_ID)
    #error "Emios_Mcl_Ip.c and Emios_Mcl_Ip.h have different vendor ids"
#endif

/* Check if  source file and Emios_Mcl_Ip.h file are of the same Autosar version */
#if ((EMIOS_MCL_IP_AR_RELEASE_MAJOR_VERSION_C != EMIOS_MCL_IP_AR_RELEASE_MAJOR_VERSION) || \
     (EMIOS_MCL_IP_AR_RELEASE_MINOR_VERSION_C != EMIOS_MCL_IP_AR_RELEASE_MINOR_VERSION) || \
     (EMIOS_MCL_IP_AR_RELEASE_REVISION_VERSION_C != EMIOS_MCL_IP_AR_RELEASE_REVISION_VERSION))
    #error "AutoSar Version Numbers of Emios_Mcl_Ip.c and Emios_Mcl_Ip.h are different"
#endif

/* Check if source file and Emios_Mcl_Ip.h file are of the same Software version */
#if ((EMIOS_MCL_IP_SW_MAJOR_VERSION_C != EMIOS_MCL_IP_SW_MAJOR_VERSION) || \
     (EMIOS_MCL_IP_SW_MINOR_VERSION_C != EMIOS_MCL_IP_SW_MINOR_VERSION) || \
     (EMIOS_MCL_IP_SW_PATCH_VERSION_C != EMIOS_MCL_IP_SW_PATCH_VERSION))
    #error "Software Version Numbers of Emios_Mcl_Ip.c and Emios_Mcl_Ip.h are different"
#endif
/*==================================================================================================
*                           LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/

/*==================================================================================================
*                                          LOCAL MACROS
==================================================================================================*/

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

/*==================================================================================================
*                                         LOCAL VARIABLES
==================================================================================================*/
#define MCL_START_SEC_VAR_INIT_UNSPECIFIED_NO_CACHEABLE
#include "Mcl_MemMap.h"

eMIOS_Type* Emios_Ip_paxBase[eMIOS_INSTANCE_COUNT] = IP_eMIOS_BASE_PTRS;

#define MCL_STOP_SEC_VAR_INIT_UNSPECIFIED_NO_CACHEABLE
#include "Mcl_MemMap.h"

#if (EMIOS_IP_MULTICORE_IS_AVAILABLE == STD_ON)

    #define MCL_START_SEC_VAR_INIT_UNSPECIFIED_NO_CACHEABLE
    #include "Mcl_MemMap.h"

    static Emios_Ip_InstStateType Emios_Ip_axIpIsInitialized[eMIOS_INSTANCE_COUNT] =
    {
        {(boolean)FALSE, (uint8)255}
    };

    #define MCL_STOP_SEC_VAR_INIT_UNSPECIFIED_NO_CACHEABLE
    #include "Mcl_MemMap.h"

#else

    #define MCL_START_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
    #include "Mcl_MemMap.h"

    static Emios_Ip_InstStateType Emios_Ip_axIpIsInitialized[eMIOS_INSTANCE_COUNT];

    #define MCL_STOP_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
    #include "Mcl_MemMap.h"

#endif


#define MCL_START_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Mcl_MemMap.h"

static Emios_Ip_ChStateType Emios_Ip_axChState[eMIOS_INSTANCE_COUNT][eMIOS_CH_UC_UC_COUNT];

#define MCL_STOP_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Mcl_MemMap.h"

#define MCL_START_SEC_VAR_CLEARED_16
#include "Mcl_MemMap.h"

/* Array to store the period master bus */
static uint16 Emios_Ip_ChPeriodMasterBus[eMIOS_INSTANCE_COUNT][eMIOS_CH_UC_UC_COUNT];

#define MCL_STOP_SEC_VAR_CLEARED_16
#include "Mcl_MemMap.h"

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

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

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

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

/*==================================================================================================
*                                        GLOBAL FUNCTIONS
==================================================================================================*/
#define MCL_START_SEC_CODE
#include "Mcl_MemMap.h"

/** @implements Emios_Mcl_Ip_Init_Activity */
Emios_Ip_CommonStatusType Emios_Mcl_Ip_Init(uint8 instance, const Emios_Mcl_Ip_ConfigType* const pConfig)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert(instance < eMIOS_INSTANCE_COUNT);
    DevAssert(pConfig != NULL_PTR);
#endif

    uint8                     CurrentChannel;
    eMIOS_Type*               Base   = Emios_Ip_paxBase[instance];
    Emios_Ip_CommonStatusType Status = EMIOS_IP_COMMON_STATUS_SUCCESS;

#if (STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE)
    uint8 coreID = (uint8)OsIf_GetCoreID();
    if ( MULTICORE_INIT_CORE == coreID )
    {
#endif /* STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE */

        if (Emios_Ip_axIpIsInitialized[instance].instanceInitState == TRUE)
        {
            Status = EMIOS_IP_COMMON_STATUS_FAIL;
        }
        else
        {
            /* Initialization of EMIOS instance specific parameters. */
            Base->MCR &= ~eMIOS_MCR_GPREN_MASK;
            Base->MCR = eMIOS_MCR_GPRE(pConfig->emiosGlobalConfig->clkDivVal) | eMIOS_MCR_FRZ(((uint32)pConfig->emiosGlobalConfig->allowDebugMode)) | \
                        eMIOS_MCR_GTBE(pConfig->emiosGlobalConfig->enableGlobalTimeBase);

            /* Initialization of EMIOS channel specific parameters. */
            for (CurrentChannel = 0; CurrentChannel < pConfig->channelsNumber; CurrentChannel++)
            {
                if ((*pConfig->masterBusConfig)[CurrentChannel].allowDebugMode)
                {
                    Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].C |= eMIOS_C_FREN_MASK;
                }

                /* Set Cn UCPRE to divider. */
                Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].C2 |= eMIOS_C2_UCEXTPRE((*pConfig->masterBusConfig)[CurrentChannel].masterBusPrescaler);

                switch ((*pConfig->masterBusConfig)[CurrentChannel].masterMode)
                {
                case EMIOS_IP_MC_UP_COUNTER_START:
                    Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].A = (*pConfig->masterBusConfig)[CurrentChannel].defaultPeriod;
                    break;
                case EMIOS_IP_MC_UP_COUNTER_END:
                    Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].A = (*pConfig->masterBusConfig)[CurrentChannel].defaultPeriod;
                    break;
                case EMIOS_IP_MC_UP_DOWN_COUNTER:
                    Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].B = 0;
                    Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].A = (*pConfig->masterBusConfig)[CurrentChannel].defaultPeriod;
                    break;
                case EMIOS_IP_MCB_UP_COUNTER:
                    Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].A = (*pConfig->masterBusConfig)[CurrentChannel].defaultPeriod;
                    break;
                case EMIOS_IP_MCB_UP_DOWN_COUNTER:
                    Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].A = (*pConfig->masterBusConfig)[CurrentChannel].defaultPeriod;
                    break;
                default:
                    /* Do nothing. */
                    break;
                }

                /* Write CNT register with start offset value. */
                Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].CNT = (*pConfig->masterBusConfig)[CurrentChannel].offsetStartValue;

                /* Set mode Cn_MODE = mode. */
                Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].C |= eMIOS_C_MODE((*pConfig->masterBusConfig)[CurrentChannel].masterMode);

                Base->CH.UC[(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].C |= eMIOS_C_UCPREN(1U);

                /* Save current state of channel. */
                Emios_Ip_axChState[instance][(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].counterMode      = (*pConfig->masterBusConfig)[CurrentChannel].masterMode;
                Emios_Ip_axChState[instance][(*pConfig->masterBusConfig)[CurrentChannel].hwChannel].channelInitState = TRUE;
                /* Save the period of master bus channel. */
                Emios_Ip_ChPeriodMasterBus[instance][(*pConfig->masterBusConfig)[CurrentChannel].hwChannel] = (uint16)(*pConfig->masterBusConfig)[CurrentChannel].defaultPeriod;
            }

            /* Save current state of the instance. */
            Emios_Ip_axIpIsInitialized[instance].instanceInitState = TRUE;
#if (STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE)
            Emios_Ip_axIpIsInitialized[instance].runCore           = pConfig->instanceCoreNumber;
#endif
        }

        Base->MCR |= eMIOS_MCR_GPREN_MASK;

#if (STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE)
    }
    else
    {
        Status = EMIOS_IP_COMMON_STATUS_WRONG_CORE;
    }
#endif /* STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE */

    return Status;
}

/** @implements Emios_Mcl_Ip_EnableChannel_Activity */
void Emios_Mcl_Ip_EnableChannel(uint8 instance, uint8 u8HwChannel)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert(instance < eMIOS_INSTANCE_COUNT);
    DevAssert(u8HwChannel < eMIOS_CH_UC_UC_COUNT);
#endif

    eMIOS_Type* Base = Emios_Ip_paxBase[instance];
    Base->UCDIS &= ~(uint32)((uint32)1 << ((uint32)u8HwChannel));
}

/** @implements Emios_Mcl_Ip_DisableChannel_Activity */
void Emios_Mcl_Ip_DisableChannel(uint8 instance, uint8 u8HwChannel)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert(instance < eMIOS_INSTANCE_COUNT);
    DevAssert(u8HwChannel < eMIOS_CH_UC_UC_COUNT);
#endif

    eMIOS_Type* Base = Emios_Ip_paxBase[instance];
    Base->UCDIS |= (uint32)((uint32)1 << ((uint32)u8HwChannel));
}

/** @implements Emios_Mcl_Ip_ComparatorTransferEnable_Activity */
void Emios_Mcl_Ip_ComparatorTransferEnable(uint8 instance, uint32 channelMask)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert(instance < eMIOS_INSTANCE_COUNT);
    DevAssert(channelMask < EMIOS_CHANNELMASK_MAXVAL);
#endif

    eMIOS_Type* Base = Emios_Ip_paxBase[instance];
    /* Update enable. */
    Base->OUDIS &= ~(channelMask);
}

/** @implements Emios_Mcl_Ip_ComparatorTransferDisable_Activity */
void Emios_Mcl_Ip_ComparatorTransferDisable(uint8 instance, uint32 channelMask)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert(instance < eMIOS_INSTANCE_COUNT);
    DevAssert(channelMask < EMIOS_CHANNELMASK_MAXVAL);
#endif

    eMIOS_Type* Base = Emios_Ip_paxBase[instance];
    /* Disable channel output. */
    Base->OUDIS |= channelMask;
}

/** @implements Emios_Mcl_Ip_Deinit_Activity */
Emios_Ip_CommonStatusType Emios_Mcl_Ip_Deinit(uint8 instance)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert(instance < eMIOS_INSTANCE_COUNT);
#endif

    uint8                     CurrentChannel;
    Emios_Ip_CommonStatusType Status = EMIOS_IP_COMMON_STATUS_SUCCESS;
    eMIOS_Type*               Base   = Emios_Ip_paxBase[instance];

#if (STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE)
    uint8 coreID = (uint8)OsIf_GetCoreID();
    if ( MULTICORE_INIT_CORE == coreID )
    {
#endif /* STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE */
        if (Emios_Ip_axIpIsInitialized[instance].instanceInitState == FALSE)
        {
            Status = EMIOS_IP_COMMON_STATUS_FAIL;
        }
        else
        {
            Base->MCR &= ~eMIOS_MCR_GPREN_MASK;
            Base->MCR = eMIOS_MCR_GPRE(0U) | eMIOS_MCR_FRZ(0U) | eMIOS_MCR_GTBE(0U);

            for (CurrentChannel = 0; CurrentChannel < eMIOS_CH_UC_UC_COUNT; CurrentChannel++)
            {
                if(Emios_Ip_axChState[instance][CurrentChannel].channelInitState == TRUE)
                {
                    /* Disable channel pre-scaler (reset default) */
                    Emios_Ip_paxBase[instance]->CH.UC[CurrentChannel].C = 0U;
                    /* Reset An and Bn registers */
                    Emios_Ip_paxBase[instance]->CH.UC[CurrentChannel].A = 0UL;
                    Emios_Ip_paxBase[instance]->CH.UC[CurrentChannel].B = 0UL;

                    Emios_Ip_paxBase[instance]->UCDIS |= (uint32)((uint32)0 << ((uint32)CurrentChannel));
                    /* Clear the period of master bus channel. */
                    Emios_Ip_ChPeriodMasterBus[instance][CurrentChannel] = (uint16)0U;
                    Emios_Ip_axChState[instance][CurrentChannel].channelInitState = FALSE;
                }
            }
            Emios_Ip_axIpIsInitialized[instance].instanceInitState = FALSE;
        }
#if (STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE)
    }
    else
    {
        Status = EMIOS_IP_COMMON_STATUS_WRONG_CORE;
    }
#endif /* STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE */

    return Status;
}

/* Emios_Mcl_Ip_SetReloadInterval_Activity */
void Emios_Mcl_Ip_SetReloadInterval(uint8 hwInstance, uint8 hwChannel, uint8 interval)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert((uint8)31 > interval);
    DevAssert(hwInstance < eMIOS_INSTANCE_COUNT);
    DevAssert(hwChannel < eMIOS_CH_UC_UC_COUNT);
#endif
    /* Specifies the delay interval, in counter bus reload events, between each assertion
     * of AS1-BS1 reload in MC and MCB modes. */
    Emios_Ip_paxBase[hwInstance]->CH.UC[hwChannel].C2 = eMIOS_C2_UCRELDEL_INT(interval);
}

boolean Emios_Mcl_Ip_ValidateChannel(uint8 hwInstance, uint8 hwChannel)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    /* Check input parameter*/
    DevAssert(hwInstance < eMIOS_INSTANCE_COUNT);
    DevAssert(hwChannel < eMIOS_CH_UC_UC_COUNT);
#endif
    boolean Valid = FALSE;

    if (TRUE == Emios_Ip_axChState[hwInstance][hwChannel].channelInitState)
    {
        Valid = TRUE;
    }
    return Valid;
}

/** @implements Emios_Mcl_Ip_SetCounterBusPeriod_Activity */
Emios_Ip_CommonStatusType Emios_Mcl_Ip_SetCounterBusPeriod(uint8 hwInstance, uint8 hwChannel, uint16 period)
{
#if (STD_ON == EMIOS_MCL_IP_DEV_ERROR_DETECT)
    DevAssert((uint16)65535 > period);
    DevAssert(hwInstance < eMIOS_INSTANCE_COUNT);
    DevAssert(hwChannel < eMIOS_CH_UC_UC_COUNT);
#endif
    Emios_Ip_CommonStatusType Status = EMIOS_IP_COMMON_STATUS_FAIL;

    if (( (Emios_Ip_axChState[hwInstance][hwChannel].counterMode == EMIOS_IP_MCB_UP_COUNTER) || \
          (Emios_Ip_axChState[hwInstance][hwChannel].counterMode == EMIOS_IP_MCB_UP_DOWN_COUNTER) ) && \
          (period < 1U) )
    {
        Status = EMIOS_IP_COMMON_STATUS_FAIL;
    }
    else
    {
        Emios_Ip_paxBase[hwInstance]->CH.UC[hwChannel].A = period;
        /* Store the new period */
        Emios_Ip_ChPeriodMasterBus[hwInstance][hwChannel] = period;
        Status = EMIOS_IP_COMMON_STATUS_SUCCESS;
    }
    return Status;
}


/** @implements Emios_Mcl_Ip_GetCounterBusPeriod_Activity */
uint16 Emios_Mcl_Ip_GetCounterBusPeriod(uint8 Instance, uint8 Channel)
{
#if (EMIOS_MCL_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(Instance < eMIOS_INSTANCE_COUNT);
    DevAssert(Channel < eMIOS_CH_UC_UC_COUNT);
#endif
    /* Get period of counter bus channels. */
    uint16 PeriodCounterBus = Emios_Ip_ChPeriodMasterBus[Instance][Channel];

    return PeriodCounterBus;
}

#if (STD_ON == EMIOS_IP_MULTICORE_IS_AVAILABLE)
boolean Emios_Ip_ValidateMultiCoreInit(uint8 hwInstance)
{
    boolean Valid = FALSE;
    uint8 CoreId  = (uint8)OsIf_GetCoreID();

    if (Emios_Ip_axIpIsInitialized[hwInstance].runCore == CoreId)
    {
        Valid = TRUE;
    }

    return Valid;
}
#endif

#define MCL_STOP_SEC_CODE
#include "Mcl_MemMap.h"

#ifdef __cplusplus
}
#endif

/** @} */
