//------------------------------------------------------------------------------
static tOplkError processCdc(tObdCdcInfo* pCdcInfo_p)
{
    tOplkError      ret = kErrorOk;
    UINT32          entriesRemaining;
    UINT            objectIndex;
    UINT            objectSubIndex;
    size_t          curDataSize;

    if ((ret = loadNextBuffer(pCdcInfo_p, sizeof(UINT32))) != kErrorOk)
        return ret;

    entriesRemaining = ami_getUint32Le(pCdcInfo_p->pCurBuffer);

    if (entriesRemaining == 0)
    {
        ret = eventu_postError(kEventSourceObdu, kErrorObdNoConfigData, 0, NULL);
        return ret;
    }

    for (; entriesRemaining != 0; entriesRemaining--)
    {
        if ((ret = loadNextBuffer(pCdcInfo_p, CDC_OFFSET_DATA))  != kErrorOk)
            return ret;

        objectIndex = ami_getUint16Le(&pCdcInfo_p->pCurBuffer[CDC_OFFSET_INDEX]);
        objectSubIndex = ami_getUint8Le(&pCdcInfo_p->pCurBuffer[CDC_OFFSET_SUBINDEX]);
        curDataSize = (size_t)ami_getUint32Le(&pCdcInfo_p->pCurBuffer[CDC_OFFSET_SIZE]);

        DEBUG_LVL_OBD_TRACE("%s: Reading object 0x%04X/%u with size %u from CDC\n",
                             __func__, objectIndex, objectSubIndex, curDataSize);
        if ((ret = loadNextBuffer(pCdcInfo_p, curDataSize)) != kErrorOk)
        {
            DEBUG_LVL_OBD_TRACE("%s: Reading the corresponding data from CDC failed with 0x%02X\n", __func__, ret);
            return ret;
        }

        ret = obd_writeEntryFromLe(objectIndex, objectSubIndex, pCdcInfo_p->pCurBuffer,
                                   (tObdSize)curDataSize);
        if (ret != kErrorOk)
        {
            tEventObdError          obdError;

            obdError.index = objectIndex;
            obdError.subIndex = objectSubIndex;

            DEBUG_LVL_OBD_TRACE("%s: Writing object 0x%04X/%u to local OBD failed with 0x%02X\n",
                                 __func__, objectIndex, objectSubIndex, ret);
            ret = eventu_postError(kEventSourceObdu, ret, sizeof(tEventObdError), &obdError);
            if (ret != kErrorOk)
                return ret;
        }
    }

    return ret;
}
//------------------------------------------------------------------------------
static tOplkError loadCdcFile(char* pCdcFilename_p)
{
    tOplkError      ret = kErrorOk;
    tObdCdcInfo     cdcInfo;
    UINT32          error;

    OPLK_MEMSET(&cdcInfo, 0, sizeof(tObdCdcInfo));
    cdcInfo.type = kObdCdcTypeFile;
    cdcInfo.handle.fdCdcFile = open(pCdcFilename_p, O_RDONLY | O_BINARY, 0666);
    if (!IS_FD_VALID(cdcInfo.handle.fdCdcFile))
    {   // error occurred
        error = (UINT32)errno;
        ret = eventu_postError(kEventSourceObdu, kErrorObdErrnoSet, sizeof(UINT32), &error);
        return ret;
    }

    cdcInfo.cdcSize = lseek(cdcInfo.handle.fdCdcFile, 0, SEEK_END);
    lseek(cdcInfo.handle.fdCdcFile, 0, SEEK_SET);

    ret = processCdc(&cdcInfo);

    if (cdcInfo.pCurBuffer != NULL)
    {
        OPLK_FREE(cdcInfo.pCurBuffer);
        cdcInfo.pCurBuffer = NULL;
        cdcInfo.bufferSize = 0;
    }

    close(cdcInfo.handle.fdCdcFile);

    return ret;
}
//------------------------------------------------------------------------------
static tOplkError loadCdcBuffer(UINT8* pCdc_p, size_t cdcSize_p)
{
    tOplkError      ret = kErrorOk;
    tObdCdcInfo     cdcInfo;

    OPLK_MEMSET(&cdcInfo, 0, sizeof(tObdCdcInfo));
    cdcInfo.type = kObdCdcTypeBuffer;
    cdcInfo.handle.pNextBuffer = pCdc_p;
    if (cdcInfo.handle.pNextBuffer == NULL)
    {   // error occurred
        ret = eventu_postError(kEventSourceObdu, kErrorObdInvalidDcf, 0, NULL);
        goto Exit;
    }

    cdcInfo.cdcSize = (size_t)cdcSize_p;
    cdcInfo.bufferSize = cdcInfo.cdcSize;

    ret = processCdc(&cdcInfo);

Exit:
    return ret;
}
//------------------------------------------------------------------------------
tOplkError eventu_process(const tEvent* pEvent_p)
{
    tOplkError      ret = kErrorOk;
    tEventSource    eventSource = kEventSourceInvalid;

    // Check parameter validity
    ASSERT(pEvent_p != NULL);

    if (!instance_l.fInitialized)
    {
        DEBUG_LVL_ERROR_TRACE("%s() Eventu module is not initialized\n", __func__);
        return kErrorNoResource;
    }

    switch (pEvent_p->eventSink)
    {
        case kEventSinkDlluCal:
            ret = dllucal_process(pEvent_p);
            eventSource = kEventSourceDllu;
            break;

        case kEventSinkNmtu:
            ret = nmtu_processEvent(pEvent_p);
            eventSource = kEventSourceNmtu;
            break;

#if defined(CONFIG_INCLUDE_NMT_MN)
        case kEventSinkNmtMnu:
            ret = nmtmnu_processEvent(pEvent_p);
            eventSource = kEventSourceNmtMnu;
            break;
#endif

#if (defined(CONFIG_INCLUDE_SDOC) || defined(CONFIG_INCLUDE_SDOS))
        case kEventSinkSdoAsySeq:
            ret = sdoseq_processEvent(pEvent_p);
            eventSource = kEventSourceSdoAsySeq;
            break;
#endif

        case kEventSinkErru:
            break;

        case kEventSinkApi:
            ret = callApiEventCb(pEvent_p);
            eventSource = kEventSourceOplkApi;
            break;

        case kEventSinkSdoTest:
            ret = sdotestcom_cbEvent(pEvent_p);
            eventSource = kEventSourceSdoTest;
            break;

        default:
            // Unknown sink, provide error event to API layer
            eventu_postError(kEventSourceEventu,
                             ret,
                             sizeof(pEvent_p->eventSink),
                             &pEvent_p->eventSink);
            ret = kErrorEventUnknownSink;
            break;
    }

    if ((ret != kErrorOk) && (ret != kErrorShutdown))
    {
        // forward error event to API layer
        eventu_postError(kEventSourceEventu,
                         ret,
                         sizeof(eventSource),
                         &eventSource);
    }

    return ret;
}
//------------------------------------------------------------------------------
static tOplkError loadNextBuffer(tObdCdcInfo* pCdcInfo_p, size_t bufferSize)
{
    tOplkError  ret = kErrorOk;
    int         readSize;
    UINT8*      pBuffer;

    switch (pCdcInfo_p->type)
    {
        case kObdCdcTypeFile:
            if (pCdcInfo_p->bufferSize < bufferSize)
            {
                if (pCdcInfo_p->pCurBuffer != NULL)
                {
                    OPLK_FREE(pCdcInfo_p->pCurBuffer);
                    pCdcInfo_p->pCurBuffer = NULL;
                    pCdcInfo_p->bufferSize = 0;
                }
                pCdcInfo_p->pCurBuffer = OPLK_MALLOC(bufferSize);
                if (pCdcInfo_p->pCurBuffer == NULL)
                {
                    ret = eventu_postError(kEventSourceObdu, kErrorObdOutOfMemory, 0, NULL);
                    if (ret != kErrorOk)
                        return ret;
                    return kErrorReject;
                }
                pCdcInfo_p->bufferSize = bufferSize;
            }
            pBuffer = pCdcInfo_p->pCurBuffer;

            do
            {
                readSize = read(pCdcInfo_p->handle.fdCdcFile, pBuffer, bufferSize);
                if (readSize <= 0)
                {
                    ret = eventu_postError(kEventSourceObdu, kErrorObdInvalidDcf, 0, NULL);
                    if (ret != kErrorOk)
                        return ret;
                    return kErrorReject;
                }
                pBuffer += readSize;
                bufferSize -= readSize;
                pCdcInfo_p->cdcSize -= readSize;
            }
            while (bufferSize > 0);
            break;

        case kObdCdcTypeBuffer:
            if (pCdcInfo_p->bufferSize < bufferSize)
            {
                ret = eventu_postError(kEventSourceObdu, kErrorObdInvalidDcf, 0, NULL);
                if (ret != kErrorOk)
                    return ret;
                return kErrorReject;
            }
            pCdcInfo_p->pCurBuffer = pCdcInfo_p->handle.pNextBuffer;
            pCdcInfo_p->handle.pNextBuffer += bufferSize;
            pCdcInfo_p->bufferSize -= bufferSize;
            break;
    }

    return ret;
}