

#include "rba_DemObdBasic_Prv.h"

#define DEM_START_SEC_ROM_CODE
#include "Dem_Cfg_MemMap.h"

/* Optimization to avoid copy of whole memory location only to retrieve EventId for location or ObdFF */
static Std_ReturnType rba_DemObdBasic_EvMem_GetEventIdOfReaderCopy(Dem_EventIdType* EventId, uint16_least LocId)
{
    Std_ReturnType retval;

    if (!Dem_EvMemIsEventMemLocIdValid(LocId))
    {
        return E_NOT_OK;
    }

    Dem_EvMemReaderCopiesEnterLock();
    { /* Critical section */
        LocId = Dem_EvMemLocId2ReaderCopyLocId(LocId);
        if (Dem_EvMemIsStored(Dem_EvMemGetEventMemStatus(LocId)))
        {
            *EventId = Dem_EvMemGetEventMemEventId(LocId);
            retval = E_OK;
        }
        else
        {
            retval = E_NOT_OK;
        }
    }
    Dem_EvMemReaderCopiesExitLock();

    return retval;
}

boolean rba_DemObdBasic_EvMem_GetNextFilteredDtcId(uint16_least* evMemLocIt, Dem_DtcIdType* dtcId)
{
    uint16_least currentEvMemLoc;
    Dem_EventIdType eventId;
    boolean dtcFound = FALSE;

    //For filtering OBD services loop through Event Memory locationand set the matching DTC fot this particular DTC
    while(Dem_EvMemEventMemoryLocIteratorIsValid(evMemLocIt, DEM_CFG_EVMEM_MEMID_PRIMARY))
    {
        currentEvMemLoc = *evMemLocIt;

        //Iterate to the next location
        Dem_EvMemEventMemoryLocIteratorNext(evMemLocIt, DEM_CFG_EVMEM_MEMID_PRIMARY);

        //check if the EvMem loc is not empty
        if (rba_DemObdBasic_EvMem_GetEventIdOfReaderCopy(&eventId, currentEvMemLoc) == E_OK)
        {
            //Get the Dtc id for this particular location
            *dtcId = Dem_DtcIdFromEventId(eventId);

            if(Dem_isDtcIdValid(*dtcId))
            {
                //Check if the filter matches
                if (Dem_DTCFilterMatches(*dtcId))
                {
                    dtcFound = TRUE;
                    break;
                }
            }
        }
    }
    return dtcFound;
}

/* --- Mil Counter --- */
void rba_DemObdBasic_EvMem_SetMilCounter(uint16_least LocId, uint8 counter)
{
    Dem_EvMemEventMemory[LocId].ObdMilCounter = counter;
    Dem_EvMemSetEventMemStatus(LocId, Dem_EvMemGetEventMemStatus(LocId) & (~DEM_EVMEM_STSMASK_READER_COPY_CURRENT));
    Dem_NvMWriteBlockOnShutdown(Dem_EvMemGetNvmIdFromLocId(LocId));
}

uint8 rba_DemObdBasic_EvMem_GetMilCounter(uint16_least LocId)
{
    return Dem_EvMemEventMemory[LocId].ObdMilCounter;
}

/* --- Freeze Frame / TimeId --- */
void rba_DemObdBasic_EvMem_SetFFTimeId(uint16_least LocId, uint32 ObdFFTimeId)
{
    Dem_EvMemEventMemory[LocId].ObdFFTimeId = ObdFFTimeId;
    Dem_EvMemSetEventMemStatus(LocId, Dem_EvMemGetEventMemStatus(LocId) & (~DEM_EVMEM_STSMASK_READER_COPY_CURRENT));
    Dem_NvMWriteBlockOnShutdown(Dem_EvMemGetNvmIdFromLocId(LocId));
}

uint32 rba_DemObdBasic_EvMem_GetFFTimeId(uint16_least LocId)
{
    return Dem_EvMemEventMemory[LocId].ObdFFTimeId;
}

void rba_DemObdBasic_EvMem_CopyFreezeFrame(Dem_EventIdType EventId, uint8* dest, uint16 destSize, const uint8* src)
{
    rba_DemObdBasic_FF_CopyFF(EventId, dest, destSize, src);
}

uint16_least rba_DemObdBasic_EvMem_GetLocationOfOBDFreezeFrame(void)
{
    return rba_DemObdBasic_FF_GetFFLocation();
}

boolean rba_DemObdBasic_EvMem_IsTriggerObdFreezeFrame(Dem_EventIdType EventId, uint16_least MemId,
        uint16_least StatusOld, uint16_least StatusNew)
{
    boolean trigger = FALSE;

    DEM_UNUSED_PARAM(MemId);

    if (rba_DemObdBasic_Dtc_IsEmissionRelated(Dem_DtcIdFromEventId(EventId)))
    {
        if ((StatusOld & DEM_EVMEM_STSMASK_CONFIRMED) != DEM_EVMEM_STSMASK_CONFIRMED)
        {
            trigger = Dem_EvMemIsEdgeTrigger(StatusOld, StatusNew, DEM_EVMEM_STSMASK_PENDING);
        }
#if (DEM_CFG_OBD_FREEZEFRAME_CAPTURE == DEM_CFG_OBD_FREEZEFRAME_CAPTURE_CONFIRMED)
        if (Dem_EvMemIsEdgeTrigger(StatusOld, StatusNew, DEM_EVMEM_STSMASK_CONFIRMED))
        {
            trigger = TRUE;
        }
#endif
    }
    return trigger;
}

/* --- Common mil debouncing --- */
void rba_DemObdBasic_EvMem_CommonMilDebModifyFailureCounter(uint16_least LocId, uint16_least MemId,
        Dem_EventIdType EventId, uint16_least *failureCounter)
{
#if (DEM_CFG_OBDCOMMONMILDEB == DEM_CFG_OBDCOMMONMILDEB_ON)

    uint16_least LocIdIt;
    uint16_least CounterOtherEvent;
    Dem_EventIdType MilRepEventId = rba_DemObdBasic_Event_GetMilRepEvent(EventId);

    if (MilRepEventId != DEM_EVENTID_INVALID)
    {
        for ( Dem_EvMemEventMemoryLocIteratorNew (&LocIdIt, MemId);
                Dem_EvMemEventMemoryLocIteratorIsValid(&LocIdIt, MemId);
                Dem_EvMemEventMemoryLocIteratorNext (&LocIdIt, MemId))
        {
            if (Dem_EvMemIsStored(Dem_EvMemGetEventMemStatus(LocIdIt)))
            {
                if ((LocId != LocIdIt) && (MilRepEventId == rba_DemObdBasic_Event_GetMilRepEvent(Dem_EvMemGetEventMemEventId(LocIdIt))))
                {
                    /* Get the fault failure counter of event of same group */
                    CounterOtherEvent = Dem_EvMemGetEventMemFailureCounter (LocIdIt);

                    /* Only pending is relevant for MIL counters*/
                    if ((CounterOtherEvent > *failureCounter)
                            && (CounterOtherEvent < Dem_EvtGetFailureConfirmationThreshold(Dem_EvMemGetEventMemEventId(LocIdIt))))

                    {
                        /* take over counter value */
                        if (Dem_EvMemIsTestFailedTFC(Dem_EvMemGetEventMemStatus(LocIdIt)))
                        {
                            /* counter already incremented in this DCY -> avoid new incrementation */
                            *failureCounter = CounterOtherEvent - 1;
                        }
                        else
                        {
                            *failureCounter = CounterOtherEvent;
                        }
                    }
                }
            }
        }
    }
#else
    DEM_UNUSED_PARAM(LocId);
    DEM_UNUSED_PARAM(MemId);
    DEM_UNUSED_PARAM(EventId);
    *failureCounter = *failureCounter; /* MISRA */
#endif
}

/* --- Aging / Displacement --- */
boolean rba_DemObdBasic_EvMem_IsAgingOfLocationAllowed(uint16_least LocId)
{
    /* allow aging if:
     * - DTC is not OBD relevant: always (MilCounter always = 0)
     * - DTC is OBD relevant:
     *    Mil healing completed (MilCounter = 0)
     *    AND
     *    DTC has not been detected again in current cycle (complete cycles without failure is necessary for OBD aging)
     */
    return ((rba_DemObdBasic_EvMem_GetMilCounter(LocId) == 0)
            && ((!rba_DemObdBasic_Dtc_IsEmissionRelated(Dem_DtcIdFromEventId(Dem_EvMemGetEventMemEventId(LocId))))
                    || (((Dem_EvMemGetEventMemStatus(LocId) & DEM_EVMEM_STSMASK_PENDING)) != DEM_EVMEM_STSMASK_PENDING)));
}

boolean rba_DemObdBasic_EvMem_IsDisplaceEventMemoryLocAllowed(Dem_EventIdType NewEventId, uint16_least LocId,
        uint16_least LocIdObdServ02)
{
    /* OBD displacement:
     * Emission related events that are
     * - Pending
     * - Illuminating the MIL
     * - Providing the Serv $02 freeze frame
     * and have the same or an higher priority than the new event
     * or are visible in Serv $0A (permanent) are not displaced */

    Dem_EventIdType EventId = Dem_EvMemGetEventMemEventId(LocId);
    boolean retVal = TRUE;

    if (rba_DemObdBasic_Event_IsEmissionRelated(EventId))
    {
        if (rba_DemObdBasic_PdtcMem_IsEvtPdtc(EventId))
        {
            retVal = FALSE;
        }
        else if (Dem_EvtGetEventPriority(EventId) <= Dem_EvtGetEventPriority(NewEventId))
        {
            /* old event has same or higher prio than new event: consider OBD criteria */

            if(LocId == LocIdObdServ02)
            {
                retVal = FALSE;
            }
            else if(rba_DemObdBasic_Mil_IsEvMemLocRequestingMil(LocId, DEM_CFG_EVMEM_MEMID_PRIMARY))
            {
                retVal = FALSE;
            }
            else if((Dem_EvMemGetEventMemStatus(LocId) & DEM_EVMEM_STSMASK_PENDING) == DEM_EVMEM_STSMASK_PENDING)
            {
                retVal = FALSE;
            }
            else
            {
                /* MISRA */
            }
        }
        else
        {
            /* MISRA */
        }
    }

    return retVal;
}

void rba_DemObdBasic_EvMem_HandleImmediateAgeing(Dem_EventIdType EventId)
{
    /* Clear Permanent memory for the Event*/
    rba_DemObdBasic_PdtcMem_DeleteEvent(EventId);
    /* Clear WIR-bit of event */
    rba_DemObdBasic_Event_SetWarningIndicator(EventId, FALSE);
}

/* --- Status Nofications --- */
void rba_DemObdBasic_EvMem_StatusNotificationPending(uint16_least LocId, Dem_EventIdType EventId)
{
    if (rba_DemObdBasic_Dtc_IsEmissionRelated(Dem_DtcIdFromEventId(EventId)))
    {
#if (DEM_CFG_OBD_FREEZEFRAME_VISIBILITY == DEM_CFG_OBD_FREEZEFRAME_VISIBILITY_PENDING_AND_CONFIRMED)
        if ((Dem_EvMemGetEventMemStatus(LocId) & DEM_EVMEM_STSMASK_CONFIRMED) != DEM_EVMEM_STSMASK_CONFIRMED)
        {
            rba_DemObdBasic_FF_SetNewTimeId(LocId);
        }
#else
        DEM_UNUSED_PARAM(LocId);
#endif
    }
}

void rba_DemObdBasic_EvMem_StatusNotificationPendingConfirmed(uint16_least LocId, Dem_EventIdType EventId)
{
    if (rba_DemObdBasic_Dtc_IsEmissionRelated(Dem_DtcIdFromEventId(EventId)))
    {
        rba_DemObdBasic_EvMem_SetMilCounter(LocId, DEM_OBD_MIL_HEALING_CYCLES);
        rba_DemObdBasic_Mil_Request(TRUE);
        rba_DemObdBasic_Event_SetWarningIndicator(EventId, TRUE);
        rba_DemObdBasic_PdtcMem_StoreNewEventId(EventId);
    }
    else
    {
        rba_DemObdBasic_EvMem_SetMilCounter(LocId, 0);
    }
}

void rba_DemObdBasic_EvMem_StatusNotificationConfirmed(uint16_least LocId, Dem_EventIdType EventId)
{
    if (rba_DemObdBasic_Dtc_IsEmissionRelated(Dem_DtcIdFromEventId(EventId)))
    {
        rba_DemObdBasic_FF_SetNewTimeId(LocId);
    }
}

#define DEM_STOP_SEC_ROM_CODE
#include "Dem_Cfg_MemMap.h"

