/** ---------------------------------------------------------------------------
 * \file        EcDemoApp.cpp
 * \brief       EC-Monitor demo application
 * \author      Holger Oelhaf
 * \copyright   acontis technologies GmbH, Weingarten, Germany
 *---------------------------------------------------------------------------*/

/*-INCLUDES------------------------------------------------------------------*/
#include "EcDemoApp.h"

#if (defined INCLUDE_DAQ_SUPPORT)
#ifdef _WIN32
#pragma comment(lib, "EcDaq.lib")
#endif
#endif

/*-DEFINES-------------------------------------------------------------------*/
#define PERF_myAppWorkpd       0
#define MAX_JOB_NUM            1

/*-LOCAL VARIABLES-----------------------------------------------------------*/
static EC_T_PERF_MEAS_INFO_PARMS S_aPerfMeasInfos[MAX_JOB_NUM] =
{
    {"myAppWorkPd                    ", 0}
};

/*-FUNCTION DECLARATIONS-----------------------------------------------------*/
static EC_T_VOID  EcMonitorJobTask(EC_T_VOID* pvAppContext);
static EC_T_VOID  EcMonitorTimerWatchdog(EC_T_VOID* pvAppContext);
static EC_T_VOID  CycFrameReceivedCallback(EC_T_DWORD dwTaskId, EC_T_VOID* pvAppContext);
#if (defined INCLUDE_RAS_SERVER)
static EC_T_DWORD RasNotifyCallback(EC_T_DWORD dwCode, EC_T_NOTIFYPARMS* pParms);
#endif

typedef struct _T_EC_MONITOR_DEMO_PARMS
{
    EC_T_VOID*  pvMonitorTimerWatchdogEvent;
    EC_T_VOID*  pvMonitorTimerLock;
    EC_T_BOOL   bTaskRunning;
    EC_T_BOOL   bTaskShutdown;
} T_EC_MONITOR_DEMO_PARMS;

/*-MYAPP---------------------------------------------------------------------*/
typedef struct _T_MY_APP_DESC
{
#if (defined INCLUDE_DAQ_SUPPORT)
    EC_T_DAQ_REC    hDaq;
#endif
    EC_T_BOOL       bDaqRecStarted;
} T_MY_APP_DESC;
static EC_T_DWORD myAppInit(T_EC_DEMO_APP_CONTEXT* pAppContext);
static EC_T_DWORD myAppDeinit(T_EC_DEMO_APP_CONTEXT* pAppContext);
static EC_T_DWORD myAppPrepare(T_EC_DEMO_APP_CONTEXT* pAppContext);
static EC_T_DWORD myAppSetup(T_EC_DEMO_APP_CONTEXT* pAppContext);
static EC_T_DWORD myAppWorkpd(T_EC_DEMO_APP_CONTEXT* pAppContext);
static EC_T_DWORD myAppDiagnosis(T_EC_DEMO_APP_CONTEXT* pAppContext);

/*-FUNCTION DEFINITIONS------------------------------------------------------*/

/********************************************************************************/
/** \brief EC-Monitor demo application.
*
* \return  Status value.
*/
EC_T_DWORD EcDemoApp(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
    EC_T_DWORD dwRetVal = EC_E_NOERROR;
    EC_T_DWORD dwRes    = EC_E_NOERROR;

    T_EC_DEMO_APP_PARMS* pAppParms = &pAppContext->AppParms;
    T_EC_MONITOR_DEMO_PARMS MonitorDemoParms;

    EC_T_VOID*  pvTaskHandle = EC_NULL;

    CEcTimer    oAppDuration;

#if (defined INCLUDE_RAS_SERVER)
    EC_T_VOID* pvRasServerHandle = EC_NULL;
#endif

    EC_T_REGISTERRESULTS   RegisterClientResults;
    OsMemset(&RegisterClientResults, 0, sizeof(EC_T_REGISTERRESULTS));

    OsMemset(&MonitorDemoParms, 0, sizeof(T_EC_MONITOR_DEMO_PARMS));
    pAppContext->pMonitorParms = &MonitorDemoParms;

    /* check link layer parameter if necessary */
    if ((EC_NULL == pAppParms->apLinkParms[0]) && !pAppParms->bPcapProcessing)
    {
        dwRetVal = EC_E_INVALIDPARM;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Error: Missing link layer parameter\n"));
        goto Exit;
    }
    pAppContext->pNotificationHandler = EC_NEW(CEmNotification(pAppContext));
    if (EC_NULL == pAppContext->pNotificationHandler)
    {
        dwRetVal = EC_E_NOMEMORY;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot create notification handler\n"));
        goto Exit;
    }

    pAppContext->pMyAppDesc = (T_MY_APP_DESC*)OsMalloc(sizeof(T_MY_APP_DESC));
    if (EC_NULL == pAppContext->pMyAppDesc)
    {
        dwRetVal = EC_E_NOMEMORY;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot create myApp descriptor\n"));
        goto Exit;
    }
    dwRes = myAppInit(pAppContext);
    if (EC_E_NOERROR != dwRes)
    {
        dwRetVal = dwRes;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: myAppInit failed: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        goto Exit;
    }

    /* initialize EC-Monitor */
    {
        EC_T_MONITOR_INIT_PARMS oInitParms;

        OsMemset(&oInitParms, 0, sizeof(EC_T_MONITOR_INIT_PARMS));
        OsMemcpy(&oInitParms.LogParms, &pAppContext->LogParms, sizeof(EC_T_LOG_PARMS));
        oInitParms.LogParms.dwLogLevel = pAppParms->dwMasterLogLevel;
        oInitParms.dwSignature         = MONITOR_SIGNATURE;
        oInitParms.dwSize              = sizeof(EC_T_MONITOR_INIT_PARMS);
        if (!pAppParms->bPcapProcessing)
        {
            oInitParms.pLinkParms = pAppParms->apLinkParms[0];
        }
        oInitParms.eEthTapType         = eEthTap_AutoDetect;
        oInitParms.dwBusCycleTimeNsec  = pAppParms->dwBusCycleTimeNsec;
        oInitParms.WorkerThreadParms.dwPrio = MAIN_THREAD_PRIO;
        oInitParms.WorkerThreadParms.cpuAffinityMask = pAppParms->CpuSet;
        if (pAppParms->dwPerfMeasLevel > 0)
        {
            oInitParms.PerfMeasInternalParms.bEnabled = EC_TRUE;

            if (pAppParms->dwPerfMeasLevel > 1)
            {
                oInitParms.PerfMeasInternalParms.HistogramParms.dwBinCount = 202;
            }
        }
        else
        {
            oInitParms.PerfMeasInternalParms.bEnabled = EC_FALSE;
        }

        dwRes = emonInitMonitor(pAppContext->dwInstanceId, &oInitParms);
        if (dwRes != EC_E_NOERROR)
        {
            dwRetVal = dwRes;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot initialize EC-Monitor: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            goto Exit;
        }
        if (0 != OsStrlen(pAppParms->szLicenseKey))
        {
            dwRes = emonSetLicenseKey(pAppContext->dwInstanceId, pAppParms->szLicenseKey);
            if (dwRes != EC_E_NOERROR)
            {
                dwRetVal = dwRes;
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot set license key: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
                goto Exit;
            }
        }
    }

    /* initialize performance measurement */
    if (pAppParms->dwPerfMeasLevel > 0)
    {
        EC_T_PERF_MEAS_APP_PARMS oPerfMeasAppParms;
        OsMemset(&oPerfMeasAppParms, 0, sizeof(EC_T_PERF_MEAS_APP_PARMS));
        oPerfMeasAppParms.dwNumMeas = MAX_JOB_NUM;
        oPerfMeasAppParms.aPerfMeasInfos = S_aPerfMeasInfos;
        if (pAppParms->dwPerfMeasLevel > 1)
        {
            oPerfMeasAppParms.HistogramParms.dwBinCount = 202;
        }

        dwRes = emonPerfMeasAppCreate(pAppContext->dwInstanceId, &oPerfMeasAppParms, &pAppContext->pvPerfMeas);
        if (dwRes != EC_E_NOERROR)
        {
            dwRetVal = dwRes;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot initialize APP performance measurement: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            goto Exit;
        }
        pAppContext->dwPerfMeasLevel = pAppParms->dwPerfMeasLevel;
    }

    if (pAppParms->bUseFingerprint)
    {
        EC_T_CHAR szLicenseFingerprint[EC_LICENSE_FINGERPRINT_STRSIZE];

        dwRes = emonGetLicenseFingerprint(pAppContext->dwInstanceId, pAppParms->byFingerprintMethod, szLicenseFingerprint);
        if (dwRes != EC_E_NOERROR)
        {
            dwRetVal = dwRes;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot get fingerprint: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            goto Exit;
        }
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Fingerprint: %s\n", szLicenseFingerprint));
    }
    else
    /* print MAC address */
    {
        ETHERNET_ADDRESS oSrcMacAddress;
        OsMemset(&oSrcMacAddress, 0, sizeof(ETHERNET_ADDRESS));

        dwRes = emonGetSrcMacAddress(pAppContext->dwInstanceId , &oSrcMacAddress);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot get MAC address: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        }
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "EtherCAT network adapter MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",
            oSrcMacAddress.b[0], oSrcMacAddress.b[1], oSrcMacAddress.b[2], oSrcMacAddress.b[3], oSrcMacAddress.b[4], oSrcMacAddress.b[5]));
    }

    /* configure network */
    dwRes = emonConfigureNetwork(pAppContext->dwInstanceId, pAppParms->eCnfType, pAppParms->pbyCnfData, pAppParms->dwCnfDataLen);
    if (dwRes != EC_E_NOERROR)
    {
        dwRetVal = dwRes;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot configure EtherCAT network: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        goto Exit;
    }

    if (pAppParms->bPcapRecorder)
    {
        const EC_T_CHAR* szFileExt = "00000.pcapng";
        EC_T_PACKETCAPTURE_PARMS oPcapParms;
        OsMemset(&oPcapParms, 0, sizeof(EC_T_PACKETCAPTURE_PARMS));
        
        if ((0 != OsStrlen(pAppParms->szPcapRecorderFileprefix)) && (EC_PACKETCAPTURE_FILE_NAME_SIZE > (OsStrlen(pAppParms->szPcapRecorderFileprefix) + OsStrlen(szFileExt))))
        {
            OsSnprintf(oPcapParms.szFileName, EC_PACKETCAPTURE_FILE_NAME_SIZE, "%s.%s", pAppParms->szPcapRecorderFileprefix, szFileExt);
        }
        else
        {
            OsSnprintf(oPcapParms.szFileName, EC_PACKETCAPTURE_FILE_NAME_SIZE, "ecmonitor%d.%s", pAppContext->dwInstanceId, szFileExt);
        }
        oPcapParms.dwMaxFileSize = 100 * 1024 * 1024; /* Create new file after size exceeds 100 MB */

        dwRes = emonStartLivePacketCapture(pAppContext->dwInstanceId, &oPcapParms);
        if (dwRes != EC_E_NOERROR)
        {
            dwRetVal = dwRes;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot start live packet capture: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            goto Exit;
        }
    }

    /* create cyclic task to trigger jobs */
    {
        CEcTimer oTimeout;

        if (pAppParms->bPcapProcessing || (pAppParms->apLinkParms[0]->eLinkMode == EcLinkMode_POLLING))
        {
            pvTaskHandle = OsCreateThread((EC_T_CHAR*)"EcMonitorJobTask", EcMonitorJobTask, pAppParms->CpuSet,
                pAppParms->dwJobsThreadPrio, pAppParms->dwJobsThreadStackSize, (EC_T_VOID*)pAppContext);
        }
        else if (pAppParms->apLinkParms[0]->eLinkMode == EcLinkMode_INTERRUPT) 
        {
            EC_T_CYCFRAME_RX_CBDESC CycFrameRxCallbackDesc;

            /* setup monitor watchdog */
            MonitorDemoParms.pvMonitorTimerWatchdogEvent = OsCreateEvent();
            if (EC_NULL == MonitorDemoParms.pvMonitorTimerWatchdogEvent)
            {
                dwRetVal = EC_E_NOMEMORY;
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Insufficient memory to create monitor watchdog event %s (0x%lx)", emonGetText(pAppContext->dwInstanceId, dwRetVal), dwRetVal));
                goto Exit;
            }

            /* create lock to avoid reentrant access to eUsrJob_MonitorTimer */
            MonitorDemoParms.pvMonitorTimerLock = OsCreateLock();
            if (EC_NULL == MonitorDemoParms.pvMonitorTimerLock)
            {
                dwRetVal = EC_E_LOCK_CREATE_FAILED;
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Failed to create monitor timer lock %s (0x%lx)", emonGetText(pAppContext->dwInstanceId, dwRetVal), dwRetVal));
                goto Exit;
            }

            /* setup callback function which is called after RX */
            OsMemset(&CycFrameRxCallbackDesc, 0, sizeof(EC_T_CYCFRAME_RX_CBDESC));
            CycFrameRxCallbackDesc.pfnCallback = CycFrameReceivedCallback;
            CycFrameRxCallbackDesc.pCallbackContext = pAppContext;

            dwRes = emonIoCtl(pAppContext->dwInstanceId, EC_IOCTL_REGISTER_CYCFRAME_RX_CB, &CycFrameRxCallbackDesc, sizeof(EC_T_CYCFRAME_RX_CBDESC), EC_NULL, 0, EC_NULL);
            if (EC_E_NOERROR != dwRes)
            {
                dwRetVal = dwRes;
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot setup callback for Cyclic frame received %s (0x%lx)", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
                goto Exit;
            }

            pvTaskHandle = OsCreateThread((EC_T_CHAR*)"EcMonitorTimerWatchdog", EcMonitorTimerWatchdog, pAppParms->CpuSet,
                JOBS_THREAD_PRIO, JOBS_THREAD_STACKSIZE, (EC_T_VOID*)pAppContext);
        }
        else
        {
            dwRetVal = EC_E_INVALIDPARM;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot create cyclic task"));
            goto Exit;
        }

        /* wait until thread is running */
        for (oTimeout.Start(2000); !oTimeout.IsElapsed(); OsSleep(10))
        {
            if (MonitorDemoParms.bTaskRunning)
                break;
        }
        if (!MonitorDemoParms.bTaskRunning)
        {
            dwRetVal = EC_E_TIMEOUT;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Timeout starting Task\n"));
            goto Exit;
        }
    }

#ifdef INCLUDE_RAS_SERVER
    /* start RAS server if enabled */
    if (pAppParms->bStartRasServer)
    {
        EC_T_RAS_SERVER_PARMS oRemoteApiConfig;

        OsMemset(&oRemoteApiConfig, 0, sizeof(EC_T_RAS_SERVER_PARMS));
        oRemoteApiConfig.dwSignature        = EC_RAS_SERVER_SIGNATURE;
        oRemoteApiConfig.dwSize             = sizeof(EC_T_RAS_SERVER_PARMS);
        oRemoteApiConfig.oAddr.dwAddr       = 0;                            /* INADDR_ANY */
        oRemoteApiConfig.wPort              = pAppParms->wRasServerPort;
        oRemoteApiConfig.dwCycleTime        = EC_RAS_CYCLE_TIME;
        oRemoteApiConfig.dwCommunicationTimeout = EC_RAS_MAX_WATCHDOG_TIMEOUT;
        oRemoteApiConfig.oAcceptorThreadCpuAffinityMask = pAppParms->CpuSet;
        oRemoteApiConfig.dwAcceptorThreadPrio           = MAIN_THREAD_PRIO;
        oRemoteApiConfig.dwAcceptorThreadStackSize      = JOBS_THREAD_STACKSIZE;
        oRemoteApiConfig.oClientWorkerThreadCpuAffinityMask = pAppParms->CpuSet;
        oRemoteApiConfig.dwClientWorkerThreadPrio           = MAIN_THREAD_PRIO;
        oRemoteApiConfig.dwClientWorkerThreadStackSize      = JOBS_THREAD_STACKSIZE;
        oRemoteApiConfig.pfnRasNotify    = RasNotifyCallback;                       /* RAS notification callback function */
        oRemoteApiConfig.pvRasNotifyCtxt = pAppContext->pNotificationHandler;       /* RAS notification callback function context */
        oRemoteApiConfig.dwMaxQueuedNotificationCnt = 100;                          /* pre-allocation */
        oRemoteApiConfig.dwMaxParallelMbxTferCnt    = 50;                           /* pre-allocation */
        oRemoteApiConfig.dwCycErrInterval           = 500;                          /* span between to consecutive cyclic notifications of same type */

        if (pAppParms->nVerbose >= 1)
        {
            OsMemcpy(&oRemoteApiConfig.LogParms, &pAppContext->LogParms, sizeof(EC_T_LOG_PARMS));
            oRemoteApiConfig.LogParms.dwLogLevel = EC_LOG_LEVEL_ERROR;
        }
        dwRes = emonRasSrvStart(&oRemoteApiConfig, &pvRasServerHandle);
        if (EC_E_NOERROR != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emonRasSrvStart(): %s (0x%08X))\n", emonGetText(0, dwRes), dwRes));
        }
    }
#endif
    /* register client */
    dwRes = emonRegisterClient(pAppContext->dwInstanceId, CEmNotification::NotifyWrapper, pAppContext->pNotificationHandler, &RegisterClientResults);
    if (dwRes != EC_E_NOERROR)
    {
        dwRetVal = dwRes;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Cannot register client: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        goto Exit;
    }
    pAppContext->pNotificationHandler->SetClientID(RegisterClientResults.dwClntId);

    dwRes = myAppPrepare(pAppContext);
    if (EC_E_NOERROR != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: myAppPrepare failed: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        dwRetVal = dwRes;
        goto Exit;
    }

    dwRes = myAppSetup(pAppContext);
    if (EC_E_NOERROR != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: myAppSetup failed: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        dwRetVal = dwRes;
        goto Exit;
    }

    /* open packet capture */
    if (pAppParms->bPcapProcessing)
    {
        EC_T_PACKETCAPTURE_PARMS PcapParms;
        OsMemset(&PcapParms, 0, sizeof(EC_T_PACKETCAPTURE_PARMS));

        OsSafeStrcpy2(PcapParms.szFileName, pAppParms->szPcapFilename);

        dwRes = emonOpenPacketCapture(pAppContext->dwInstanceId, &PcapParms);
        if (dwRes != EC_E_NOERROR)
        {
            dwRetVal = dwRes;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot open packet capture file: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            goto Exit;
        }
    }

    /* run the demo */
    if (pAppParms->dwDemoDuration != 0)
    {
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "%s will stop in %ds...\n", EC_DEMO_APP_NAME, pAppParms->dwDemoDuration / 1000));
        oAppDuration.Start(pAppParms->dwDemoDuration);
    }
    bRun = EC_TRUE;
    {
        CEcTimer oPerfMeasPrintTimer;

        if (pAppParms->bPerfMeasShowCyclic)
        {
            oPerfMeasPrintTimer.Start(2000);
        }

        while (bRun)
        {
            if (oPerfMeasPrintTimer.IsElapsed())
            {
                PRINT_PERF_MEAS();
                oPerfMeasPrintTimer.Restart();
            }


            /* check if demo shall terminate */
            bRun = !(OsTerminateAppRequest() || oAppDuration.IsElapsed());
            if (pAppParms->bPcapProcessing)
            {
                EC_T_PACKETCAPTURE_INFO PcapInfo;
                dwRes = emonGetPacketCaptureInfo(pAppContext->dwInstanceId, &PcapInfo);
                if (EC_E_NOERROR == dwRes)
                {
                    if (ePcapStatus_Finished == PcapInfo.eStatus)
                    {
                        bRun = EC_FALSE;
                    }
                }
            }

            myAppDiagnosis(pAppContext);

            /* process notification jobs */
            pAppContext->pNotificationHandler->ProcessNotificationJobs();

            OsSleep(5);
        }
    }
    emonStopLivePacketCapture(pAppContext->dwInstanceId);

    if (pAppContext->dwPerfMeasLevel > 0)
    {
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "\nJob times before shutdown\n"));
        PRINT_PERF_MEAS();
    }
    if (pAppParms->dwPerfMeasLevel > 1)
    {
        PRINT_HISTOGRAM();
    }

Exit:
#if (defined INCLUDE_RAS_SERVER)
    /* stop RAS server */
    if (EC_NULL != pvRasServerHandle)
    {
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Stop Remote API Server\n"));
        dwRes = emonRasSrvStop(pvRasServerHandle, 2000);
        if (EC_E_NOERROR != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Remote API Server shutdown failed\n"));
        }
    }
#endif

    dwRes = myAppDeinit(pAppContext);
    if (EC_E_NOERROR != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "myAppDeinit failed: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
    }

    /* unregister client */
    if (EC_NULL != pAppContext->pNotificationHandler)
    {
        EC_T_DWORD dwClientId = pAppContext->pNotificationHandler->GetClientID();
        if (INVALID_CLIENT_ID != dwClientId)
        {
            dwRes = emonUnregisterClient(pAppContext->dwInstanceId, dwClientId);
            if (EC_E_NOERROR != dwRes)
            {
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot unregister client: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
            }
            pAppContext->pNotificationHandler->SetClientID(INVALID_CLIENT_ID);
        }
    }

    /* shutdown Task */
    {
        CEcTimer oTimeout;
        MonitorDemoParms.bTaskShutdown = EC_TRUE;
        for(oTimeout.Start(2000); !oTimeout.IsElapsed(); OsSleep(10))
        {
            if (!MonitorDemoParms.bTaskRunning)
                break;
        }
        if (EC_NULL != pvTaskHandle)
        {
            OsDeleteThreadHandle(pvTaskHandle);
        }
    }

    if (0 != OsStrlen(pAppContext->AppParms.szEBIFilename))
    {
        dwRes = emonExportEniBuilderConfig(pAppContext->dwInstanceId, pAppContext->AppParms.szEBIFilename);
        if (EC_E_NOERROR != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emonExportEniBuilderConfig: %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        }
    }

    dwRes = emonDeinitMonitor(pAppContext->dwInstanceId);
    if (EC_E_NOERROR != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot de-initialize EC-Monitor: %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
    }

    SafeDelete(pAppContext->pNotificationHandler);
    OsSafeFree(pAppContext->pMyAppDesc);

    return dwRetVal;
}

/********************************************************************************/
/** \brief  Trigger jobs to update process data.
*
* \return N/A
*/
static EC_T_VOID EcMonitorJobTask(EC_T_VOID* pvAppContext)
{
    EC_T_DWORD dwRes = EC_E_ERROR;
    EC_T_BOOL bWaitForEvent = EC_TRUE;
    T_EC_DEMO_APP_CONTEXT* pAppContext = (T_EC_DEMO_APP_CONTEXT*)pvAppContext;
    T_EC_MONITOR_DEMO_PARMS* pMonitorDemoParms = pAppContext->pMonitorParms;

    EC_T_USER_JOB_PARMS oJobParms;
    OsMemset(&oJobParms, 0, sizeof(EC_T_USER_JOB_PARMS));

    /* demo loop */
    pMonitorDemoParms->bTaskRunning = EC_TRUE;
    do
    {
        if (bWaitForEvent)
        {
            /* wait for next cycle (event from scheduler task) */
            dwRes = OsWaitForEvent(pAppContext->pvJobTaskEvent, 3000);
            if (EC_E_NOERROR != dwRes)
            {
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: OsWaitForEvent(): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
                OsSleep(500);
            }
        }

        /* start Task (required for enhanced performance measurement) */
        dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_StartTask, EC_NULL);
        if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes && EC_E_LINK_DISCONNECTED != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: emExecJob(eUsrJob_StartTask): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        }

        /* process all received frames (read new input values) */
        dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_ProcessAllRxFrames, &oJobParms);
        if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes && EC_E_LINK_DISCONNECTED != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: emExecJob(eUsrJob_ProcessAllRxFrames): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        }
        /* remove this code when using licensed version */
        if (EC_E_EVAL_EXPIRED == dwRes)
        {
            bRun = EC_FALSE;
        }

        emonPerfMeasAppStart(pAppContext->dwInstanceId, pAppContext->pvPerfMeas, PERF_myAppWorkpd);
        {
            myAppWorkpd(pAppContext);
        }
        emonPerfMeasAppEnd(pAppContext->dwInstanceId, pAppContext->pvPerfMeas, PERF_myAppWorkpd);

        /* execute some administrative jobs */
        dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_MonitorTimer, EC_NULL);
        if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emExecJob(eUsrJob_MonitorTimer): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        }

        /* to protect against data loss during startup or bad timing don't wait for next cycle event if the next EtherCAT cycle has already been received */
        /* this can happen because eUsrJob_ProcessAllRxFrames returns after one cycle has been detected */
        {
            EC_T_MONITOR_STATUS oMonitorStatus;
            OsMemset(&oMonitorStatus, 0, sizeof(EC_T_MONITOR_STATUS));

            dwRes = emonGetMonitorStatus(pAppContext->dwInstanceId, &oMonitorStatus);
            if (EC_E_NOERROR != dwRes)
            {
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emGetMonitorStatus(): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            }

            bWaitForEvent = !oMonitorStatus.bNextCyclicEntryReceived;
        }

        /* stop Task (required for enhanced performance measurement) */
        dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_StopTask, EC_NULL);
        if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes && EC_E_LINK_DISCONNECTED != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: ecatExecJob(eUsrJob_StopTask): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        }
    } while (!pMonitorDemoParms->bTaskShutdown);

    pMonitorDemoParms->bTaskRunning = EC_FALSE;

    return;
}

/********************************************************************************/
/** \brief Watchdog task to ensure eUsrJob_MonitorTimer is called even if no frames are received
*
* \return N/A
*/
EC_T_VOID  EcMonitorTimerWatchdog(EC_T_VOID* pvAppContext)
{
    EC_T_DWORD dwRes = EC_E_ERROR;
    T_EC_DEMO_APP_CONTEXT* pAppContext = (T_EC_DEMO_APP_CONTEXT*)pvAppContext;
    T_EC_MONITOR_DEMO_PARMS* pMonitorDemoParms = pAppContext->pMonitorParms;

    pMonitorDemoParms->bTaskRunning = EC_TRUE;
    do
    {
        dwRes = OsWaitForEvent(pMonitorDemoParms->pvMonitorTimerWatchdogEvent, 5 * EC_AT_LEAST(pAppContext->AppParms.dwBusCycleTimeNsec / 1000000, 1));
        if (EC_E_TIMEOUT == dwRes)
        {
            /* watchdog not kicked from CycFrameReceivedCallback in time. Assume no frames received. */
            /* execute some administrative jobs, lock call to avoid reentrant access by callback */
            OsLock(pMonitorDemoParms->pvMonitorTimerLock);
            dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_MonitorTimer, EC_NULL);
            if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes)
            {
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emExecJob(eUsrJob_MonitorTimer): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            }
            OsUnlock(pMonitorDemoParms->pvMonitorTimerLock);
        }
    } while (!pMonitorDemoParms->bTaskShutdown);

    pMonitorDemoParms->bTaskRunning = EC_FALSE;
}

/********************************************************************************/
/** \brief  This function is called after the cyclic frames are received and processed by EC-Monitor.
*           If more than one frame, after the last frame.
* \return N/A
*/
static EC_T_VOID CycFrameReceivedCallback(EC_T_DWORD dwTaskId, EC_T_VOID* pvAppContext)
{
    EC_T_DWORD dwRes = EC_E_NOERROR;
    T_EC_DEMO_APP_CONTEXT* pAppContext = (T_EC_DEMO_APP_CONTEXT*)pvAppContext;
    T_EC_MONITOR_DEMO_PARMS* pMonitorDemoParms = pAppContext->pMonitorParms;
    EC_T_USER_JOB_PARMS oTaskJobParms;
    OsMemset(&oTaskJobParms, 0, sizeof(EC_T_USER_JOB_PARMS));

    /* start Task (required for enhanced performance measurement) */
    oTaskJobParms.StartTask.dwTaskId = dwTaskId;
    dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_StartTask, &oTaskJobParms);
    if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes && EC_E_LINK_DISCONNECTED != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: emExecJob(eUsrJob_StartTask): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
    }

    emonPerfMeasAppStart(pAppContext->dwInstanceId, pAppContext->pvPerfMeas, PERF_myAppWorkpd);
    {
        myAppWorkpd(pAppContext);
    }
    emonPerfMeasAppEnd(pAppContext->dwInstanceId, pAppContext->pvPerfMeas, PERF_myAppWorkpd);

    /* execute some administrative jobs, lock call to avoid reentrant access by watchdog task */
    OsLock(pMonitorDemoParms->pvMonitorTimerLock);
    dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_MonitorTimer, EC_NULL);
    if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emExecJob(eUsrJob_MonitorTimer): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
    }
    OsUnlock(pMonitorDemoParms->pvMonitorTimerLock);

    /* stop Task (required for enhanced performance measurement) */
    oTaskJobParms.StopTask.dwTaskId = dwTaskId;
    dwRes = emonExecJob(pAppContext->dwInstanceId, eUsrJob_StopTask, &oTaskJobParms);
    if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes && EC_E_LINK_DISCONNECTED != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: ecatExecJob(eUsrJob_StopTask): %s (0x%lx)\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
    }
    /* kick watchdog */
    OsSetEvent(pMonitorDemoParms->pvMonitorTimerWatchdogEvent);
}

/********************************************************************************/
/** \brief  Handler for monitor RAS notifications
*
*
* \return  Status value.
*/
#ifdef INCLUDE_RAS_SERVER
static EC_T_DWORD RasNotifyCallback(
    EC_T_DWORD         dwCode,
    EC_T_NOTIFYPARMS*  pParms
)
{
    EC_T_DWORD dwRetVal = EC_E_NOERROR;
    CEmNotification* pNotificationHandler = EC_NULL;

    if ((EC_NULL == pParms) || (EC_NULL == pParms->pCallerData))
    {
        dwRetVal = EC_E_INVALIDPARM;
        goto Exit;
    }

    pNotificationHandler = (CEmNotification*)pParms->pCallerData;
    dwRetVal = pNotificationHandler->emRasNotify(dwCode, pParms);

Exit:
    return dwRetVal;
}
#endif

/*-MYAPP---------------------------------------------------------------------*/

/***************************************************************************************************/
/**
\brief  Initialize Application

\return EC_E_NOERROR on success, error code otherwise.
*/
static EC_T_DWORD myAppInit(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
    OsMemset(pAppContext->pMyAppDesc, 0, sizeof(T_MY_APP_DESC));
    return EC_E_NOERROR;
}

/***************************************************************************************************/
/**
\brief  De-initialize Application

\return EC_E_NOERROR on success, error code otherwise.
*/
static EC_T_DWORD myAppDeinit(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
    EC_T_DWORD dwRetVal = EC_E_ERROR;
    EC_T_DWORD dwRes = EC_E_NOERROR;
    T_MY_APP_DESC* pMyAppDesc = pAppContext->pMyAppDesc;

    if (EC_NULL == pMyAppDesc)
    {
        dwRetVal = EC_E_NOERROR;
        goto Exit;
    }
#if (defined INCLUDE_DAQ_SUPPORT)
    if (EC_NULL != pMyAppDesc->hDaq)
    {
        /* stop recorder */
        dwRes = ecDaqRecStop(pMyAppDesc->hDaq);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqRecStop: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }
        pMyAppDesc->bDaqRecStarted = EC_FALSE;

        /* delete recorder instance */
        dwRes = ecDaqRecDelete(pMyAppDesc->hDaq);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqRecDelete: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }
        pMyAppDesc->hDaq = EC_NULL;
    }
#else
    EC_UNREFPARM(dwRes);
#endif
    dwRetVal = EC_E_NOERROR;
Exit:
    return dwRetVal;
}

/***************************************************************************************************/
/**
\brief  Initialize Slave Instance.

Find slave parameters.
\return EC_E_NOERROR on success, error code otherwise.
*/
static EC_T_DWORD myAppPrepare(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
#if (defined INCLUDE_DAQ_SUPPORT)
    EC_T_DWORD           dwRetVal   = EC_E_ERROR;
    EC_T_DWORD           dwRes      = EC_E_ERROR;
    T_EC_DEMO_APP_PARMS* pAppParms  = &pAppContext->AppParms;
    T_MY_APP_DESC*       pMyAppDesc = pAppContext->pMyAppDesc;

    if (pAppParms->bDaqRecorder)
    {
        EC_T_DAQ_FP oEcDaqFp;
        EC_T_DAQ_REC_PARMS  oEcDaqParms;

        /* create recorder */
        OsMemset(&oEcDaqFp, 0, sizeof(EC_T_DAQ_FP));
        oEcDaqFp.GetVersion = emonGetVersion;
        oEcDaqFp.RegisterClient = emonRegisterClient;
        oEcDaqFp.UnregisterClient = emonUnregisterClient;
        oEcDaqFp.GetCfgSlaveInfo = emonGetCfgSlaveInfo;
        oEcDaqFp.GetSlaveInpVarInfoNumOf = emonGetSlaveInpVarInfoNumOf;
        oEcDaqFp.GetSlaveInpVarInfo = emonGetSlaveInpVarInfoEx;
        oEcDaqFp.GetSlaveOutpVarInfoNumOf = emonGetSlaveOutpVarInfoNumOf;
        oEcDaqFp.GetSlaveOutpVarInfo = emonGetSlaveOutpVarInfoEx;
        oEcDaqFp.SystemTimeGet = OsSystemTimeGet;
        oEcDaqFp.QueryMsecCount = OsQueryMsecCount;

        OsMemset(&oEcDaqParms, 0, sizeof(EC_T_DAQ_REC_PARMS));
        oEcDaqParms.dwMasterInstanceId = pAppContext->dwInstanceId;
        oEcDaqParms.dwBusCycleTimeNsec = pAppContext->AppParms.dwBusCycleTimeNsec;
        oEcDaqParms.bCycleCounter = EC_TRUE;
        oEcDaqParms.bElapsedTimeMsec = EC_TRUE;

        /* thread */
        oEcDaqParms.qwThreadCpuSet = pAppContext->AppParms.CpuSet;
        oEcDaqParms.dwThreadPrio = LOG_THREAD_PRIO;
        oEcDaqParms.dwThreadStackSize = LOG_THREAD_STACKSIZE;

        /* logging */
        OsMemcpy(&oEcDaqParms.LogParms, &pAppContext->LogParms, sizeof(EC_T_LOG_PARMS));
        oEcDaqParms.LogParms.dwLogLevel = pAppContext->AppParms.dwMasterLogLevel;

        /* initialize recorder */
        dwRes = ecDaqRecCreate(&pMyAppDesc->hDaq, &oEcDaqFp, &oEcDaqParms);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqRecCreate: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }

        /* add bus time variable if available */
        {
            EC_T_PROCESS_VAR_INFO_EX BusTimeVarInfo;
            
            dwRes = emonFindInpVarByNameEx(pAppContext->dwInstanceId, "Inputs.BusTime", &BusTimeVarInfo);
            if (EC_E_NOERROR == dwRes)
            {
                EC_T_BYTE* pbyPdIn = emonGetProcessImageInputPtr(pAppContext->dwInstanceId);
                dwRes = ecDaqConfigRegisterAppVariable(pMyAppDesc->hDaq, BusTimeVarInfo.szName, BusTimeVarInfo.wDataType, BusTimeVarInfo.nBitOffs, BusTimeVarInfo.nBitSize, pbyPdIn);
                if (dwRes != EC_E_NOERROR)
                {
                    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqConfigRegisterAppVariable: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
                    dwRetVal = dwRes;
                    goto Exit;
                }
                ecDaqConfigAddDataVariable(pMyAppDesc->hDaq, BusTimeVarInfo.szName);
            }
        }

        /* load recorder configuration from file */
        dwRes = ecDaqConfigLoad(pMyAppDesc->hDaq, pAppContext->AppParms.szDaqRecorder);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqConfigLoad: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }

        /* apply configuration to recorder */
        dwRes = ecDaqConfigApply(pMyAppDesc->hDaq);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqConfigApply: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }

        /* start recorder */
        dwRes = ecDaqRecStart(pMyAppDesc->hDaq);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqRecStart: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }
        pMyAppDesc->bDaqRecStarted = EC_TRUE;
    }
    dwRetVal = EC_E_NOERROR;
Exit:
    return dwRetVal;
#else
    EC_UNREFPARM(pAppContext);
    return EC_E_NOERROR;
#endif
}

/***************************************************************************************************/
/**
\brief  Setup slave parameters (normally done in PREOP state)

  - SDO up- and Downloads
  - Read Object Dictionary

\return EC_E_NOERROR on success, error code otherwise.
*/
static EC_T_DWORD myAppSetup(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
    EC_UNREFPARM(pAppContext);
    return EC_E_NOERROR;
}

/***************************************************************************************************/
/**
\brief  demo application working process data function.

  This function is called in every cycle after the monitor stack is started.

*/
static EC_T_DWORD myAppWorkpd(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
#if (defined INCLUDE_DAQ_SUPPORT)
    EC_T_DWORD dwRes = EC_E_NOERROR;
    T_MY_APP_DESC* pMyAppDesc = pAppContext->pMyAppDesc;
    if (pMyAppDesc->bDaqRecStarted)
    {
        dwRes = ecDaqProcessRt(pMyAppDesc->hDaq);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecDaqProcessRt: %s (0x%lx))\n", emonGetText(pAppContext->dwInstanceId, dwRes), dwRes));
        }
    }
#else
    EC_UNREFPARM(pAppContext);
#endif
    return EC_E_NOERROR;
}

/***************************************************************************************************/
/**
\brief  demo application doing some diagnostic tasks

  This function is called in sometimes from the main demo task
*/
static EC_T_DWORD myAppDiagnosis(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
    EC_UNREFPARM(pAppContext);
    return EC_E_NOERROR;
}

EC_T_VOID ShowSyntaxAppUsage(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
    const EC_T_CHAR* szAppUsage = "<LinkLayer> [-f ENI-FileName] [-t time] [-b cycle time] [-a affinity] [-v lvl] [-perf] [-log prefix [msg cnt]] [-lic key] [-play pcap-FileName] [-rec [<prefix>]]"
#if (defined INCLUDE_RAS_SERVER)
        " [-sp [port]]"
#endif
#if (defined INCLUDE_DAQ_SUPPORT)
        " [-daqrec FileName]"
#endif
        ;
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "%s V%s for %s %s\n", EC_DEMO_APP_NAME, EC_FILEVERSIONSTR, ATECAT_PLATFORMSTR, EC_COPYRIGHT));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Syntax:\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "%s %s\n", EC_DEMO_APP_NAME, szAppUsage));
}

EC_T_VOID ShowSyntaxApp(T_EC_DEMO_APP_CONTEXT* pAppContext)
{
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -play             Packet capture file processing\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     File name       File name (*.pcap|*.pcapng)\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -rec              Packet capture file recording\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     [prefix]        File name prefix\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -genebi           Enable operation without ENI and export ENI Builder on demo stop\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     File name       Export file name (*.xml)\n"));
#if (defined INCLUDE_DAQ_SUPPORT)
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -daqrec           DAQ recorder\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     File name       Configuration file name\n"));
#endif
}

/*-END OF SOURCE FILE--------------------------------------------------------*/
