//------------------------------------------------------------------------------
static tOplkError initPowerlink(tInstance* pInstance_p)
{
    tOplkError                  ret = kErrorOk;
    static tOplkApiInitParam    initParam;

    PRINTF("Initializing openPOWERLINK stack...\n");

    OPLK_MEMSET(&initParam, 0, sizeof(initParam));
    initParam.sizeOfInitParam = sizeof(initParam);

    initParam.nodeId = pInstance_p->nodeId;
    initParam.ipAddress = (0xFFFFFF00 & IP_ADDR) | initParam.nodeId;

    OPLK_MEMCPY(initParam.aMacAddress, pInstance_p->aMacAddr, sizeof(initParam.aMacAddress));

    initParam.fAsyncOnly              = FALSE;
    initParam.featureFlags            = -1;
    initParam.cycleLen                = pInstance_p->cycleLen;  // required for error detection
    initParam.isochrTxMaxPayload      = 36;                     // const
    initParam.isochrRxMaxPayload      = 36;                     // const
    initParam.presMaxLatency          = 2000;                   // const; only required for IdentRes
    initParam.asndMaxLatency          = 2000;                   // const; only required for IdentRes
    initParam.preqActPayloadLimit     = 36;                     // required for initialization (+28 bytes)
    initParam.presActPayloadLimit     = 36;                     // required for initialization of Pres frame (+28 bytes)
    initParam.multiplCylceCnt         = 0;                      // required for error detection
    initParam.asyncMtu                = 300;                    // required to set up max frame size
    initParam.prescaler               = 2;                      // required for sync
    initParam.lossOfFrameTolerance    = 100000;
    initParam.asyncSlotTimeout        = 3000000;
    initParam.waitSocPreq             = 0;
    initParam.deviceType              = -1;               // NMT_DeviceType_U32
    initParam.vendorId                = -1;               // NMT_IdentityObject_REC.VendorId_U32
    initParam.productCode             = -1;               // NMT_IdentityObject_REC.ProductCode_U32
    initParam.revisionNumber          = -1;               // NMT_IdentityObject_REC.RevisionNo_U32
    initParam.serialNumber            = -1;               // NMT_IdentityObject_REC.SerialNo_U32
    initParam.applicationSwDate       = 0;
    initParam.applicationSwTime       = 0;
    initParam.subnetMask              = SUBNET_MASK;
    initParam.defaultGateway          = DEFAULT_GATEWAY;
    sprintf((char*)initParam.sHostname, "%02x-%08x", initParam.nodeId, initParam.vendorId);
    initParam.syncNodeId              = C_ADR_SYNC_ON_SOC;
    initParam.fSyncOnPrcNode          = FALSE;

    // set callback functions
    initParam.pfnCbEvent = processEvents;
    initParam.pfnCbSync  = processSync;

    // initialize POWERLINK stack
    ret = oplk_init(&initParam);
    if (ret != kErrorOk)
    {
        PRINTF("oplk_init() failed (Error:0x%x!\n", ret);
        return ret;
    }

    return kErrorOk;
}
//------------------------------------------------------------------------------
static tOplkError initPowerlink(UINT32 cycleLen_p, char* pszCdcFileName_p,
                                const BYTE* macAddr_p)
{
    tOplkError                  ret = kErrorOk;
    static tOplkApiInitParam    initParam;
    static char                 devName[128];

    printf("Initializing openPOWERLINK stack...\n");

#if defined(CONFIG_USE_PCAP)
    if (selectPcapDevice(devName) < 0)
        return kErrorIllegalInstance;
#elif defined(__COBALT__)
    if (selectDevice(devName) < 0)
        return kErrorIllegalInstance;
#endif

    memset(&initParam, 0, sizeof(initParam));
    initParam.sizeOfInitParam = sizeof(initParam);

    // pass selected device name to Edrv
    initParam.hwParam.pDevName = devName;
    initParam.nodeId = NODEID;
    initParam.ipAddress = (0xFFFFFF00 & IP_ADDR) | initParam.nodeId;

    /* write 00:00:00:00:00:00 to MAC address, so that the driver uses the real hardware address */
    memcpy(initParam.aMacAddress, macAddr_p, sizeof(initParam.aMacAddress));

    initParam.fAsyncOnly              = FALSE;
    initParam.featureFlags            = UINT_MAX;
    initParam.cycleLen                = cycleLen_p;       // required for error detection
    initParam.isochrTxMaxPayload      = 256;              // const
    initParam.isochrRxMaxPayload      = 256;              // const
    initParam.presMaxLatency          = 50000;            // const; only required for IdentRes
    initParam.preqActPayloadLimit     = 36;               // required for initialisation (+28 bytes)
    initParam.presActPayloadLimit     = 36;               // required for initialisation of Pres frame (+28 bytes)
    initParam.asndMaxLatency          = 150000;           // const; only required for IdentRes
    initParam.multiplCylceCnt         = 0;                // required for error detection
    initParam.asyncMtu                = 1500;             // required to set up max frame size
    initParam.prescaler               = 2;                // required for sync
    initParam.lossOfFrameTolerance    = 500000;
    initParam.asyncSlotTimeout        = 3000000;
    initParam.waitSocPreq             = 1000;
    initParam.deviceType              = UINT_MAX;         // NMT_DeviceType_U32
    initParam.vendorId                = UINT_MAX;         // NMT_IdentityObject_REC.VendorId_U32
    initParam.productCode             = UINT_MAX;         // NMT_IdentityObject_REC.ProductCode_U32
    initParam.revisionNumber          = UINT_MAX;         // NMT_IdentityObject_REC.RevisionNo_U32
    initParam.serialNumber            = UINT_MAX;         // NMT_IdentityObject_REC.SerialNo_U32

    initParam.subnetMask              = SUBNET_MASK;
    initParam.defaultGateway          = DEFAULT_GATEWAY;
    sprintf((char*)initParam.sHostname, "%02x-%08x", initParam.nodeId, initParam.vendorId);
    initParam.syncNodeId              = C_ADR_SYNC_ON_SOA;
    initParam.fSyncOnPrcNode          = FALSE;

    // set callback functions
    initParam.pfnCbEvent = processEvents;

#if defined(CONFIG_KERNELSTACK_DIRECTLINK)
    initParam.pfnCbSync  = processSync;
#else
    initParam.pfnCbSync  = NULL;
#endif

    // initialize POWERLINK stack
    ret = oplk_init(&initParam);
    if (ret != kErrorOk)
    {
        fprintf(stderr, "oplk_init() failed with \"%s\" (0x%04x)\n", debugstr_getRetValStr(ret), ret);
        return ret;
    }

    ret = oplk_setCdcFilename(pszCdcFileName_p);
    if (ret != kErrorOk)
    {
        fprintf(stderr, "oplk_setCdcFilename() failed with \"%s\" (0x%04x)\n", debugstr_getRetValStr(ret), ret);
        return ret;
    }

    return kErrorOk;
}
//------------------------------------------------------------------------------
static tOplkError initPowerlink(tInstance* pInstance_p)
{
    tOplkError                  ret = kErrorOk;
    static tOplkApiInitParam    initParam;

    PRINTF("Initializing openPOWERLINK stack...\n");

    memset(&initParam, 0, sizeof(initParam));
    initParam.sizeOfInitParam = sizeof(initParam);

    initParam.nodeId = pInstance_p->nodeId;
    initParam.ipAddress = (0xFFFFFF00 & IP_ADDR) | initParam.nodeId;

    memcpy(initParam.aMacAddress, pInstance_p->aMacAddr, sizeof(initParam.aMacAddress));

    initParam.fAsyncOnly              = FALSE;
    initParam.featureFlags            = -1;
    initParam.cycleLen                = pInstance_p->cycleLen;  // required for error detection
    initParam.isochrTxMaxPayload      = 256;                    // const
    initParam.isochrRxMaxPayload      = 256;                    // const
    initParam.presMaxLatency          = 50000;                  // const; only required for IdentRes
    initParam.preqActPayloadLimit     = 36;                     // required for initialisation (+28 bytes)
    initParam.presActPayloadLimit     = 36;                     // required for initialisation of Pres frame (+28 bytes)
    initParam.asndMaxLatency          = 150000;                 // const; only required for IdentRes
    initParam.multiplCylceCnt         = 0;                      // required for error detection
    initParam.asyncMtu                = 1500;                   // required to set up max frame size
    initParam.prescaler               = 2;                      // required for sync
    initParam.lossOfFrameTolerance    = 500000;
    initParam.asyncSlotTimeout        = 3000000;
    initParam.waitSocPreq             = -1;
    initParam.deviceType              = -1;                     // NMT_DeviceType_U32
    initParam.vendorId                = -1;                     // NMT_IdentityObject_REC.VendorId_U32
    initParam.productCode             = -1;                     // NMT_IdentityObject_REC.ProductCode_U32
    initParam.revisionNumber          = -1;                     // NMT_IdentityObject_REC.RevisionNo_U32
    initParam.serialNumber            = -1;                     // NMT_IdentityObject_REC.SerialNo_U32

    initParam.subnetMask              = SUBNET_MASK;
    initParam.defaultGateway          = DEFAULT_GATEWAY;
    sprintf((char*)initParam.sHostname, "%02x-%08x", initParam.nodeId, initParam.vendorId);
    initParam.syncNodeId              = C_ADR_SYNC_ON_SOC;
    initParam.fSyncOnPrcNode          = FALSE;

    // set callback functions
    initParam.pfnCbEvent = processEvents;
    initParam.pfnCbSync  = processSync;

    // initialize POWERLINK stack
    ret = oplk_init(&initParam);
    if (ret != kErrorOk)
    {
        PRINTF("oplk_init() failed with \"%s\"\n(Error:0x%x!)\n", debugstr_getRetValStr(ret), ret);
        return ret;
    }

    ret = oplk_setCdcBuffer(pInstance_p->pCdcBuffer, pInstance_p->cdcBufferSize);
    if (ret != kErrorOk)
    {
        PRINTF("oplk_setCdcBuffer() failed with \"%s\"\n(Error:0x%x!)\n", debugstr_getRetValStr(ret), ret);
        return ret;
    }

    // Set real MAC address to ARP module
    oplk_getEthMacAddr(initParam.aMacAddress);
    arp_setMacAddr(initParam.aMacAddress);

    // Set IP address to ARP module
    arp_setIpAddr(initParam.ipAddress);

    // Set default gateway to ARP module
    arp_setDefGateway(initParam.defaultGateway);

    return kErrorOk;
}
//------------------------------------------------------------------------------
Api::Api(MainWindow* pMainWindow_p, UINT nodeId_p, QString devName_p)
{
    tOplkError          ret;
    State*              pState;
    Output*             pOutput;
    Input*              pInput;
    CnState*            pCnState;

    pState = pMainWindow_p->getStateWidget();
    pOutput = pMainWindow_p->getOutputWidget();
    pInput = pMainWindow_p->getInputWidget();
    pCnState = pMainWindow_p->getCnStateWidget();

    pProcessThread = new ProcessThread(pMainWindow_p);
    QObject::connect(pProcessThread, SIGNAL(oplkStatusChanged(int)),
                     pState, SLOT(setStatusLed(int)));
    QObject::connect(pProcessThread, SIGNAL(nmtStateChanged(const QString&)),
                     pState, SLOT(setNmtStateText(const QString &)));

    QObject::connect(pProcessThread, SIGNAL(nodeAppeared(int)),
                     pInput, SLOT(addNode(int)));
    QObject::connect(pProcessThread, SIGNAL(allNodesRemoved()),
                     pInput, SLOT(removeAllNodes()));
    QObject::connect(pProcessThread, SIGNAL(nodeDisappeared(int)),
                     pInput, SLOT(removeNode(int)));

    QObject::connect(pProcessThread, SIGNAL(nodeAppeared(int)),
                     pOutput, SLOT(addNode(int)));
    QObject::connect(pProcessThread, SIGNAL(nodeDisappeared(int)),
                     pOutput, SLOT(removeNode(int)));
    QObject::connect(pProcessThread, SIGNAL(allNodesRemoved()),
                     pOutput, SLOT(removeAllNodes()));

    QObject::connect(pProcessThread, SIGNAL(nodeAppeared(int)),
                     pCnState, SLOT(addNode(int)));
    QObject::connect(pProcessThread, SIGNAL(nodeDisappeared(int)),
                     pCnState, SLOT(removeNode(int)));
    QObject::connect(pProcessThread, SIGNAL(allNodesRemoved()),
                     pCnState, SLOT(removeAllNodes()));

    QObject::connect(pProcessThread, SIGNAL(nodeStatusChanged(int, int)),
                     pCnState, SLOT(setState(int, int)));

    QObject::connect(pProcessThread, SIGNAL(printLog(const QString&)),
                     pMainWindow_p, SLOT(printlog(const QString&)));


    pDataInOutThread = new DataInOutThread;
    QObject::connect(pDataInOutThread, SIGNAL(processImageOutChanged(int, int)),
                     pOutput, SLOT(setValue(int, int)));
    QObject::connect(pDataInOutThread, SIGNAL(processImageInChanged(int, int)),
                     pInput, SLOT(setLeds(int, int)));

    OPLK_MEMSET(&initParam, 0, sizeof(initParam));
    initParam.sizeOfInitParam = sizeof(initParam);

    initParam.nodeId = nodeId_p;
    initParam.ipAddress = (IP_ADDR & 0xFFFFFF00) | initParam.nodeId;

    initParam.fAsyncOnly = FALSE;
    initParam.featureFlags = UINT_MAX;
    initParam.cycleLen = CYCLE_LEN;           // required for error detection
    initParam.isochrTxMaxPayload = 256;       // const
    initParam.isochrRxMaxPayload = 256;       // const
    initParam.presMaxLatency = 50000;         // const; only required for IdentRes
    initParam.preqActPayloadLimit = 36;       // required for initialisation (+28 bytes)
    initParam.presActPayloadLimit = 36;       // required for initialisation of Pres frame (+28 bytes)
    initParam.asndMaxLatency = 150000;        // const; only required for IdentRes
    initParam.multiplCylceCnt = 0;            // required for error detection
    initParam.asyncMtu = 1500;                // required to set up max frame size
    initParam.prescaler = 2;                  // required for sync
    initParam.lossOfFrameTolerance = 500000;
    initParam.asyncSlotTimeout = 3000000;
    initParam.waitSocPreq = 150000;
    initParam.deviceType = UINT_MAX;          // NMT_DeviceType_U32
    initParam.vendorId = UINT_MAX;            // NMT_IdentityObject_REC.VendorId_U32
    initParam.productCode = UINT_MAX;         // NMT_IdentityObject_REC.ProductCode_U32
    initParam.revisionNumber = UINT_MAX;      // NMT_IdentityObject_REC.RevisionNo_U32
    initParam.serialNumber = UINT_MAX;        // NMT_IdentityObject_REC.SerialNo_U32

    initParam.subnetMask = SUBNET_MASK;
    initParam.defaultGateway = DEFAULT_GATEWAY;
    sprintf((char*)initParam.sHostname, "%02x-%08x", initParam.nodeId, initParam.vendorId);
    initParam.syncNodeId = C_ADR_SYNC_ON_SOA;
    initParam.fSyncOnPrcNode = FALSE;

    // set callback functions
    initParam.pfnCbEvent = pProcessThread->getEventCbFunc();

    /* write 00:00:00:00:00:00 to MAC address, so that the driver uses the real hardware address */
    OPLK_MEMCPY(initParam.aMacAddress, abMacAddr, sizeof(initParam.aMacAddress));

    // Copy the selected interface string to a local variable
    strcpy(devName_g, devName_p.toStdString().c_str());
    initParam.hwParam.pDevName = devName_g;

#if defined(CONFIG_KERNELSTACK_DIRECTLINK)
    initParam.pfnCbSync = pDataInOutThread->getSyncCbFunc();
#else
    initParam.pfnCbSync  =    NULL;
#endif

    // init POWERLINK
    ret = oplk_init(&initParam);
    if (ret != kErrorOk)
    {
        QMessageBox::critical(0, "POWERLINK demo",
                              QString("Initialization of openPOWERLINK Stack failed.\n") +
                                      "Error code: 0x"+ QString::number(ret, 16) +
                                      "\nThe most common error source are an unsupported Ethernet controller or the kernel module is not loaded."
                                      "\nFor further information please consult the manual.");
        goto Exit;
    }

    ret = oplk_setCdcFilename(pszCdcFilename_g);
    if (ret != kErrorOk)
    {
        goto Exit;
    }

    ret = pDataInOutThread->setupProcessImage();
    if (ret != kErrorOk)
    {
        QMessageBox::critical(0, "POWERLINK demo",
                              QString("Initialization of process image failed.\n") +
                                      "Error code: 0x"+ QString::number(ret, 16));
        goto Exit;
    }
    // start the openPOWERLINK stack
    ret = oplk_execNmtCommand(kNmtEventSwReset);

    // start process thread
    pProcessThread->start();

#if !defined(CONFIG_KERNELSTACK_DIRECTLINK)
    // start data in out thread
    pDataInOutThread->start();
#endif

Exit:
    return;

}