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

/*-INCLUDES------------------------------------------------------------------*/


#include "CatMasterMainLoop.h"
#include "CatDataInfo.h"
#include "FwAppError.h"
#include "InProcessRxTaskClass.h"
#include "OutProcessTxTaskClass.h"
#include "SlaveConfigInfo.h"
#include "CatMasterInfo.h"

#include <xdc\runtime/Error.h>
#include <ti/drv/uart/UART_stdio.h>
//#include <EcLog.h>
//#include <ti/sysbios/knl/Event.h>
//#include <ti/sysbios/BIOS.h>
//#include <EcOsPlatform.h>





// 外部参照
extern CatDataInfo* catDataInfo;
extern ProcessDataBuffer* processData;
extern SlaveConfigInfo* slaveConfInfo;
extern CatMasterInfo* catMasterInfo;

// データ構造定義
typedef struct {
    EC_T_BYTE* inDataAddr;   // メモリプロバイダへのパラメータバッファ
    EC_T_BYTE* outDataAddr;
    ProcessDataBuffer* processData;
} MEMORY_HANDL_PARAM;




/*-LOCAL VARIABLES-----------------------------------------------------------*/
static EC_T_REGISTERRESULTS S_oRegisterResults;
static T_DEMO_THREAD_PARAM  S_DemoThreadParam;
static EC_T_PVOID           S_pvtJobThread    = EC_NULL;
static EC_T_CHAR*           S_aszMeasInfo[MAX_JOB_NUM] =
{
    (EC_T_CHAR*)"JOB_ProcessAllRxFrames",
    (EC_T_CHAR*)"JOB_SendAllCycFrames  ",
    (EC_T_CHAR*)"JOB_MasterTimer       ",
    (EC_T_CHAR*)"JOB_SendAcycFrames    ",
    (EC_T_CHAR*)"Cycle Time            ",
    (EC_T_CHAR*)"myAppWorkPd           "
};

static MEMORY_HANDL_PARAM memHandlParam;

static EC_T_BYTE inputProcessData[200];
static EC_T_BYTE outputProcessData[200];

static ST_PRO_RX_TASK_PRAM processRxTaskParam;
static ST_PRO_TX_TASK_PRAM processTxTaskParam;




// 後方参照
static EC_T_DWORD ecatNotifyCallback(EC_T_DWORD dwCode, EC_T_NOTIFYPARMS* pParms);
static EC_T_VOID  tEcJobTask(EC_T_VOID* pvThreadParamDesc);
static void getProcessDataSize(CatDataInfo*);
static EC_T_DWORD registMemoryProvider(void);
static EC_T_VOID pfPDInWriteRequest(EC_T_PVOID pvContext, EC_T_DWORD, EC_T_PBYTE*);
static EC_T_VOID pfPDInWriteRelease(EC_T_PVOID pvContext, EC_T_DWORD);
static EC_T_VOID pfPDOutReadRequest(EC_T_PVOID pvContext, EC_T_DWORD, EC_T_PBYTE*);
static EC_T_VOID pfPDOutReadRelease(EC_T_PVOID pvContext,EC_T_DWORD);

static void setInitTxData(ProcessDataBuffer*);

/*-MYAPP---------------------------------------------------------------------*/
/* Demo code: Remove/change this in your application */
static EC_T_DWORD myAppInit     (T_DEMO_THREAD_PARAM* pDemoThreadParam);
static EC_T_DWORD myAppPrepare  (T_DEMO_THREAD_PARAM* pDemoThreadParam);
static EC_T_DWORD myAppSetup    (T_DEMO_THREAD_PARAM* pDemoThreadParam);
static EC_T_DWORD myAppWorkpd   (T_DEMO_THREAD_PARAM* pDemoThreadParam, EC_T_BYTE* pbyPDIn, EC_T_BYTE* pbyPDOut);
static EC_T_DWORD myAppDiagnosis(T_DEMO_THREAD_PARAM* pDemoThreadParam);
static EC_T_DWORD myAppNotify   (EC_T_DWORD dwCode, EC_T_NOTIFYPARMS* pParms);
/* Demo code: End */

/*-FUNCTION DEFINITIONS------------------------------------------------------*/

/**
 * 受信済み入力プロセスデータ転送処理タスクメイン
 */
static EC_T_VOID InProcessRxTask(EC_T_VOID* aParam) {
    EC_T_DWORD  dwCpuIndex = 0;
    EC_T_CPUSET CpuSet;
    EC_CPUSET_ZERO(CpuSet);
    EC_CPUSET_SET(CpuSet, dwCpuIndex);
    EC_T_BOOL bOk = OsSetThreadAffinity(EC_NULL, CpuSet);
    if (!bOk)
    {
 //       EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Error: Set thread affinity, invalid CPU index %d\n", dwCpuIndex));
        return;
    }

    ST_PRO_RX_TASK_PRAM * parm = (ST_PRO_RX_TASK_PRAM*)aParam;
    // 処理くクラスを生成し、初期化
    InProcessRxTaskClass* taskClass = new InProcessRxTaskClass();
    taskClass->init(parm);

    // タスクメイン処理へ（無限ループ）
    taskClass->loopMain();
}

/**
 * 送信用プロセス出力データ転送タスクメイン
 */
static EC_T_VOID OutProcessTxTask(EC_T_VOID* aParam) {
    EC_T_DWORD  dwCpuIndex = 0;

    EC_T_CPUSET CpuSet;
    EC_CPUSET_ZERO(CpuSet);
    EC_CPUSET_SET(CpuSet, dwCpuIndex);
    EC_T_BOOL bOk = OsSetThreadAffinity(EC_NULL, CpuSet);
    if (!bOk)
    {
//        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Error: Set thread affinitiy, invalid CPU index %d\n", dwCpuIndex));
        return;
    }

    ST_PRO_TX_TASK_PRAM * parm = (ST_PRO_TX_TASK_PRAM*)aParam;
    // 処理くクラスを生成し、初期化
    OutProcessTxTaskClass* taskClass = new OutProcessTxTaskClass();
    taskClass->init(parm);

    // タスクメイン処理へ（無限ループ）
    taskClass->loopMain();
}


/**
 * EtherCAT 送受信メインループ処理
 * (参照元ATEMDemo)
 *
 */
EC_T_DWORD CatMasterIni(
    EC_T_CNF_TYPE       eCnfType            /* [in]  Enum type of configuration data provided */
   ,EC_T_PBYTE          pbyCnfData          /* [in]  Configuration data */
   ,EC_T_DWORD          dwCnfDataLen        /* [in]  Length of configuration data in byte */
   ,EC_T_DWORD          dwBusCycleTimeUsec  /* [in]  bus cycle time in usec */
   ,EC_T_INT            nVerbose            /* [in]  verbosity level */
   ,EC_T_DWORD          dwDuration          /* [in]  test duration in msec (0 = forever) */
   ,EC_T_LINK_PARMS*    poLinkParms         /* [in]  pointer to link parameter */
   ,EC_T_VOID*          pvTimingEvent       /* [in]  Timing event handle */
   ,EC_T_DWORD          dwCpuIndex          /* [in]  SMP only: CPU index */
   ,EC_T_BOOL           bEnaPerfJobs        /* [in]  Performance measurement */
   ,EC_T_INT            nFlashAddress       /* [in]  Flash: -1= no,  0=all outputs, >0=slave address */
   ,EC_T_LINK_PARMS*    poLinkParmsRed      /* [in]  Redundancy Link Layer Parameter */
)
{
    EC_T_DWORD           dwRetVal         = EC_E_NOERROR;
    EC_T_DWORD           dwRes            = EC_E_NOERROR;
    EC_T_BOOL            bRes             = EC_FALSE;
    T_DEMO_THREAD_PARAM* pDemoThreadParam = &S_DemoThreadParam;
    EC_T_CPUSET CpuSet;
    EC_CPUSET_ZERO(CpuSet);
    EC_CPUSET_SET(CpuSet, dwCpuIndex);

    /* store parameters */
    OsMemset(pDemoThreadParam, 0, sizeof(T_DEMO_THREAD_PARAM));
    pDemoThreadParam->pvTimingEvent = pvTimingEvent;
    OsMemcpy(&pDemoThreadParam->LogParms, G_pEcLogParms, sizeof(EC_T_LOG_PARMS));
    pDemoThreadParam->nVerbose = nVerbose;
    pDemoThreadParam->dwCpuIndex = dwCpuIndex;
    pDemoThreadParam->dwMasterID = INSTANCE_MASTER_DEFAULT;
    pDemoThreadParam->dwBusCycleTimeUsec = dwBusCycleTimeUsec;
    pDemoThreadParam->FlashData.nFlashAddress = nFlashAddress;

    /* check if interrupt mode is selected */
    if (poLinkParms->eLinkMode != EcLinkMode_POLLING)
    {
        dwRetVal = EC_E_INVALIDPARM;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Error: Link layer in 'interrupt' mode is not supported by EcMasterDemo. Please select 'polling' mode.\n"));
        goto Exit;
    }
    /* set thread affinity */
    {
        bRes = OsSetThreadAffinity(EC_NULL, CpuSet);
        if (!bRes)
        {
            dwRetVal = EC_E_INVALIDPARM;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Error: Set thread affinitiy, invalid CPU index %d\n", dwCpuIndex));
            goto Exit;
        }
    }
    /* create notification context */
    pDemoThreadParam->pNotInst = EC_NEW(CEmNotification(pDemoThreadParam->dwMasterID));
    if (EC_NULL == pDemoThreadParam->pNotInst)
    {
        dwRetVal = EC_E_NOMEMORY;
        goto Exit;
    }
    if (bEnaPerfJobs)
    {
        PERF_MEASURE_JOBS_INIT(EC_NULL);
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "OsMeasGet100kHzFrequency(): %d MHz\n", OsMeasGet100kHzFrequency() / 10));
    }
    /*****************************************************************************/
    /* Demo code: Remove/change this in your application: Initialize application */
    /*****************************************************************************/
    dwRes = myAppInit(pDemoThreadParam);
    if (EC_E_NOERROR != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, (EC_T_CHAR*)"myAppInit failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
        dwRetVal = dwRes;
        goto Exit;
    }

    /* Initialize EtherCAT master */
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "==========================\n"));
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Initialize EtherCAT Master\n"));
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "==========================\n"));
    {

        // EtherCAT Masterの初期設定値を取得し、設定する
        EC_T_INIT_MASTER_PARMS oInitParms;
        memset(&oInitParms, 0, sizeof(EC_T_INIT_MASTER_PARMS));
        catMasterInfo->getMasterParam(&oInitParms, poLinkParms, nVerbose);

        // CAT Masterの初期化パラメータ設定
//        EC_T_INIT_MASTER_PARMS oInitParms;

//        OsMemset(&oInitParms, 0, sizeof(EC_T_INIT_MASTER_PARMS));
 //       oInitParms.dwSignature                   = ATECAT_SIGNATURE;
 //       oInitParms.dwSize                        = sizeof(EC_T_INIT_MASTER_PARMS);
 //       oInitParms.pLinkParms                    = poLinkParms;
 //       oInitParms.pLinkParmsRed                 = poLinkParmsRed;
 //       oInitParms.dwBusCycleTimeUsec            = dwBusCycleTimeUsec;
 //       oInitParms.dwMaxBusSlaves                = MASTER_CFG_ECAT_MAX_BUS_SLAVES;
//        oInitParms.dwMaxAcycFramesQueued         = MASTER_CFG_MAX_ACYC_FRAMES_QUEUED;
 //       if (oInitParms.dwBusCycleTimeUsec >= 1000)
 //       {
//            oInitParms.dwMaxAcycBytesPerCycle    = MASTER_CFG_MAX_ACYC_BYTES_PER_CYC;
//        }
//        else
//        {
//            oInitParms.dwMaxAcycBytesPerCycle    = 1500;
//            oInitParms.dwMaxAcycFramesPerCycle   = 1;
//            oInitParms.dwMaxAcycCmdsPerCycle     = 20;
//        }
//        oInitParms.dwEcatCmdMaxRetries           = MASTER_CFG_MAX_ACYC_CMD_RETRIES;
 //       if (1 <= nVerbose)
 //       {
 //           OsMemcpy(&oInitParms.LogParms, G_pEcLogParms, sizeof(EC_T_LOG_PARMS));
 //           switch (nVerbose)
 //           {
 //           case 0: oInitParms.LogParms.dwLogLevel = EC_LOG_LEVEL_SILENT;      break;
 //           case 1: oInitParms.LogParms.dwLogLevel = EC_LOG_LEVEL_WARNING;     break;
 //           case 2: oInitParms.LogParms.dwLogLevel = EC_LOG_LEVEL_WARNING;     break;
 //           case 3: oInitParms.LogParms.dwLogLevel = EC_LOG_LEVEL_WARNING;     break;
//          case 4: oInitParms.LogParms.dwLogLevel = EC_LOG_LEVEL_INFO;        break;
//            case 5: oInitParms.LogParms.dwLogLevel = EC_LOG_LEVEL_VERBOSE;     break;
//            default: /* no break */
//            case 6: oInitParms.LogParms.dwLogLevel = EC_LOG_LEVEL_VERBOSE_CYC; break;
//            }
//        }
        // Cat Master　初期化
        dwRes = ecatInitMaster(&oInitParms);
        if (dwRes != EC_E_NOERROR)
        {
            dwRetVal = dwRes;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot initialize EtherCAT-Master: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
            goto Exit;
        }
    }


    /* Print MAC address */
    if (nVerbose > 0)
    {
        ETHERNET_ADDRESS oSrcMacAddress;

        dwRes = ecatGetSrcMacAddress(&oSrcMacAddress);
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot get MAC address: %s (0x%lx))\n", ecatGetText(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]));
    }
    /* tEcJobTaskの生成タイミングを、後ろに変更した。マスターのコンフィグレーションを先に行う。 */
    /* Configure master */
    dwRes = ecatConfigureMaster(eCnfType, pbyCnfData, dwCnfDataLen);
    if (dwRes != EC_E_NOERROR)
    {
        dwRetVal = dwRes;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot configure EtherCAT-Master: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
        goto Exit;
    }

    // プロセスデータサイズの取得
    getProcessDataSize(catDataInfo);
    // プロセスデータクラスの初期化
    processData->init(192, 192);
    // メモリプロバイダ（ハンドラ）登録
    dwRes = registMemoryProvider();
    // 送信データの初期化
    setInitTxData(processData);
    // スレーブ情報の取得
    slaveConfInfo->readEniInfo();
    // デバッグ用
    slaveConfInfo->print();

    /* Create cyclic task to trigger master jobs */
    /*********************************************/
    {
        CEcTimer oTimeout;

        pDemoThreadParam->bJobThreadRunning  = EC_FALSE;
        pDemoThreadParam->bJobThreadShutdown = EC_FALSE;
        S_pvtJobThread = OsCreateThread((EC_T_CHAR*)"tEcJobTask", tEcJobTask,
                                                        JOBS_THREAD_PRIO, JOBS_THREAD_STACKSIZE, (EC_T_VOID*)pDemoThreadParam);

        /* wait until thread is running */
        oTimeout.Start(2000);
        while (!oTimeout.IsElapsed() && !pDemoThreadParam->bJobThreadRunning)
        {
            OsSleep(10);
        }
        if (!pDemoThreadParam->bJobThreadRunning)
        {
            dwRetVal = EC_E_TIMEOUT;
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Timeout starting JobTask\n"));
            goto Exit;
        }
    }

    /* Register client */   // EcMasterクライント登録
    OsMemset(&S_oRegisterResults, 0, sizeof(EC_T_REGISTERRESULTS));
    dwRes = ecatRegisterClient(ecatNotifyCallback, pDemoThreadParam, &S_oRegisterResults);
    if (dwRes != EC_E_NOERROR)
    {
        dwRetVal = dwRes;
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot register client: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
        goto Exit;
    }
    pDemoThreadParam->pNotInst->SetClientID(S_oRegisterResults.dwClntId);
    pDemoThreadParam->FlashData.dwFlashPDOutSize = S_oRegisterResults.dwPDOutSize;

    /* Print found slaves */
    if (nVerbose >= 2)
    {
        dwRes = ecatScanBus(ETHERCAT_SCANBUS_TIMEOUT);
        pDemoThreadParam->pNotInst->ProcessNotificationJobs();
        switch (dwRes)
        {
        case EC_E_NOERROR:
        case EC_E_BUSCONFIG_MISMATCH:
        case EC_E_LINE_CROSSED:
            PrintSlaveInfos(pDemoThreadParam);
            break;
        default:
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot scan bus: %s (0x%lx)\n", ecatGetText(dwRes), dwRes));
            break;
        }
        if (dwRes != EC_E_NOERROR)
        {
            dwRetVal = dwRes;
            goto Exit;
        }
    }
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "=====================\n"));
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Start EtherCAT Master\n"));
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "=====================\n"));

    /* set master and bus state to INIT */
    dwRes = ecatSetMasterState(ETHERCAT_STATE_CHANGE_TIMEOUT, eEcatState_INIT);
    pDemoThreadParam->pNotInst->ProcessNotificationJobs();
    if (dwRes != EC_E_NOERROR)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot start set master state to INIT: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
        dwRetVal = dwRes;
        goto Exit;
    }
    /******************************************************/
    /* Demo code: Remove/change this in your application  */
    /******************************************************/
    dwRes = myAppPrepare(pDemoThreadParam);
    if (EC_E_NOERROR != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, (EC_T_CHAR*)"myAppPrepare failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
        dwRetVal = dwRes;
        goto Exit;
    }
    /* set master and bus state to PREOP */
    dwRes = ecatSetMasterState(ETHERCAT_STATE_CHANGE_TIMEOUT, eEcatState_PREOP);
    pDemoThreadParam->pNotInst->ProcessNotificationJobs();
    if (dwRes != EC_E_NOERROR)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot start set master state to PREOP: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
        dwRetVal = dwRes;
        goto Exit;
    }
    /* skip this step if demo started without ENI */
    if (pbyCnfData != EC_NULL)
    {
        /******************************************************/
        /* Demo code: Remove/change this in your application  */
        /******************************************************/
        dwRes = myAppSetup(pDemoThreadParam);
        if (EC_E_NOERROR != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, (EC_T_CHAR*)"myAppSetup failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }
        /* set master and bus state to SAFEOP */
        dwRes = ecatSetMasterState(ETHERCAT_STATE_CHANGE_TIMEOUT, eEcatState_SAFEOP);
        pDemoThreadParam->pNotInst->ProcessNotificationJobs();
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot start set master state to SAFEOP: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }
        /* set master and bus state to OP */
        dwRes = ecatSetMasterState(ETHERCAT_STATE_CHANGE_TIMEOUT, eEcatState_OP);
        pDemoThreadParam->pNotInst->ProcessNotificationJobs();
        if (dwRes != EC_E_NOERROR)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot start set master state to OP: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
            dwRetVal = dwRes;
            goto Exit;
        }
    }
    else
    {
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "No ENI file provided. EC-Master started with generated ENI file.\n"));
    }

    if (pDemoThreadParam->TscMeasDesc.bMeasEnabled)
    {
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "\n"));
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Job times during startup <INIT> to <%s>:\n", ecatStateToStr(ecatGetMasterState())));
        PERF_MEASURE_JOBS_SHOW();       /* show job times */
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "\n"));
        ecatPerfMeasReset(&pDemoThreadParam->TscMeasDesc, 0xFFFFFFFF);        /* clear job times of startup phase */
    }


    /* run the demo */
    if (dwDuration != 0)
    {
        pDemoThreadParam->oDuration.Start(dwDuration);
    }
    while (bRun && (!pDemoThreadParam->oDuration.IsStarted() || !pDemoThreadParam->oDuration.IsElapsed()))
    {
        if (nVerbose >= 2)
        {
            PERF_MEASURE_JOBS_SHOW();       /* show job times */
        }
        bRun = !OsTerminateAppRequest();/* check if demo shall terminate */

        /*****************************************************************************************/
        /* Demo code: Remove/change this in your application: Do some diagnosis outside job task */
        /*****************************************************************************************/
        myAppDiagnosis(pDemoThreadParam);

        /* process notification jobs */
        pDemoThreadParam->pNotInst->ProcessNotificationJobs();

        OsSleep(5);
    }

    if (pDemoThreadParam->TscMeasDesc.bMeasEnabled)
    {
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "\n"));
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Job times before shutdown\n"));
        PERF_MEASURE_JOBS_SHOW();       /* show job times */
    }

Exit:
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "========================\n"));
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Shutdown EtherCAT Master\n"));
    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "========================\n"));

    /* Set Master state back to INIT */
    if (eEcatState_UNKNOWN != ecatGetMasterState())
    {
        dwRes = ecatSetMasterState(ETHERCAT_STATE_CHANGE_TIMEOUT, eEcatState_INIT);
        if (EC_E_NOERROR != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot stop EtherCAT-Master: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
        }
    }
    /* Unregister client */
    if (S_oRegisterResults.dwClntId != 0)
    {
        dwRes = ecatUnregisterClient(S_oRegisterResults.dwClntId);
        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));
        }
        S_oRegisterResults.dwClntId = 0;
    }

   /* Shutdown tEcJobTask */
    CEcTimer oTimeout;
    pDemoThreadParam->bJobThreadShutdown = EC_TRUE;
    oTimeout.Start(2000);
    while (pDemoThreadParam->bJobThreadRunning && !oTimeout.IsElapsed())
    {
        OsSleep(10);
    }
    if (S_pvtJobThread != EC_NULL)
    {
        OsDeleteThreadHandle(S_pvtJobThread);
        S_pvtJobThread = EC_NULL;
    }

    /* Deinitialize master */
    dwRes = ecatDeinitMaster();
    if (EC_E_NOERROR != dwRes)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Cannot de-initialize EtherCAT-Master: %s (0x%lx)\n", ecatGetText(dwRes), dwRes));
    }

    if (pDemoThreadParam->TscMeasDesc.bMeasEnabled)
    {
        PERF_MEASURE_JOBS_DEINIT();
    }
    /* delete notification context */
    SafeDelete(pDemoThreadParam->pNotInst);

    return dwRetVal;
}


/**
 * 初期化処理
 */
static EC_T_DWORD myAppInit(T_DEMO_THREAD_PARAM* pDemoThreadParam)
{
    EC_UNREFPARM(pDemoThreadParam);
    Error_Block eb;

    memset(&inputProcessData[0], 0, sizeof(inputProcessData));
    memset(&outputProcessData[0], 0, sizeof(outputProcessData));

    // プロセスデータ受信タスク用、通知イベントオブジェクト作成
    memset(&processRxTaskParam, 0, sizeof(processRxTaskParam));

    Error_init(&eb);
    Event_Handle rxEvent = Event_create(NULL, &eb);
    processRxTaskParam.eventHnd = rxEvent;
    processRxTaskParam.dataBuffer = processData;
    processRxTaskParam.inputDataBuff = &inputProcessData[0];
    processRxTaskParam.inputDataSize = sizeof(inputProcessData);
    // プロセスデータ受信タスク起動
    OsCreateThread( (EC_T_CHAR*)"tprocRxTask", (EC_PF_THREADENTRY)InProcessRxTask, PROC_RX_THREAD_PRIO, LOG_THREAD_STACKSIZE, (EC_T_VOID*)&processRxTaskParam );

    // プロセスデータ出力タスク用、通知イベント、タスク起動パラメータ作成
    Event_Handle txEvent = Event_create(NULL, &eb);
    processTxTaskParam.eventHnd = txEvent;
    processTxTaskParam.dataBuffer = processData;
    processTxTaskParam.outputDataBuff = &outputProcessData[0];
    processTxTaskParam.outputDataSize = sizeof(outputProcessData);
    // プロセス出力データ転送タスク起動
     OsCreateThread( (EC_T_CHAR*)"tprocTxTask", (EC_PF_THREADENTRY)OutProcessTxTask, PROC_RX_THREAD_PRIO, LOG_THREAD_STACKSIZE, (EC_T_VOID*)&processTxTaskParam );

    return EC_E_NOERROR;
}










/********************************************************************************/
/** \brief  Trigger jobs to drive master, and update process data.
*
* \return N/A
*/
static EC_T_VOID tEcJobTask(EC_T_VOID* pvThreadParamDesc)
{
    EC_T_DWORD           dwRes             = EC_E_ERROR;
    T_DEMO_THREAD_PARAM* pDemoThreadParam  = (T_DEMO_THREAD_PARAM*)pvThreadParamDesc;
    EC_T_CPUSET          CpuSet;
    EC_T_INT             nOverloadCounter  = 0;               /* counter to check if cycle time is to short */
    EC_T_BOOL            bOk;
    EC_T_USER_JOB_PARMS  oJobParms;
    OsMemset(&oJobParms, 0, sizeof(EC_T_USER_JOB_PARMS));

    int rxCount = 0;

    EC_CPUSET_ZERO(CpuSet);
    EC_CPUSET_SET(CpuSet, pDemoThreadParam->dwCpuIndex);
    bOk = OsSetThreadAffinity(EC_NULL, CpuSet);
    if (!bOk)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Error: Set job task affinitiy, invalid CPU index %d\n", pDemoThreadParam->dwCpuIndex));
        goto Exit;
    }

    /* demo loop */
    pDemoThreadParam->bJobThreadRunning = EC_TRUE;
    do
    {
        /* wait for next cycle (event from scheduler task) */
 //       OsWaitForEvent(pDemoThreadParam->pvTimingEvent, EC_WAITINFINITE);
 //       UInt events = Event_pend((Event_Handle)pDemoThreadParam->pvTimingEvent, Event_Id_NONE, Event_Id_00, BIOS_WAIT_FOREVER);

        PERF_JOB_END(PERF_CycleTime);
        PERF_JOB_START(PERF_CycleTime);

        /* process all received frames (read new input values) */
        PERF_JOB_START(JOB_ProcessAllRxFrames);
        dwRes = ecatExecJob(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: ecatExecJob( eUsrJob_ProcessAllRxFrames): %s (0x%lx)\n", ecatGetText(dwRes), dwRes));
        }
        PERF_JOB_END(JOB_ProcessAllRxFrames);

        if (EC_E_NOERROR == dwRes)
        {
            if (!oJobParms.bAllCycFramesProcessed)
            {
                /* it is not reasonable, that more than 5 continuous frames are lost */
                nOverloadCounter += 10;
                if (nOverloadCounter >= 50)
                {
                    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Error: System overload: Cycle time too short or huge jitter!\n"));
                }
                else
                {
                    EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "eUsrJob_ProcessAllRxFrames - not all previously sent frames are received/processed (frame loss)!\n"));
                }
                if (pDemoThreadParam->TscMeasDesc.bMeasEnabled)
                {
                    EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "PerfMsmt '%s' (current) [usec]: %3d.%d\n", S_aszMeasInfo[PERF_CycleTime], pDemoThreadParam->TscMeasDesc.aTscTime[PERF_CycleTime].dwCurr / 10, pDemoThreadParam->TscMeasDesc.aTscTime[PERF_CycleTime].dwCurr % 10));
                }
            }
            else
            {
                /* everything o.k.? If yes, decrement overload counter */
                if (nOverloadCounter > 0)    nOverloadCounter--;
            }
        }

        /*****************************************************/
        /* Demo code: Remove/change this in your application: Working process data cyclic call */
        /*****************************************************/
        PERF_JOB_START(PERF_myAppWorkpd);
        {
            // 受信データ転送タスク起動
            Event_post(processRxTaskParam.eventHnd, UInt Event_Id_00);

#if 0            // サンプル処理をコメント
          EC_T_BYTE* abyPdIn = ecatGetProcessImageInputPtr();
          EC_T_BYTE* abyPdOut = ecatGetProcessImageOutputPtr();

            if((abyPdIn != EC_NULL) && (abyPdOut != EC_NULL))
            {
                myAppWorkpd(pDemoThreadParam, abyPdIn, abyPdOut);
            }
#endif //サンプル
        }
        PERF_JOB_END(PERF_myAppWorkpd);
        // -------------------------------------------------------------------
        /* write output values of current cycle, by sending all cyclic frames */
        PERF_JOB_START(JOB_SendAllCycFrames);
        dwRes = ecatExecJob(eUsrJob_SendAllCycFrames, &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, "ecatExecJob( eUsrJob_SendAllCycFrames,    EC_NULL ): %s (0x%lx)\n", ecatGetText(dwRes), dwRes));
        }
        PERF_JOB_END(JOB_SendAllCycFrames);
        /* remove this code when using licensed version */
        if (EC_E_EVAL_EXPIRED == dwRes)
        {
            bRun = EC_FALSE;        /* set shutdown flag */
        }
        //-------------------------------------------------------------
        /* Execute some administrative jobs. No bus traffic is performed by this function */
        PERF_JOB_START(JOB_MasterTimer);
        dwRes = ecatExecJob(eUsrJob_MasterTimer, EC_NULL);
        if (EC_E_NOERROR != dwRes && EC_E_INVALIDSTATE != dwRes)
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ecatExecJob(eUsrJob_MasterTimer, EC_NULL): %s (0x%lx)\n", ecatGetText(dwRes), dwRes));
        }
        PERF_JOB_END(JOB_MasterTimer);
        //-------------------------------------------------------------

        /* send queued acyclic EtherCAT frames */
        PERF_JOB_START(JOB_SendAcycFrames);
        dwRes = ecatExecJob(eUsrJob_SendAcycFrames, 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, "ecatExecJob(eUsrJob_SendAcycFrames, EC_NULL): %s (0x%lx)\n", ecatGetText(dwRes), dwRes));
        }
        PERF_JOB_END(JOB_SendAcycFrames);

        // -------------------------------------------------------------------
        rxCount++;
         if (rxCount >= 1000) {
                rxCount = 0;
                // 送信データを更新して送信準備
                // 出力データを作成
                myAppWorkpd(pDemoThreadParam,
                            &inputProcessData[0], &outputProcessData[0]);


                // 送信データ転送タスク起動
                Event_post(processTxTaskParam.eventHnd, UInt Event_Id_00);
         }
    } while (!pDemoThreadParam->bJobThreadShutdown);



    PERF_MEASURE_JOBS_SHOW();

    pDemoThreadParam->bJobThreadRunning = EC_FALSE;


Exit:
    return;
}

/********************************************************************************/
/** \brief  Handler for master notifications
*
* \return  Status value.
*/
static EC_T_DWORD ecatNotifyCallback(
    EC_T_DWORD         dwCode,  /**< [in]   Notification code */
    EC_T_NOTIFYPARMS*  pParms   /**< [in]   Notification parameters */
                                         )
{
    EC_T_DWORD dwRetVal = EC_E_NOERROR;
    T_DEMO_THREAD_PARAM* pDemoThreadParam = EC_NULL;

    if ((EC_NULL == pParms) || (EC_NULL == pParms->pCallerData))
    {
        dwRetVal = EC_E_INVALIDPARM;
        goto Exit;
    }

    pDemoThreadParam = (T_DEMO_THREAD_PARAM*)(pParms->pCallerData);

    /* notification for application ? */
    if ((dwCode >= EC_NOTIFY_APP) && (dwCode <= EC_NOTIFY_APP+EC_NOTIFY_APP_MAX_CODE))
    {
        /*****************************************************/
        /* Demo code: Remove/change this in your application */
        /* to get here the API ecatNotifyApp(dwCode, pParms) has to be called */
        /*****************************************************/
        dwRetVal = myAppNotify(dwCode - EC_NOTIFY_APP, pParms);
    }
    else
    {
        /* call the default handler */
        dwRetVal = pDemoThreadParam->pNotInst->ecatNotify(dwCode, pParms);
    }

Exit:
    return dwRetVal;
}

/*-MYAPP---------------------------------------------------------------------*/


/***************************************************************************************************/
/**
\brief  Initialize Slave Instance.

Find slave parameters.
\return EC_E_NOERROR on success, error code otherwise.
*/
static EC_T_DWORD myAppPrepare(T_DEMO_THREAD_PARAM* pDemoThreadParam)
{
    EC_T_WORD           wFixedAddress = INVALID_FIXED_ADDR;
    EC_T_CFG_SLAVE_INFO oCfgSlaveListInfo;
    EC_T_DWORD          dwRes         = EC_E_NOERROR;
    OsMemset(&oCfgSlaveListInfo, 0, sizeof(EC_T_CFG_SLAVE_INFO));

    EC_UNREFPARM(pDemoThreadParam);

    // 試験用スレーブを追加 cosmo EtherCAT
    if (!FindSlaveGetFixedAddr(pDemoThreadParam, INSTANCE_MASTER_DEFAULT,  ecvendor_cosmo, ecprodcode_cosmo_cat, &wFixedAddress))
    {
        return -1;
    }


        /* now get the offset of this device in the process data buffer and some other infos */
    dwRes = ecatGetCfgSlaveInfo(EC_TRUE, wFixedAddress, &oCfgSlaveListInfo);
    if (dwRes != EC_E_NOERROR)
    {
        EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "ERROR: ecatGetCfgSlaveInfo() returns with error=0x%x, slave address=%d\n", dwRes, wFixedAddress));
    } else {
        if(oCfgSlaveListInfo.dwPdSizeOut != 0)
        {
            pDemoThreadParam->FlashData.dwFlashPDOutSize = oCfgSlaveListInfo.dwPdSizeOut;
            pDemoThreadParam->FlashData.dwFlashPdOffsOut = oCfgSlaveListInfo.dwPdOffsOut;
        }
        else
        {
            EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "Slave address=%d has no outputs, therefore flashing not possible\n", wFixedAddress));
        }
    }

    return EC_E_NOERROR;
}

/***************************************************************************************************/
/**
\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_DEMO_THREAD_PARAM* pDemoThreadParam)
{
    EC_UNREFPARM(pDemoThreadParam);

    return EC_E_NOERROR;
}

/***************************************************************************************************/
/**
\brief  demo application working process data function.

  This function is called in every cycle after the the master stack is started.

*/
static EC_T_DWORD myAppWorkpd(T_DEMO_THREAD_PARAM* pDemoThreadParam,
    EC_T_BYTE*          pbyPDIn,        /* [in]  pointer to process data input buffer */
    EC_T_BYTE*          pbyPDOut        /* [in]  pointer to process data output buffer */
    )
{


    EC_UNREFPARM(pDemoThreadParam);
    EC_UNREFPARM(pbyPDIn);


#if 0   // テストデータ作成処理を思えるのでコメント
         pbyVal = (EC_T_BYTE*)&pbyPDIn[pMySlave->dwPdOffsIn/8];
         inVal = *pbyVal;
         inVal++;
         pbyVal = (EC_T_BYTE*)&pbyPDOut[pMySlave->dwPdOffsOut/8];
         *pbyVal = inVal;
#endif






#if 0 // サンプルコード
    /* demo code flashing */
    if (pDemoThreadParam->FlashData.dwFlashPDOutSize != 0)
    {
        pDemoThreadParam->FlashData.dwFlashTimer += pDemoThreadParam->dwBusCycleTimeUsec;
        if (pDemoThreadParam->FlashData.dwFlashTimer >= 20000)     /* flash with 20 msec */
        {
            pDemoThreadParam->FlashData.dwFlashTimer = 0;

            if (pDemoThreadParam->FlashData.nFlashAddress == 0)
            {
                /* flash all */
                OsMemset(pbyPDOut, pDemoThreadParam->FlashData.byFlashVal, pDemoThreadParam->FlashData.dwFlashPDOutSize);
                pDemoThreadParam->FlashData.byFlashVal++;
            }
            else if (pDemoThreadParam->FlashData.nFlashAddress > 0)
            {
                EC_GETBITS(pbyPDOut, &pDemoThreadParam->FlashData.byFlashVal, pDemoThreadParam->FlashData.dwFlashPdOffsOut, pDemoThreadParam->FlashData.dwFlashPDOutSize);
                pDemoThreadParam->FlashData.byFlashVal++;
                EC_SETBITS(pbyPDOut, &pDemoThreadParam->FlashData.byFlashVal, pDemoThreadParam->FlashData.dwFlashPdOffsOut, pDemoThreadParam->FlashData.dwFlashPDOutSize);
            }
        }
    }
#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_DEMO_THREAD_PARAM* pDemoThreadParam)
{
    EC_UNREFPARM(pDemoThreadParam);

    return EC_E_NOERROR;
}

/********************************************************************************/
/** \brief  Handler for application notifications
*
*  !!! No blocking API shall be called within this function!!!
*  !!! Function is called by cylic task                    !!!
*
* \return  Status value.
*/
static EC_T_DWORD myAppNotify(
    EC_T_DWORD              dwCode,     /* [in]  Application notification code */
    EC_T_NOTIFYPARMS*       pParms      /* [in]  Notification parameters */
    )
{
    EC_T_DWORD dwRetVal = EC_E_ERROR;
#if (defined INCLUDE_LOG_MESSAGES)
    T_DEMO_THREAD_PARAM* pDemoThreadParam = (T_DEMO_THREAD_PARAM*)(pParms->pCallerData);
#else
    EC_UNREFPARM(pParms);
#endif

    /* dispatch notification code */
    switch(dwCode)
    {
    case 1:
        EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "Application notification code=%d received\n", dwCode));
        /* dwRetVal = EC_E_NOERROR; */
        break;
    case 2:
        break;
    default:
        break;
    }

    return dwRetVal;
}

/**
 * ENI情報より決定した、プロセスデータサイズを取得する。
 * @param aInfo CAT情報クラス
 *
 */
static void getProcessDataSize(CatDataInfo *aInfo) {

    EC_T_MEMREQ_DESC dataSize;  // 結果取得用バッファ
    EC_T_DWORD infoLen;
    EC_T_DWORD stat;

    // マスタースタックより情報を取得
    stat =  ecatIoCtl(EC_IOCTL_GET_PDMEMORYSIZE,
                         EC_NULL, 0, &dataSize, sizeof(dataSize), &infoLen);

    if (stat == EC_E_NOERROR) {
        UART_printf("no error Out Size = %d, IN = %d\n", dataSize.dwPDOutSize, dataSize.dwPDInSize);
        aInfo->inDataSize = dataSize.dwPDInSize;
        aInfo->outDataSize = dataSize.dwPDOutSize;
    } else {
        UART_printf("サイズ取得エラー　");

    }
}

/**
 * プロセスデータの送受信バッファを指示するためのコールバックハンドラを設定する。
 */
static EC_T_DWORD registMemoryProvider() {
    EC_T_DWORD stat = 0;

    memHandlParam.inDataAddr = NULL;
    memHandlParam.outDataAddr = NULL;
    memHandlParam.processData = processData;

    EC_T_MEMPROV_DESC memoryDesc;

    memoryDesc.pvContext = &memHandlParam;    // ハンドラへのパラメータ情報ポインタ
// 無くなってる    memoryDesc.bUseMasterShadowInUserSyncNowaitMode = EC_FALSE;    // 未使用
    memoryDesc.pbyPDOutData = EC_NULL;     // 出力データポインタ
    memoryDesc.dwPDOutDataLength = 192 * 8; // データbitサイズ（暫定）ecatIoControl - EC_IOCTL_GET_PDMEMORYSIZE で取得すること
    memoryDesc.pbyPDInData = EC_NULL;          // 入力データポインタ
    memoryDesc.dwPDInDataLength = 192 * 8;  // 入力データbitサイズ（暫定）
    memoryDesc.pfPDOutDataReadRequest = pfPDOutReadRequest;
    memoryDesc.pfPDOutDataReadRelease = pfPDOutReadRelease;
    memoryDesc.pfPDInDataWriteRequest = pfPDInWriteRequest;
    memoryDesc.pfPDInDataWriteRelease = pfPDInWriteRelease;


    stat =  ecatIoCtl(EC_IOCTL_REGISTER_PDMEMORYPROVIDER,
                      &memoryDesc, sizeof(memoryDesc), EC_NULL, 0, EC_NULL);

    return stat;

}

// ------------------- スタップへの登録ハンドラ ------------

/**
 * 受信バッファへの入力データ書込み開始通知ハンドラ
 * 書込み先受信バッファアドレスを返す。
 */
static EC_T_VOID pfPDInWriteRequest(EC_T_PVOID pvContext, EC_T_DWORD dwTaskID, EC_T_PBYTE* ppbyPDInData) {
    MEMORY_HANDL_PARAM* param;
    EC_T_BYTE* inDataAddr;

    // パラメータ内のバッファ管理クラスより使用可能なバッファアドレスを取得
    param = (MEMORY_HANDL_PARAM*)pvContext;
    inDataAddr = param->processData->getRxFreeBuffer();

    param->inDataAddr = inDataAddr;
    *ppbyPDInData = inDataAddr;
}

/**
 * 受信バッファへの入力データ書込み完了通知ハンドラ
 */
static EC_T_VOID pfPDInWriteRelease(EC_T_PVOID pvContext,  EC_T_DWORD dwTaskID) {
    MEMORY_HANDL_PARAM* param;
    param = (MEMORY_HANDL_PARAM*)pvContext;
    // バッファ状態を受信完了とする。
    param->processData->indRxEnd(param->inDataAddr);
}

/**
 * 出力データ読み込み開始ハンドラ
 * 出力データのバッファアドレスを返す。
 */
static EC_T_VOID pfPDOutReadRequest(EC_T_PVOID pvContext, EC_T_DWORD dwTaskID, EC_T_PBYTE* ppbyPDOutData) {
    MEMORY_HANDL_PARAM* param;
    EC_T_BYTE* outDataAddr;

    if (dwTaskID != TASKID_COMPLETE_PD) {
        return;
    }
    // 送信（出力）データが用意されたバッファアドレスを取得
    param = (MEMORY_HANDL_PARAM*)pvContext;
    outDataAddr = param->processData->getTxDataBuffer();

    param->outDataAddr = outDataAddr;
    *ppbyPDOutData = outDataAddr;

    param->processData->checkTxAddr(outDataAddr);

}

/**
 * 送信（出力）完了通知ハンドラ
 */
static EC_T_VOID pfPDOutReadRelease(EC_T_PVOID pvContext, EC_T_DWORD dwTaskID) {
    MEMORY_HANDL_PARAM* param;
    param = (MEMORY_HANDL_PARAM*)pvContext;
    // バッファ状態を受信完了とする。
    param->processData->indTxEnd(param->outDataAddr);
}

/**
 * 送信する出力データの初期値を設定し、バッファ管理に登録する。
 */
static void setInitTxData(ProcessDataBuffer* aProBuff) {

    // 未使用の送信データ用バッファを取得
    EC_T_BYTE* p_txBuff = aProBuff->getOutDataWriteBuffer();
    // データ領域をクリア
    OsMemset(p_txBuff, 0, aProBuff->txBufferByteSize);
    // データ領域を返す
    aProBuff->indMoveEnd(p_txBuff);
}
/*-END OF SOURCE FILE--------------------------------------------------------*/
