/*
 * CatMasterMain.cpp
 *
 *  Created on: 2018/09/07
 *      Author: shingo
 */


/*-INCLUDES------------------------------------------------------------------*/
#include "Logging.h"

//#include "ATEMDemo.h"
#include "CatMasterMainLoop.h"

#include "selectLinkLayer.h"

#include <stdio.h>
#include <stdlib.h>

// インクルートのネストが分からなので直接取りあえず宣言する
#include "ATEMDemoConfig.h"

#include "CatDataInfo.h"
#include "ProcessDataBuffer.h"
#include "SlaveConfigInfo.h"
#include "CatMasterInfo.h"



/*-DEFINES-------------------------------------------------------------------*/
#define COMMAND_LINE_BUFFER_LENGTH 512



#if (defined EC_VERSION_SYSBIOS) || (defined EC_VERSION_RIN32M3) ||\
    (defined EC_VERSION_XILINX_STANDALONE) || (defined EC_VERSION_RZT1) || (defined EC_VERSION_ETKERNEL) ||\
    (defined EC_VERSION_RZGNOOS) || (defined EC_VERSION_JSLWARE) || (defined EC_VERSION_UC3) || (defined EC_VERSION_XMC)
extern EC_T_BYTE  MasterENI_xml_data[];
extern EC_T_DWORD MasterENI_xml_data_size;

#define STATIC_MASTERENI_XML_DATA          MasterENI_xml_data
#define STATIC_MASTERENI_XML_DATA_SIZE     MasterENI_xml_data_size
#endif

#if (defined EC_VERSION_WINDOWS) || ((defined VXWORKS) && (!defined __RTP__)) || ((defined UNDER_CE) && (_WIN32_WCE >= 0x600)) ||\
    (defined UNDER_RTSS) || (defined STARTERWARE_NOOS) || (defined EC_VERSION_SYLIXOS) ||\
    (defined EC_VERSION_SYSBIOS) || (defined EC_VERSION_RIN32M3) || (defined EC_VERSION_XILINX_STANDALONE) ||\
    (defined EC_VERSION_RZT1) || (defined EC_VERSION_RZGNOOS) || ((defined LINUX) && (!defined RTAI)) ||\
    (defined EC_VERSION_JSLWARE) || ((defined EC_VERSION_QNX) && (EC_VERSION_QNX >= 700)) ||\
    (defined EC_VERSION_UC3) || (defined EC_VERSION_XMC) || (defined EC_VERSION_RTXC)
#define AUXCLOCK_SUPPORTED
#endif

/*-TYPEDEFS------------------------------------------------------------------*/
typedef struct _EC_T_TIMING_DESC
{
    EC_T_VOID*          pvTimingEvent;      /* event handle */

    EC_T_DWORD          dwBusCycleTimeUsec; /* cycle time in usec */
    EC_T_BOOL           bShutdown;          /* EC_TRUE if aux thread shall shut down */
    EC_T_BOOL           bIsRunning;         /* EC_TRUE if the aux thread is running */
#if (defined AUXCLOCK_SUPPORTED)
    EC_T_BOOL           bUseAuxClock;       /* Either connect to IRQ or use sleep */
    EC_T_VOID*          pvAuxClkEvent;      /* event handle */
#endif
    EC_T_DWORD          dwCpuIndex;         /* SMP systems: CPU index */
} EC_T_TIMING_DESC;

// 後方参照用
static void  initFw();

// グローバル共通データ
CatDataInfo* catDataInfo;
ProcessDataBuffer* processData;
SlaveConfigInfo* slaveConfInfo;
CatMasterInfo* catMasterInfo;

/*-LOCAL FUNCTIONS-----------------------------------------------------------*/

/********************************************************************************/
/** Show syntax
*
* Return: N/A
*/
static EC_T_VOID ShowSyntax(EC_T_VOID)
{
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Syntax:\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "EcMasterDemo [-f ENI-FileName] [-t time] [-b time] [-a affinity] [-v lvl] [-perf] [-log Prefix]"));
#if (defined AUXCLOCK_SUPPORTED)
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, " [-auxclk period]"));
#endif

    ShowLinkLayerSyntax1();
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -f                Use given ENI file\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     FileName        file name .xml\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -t                Demo duration\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     time            Time in msec, 0 = forever (default = 120000)\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -b                Bus cycle time\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     cycle time      Cycle time in usec\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -a                CPU affinity\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     affinity        0 = first CPU, 1 = second, ...\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -v                Set verbosity level\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     lvl             Level: 0=off, 1(default) ...n=more messages\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -perf             Enable job measurement\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -log              Use given file name prefix for log files\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     Prefix          prefix\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -flash            Flash outputs\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     address         0=all, >0 = slave address"));
#if (defined AUXCLOCK_SUPPORTED)
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "   -auxclk           use auxiliary clock\n"));
    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "     period          clock period in usec\n"));
#endif

    ShowLinkLayerSyntax2();

    return;
}


/********************************************************************************/
/* \brief Set event according to periodical sleep or aux clock
 * Cyclically sets an event for thread synchronization purposes.
 * Either use OsSleep() or use the aux clock by means of:
 * - Enable AUX clock if selected.
 * - Wait for IRQ, aknowledge IRQ, SetEvent in loop until shutdown
 * - Disable AUX clock
 * Return: N/A
 */
/**
 *  通信タイミング通知スレッド
 */
static EC_T_VOID tEcTimingTask(EC_T_VOID* pvThreadParamDesc)
{
EC_T_TIMING_DESC* pTimingDesc = (EC_T_TIMING_DESC*)pvThreadParamDesc;
EC_T_CPUSET       CpuSet;

    EC_CPUSET_ZERO( CpuSet );
    EC_CPUSET_SET( CpuSet, pTimingDesc->dwCpuIndex );
    OsSetThreadAffinity( EC_NULL, CpuSet );

    /* timing task started */
    pTimingDesc->bIsRunning = EC_TRUE;

    /* periodically generate events as long as the application runs */
    while (!pTimingDesc->bShutdown)
    {
        /* wait for next cycle (no cycle below 1ms) */
         OsSleep(EC_MAX(pTimingDesc->dwBusCycleTimeUsec / 1000, 1));

        /* trigger jobtask */
        OsSetEvent(pTimingDesc->pvTimingEvent);
    }

    pTimingDesc->bIsRunning = EC_FALSE;
    return;
}


/**
 *  起動メイン処理
 *  起動時の初期タスクより呼ばれる。本メソッドより、通信周期のタイミングタスクを起動し、通信メインループを呼び出す。
 *
 */
extern "C" int CatMasterMain(void)
{
    //　ファームモジュールデータの初期化
    initFw();

    int                     nRetVal             = APP_ERROR;
    EC_T_DWORD              dwRes               = EC_E_ERROR;
    EC_T_BOOL               bLogInitialized     = EC_FALSE;
    EC_T_CHAR               szCommandLine[COMMAND_LINE_BUFFER_LENGTH];
    EC_T_CHAR               szFullCommandLine[COMMAND_LINE_BUFFER_LENGTH];
    EC_T_BOOL               bGetNextWord        = EC_TRUE;
    EC_T_CHAR*              ptcWord             = EC_NULL;
    EC_T_CHAR               tcStorage           = '\0';

    EC_T_CHAR               szLogFileprefix[256] = {'\0'};
    EC_T_CNF_TYPE           eCnfType            = eCnfType_Unknown;
    EC_T_PBYTE              pbyCnfData          = 0;
    EC_T_DWORD              dwCnfDataLen        = 0;
    EC_T_CHAR               szENIFilename[256]  = {'\0'};
    EC_T_DWORD              dwDuration          = 120000;
    EC_T_DWORD              dwNumLinkLayer      = 0;
    EC_T_LINK_PARMS*        apLinkParms[MAX_LINKLAYER];
    CAtEmLogging            oLogging;
    EC_T_DWORD              dwCpuIndex          = 0;
    EC_T_CPUSET             CpuSet;
    EC_T_BOOL               bEnaPerfJobs        = EC_FALSE;  /* enable job measurements */
    EC_T_INT                nFlashAddress       = -1;
    EC_T_TIMING_DESC        TimingDesc;
    EC_T_BOOL               bStartTimingTask    = EC_FALSE;
    EC_T_INT                nVerbose            = 1;

    /* printf logging until logging initialized */
    G_pEcLogParms->pfLogMsg = CAtEmLogging::LogMsgOsPrintf;
    G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_UNDEFINED;

    OsMemset(apLinkParms, 0, sizeof(EC_T_LINK_PARMS*) * MAX_LINKLAYER);
    OsMemset(&TimingDesc, 0, sizeof(EC_T_TIMING_DESC));

    szCommandLine[0] = '\0';

#if !(defined UNDER_RTSS) && !(defined RTAI)
    /* Seed the random-number generator with current time so that
     * the numbers will be different every time we run.
     */
    srand((unsigned)OsQueryMsecCount());
#endif

    /* set running flag */
    bRun = EC_TRUE;

    /* Initialize Timing Event descriptor */
    TimingDesc.bShutdown          = EC_FALSE;
    TimingDesc.bIsRunning         = EC_FALSE;
    TimingDesc.dwBusCycleTimeUsec = CYCLE_TIME * 1000;

    /* prepare command line */
    OsStrncpy(szCommandLine, DEMO_PARAMETERS, sizeof(szCommandLine) - 1);

    /* backup full command line */
    OsStrncpy(szFullCommandLine, szCommandLine, sizeof(szFullCommandLine) - 1);

    /* parse command line */
    for (ptcWord = OsStrtok(szCommandLine, " "); ptcWord != EC_NULL;)
    {
        if (0 == OsStricmp( ptcWord, "-f"))
        {
            EC_T_INT nPtcWordIndex = 3;

            /* Search for the start of the config file name. The config file
               name may start with quotation marks because of blanks in the filename */
            while (ptcWord[nPtcWordIndex] != '\0')
            {
                if ((ptcWord[nPtcWordIndex] == '\"') || (ptcWord[nPtcWordIndex] != ' '))
                {
                    break;
                }
                nPtcWordIndex++;
            }

            /* Depending of a config file name within quotation marks (or without
               quotation marks) extract the filename */
            if (ptcWord[nPtcWordIndex] == '\"')
            {
                /* Check if the strtok position is already correct */
                if (nPtcWordIndex > 3)
                {
                    /* More than 1 blank before -f. Correct strtok position. */
                    OsStrtok(EC_NULL,"\"");
                }

                /* Now extract the config file name */
                ptcWord = OsStrtok(EC_NULL,"\"");
            }
            else
            {
                /* Extract the config file name if it was not set within quotation marks */
                ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage );
            }

            if ((ptcWord == EC_NULL)
             || (OsStrncmp(ptcWord, "-", 1) == 0))
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            OsSnprintf(szENIFilename, sizeof(szENIFilename) - 1, "%s", ptcWord);
        }
        else if (0 == OsStricmp(ptcWord, "-log"))
        {
            EC_T_INT nPtcWordIndex = 4;

            /* Search for the start of the config file name. The config file
               name may start with quotation marks because of blanks in the filename */
            while (ptcWord[nPtcWordIndex] != '\0')
            {
                if ((ptcWord[nPtcWordIndex] == '\"') || (ptcWord[nPtcWordIndex] != ' '))
                {
                    break;
                }
                nPtcWordIndex++;
            }

            /* Depending of a config file name within quotation marks (or without
               quotation marks) extract the filename */
            if (ptcWord[nPtcWordIndex] == '\"')
            {
                /* Check if the strtok position is already correct */
                if (nPtcWordIndex > 3)
                {
                    /* More than 1 blank before -f. Correct strtok position. */
                    OsStrtok(EC_NULL,"\"");
                }

                /* Now extract the config file name */
                ptcWord = OsStrtok(EC_NULL,"\"");
            }
            else
            {
                /* Extract the config file name if it was not set within quotation marks */
                ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage );
            }

            if ((ptcWord == EC_NULL) || (OsStrncmp(ptcWord, "-", 1) == 0))
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            OsSnprintf(szLogFileprefix, sizeof(szLogFileprefix) - 1, "%s", ptcWord);
        }
        else if (OsStricmp( ptcWord, "-t") == 0)
        {
            ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage );
            if ((ptcWord == EC_NULL) || (OsStrncmp(ptcWord, "-", 1) == 0))
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            dwDuration = OsStrtol(ptcWord, EC_NULL, 0);
        }
        else if (OsStricmp( ptcWord, "-auxclk") == 0)
        {

            TimingDesc.bUseAuxClock = EC_TRUE;
            ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage);
            if ((ptcWord == EC_NULL) || (OsStrncmp(ptcWord, "-", 1) == 0))
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            TimingDesc.dwBusCycleTimeUsec = OsStrtol(ptcWord, EC_NULL, 0);
            if (TimingDesc.dwBusCycleTimeUsec < 10)
            {
                TimingDesc.dwBusCycleTimeUsec = 10;
            }
        }
        else if (OsStricmp( ptcWord, "-b") == 0)
        {
            if (TimingDesc.bUseAuxClock)
            {
                EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Using bus cycle time %d usec from auxclock parameter\n", TimingDesc.dwBusCycleTimeUsec));
            }
            else
            {
                ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage );
                if ((ptcWord == EC_NULL) || (OsStrncmp(ptcWord, "-", 1) == 0))
                {
                    nRetVal = SYNTAX_ERROR;
                    goto Exit;
                }
                TimingDesc.dwBusCycleTimeUsec = OsStrtol(ptcWord, EC_NULL, 0);
            }
        }
        else if (OsStricmp(ptcWord, "-a") == 0)
        {
            ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage);
            if ((ptcWord == EC_NULL) || (OsStrncmp(ptcWord, "-", 1) == 0))
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            dwCpuIndex = OsStrtol(ptcWord, EC_NULL, 0);
        }
        else if (OsStricmp( ptcWord, "-v") == 0)
        {
            ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage);
            if ((ptcWord == EC_NULL) || (OsStrncmp(ptcWord, "-", 1) == 0))
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            nVerbose = OsStrtol(ptcWord, EC_NULL, 10);
        }
        else if (OsStricmp( ptcWord, "-perf") == 0)
        {
            bEnaPerfJobs = EC_TRUE;
        }
        else if (OsStricmp(ptcWord, "-flash") == 0)
        {
            ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage);
            if ((ptcWord == EC_NULL)|| (OsStrncmp(ptcWord, "-", 1) == 0))
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            nFlashAddress = OsStrtol(ptcWord, EC_NULL, 10);
        }
        else
        {
            EC_T_CHAR* szNextParm = ptcWord;
            EC_T_DWORD dwNewCycleDurationUsec = 0;

            dwRes = CreateLinkParmsFromCmdLine(&ptcWord, (EC_T_CHAR**)&szCommandLine, &tcStorage, &bGetNextWord,
                                               &apLinkParms[dwNumLinkLayer]);
            if (EC_E_NOERROR != dwRes)
            {
                EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "SYNTAX_ERROR: %s!\n", szNextParm));
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            if (dwNumLinkLayer > 1)
            {
                nRetVal = SYNTAX_ERROR;
                goto Exit;
            }
            else
            {

                apLinkParms[dwNumLinkLayer]->dwIstPriority = RECV_THREAD_PRIO;
                dwNumLinkLayer++;

                if( dwNewCycleDurationUsec != 0 )
                {
                    TimingDesc.dwBusCycleTimeUsec = dwNewCycleDurationUsec;
                }
            }
        }
        /* get next word */
        if (bGetNextWord)
        {
            ptcWord = GetNextWord((EC_T_CHAR**)&szCommandLine, &tcStorage );
        }
        bGetNextWord = EC_TRUE;
    }
    /* set application log level */
    switch (nVerbose)
    {
    case 0:  G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_SILENT;      break;
    case 1:  G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_INFO;        break;
    case 2:  G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_INFO;        break;
    case 3:  G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_INFO;        break;
    case 4:  G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_INFO;        break;
    case 5:  G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_VERBOSE;     break;
    default: /* no break */
    case 6:  G_pEcLogParms->dwLogLevel = EC_LOG_LEVEL_VERBOSE_CYC; break;
    }
    /* initialize logging */
    oLogging.InitLogging(INSTANCE_MASTER_DEFAULT, G_pEcLogParms->dwLogLevel, LOG_ROLLOVER, LOG_THREAD_PRIO, dwCpuIndex, szLogFileprefix, LOG_THREAD_STACKSIZE);
    G_pEcLogParms->pfLogMsg = CAtEmLogging::LogMsg;
    G_pEcLogParms->pLogContext = (struct _EC_T_LOG_CONTEXT*)&oLogging;
    bLogInitialized = EC_TRUE;

#if !(defined XENOMAI) || (defined CONFIG_XENO_COBALT) || (defined CONFIG_XENO_MERCURY)
    oLogging.SetLogThreadAffinity(dwCpuIndex);
#endif /* !XENOMAI || CONFIG_XENO_COBALT || CONFIG_XENO_MERCURY */
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO,  "Full command line: %s\n", szFullCommandLine));

    /* determine master configuration type */
    if ('\0' != szENIFilename[0])
    {
        eCnfType     = eCnfType_Filename;
        pbyCnfData   = (EC_T_BYTE*)&szENIFilename[0];
        dwCnfDataLen = 256;
    }
    else
    {
        eCnfType     = eCnfType_Data;
        pbyCnfData   = STATIC_MASTERENI_XML_DATA;
        dwCnfDataLen = STATIC_MASTERENI_XML_DATA_SIZE;
    }

    if (0 == dwNumLinkLayer)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Syntax error: missing link layer command line parameter\n"));
        nRetVal = SYNTAX_ERROR;
        goto Exit;
    }


    /* for multi core cpus: select cpu number for this thread */
    EC_CPUSET_ZERO(CpuSet);
    EC_CPUSET_SET(CpuSet, dwCpuIndex);
    if (!OsSetThreadAffinity(EC_NULL, CpuSet))
    {
       EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: Set Affinity Failed!\n"));
    }

    TimingDesc.dwCpuIndex = dwCpuIndex;

    /* create timing event to trigger the job task */
    TimingDesc.pvTimingEvent = OsCreateEvent();

    if( EC_NULL == TimingDesc.pvTimingEvent )
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: insufficient memory to create timing event!\n"));
        goto Exit;
    }

    /* initialize auxiliary clock */
    if (TimingDesc.bUseAuxClock)
    {
        dwRes = OsAuxClkInit(dwCpuIndex, 1000000 / TimingDesc.dwBusCycleTimeUsec, TimingDesc.pvTimingEvent);
        if (EC_E_NOERROR != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR at auxiliary clock initialization!\n"));
            goto Exit;
        }

    } /* TimingDesc.bUseAuxClock */
    else
    {
        bStartTimingTask = EC_TRUE;
    }

    /* create timing task if needed */
    if (bStartTimingTask)
    {
        OsCreateThread((EC_T_CHAR*)"tEcTimingTask", (EC_PF_THREADENTRY)tEcTimingTask, TIMER_THREAD_PRIO, LOG_THREAD_STACKSIZE, (EC_T_VOID*)&TimingDesc);
        while (!TimingDesc.bIsRunning)
        {
            OsSleep(1);
        }
    }

    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Run demo now with cycle time %d usec\n", TimingDesc.dwBusCycleTimeUsec));



    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Using %s\n",
        (TimingDesc.bUseAuxClock ? "AuxClock" : "Sleep")));

 //    dwRes = ATEMDemo( eCnfType, pbyCnfData, dwCnfDataLen,
    dwRes = CatMasterIni( eCnfType, pbyCnfData, dwCnfDataLen,
                      TimingDesc.dwBusCycleTimeUsec, nVerbose, dwDuration,
                      apLinkParms[0],
                      TimingDesc.pvTimingEvent,
                      dwCpuIndex,
                      bEnaPerfJobs, nFlashAddress
                      ,((2 == dwNumLinkLayer)?apLinkParms[1]:EC_NULL)
                    );
    if (EC_E_NOERROR != dwRes)
    {
        goto Exit;
    }
    /* no errors */
    nRetVal = APP_NOERROR;

Exit:
    if (nRetVal == SYNTAX_ERROR)
    {
        ShowSyntax();
    }
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "EcMasterDemo stop.\n"));

    if (nRetVal != APP_NOERROR)
    {
        OsSleep(5000);
    }

    /* stop timing task if running */
    if (TimingDesc.bIsRunning)
    {
        TimingDesc.bShutdown = EC_TRUE;
        while (TimingDesc.bIsRunning)
        {
            OsSleep(1);
        }
    }

    /* clean up auxclk */
    if (TimingDesc.bUseAuxClock)
    {
        OsAuxClkDeinit(0);
    }

    /* delete the timing event */
    if (EC_NULL != TimingDesc.pvTimingEvent)
    {
        OsDeleteEvent( TimingDesc.pvTimingEvent );
        TimingDesc.pvTimingEvent = EC_NULL;
    }

    if (bLogInitialized)
    {
        /* de-initialize message logging */
        oLogging.DeinitLogging();
    }
    /* final OS layer cleanup */
    OsDeinit();

    /* free link parms created by CreateLinkParmsFromCmdLine() */
    for (;dwNumLinkLayer != 0; dwNumLinkLayer--)
    {
        if (EC_NULL != apLinkParms[dwNumLinkLayer-1])
        {
            OsFree(apLinkParms[dwNumLinkLayer-1]);
            apLinkParms[dwNumLinkLayer-1] = EC_NULL;
        }
    }
    return nRetVal;
}


/*-Handle static linked link layers -----------------------------------------*/
#if !defined(ATECAT_DLL)
#if (defined RTOS_32) || (defined __INTEGRITY) || ((defined __TKERNEL)&& (!defined __arm__)) || (defined __RCX__)\
    || (defined RTAI) || (defined EC_VERSION_ETKERNEL) || (defined EC_VERSION_SYSBIOS) || (defined EC_VERSION_RTEMS)\
    || (defined EC_VERSION_UCOS) || (defined EC_VERSION_ECOS) || (defined EC_VERSION_RTXC)
#include "EcLink.h"
ATEMLL_API EC_T_DWORD emllRegisterI8255x (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterI8254x (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterRTL8139(EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterRTL8169(EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterHnx    (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterCPSW   (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterCCAT   (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterICSS   (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterFslFec (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterAntaios (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterDW3504 (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);
ATEMLL_API EC_T_DWORD emllRegisterETSEC (EC_T_LINK_DRV_DESC* pLinkDrvDesc, EC_T_DWORD dwLinkDrvDescSize);

EC_PF_LLREGISTER OsGetLinkLayerRegFunc(EC_T_CHAR* szDriverIdent)
{
EC_PF_LLREGISTER pfLlRegister = EC_NULL;

    if (0 == OsStrcmp(EC_LINK_PARMS_IDENT_ICSS, szDriverIdent))
    {
        pfLlRegister = (EC_PF_LLREGISTER)emllRegisterICSS;
    } else
    {
        pfLlRegister = EC_NULL;
    }
    return pfLlRegister;
}
#endif /* RTOS_32 ||  __INTEGRITY || __TKERNEL || __RCX__ || RTAI */
#endif /* !ATECAT_DLL */


/**
 * ファームウェア内の共通初期化処理
 */
void  initFw() {
    catDataInfo = new CatDataInfo();
    processData = new ProcessDataBuffer();
    slaveConfInfo = new SlaveConfigInfo();
    catMasterInfo = new CatMasterInfo();
    }

/*-END OF SOURCE FILE--------------------------------------------------------*/
