/*==================================================================================================
*   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           : 0.9.0
*   Build Version        : S32K3_RTD_0_9_0__ASR_REL_4_4_REV_0000_20210326
*
*   (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 0.9.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
==================================================================================================*/

/*==================================================================================================
*                                      FILE VERSION CHECKS
==================================================================================================*/

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

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

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

eMIOS_Type* emiosBase[eMIOS_INSTANCE_COUNT] = eMIOS_BASE_PTRS;

static Emios_Ip_ChStateType Emios_Ip_ChState[eMIOS_INSTANCE_COUNT][eMIOS_CH_UC_UC_COUNT] =
{
    {
        {
            EMIOS_IP_NO_MASTER_MODE,
            (boolean)FALSE
        }
    }
};

static Emios_Ip_InstStateType Emios_Ip_IpIsInitialized[eMIOS_INSTANCE_COUNT] =
{
    {
        (boolean)FALSE,
#if (EMIOS_IP_MULTICORE_IS_AVAILABLE == STD_ON)
        (uint8)255
#endif
    }
};

#define MCL_STOP_SEC_VAR_INIT_UNSPECIFIED_NO_CACHEABLE
#include "Mcl_MemMap.h"

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

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

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

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

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

/*==================================================================================================
                                       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 (EMIOS_MCL_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(instance < eMIOS_INSTANCE_COUNT);
    DevAssert(pConfig != NULL_PTR);
#endif

    uint8                     currentChannel;
    eMIOS_Type*               base   = emiosBase[instance];
    Emios_Ip_CommonStatusType status = EMIOS_IP_COMMON_STATUS_SUCCESS;

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

        if (Emios_Ip_IpIsInitialized[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].C |= eMIOS_C_UCPRE((*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);

                /* Enable the interrupt flag. */
                base->CH.UC[(*pConfig->masterBusConfig)[currentChannel].hwChannel].C |= eMIOS_C_FEN((uint32)(*pConfig->masterBusConfig)[currentChannel].interruptEnable);

                /* Save current state of channel. */
                Emios_Ip_ChState[instance][(*pConfig->masterBusConfig)[currentChannel].hwChannel].counterMode      = (*pConfig->masterBusConfig)[currentChannel].masterMode;
                Emios_Ip_ChState[instance][(*pConfig->masterBusConfig)[currentChannel].hwChannel].channelInitState = TRUE;
            }

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

        base->MCR |= eMIOS_MCR_GPREN_MASK;

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

    return status;
}

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

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

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

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

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

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

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

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

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

    uint8                     currentChannel;
    Emios_Ip_CommonStatusType status = EMIOS_IP_COMMON_STATUS_SUCCESS;
    eMIOS_Type*               base   = emiosBase[instance];

#if (EMIOS_IP_MULTICORE_IS_AVAILABLE == STD_ON)
    uint8 coreID = (uint8)OsIf_GetCoreID();
    if ( MULTICORE_INIT_CORE == coreID )
    {
#endif /* EMIOS_IP_MULTICORE_IS_AVAILABLE == STD_ON */
        if (Emios_Ip_IpIsInitialized[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_ChState[instance][currentChannel].channelInitState == TRUE)
                {
                    /* Disable channel pre-scaler (reset default) */
                    emiosBase[instance]->CH.UC[currentChannel].C = 0U;
                    /* Reset An and Bn registers */
                    emiosBase[instance]->CH.UC[currentChannel].A = 0UL;
                    emiosBase[instance]->CH.UC[currentChannel].B = 0UL;

                    emiosBase[instance]->UCDIS |= (uint32)((uint32)0 << ((uint32)currentChannel));
                    Emios_Ip_ChState[instance][currentChannel].channelInitState = FALSE;
                }
            }
            Emios_Ip_IpIsInitialized[instance].instanceInitState = FALSE;
        }
#if (EMIOS_IP_MULTICORE_IS_AVAILABLE == STD_ON)
    }
    else
    {
        status = EMIOS_IP_COMMON_STATUS_WRONG_CORE;
    }
#endif /* EMIOS_IP_MULTICORE_IS_AVAILABLE == STD_ON */

    return status;
}

/* Emios_Mcl_Ip_SetReloadInterval_Activity */
void Emios_Mcl_Ip_SetReloadInterval(uint8 hwInstance, uint8 hwChannel, uint8 interval)
{
#if (EMIOS_MCL_IP_DEV_ERROR_DETECT == STD_ON)
    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. */
    emiosBase[hwInstance]->CH.UC[hwChannel].C2 = eMIOS_C2_UCRELDEL_INT(interval);
}

boolean Emios_Mcl_Ip_ValidateChannel(uint8 hwInstance, uint8 hwChannel)
{
#if (EMIOS_MCL_IP_DEV_ERROR_DETECT == STD_ON)
    DevAssert(hwInstance < eMIOS_INSTANCE_COUNT);
    DevAssert(hwChannel < eMIOS_CH_UC_UC_COUNT);
#endif
    boolean valid = FALSE;

    if (TRUE == Emios_Ip_ChState[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 (EMIOS_MCL_IP_DEV_ERROR_DETECT == STD_ON)
    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_ChState[hwInstance][hwChannel].counterMode == EMIOS_IP_MCB_UP_COUNTER) || \
          (Emios_Ip_ChState[hwInstance][hwChannel].counterMode == EMIOS_IP_MCB_UP_DOWN_COUNTER) ) && \
          (period < 1U) )
    {
        status = EMIOS_IP_COMMON_STATUS_FAIL;
    }
    else
    {
        emiosBase[hwInstance]->CH.UC[hwChannel].A = period;
        status = EMIOS_IP_COMMON_STATUS_SUCCESS;
    }
    return status;
}

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

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

    return Valid;
}
#endif

#define MCL_STOP_SEC_CODE
#include "Mcl_MemMap.h"

#ifdef __cplusplus
}
#endif

/** @} */
