

#include "rba_DemObdBasic_Prv.h"

#include "Dem_Main.h"
#include "Dem_EnvMain.h"

#define RBA_DEMOBDBASIC_FF_MAXOBDFFTIMEID    (0xFFFFFFFFuL)

typedef struct
{
    uint8 dataElementIndex;
    uint8 identifier;
} rba_DemObdBasic_PidType;

#define DEM_START_SEC_ROM_CONST
#include "Dem_Cfg_MemMap.h"

static const uint8 rba_DemObdBasic_Pid2DataElement[] = RBA_DEMOBDBASIC_CFG_PID2DATAELEMENT;
static DEM_ARRAY_DEFINE_CONST(rba_DemObdBasic_PidType, rba_DemObdBasic_Pid, DEM_CFG_OBD_PID_ARRAY_LENGTH, RBA_DEMOBDBASIC_CFG_PID);

#define DEM_STOP_SEC_ROM_CONST
#include "Dem_Cfg_MemMap.h"

#define DEM_START_SEC_ROM_CODE
#include "Dem_Cfg_MemMap.h"

#define RBA_DEMOBDBASIC_FF_PRIO_OFFSET    255

static uint16 rba_DemObdBasic_FF_GetRawByteSize (void)
{
    return DEM_CFG_OBD_FREEZEFRAME_LENGTH;
}

static uint8* rba_DemObdBasic_FF_GetPIDDataPtr(Dem_EvMemEventMemoryType* EventMemory)
{
    return (Dem_EvMemGetEventMemDataByPtr(EventMemory)
            + Dem_EnvEDGetRawByteSize(Dem_Cfg_EnvEventId2EnvData[Dem_EvMemGetEventMemEventIdByPtr(EventMemory)].extDataId)
            + (Dem_EvtGetMaxNumberOfFreezeFrames(Dem_EvMemGetEventMemEventIdByPtr(EventMemory))
                    * Dem_EnvFFGetRawByteSize(Dem_Cfg_EnvEventId2EnvData[Dem_EvMemGetEventMemEventIdByPtr(EventMemory)].freezeFrameId)));
}

static uint16_least rba_DemObdBasic_FF_GetFFOrReaderCopyLocId(boolean SearchInReaderCopy)
{
    uint16_least LocId;
    uint16_least LocIdIt;
    uint16_least FFLocId = DEM_EVMEM_INVALID_LOCID;
    uint16_least MemId = DEM_CFG_EVMEM_MEMID_PRIMARY;
    uint16 Prio = 0;
    uint16 MaxPrio = 0xFFFF;
    uint32 TimeId = RBA_DEMOBDBASIC_FF_MAXOBDFFTIMEID;
    uint32 MinTimeId = RBA_DEMOBDBASIC_FF_MAXOBDFFTIMEID;

    for    (Dem_EvMemEventMemoryLocIteratorNew    (&LocIdIt, MemId);
            Dem_EvMemEventMemoryLocIteratorIsValid(&LocIdIt, MemId);
            Dem_EvMemEventMemoryLocIteratorNext   (&LocIdIt, MemId))
    {
        if (SearchInReaderCopy)
        {
            if (Dem_LibGetParamBool(DEM_CFG_EVMEM_READ_FROM_DIFFERENT_TASK))
            {
                DEM_ASSERT_ISLOCKED();
            }
            LocId = Dem_EvMemLocId2ReaderCopyLocId(LocIdIt);
        }
        else
        {
            LocId = LocIdIt;
        }

        if (       (Dem_EvMemIsStored(Dem_EvMemGetEventMemStatus(LocId)))
                && (rba_DemObdBasic_Dtc_IsEmissionRelated(Dem_DtcIdFromEventId(Dem_EvMemGetEventMemEventId(LocId))))
                && (((Dem_EvMemGetEventMemStatus(LocId) & DEM_EVMEM_STSMASK_CONFIRMED) == DEM_EVMEM_STSMASK_CONFIRMED)
#if (DEM_CFG_OBD_FREEZEFRAME_VISIBILITY == DEM_CFG_OBD_FREEZEFRAME_VISIBILITY_PENDING_AND_CONFIRMED)
                        || ((Dem_EvMemGetEventMemStatus(LocId) & DEM_EVMEM_STSMASK_PENDING) == DEM_EVMEM_STSMASK_PENDING)
#endif
                )
        )
        {
            Prio = ((uint16)(Dem_EvtGetEventPriority(Dem_EvMemGetEventMemEventId(LocId))) << 8);

#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)
              && ((Dem_EvMemGetEventMemStatus(LocId) & DEM_EVMEM_STSMASK_PENDING) == DEM_EVMEM_STSMASK_PENDING)
              )
            {
                Prio = (Prio | RBA_DEMOBDBASIC_FF_PRIO_OFFSET);
            }
#endif

            TimeId = rba_DemObdBasic_EvMem_GetFFTimeId(LocId);

            if (Prio < MaxPrio)
            {
                /* choose location with high prio freeze frame */
                MaxPrio = Prio;
                MinTimeId = TimeId;
                FFLocId = LocId;
            }
            else if (Prio == MaxPrio)
            {
                if (TimeId <= MinTimeId)
                {
                    /* same priority: chose older confirmed entry */
                    MaxPrio = Prio;
                    MinTimeId = TimeId;
                    FFLocId = LocId;
                }
            }
            else
            {
                /* ignore entry if prio is lower */
            }
        }
    }
    return FFLocId;
}

uint16_least rba_DemObdBasic_FF_GetFFLocation (void)
{
    return rba_DemObdBasic_FF_GetFFOrReaderCopyLocId(FALSE);
}

Std_ReturnType rba_DemObdBasic_FF_RetrievePidData (uint8 PID, uint8* DestBuffer, uint16* BufSize, Dem_EvMemEventMemoryType* EventMemory)
{
    Std_ReturnType retVal = E_NOT_OK;
    uint8* pidDataPtr;
    uint8 pidIt, pidDataIt;
    uint16 pidDataSize;

    pidDataSize = 0;

    /* find the starting address of OBD freeze frame*/
    pidDataPtr = rba_DemObdBasic_FF_GetPIDDataPtr(EventMemory);

    for (pidIt = 1; pidIt < DEM_CFG_OBD_PID_ARRAY_LENGTH; pidIt++)
    {
        /* Search for the requested PID in configuration list. Abstract the PID number from PID */
        if (rba_DemObdBasic_Pid[pidIt].identifier == PID)
        {
            for (pidDataIt = rba_DemObdBasic_Pid[pidIt - 1].dataElementIndex; pidDataIt < rba_DemObdBasic_Pid[pidIt].dataElementIndex; pidDataIt++)
            {
                pidDataSize += Dem_Cfg_EnvDataElement[rba_DemObdBasic_Pid2DataElement[pidDataIt]].Size;
            }

            if (*BufSize >= pidDataSize)
            {
                *BufSize = pidDataSize;
                DEM_MEMCPY(DestBuffer, pidDataPtr, pidDataSize);
                retVal = E_OK;
            }
            else
            {
                retVal = E_NOT_OK;
            }

            break;
        }
        else
        {
            for (pidDataIt = rba_DemObdBasic_Pid[pidIt - 1].dataElementIndex; pidDataIt < rba_DemObdBasic_Pid[pidIt].dataElementIndex; pidDataIt++)
            {
                pidDataPtr = pidDataPtr + Dem_Cfg_EnvDataElement[rba_DemObdBasic_Pid2DataElement[pidDataIt]].Size;
            }
        }
    }

    return retVal;
}



void rba_DemObdBasic_FF_SetNewTimeId (uint16_least LocId)
{
    uint16_least MemId = DEM_CFG_EVMEM_MEMID_PRIMARY; /* for now only primary memory supported */
    uint16_least LocIdIt;
    uint32 MaxTimeId = 0;

    for (   Dem_EvMemEventMemoryLocIteratorNew    (&LocIdIt, MemId);
            Dem_EvMemEventMemoryLocIteratorIsValid(&LocIdIt, MemId);
            Dem_EvMemEventMemoryLocIteratorNext   (&LocIdIt, MemId))
    {
        if (   (((Dem_EvMemGetEventMemStatus(LocIdIt) & DEM_EVMEM_STSMASK_CONFIRMED) == DEM_EVMEM_STSMASK_CONFIRMED)
#if (DEM_CFG_OBD_FREEZEFRAME_VISIBILITY == DEM_CFG_OBD_FREEZEFRAME_VISIBILITY_PENDING_AND_CONFIRMED)
               || ((Dem_EvMemGetEventMemStatus(LocIdIt) & DEM_EVMEM_STSMASK_PENDING) == DEM_EVMEM_STSMASK_PENDING)
#endif
               )
               && (rba_DemObdBasic_EvMem_GetFFTimeId(LocIdIt) > MaxTimeId)
        )
        {
            MaxTimeId = rba_DemObdBasic_EvMem_GetFFTimeId(LocIdIt);
        }
    }

    /* overflow */
    if (MaxTimeId >= RBA_DEMOBDBASIC_FF_MAXOBDFFTIMEID)
    {
        for (   Dem_EvMemEventMemoryLocIteratorNew    (&LocIdIt, MemId);
                Dem_EvMemEventMemoryLocIteratorIsValid(&LocIdIt, MemId);
                Dem_EvMemEventMemoryLocIteratorNext   (&LocIdIt, MemId))
        {
            if (((Dem_EvMemGetEventMemStatus(LocIdIt) & DEM_EVMEM_STSMASK_CONFIRMED) == DEM_EVMEM_STSMASK_CONFIRMED)
#if (DEM_CFG_OBD_FREEZEFRAME_VISIBILITY == DEM_CFG_OBD_FREEZEFRAME_VISIBILITY_PENDING_AND_CONFIRMED)
                        || ((Dem_EvMemGetEventMemStatus(LocIdIt) & DEM_EVMEM_STSMASK_PENDING) == DEM_EVMEM_STSMASK_PENDING)
#endif
            )
            {
                rba_DemObdBasic_EvMem_SetFFTimeId(LocIdIt, 0);
            }
        }
        MaxTimeId = 0;
    }

    rba_DemObdBasic_EvMem_SetFFTimeId(LocId, MaxTimeId + 1u);
}


static void rba_DemObdBasic_FF_CapturePids (uint8 pidId, uint8** start, const uint8* end, const Dem_InternalEnvData *internalEnvData)
{
    uint16_least i;

    for (i = rba_DemObdBasic_Pid[pidId - 1].dataElementIndex; i < rba_DemObdBasic_Pid[pidId].dataElementIndex; i++)
    {
        Dem_EnvDACapture(rba_DemObdBasic_Pid2DataElement[i], start, end, internalEnvData);
    }
}

void rba_DemObdBasic_FF_CaptureFF (Dem_EventIdType EventId, uint8* dest, uint16 destSize)
{
    uint8* writepos;
    uint8 i;
    uint16 size;
    uint8 edId = Dem_Cfg_EnvEventId2EnvData[EventId].extDataId;
    uint8 ffId = Dem_Cfg_EnvEventId2EnvData[EventId].freezeFrameId;
    Dem_InternalEnvData internalEnvData;
    internalEnvData.eventId = EventId;
    internalEnvData.evMemLocation = NULL_PTR;

    DEM_ASSERT(Dem_isEventIdValid(EventId), DEM_DET_APIID_OBDENVCAPTUREFF,0);
    DEM_ASSERT((Dem_EnvEDGetRawByteSize (edId) + Dem_EnvFFGetRawByteSize (ffId) + rba_DemObdBasic_FF_GetRawByteSize()) <= destSize, DEM_DET_APIID_OBDENVCAPTUREFF, 1);

    writepos = dest + Dem_EnvEDGetRawByteSize(edId) + Dem_EnvFFGetRawByteSize(ffId);
    size = rba_DemObdBasic_FF_GetRawByteSize();

    for (i = 1; i < DEM_CFG_OBD_PID_ARRAY_LENGTH; i++)
    {
        rba_DemObdBasic_FF_CapturePids(i, &writepos, writepos + size, &internalEnvData);
    }
}


static void rba_DemObdBasic_FF_CopyRaw (uint8* dest, uint16 bufsize, const uint8* src)
{
    const uint16 bytesize = rba_DemObdBasic_FF_GetRawByteSize();
    DEM_ASSERT(bytesize <= bufsize, DEM_DET_APIID_OBDENVFFCOPYRAW, 0);
    DEM_MEMCPY (dest, src, bytesize);
}

void rba_DemObdBasic_FF_CopyFF (Dem_EventIdType EventId, uint8* dest, uint16 destSize, const uint8* src)
{
    uint16 obdFFsize = rba_DemObdBasic_FF_GetRawByteSize();
    uint16 EDsize = Dem_EnvEDGetRawByteSize(Dem_Cfg_EnvEventId2EnvData[EventId].extDataId);
    uint16_least FFsize = Dem_EnvFFGetRawByteSize(Dem_Cfg_EnvEventId2EnvData[EventId].freezeFrameId);
    uint8* writepos = dest + EDsize + (Dem_EvtGetMaxNumberOfFreezeFrames(EventId) * FFsize);
    const uint8* obdFFpos = src + EDsize + FFsize;

    DEM_ASSERT(Dem_isEventIdValid(EventId), DEM_DET_APIID_ENVCOPYRAWFF,0);
    DEM_ASSERT((writepos + obdFFsize) <= (dest + destSize), DEM_DET_APIID_ENVCOPYRAWFF, 1);

    rba_DemObdBasic_FF_CopyRaw(writepos, obdFFsize, obdFFpos);
}

static Std_ReturnType rba_DemObdBasic_FF_GetReaderCopy(Dem_EvMemEventMemoryType* ReaderCopy)
{
    uint16_least LocId;
    Std_ReturnType retval;

    if (ReaderCopy == NULL_PTR)
    {
        return E_NOT_OK;
    }

    Dem_EvMemReaderCopiesEnterLock();
    { /* Critical section */
        /* Find location ID of the reader copy location */
        LocId = rba_DemObdBasic_FF_GetFFOrReaderCopyLocId(TRUE);
        if (Dem_EvMemIsReaderCopyLocIdValid(LocId))
        {
            /* Copy the contents of the reader copy location to the reader copy */
            *ReaderCopy = Dem_EvMemEventMemory[LocId];
            retval = E_OK;
        }
        else
        {
            retval = E_NOT_OK;
        }
    }
    Dem_EvMemReaderCopiesExitLock();

    return retval;
}

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

    Dem_EvMemReaderCopiesEnterLock();
    { /* Critical section */
        /* Find location ID of the reader copy location */
        LocId = rba_DemObdBasic_FF_GetFFOrReaderCopyLocId(TRUE);
        if (Dem_EvMemIsReaderCopyLocIdValid(LocId))
        {
            *EventId = Dem_EvMemGetEventMemEventId(LocId);
            retval = E_OK;
        }
        else
        {
            retval = E_NOT_OK;
        }
    }
    Dem_EvMemReaderCopiesExitLock();

    return retval;
}

/* MISRA RULE 16.7 VIOLATION: parameter not made const, as it is defined by AUTOSAR */
Std_ReturnType Dem_ReadDataOfOBDFreezeFrame (uint8 PID, uint8 DataElementIndexOfPID, uint8* DestBuffer, uint8* BufSize)
{
    Std_ReturnType retVal = E_NOT_OK;
    uint8* pidDataPtr;
    uint8 pidIt, pidDataIt, pidDataIndex, pidDataSize;

    Dem_EvMemEventMemoryType ReaderCopy;

    if (rba_DemObdBasic_FF_GetReaderCopy(&ReaderCopy) != E_OK)
    {
        /* no confirmed DTC found */
        *BufSize = 0;
        retVal = E_OK;
    }
    else
    {
        pidDataPtr = rba_DemObdBasic_FF_GetPIDDataPtr(&ReaderCopy);

        for (pidIt = 1; pidIt < DEM_CFG_OBD_PID_ARRAY_LENGTH; pidIt++)
        {
            if (rba_DemObdBasic_Pid[pidIt].identifier == PID)
            {
                pidDataIndex = rba_DemObdBasic_Pid[pidIt - 1].dataElementIndex;

                for (pidDataIt = rba_DemObdBasic_Pid[pidIt - 1].dataElementIndex; pidDataIt < rba_DemObdBasic_Pid[pidIt].dataElementIndex; pidDataIt++)
                {
                    pidDataSize = Dem_Cfg_EnvDataElement[rba_DemObdBasic_Pid2DataElement[pidDataIt]].Size;

                    if ((pidDataIt - pidDataIndex) == DataElementIndexOfPID)
                    {
                        if (*BufSize >= pidDataSize)
                        {
                            *BufSize = pidDataSize;
                            DEM_MEMCPY(DestBuffer, pidDataPtr, pidDataSize);
                            retVal = E_OK;
                        }
                        break;
                    }
                    else
                    {
                        pidDataPtr = pidDataPtr + pidDataSize;
                    }
                }
                break;
            }
            else
            {
                for (pidDataIt = rba_DemObdBasic_Pid[pidIt - 1].dataElementIndex; pidDataIt < rba_DemObdBasic_Pid[pidIt].dataElementIndex; pidDataIt++)
                {
                    pidDataPtr = pidDataPtr + Dem_Cfg_EnvDataElement[rba_DemObdBasic_Pid2DataElement[pidDataIt]].Size;
                }
            }
        }
    }
    return retVal;
}


/* MISRA RULE 16.7 VIOLATION: parameter not made const, as it is defined by AUTOSAR */
Dem_ReturnGetFreezeFrameDataByRecordType Dem_GetFreezeFrameDataByRecord( uint8 RecordNumber, Dem_DTCOriginType DTCOrigin, uint32* DTC, uint8* DestBuffer, uint16* BufSize )
{
    uint16 BufLength;
    uint8* pidDataPtr;
    uint8 pidIt, pidDataIt, pidDataSize;
    Dem_EvMemEventMemoryType ReaderCopy;

    if (!Dem_OpMoIsInitialized())
    {
        DEM_DET(DEM_DET_APIID_GETFREEZEFRAMEDATABYRECORD, DEM_E_UNINIT);
        return DEM_GET_FFBYRECORD_NO_DTC_FOR_RECORD;
    }

    if (RecordNumber != 0)
    {
        DEM_DET(DEM_DET_APIID_GETFREEZEFRAMEDATABYRECORD, DEM_E_WRONG_CONFIGURATION);
        return DEM_GET_FFBYRECORD_WRONG_RECORD;
    }

    if (DTCOrigin != DEM_DTC_ORIGIN_PRIMARY_MEMORY)
    {
        DEM_DET(DEM_DET_APIID_GETFREEZEFRAMEDATABYRECORD, DEM_E_WRONG_CONFIGURATION);
        return DEM_GET_FFBYRECORD_NO_DTC_FOR_RECORD;
    }

    if ((DTC==NULL_PTR) || (DestBuffer==NULL_PTR) || (BufSize==NULL_PTR))
    {
        return DEM_GET_FFBYRECORD_WRONG_BUFFERSIZE;
    }

    if (rba_DemObdBasic_FF_GetReaderCopy(&ReaderCopy) != E_OK)
    {
        return DEM_GET_FFBYRECORD_NO_DTC_FOR_RECORD;
    }

    pidDataPtr = rba_DemObdBasic_FF_GetPIDDataPtr(&ReaderCopy);

    /* Number of PIDs */
    if (*BufSize < 1)
    {
        return DEM_GET_FFBYRECORD_WRONG_BUFFERSIZE;
    }

    *DestBuffer = DEM_CFG_OBD_NUMBER_OF_PIDS_STORED;
    DestBuffer++;
    BufLength = 1;

    for (pidIt = 1; pidIt < DEM_CFG_OBD_PID_ARRAY_LENGTH; pidIt++)
    {   /* PID */
        if (*BufSize < (BufLength + 2))
        {
            return DEM_GET_FFBYRECORD_WRONG_BUFFERSIZE;
        }
        BufLength = BufLength + 2;
        /* High Byte of DID is mapped to 0xF4 for a PID */
        *DestBuffer = 0xF4 ;
        DestBuffer++;
        /* Low Byte of DID is the 1-Byte PID */
        *DestBuffer = rba_DemObdBasic_Pid[pidIt].identifier;
        DestBuffer++;

        /* PID Data */
        for (pidDataIt = rba_DemObdBasic_Pid[pidIt - 1].dataElementIndex; pidDataIt < rba_DemObdBasic_Pid[pidIt].dataElementIndex; pidDataIt++)
        {
            /* PID Data Element Data */
            pidDataSize = Dem_Cfg_EnvDataElement[rba_DemObdBasic_Pid2DataElement[pidDataIt]].Size;
            if (*BufSize < (BufLength + pidDataSize))
            {
                return DEM_GET_FFBYRECORD_WRONG_BUFFERSIZE;
            }
            DEM_MEMCPY(DestBuffer, pidDataPtr, pidDataSize);
            BufLength  = BufLength  + pidDataSize;
            DestBuffer = DestBuffer + pidDataSize;
            pidDataPtr = pidDataPtr + pidDataSize;
        }
    }

    /* Number of written bytes */
    *BufSize = BufLength;
    /* UDS DTC Code */
    *DTC = Dem_DtcGetCode(Dem_DtcIdFromEventId(Dem_EvMemGetEventMemEventIdByPtr(&ReaderCopy)));
    return DEM_GET_FFBYRECORD_OK;
}

/* MISRA RULE 16.7 VIOLATION: parameter not made const, as it is defined by AUTOSAR */
Std_ReturnType Dem_GetDTCOfOBDFreezeFrame (uint8 FrameNumber, uint32* DTC)
{
    Std_ReturnType retVal = E_NOT_OK;
    Dem_EventIdType EventId;

    *DTC = DEM_OBD_DTC_INVALID;

    if (FrameNumber == 0x00)
    {
        if (rba_DemObdBasic_FF_GetEventIdOfObdFF(&EventId) == E_OK)
        {
            *DTC = rba_DemObdBasic_Dtc_GetCode(Dem_DtcIdFromEventId(EventId));
            retVal = E_OK;
        }
    }
    else
    {
        /* other freeze frames not specified by ISO/SAE for now */
    }
    return retVal;
}

#define DEM_STOP_SEC_ROM_CODE
#include "Dem_Cfg_MemMap.h"


