6.10. ADS over EtherCAT (AoE)
To handle AoE object transfers within the application, the callbacks pfnAoeRead, pfnAoeWrite and/or pfnAoeReadWrite can be registered using esSetSlaveAoeObjectTransferCallbacks()
or esSetSlaveSscApplication()
, e.g. in myAppPrepare()
of EcSimulatorHilDemo / EcSimulatorSilDemo.
See also AoE Simulator and Master Example
6.10.1. esAoeGetSlaveNetId
-
EC_T_DWORD esAoeGetSlaveNetId(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, EC_T_AOE_NETID *poAoeNetId)
Retrieve the NetID of a specific EtherCAT device.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
dwSlaveId – [in] Slave ID
poAoeNetId – [out] AoE NetID of the corresponding slave
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range, the input pointer is EC_NULL or contains EC_NULL pointer, or dwTimeout is EC_NOWAIT
EC_E_SLAVE_NOT_PRESENT if slave not present
EC_E_NOTFOUND if no slave matching dwSlaveId can be found
EC_E_NO_MBX_SUPPORT if slave has no mailbox support
EC_E_ADS_IS_RUNNING if ADS server is running
6.10.2. esAoeRead
-
EC_T_DWORD esAoeRead(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, EC_T_AOE_NETID *poTargetNetId, EC_T_WORD wTargetPort, EC_T_DWORD dwIndexGroup, EC_T_DWORD dwIndexOffset, EC_T_DWORD dwDataLen, EC_T_BYTE *pbyData, EC_T_DWORD *pdwDataOutLen, EC_T_DWORD *pdwErrorCode, EC_T_DWORD *pdwCmdResult, EC_T_DWORD dwTimeout)
Execute a AoE mailbox read request to an EtherCAT slave device.
This function may not be called from within the JobTask’s context.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
dwSlaveId – [in] Slave ID
poTargetNetId – [in] Target NetID.
wTargetPort – [in] Target port.
dwIndexGroup – [in] AoE read command index group.
dwIndexOffset – [in] AoE read command index offset
dwDataLen – [in] Buffer length [bytes]
pbyData – [out] Buffer receiving transfered data
pdwDataOutLen – [out] Number of bytes read from the target device
pdwErrorCode – [out] AoE response error code
pdwCmdResult – [out] AoE read command result code
dwTimeout – [in] Timeout [ms] The function will block at most for this time.
- Returns
EC_E_AOE_VENDOR_SPECIFIC: will be returned in case the AoE device has responded with an user defined error code
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
6.10.3. esAoeWrite
-
EC_T_DWORD esAoeWrite(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, EC_T_AOE_NETID *poTargetNetId, EC_T_WORD wTargetPort, EC_T_DWORD dwIndexGroup, EC_T_DWORD dwIndexOffset, EC_T_DWORD dwDataLen, EC_T_BYTE *pbyData, EC_T_DWORD *pdwErrorCode, EC_T_DWORD *pdwCmdResult, EC_T_DWORD dwTimeout)
Execute a AoE mailbox write request to an EtherCAT slave device.
This function may not be called from within the JobTask’s context.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
dwSlaveId – [in] Slave ID
poTargetNetId – [in] Target NetID.
wTargetPort – [in] Target port.
dwIndexGroup – [in] AoE write command index group.
dwIndexOffset – [in] AoE write command index offset
dwDataLen – [in] Buffer length [bytes]
pbyData – [in] Buffer containing transfered data
pdwErrorCode – [out] Pointer to AoE response error code.
pdwCmdResult – [out] Pointer to AoE write command result code.
dwTimeout – [in] Timeout [ms] The function will block at most for this time.
- Returns
EC_E_AOE_VENDOR_SPECIFIC: will be returned in case the AoE device has responded with an user defined error code
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
6.10.4. esAoeReadWrite
-
EC_T_DWORD esAoeReadWrite(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, EC_T_AOE_NETID *poTargetNetId, EC_T_WORD wTargetPort, EC_T_DWORD dwIndexGroup, EC_T_DWORD dwIndexOffset, EC_T_DWORD dwReadDataLen, EC_T_DWORD dwWriteDataLen, EC_T_BYTE *pbyData, EC_T_DWORD *pdwDataOutLen, EC_T_DWORD *pdwErrorCode, EC_T_DWORD *pdwCmdResult, EC_T_DWORD dwTimeout)
Execute a AoE mailbox read/write request to an EtherCAT slave device.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
dwSlaveId – [in] Slave ID
poTargetNetId – [in] Target NetID.
wTargetPort – [in] Target port.
dwIndexGroup – [in] AoE read/write command index group.
dwIndexOffset – [in] AoE read/write command index offset
dwReadDataLen – [in] Number of bytes to read from the target device.
dwWriteDataLen – [in] Number of bytes to read from the target device.
pbyData – [in, out] Buffer containing and receiving transfered data
pdwDataOutLen – [out] Number of bytes read from the target device
pdwErrorCode – [out] Pointer to AoE response error code.
pdwCmdResult – [out] Pointer to AoE write command result code.
dwTimeout – [in] Timeout [ms] The function will block at most for this time. EC_NOWAIT is not valid.
- Returns
EC_E_AOE_VENDOR_SPECIFIC: will be returned in case the AoE device has responded with an user defined error code
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
6.10.5. esSetSlaveAoeObjectTransferCallbacks
-
EC_T_DWORD esSetSlaveAoeObjectTransferCallbacks(EC_T_DWORD dwInstanceId, EC_T_WORD wCfgFixedAddress, EC_T_PF_AOE_READ_CB pfRead, EC_T_PF_AOE_WRITE_CB pfWrite, EC_T_PF_AOE_READWRITE_CB pfReadWrite, EC_T_VOID *pvContext)
Set AoE read/write callbacks.
- Parameters
dwInstanceId – [in] Simulator Instance ID
wCfgFixedAddress – [in] Slave’s station address. 0: all slaves
pfRead – [in] Read callback function
pfWrite – [in] Write callback function
pfReadWrite – [in] ReadWrite callback function
pvContext – [in] pointer to context passed as first parameters to callback functions
- Returns
EC_E_NOERROR or error code
6.10.6. AoE Simulator and Master Example
The following example demonstrates how to handle AoE object transfers within the simulator application:
AoE Simulator and Master Example
The following example handlers can be registered at the EC-Simulator:
/* EC_T_PF_AOE_READ_CB */
EC_T_DWORD EC_FNCALL myAppAoeReadObjectCallback(
EC_T_VOID* /* pvContext */, EC_T_DWORD dwSimulatorId, EC_T_WORD wCfgFixedAddress,
EC_T_AOE_NETID* /* poSenderNetId */, EC_T_WORD /* wSenderPort */, EC_T_AOE_NETID* /* poTargetNetId */, EC_T_WORD wTargetPort,
EC_T_DWORD dwIndexGroup, EC_T_DWORD dwIndexOffset,
EC_T_BYTE* pbyReadData, EC_T_DWORD* pdwReadDataLen,
EC_T_DWORD* pdwErrorCode, EC_T_DWORD* pdwCmdResult)
{
if (65535 != wTargetPort)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_TARGET_PORT_NOT_FOUND);
goto Exit;
}
if (0xF302 /* ADSIGRP_CANOPEN_SDO */ != dwIndexGroup)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_INVALIDGRP);
goto Exit;
}
/* check for object 0x2003, subindex 0, no complete access */
if (0x20030000 != dwIndexOffset /* example value */)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_NOTFOUND);
goto Exit;
}
/* check for size of object 0x2003, subindex 0 */
if (4 != EC_GETDWORD(pdwReadDataLen) /* UDINT: sizeof(EC_T_DWORD) */)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_INVALIDSIZE);
goto Exit;
}
/* all checks passed, return data and set success */
EC_SET_FRM_DWORD(pbyReadData, 0x12345678);
EC_SETDWORD(pdwErrorCode, EC_E_NOERROR);
Exit:
EcLogMsg(EC_LOG_LEVEL_VERBOSE, (pEcLogContext, EC_LOG_LEVEL_VERBOSE, "myAppAoeReadObjectCallback(%d, %d, %d, 0x%04X, 0x%04X, %d bytes, 0x%08X, 0x%08X): %s (0x%08X)\n",
dwSimulatorId, wCfgFixedAddress, wTargetPort,
dwIndexGroup, dwIndexOffset, EC_GETDWORD(pdwReadDataLen), EC_GETDWORD(pdwErrorCode), EC_GETDWORD(pdwCmdResult),
esGetText(dwSimulatorId, EC_GETDWORD(pdwErrorCode)), EC_GETDWORD(pdwErrorCode)));
return EC_GETDWORD(pdwErrorCode);
}
/* EC_T_PF_AOE_WRITE_CB */
EC_T_DWORD EC_FNCALL myAppAoeWriteObjectCallback(
EC_T_VOID* /* pvContext */, EC_T_DWORD dwSimulatorId, EC_T_WORD wCfgFixedAddress,
EC_T_AOE_NETID* /* poSenderNetId */, EC_T_WORD /* wSenderPort */, EC_T_AOE_NETID* /* poTargetNetId */, EC_T_WORD wTargetPort,
EC_T_DWORD dwIndexGroup, EC_T_DWORD dwIndexOffset,
EC_T_BYTE* pbyWriteData, EC_T_DWORD dwWriteDataLen,
EC_T_DWORD* pdwErrorCode, EC_T_DWORD* pdwCmdResult)
{
EC_T_DWORD dwVal = 0;
if (65535 != wTargetPort)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_TARGET_PORT_NOT_FOUND);
goto Exit;
}
if (0xF302 /* ADSIGRP_CANOPEN_SDO */ != dwIndexGroup)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_INVALIDGRP);
goto Exit;
}
/* check for object 0x2003, subindex 0, no complete access */
if (0x20030000 != dwIndexOffset /* example value */)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_NOTFOUND);
goto Exit;
}
/* check for size of object 0x2003, subindex 0 */
if (4 != dwWriteDataLen /* UDINT: sizeof(EC_T_DWORD) */)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_INVALIDSIZE);
goto Exit;
}
/* all checks passed, get data and set success */
dwVal = EC_GET_FRM_DWORD(pbyWriteData);
EC_SETDWORD(pdwErrorCode, EC_E_NOERROR);
Exit:
EcLogMsg(EC_LOG_LEVEL_VERBOSE, (pEcLogContext, EC_LOG_LEVEL_VERBOSE, "myAppAoeWriteObjectCallback(%d, %d, %d, 0x%04X, 0x%04X, %d bytes, 0x%08X, 0x%08X) = %d (0x%08X): %s (0x%08X)\n",
dwSimulatorId, wCfgFixedAddress, wTargetPort,
dwIndexGroup, dwIndexOffset, dwWriteDataLen, EC_GETDWORD(pdwErrorCode), EC_GETDWORD(pdwCmdResult),
dwVal, dwVal,
esGetText(dwSimulatorId, EC_GETDWORD(pdwErrorCode)), EC_GETDWORD(pdwErrorCode)));
return EC_GETDWORD(pdwErrorCode);
}
/* EC_T_PF_AOE_READWRITE_CB */
EC_T_DWORD EC_FNCALL myAppAoeReadWriteObjectCallback(
EC_T_VOID* /* pvContext */, EC_T_DWORD dwSimulatorId, EC_T_WORD wCfgFixedAddress,
EC_T_AOE_NETID* /* poSenderNetId */, EC_T_WORD /* wSenderPort */, EC_T_AOE_NETID* /* poTargetNetId */, EC_T_WORD wTargetPort,
EC_T_DWORD dwIndexGroup, EC_T_DWORD dwIndexOffset,
EC_T_BYTE* pbyReadData, EC_T_DWORD* pdwReadDataLen, EC_T_BYTE* pbyWriteData, EC_T_DWORD dwWriteDataLen,
EC_T_DWORD* pdwErrorCode, EC_T_DWORD* pdwCmdResult)
{
EC_T_DWORD dwVal = 0;
if (65535 != wTargetPort)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_TARGET_PORT_NOT_FOUND);
goto Exit;
}
if (0xF302 /* ADSIGRP_CANOPEN_SDO */ != dwIndexGroup)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_INVALIDGRP);
goto Exit;
}
/* check for object 0x2003, subindex 0, no complete access */
if (0x20030000 != dwIndexOffset /* example value */)
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_NOTFOUND);
goto Exit;
}
/* check for size of object 0x2003, subindex 0 */
if ((4 != EC_GETDWORD(pdwReadDataLen) /* UDINT: sizeof(EC_T_DWORD) */)
|| (4 != dwWriteDataLen /* UDINT: sizeof(EC_T_DWORD) */))
{
EC_SETDWORD(pdwErrorCode, EC_E_AOE_INVALIDSIZE);
goto Exit;
}
/* all checks passed, set and get data and set success */
EC_SET_FRM_DWORD(pbyReadData, 0x12345678);
dwVal = EC_GET_FRM_DWORD(pbyWriteData);
EC_SETDWORD(pdwErrorCode, EC_E_NOERROR);
Exit:
EcLogMsg(EC_LOG_LEVEL_VERBOSE, (pEcLogContext, EC_LOG_LEVEL_VERBOSE, "myAppAoeReadWriteObjectCallback(%d, %d, %d, 0x%04X, 0x%04X, read %d bytes, write %d bytes, 0x%08X, 0x%08X) = %d (0x%08X): %s (0x%08X)\n",
dwSimulatorId, wCfgFixedAddress, wTargetPort,
dwIndexGroup, dwIndexOffset, EC_GETDWORD(pdwReadDataLen), dwWriteDataLen, EC_GETDWORD(pdwErrorCode), EC_GETDWORD(pdwCmdResult),
dwVal, dwVal,
esGetText(dwSimulatorId, EC_GETDWORD(pdwErrorCode)), EC_GETDWORD(pdwErrorCode)));
return EC_GETDWORD(pdwErrorCode);
}
The following example demonstrates objects transfers between Master and Simulator:
EC_T_DWORD dwRes = EC_E_ERROR;
EC_T_DWORD dwRetVal = EC_E_ERROR;
EC_T_BYTE abyWriteData[sizeof(EC_T_DWORD)];
EC_T_BYTE abyReadData[sizeof(EC_T_DWORD)];
EC_T_BYTE abyReadWriteData[sizeof(EC_T_DWORD)];
EC_T_DWORD dwDataOutLen = 0;
EC_T_AOE_NETID oAoeNetId;
EC_T_DWORD dwSlaveId = emGetSlaveId(dwMasterId, wSlaveAddress);
EC_T_DWORD dwErrorCode = EC_E_ERROR;
EC_T_DWORD dwCmdResult = EC_E_ERROR;
OsMemset(abyWriteData, 0, sizeof(abyWriteData));
OsMemset(abyReadData, 0, sizeof(abyReadData));
OsMemset(abyReadWriteData, 0, sizeof(abyReadWriteData));
/* EC-Master: get configured AoE net ID */
dwRes = emAoeGetSlaveNetId(dwMasterId, dwSlaveId, &oAoeNetId);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emAoeGetSlaveNetId failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Simulator: register AoE handlers */
dwRes = esSetSlaveAoeObjectTransferCallbacks(dwSimulatorId, wSlaveAddress,
myAppAoeReadObjectCallback, myAppAoeWriteObjectCallback, myAppAoeReadWriteObjectCallback, pAppContext);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "esSetSlaveAoeObjectTransferCallbacks failed: %s (0x%lx))\n", esGetText(dwSimulatorId, dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Master: set PREOP state */
dwRes = emSetMasterState(dwMasterId, 30000, eEcatState_PREOP);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emSetMasterState failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
#define AOE_TARGET_PORT 65535
#define AOE_INDEX_GROUP 0xF302 /* ADSIGRP_CANOPEN_SDO */
/* CoE objects to access via AoE */
#define AOE_COE_OBJ_IDX 0x2003
#define AOE_COE_OBJ_SUBINDEX 0
#define AOE_COE_OBJ_COMPLETEACCESS EC_FALSE
/* Bit 16-31: index, Bit 8: complete access, Bit 0-7: subindex */
#define AOE_INDEX_OFFSET ((AOE_COE_OBJ_IDX << 16) | (AOE_COE_OBJ_COMPLETEACCESS << 8) | AOE_COE_OBJ_SUBINDEX)
/* EC-Master: write AoE to slave */
EC_SET_FRM_DWORD(abyWriteData, 0x11223344 /* example value */);
dwRes = emAoeWrite(dwMasterId, dwSlaveId, &oAoeNetId, AOE_TARGET_PORT, AOE_INDEX_GROUP, AOE_INDEX_OFFSET,
sizeof(EC_T_DWORD), abyWriteData, &dwErrorCode, &dwCmdResult, MBX_TIMEOUT);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emAoeWrite failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Master: read AoE from slave */
EC_SET_FRM_DWORD(abyReadData, 0);
dwRes = emAoeRead(dwMasterId, dwSlaveId, &oAoeNetId, AOE_TARGET_PORT, AOE_INDEX_GROUP, AOE_INDEX_OFFSET,
sizeof(EC_T_DWORD), abyReadData, &dwDataOutLen, &dwErrorCode, &dwCmdResult, MBX_TIMEOUT);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emAoeRead failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Master: read + write AoE from/to slave */
EC_SET_FRM_DWORD(abyReadWriteData, 0x11223344 /* example value */);
dwRes = emAoeReadWrite(dwMasterId, dwSlaveId, &oAoeNetId, AOE_TARGET_PORT, AOE_INDEX_GROUP, AOE_INDEX_OFFSET,
sizeof(EC_T_DWORD), sizeof(EC_T_DWORD), abyReadWriteData, &dwDataOutLen, &dwErrorCode, &dwCmdResult, MBX_TIMEOUT);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emAoeReadWrite failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Simulator: write AoE to slave */
EC_SET_FRM_DWORD(abyWriteData, 0x11223344 /* example value */);
dwRes = esAoeWrite(dwSimulatorId, dwSlaveId, &oAoeNetId, AOE_TARGET_PORT, AOE_INDEX_GROUP, AOE_INDEX_OFFSET,
sizeof(EC_T_DWORD), abyWriteData, &dwErrorCode, &dwCmdResult, MBX_TIMEOUT);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emAoeWrite failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Simulator: read AoE from slave */
EC_SET_FRM_DWORD(abyReadData, 0);
dwRes = esAoeRead(dwSimulatorId, dwSlaveId, &oAoeNetId, AOE_TARGET_PORT, AOE_INDEX_GROUP, AOE_INDEX_OFFSET,
sizeof(EC_T_DWORD), abyReadData, &dwDataOutLen, &dwErrorCode, &dwCmdResult, MBX_TIMEOUT);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emAoeRead failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Simulator: read + write AoE from/to slave */
EC_SET_FRM_DWORD(abyReadWriteData, 0x11223344 /* example value */);
dwRes = esAoeReadWrite(dwSimulatorId, dwSlaveId, &oAoeNetId, AOE_TARGET_PORT, AOE_INDEX_GROUP, AOE_INDEX_OFFSET,
sizeof(EC_T_DWORD), sizeof(EC_T_DWORD), abyReadWriteData, &dwDataOutLen, &dwErrorCode, &dwCmdResult, MBX_TIMEOUT);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emAoeReadWrite failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
6.11. CAN application protocol over EtherCAT (CoE)
6.11.1. esExtendSlaveCoeObjectDictionary
-
EC_T_DWORD esExtendSlaveCoeObjectDictionary(EC_T_DWORD dwInstanceId, EC_T_WORD wCfgFixedAddress, struct _EC_T_COE_DICTIONARY_DESC *pDict)
Add data types and / or objects to slave’s CoE object dictionary.
- Parameters
dwInstanceId – [in] Simulator Instance ID
wCfgFixedAddress – [in] Slave’s station address
pDict – [in] Pointer to dictionary descriptor
- Returns
EC_E_NOERROR or error code
6.11.2. esDeleteSlaveCoeObject
-
EC_T_DWORD esDeleteSlaveCoeObject(EC_T_DWORD dwInstanceId, EC_T_WORD wCfgFixedAddress, EC_T_WORD wObjectIndex)
Delete object from slave’s CoE object dictionary.
- Parameters
dwInstanceId – [in] Simulator Instance ID
wCfgFixedAddress – [in] Slave’s station address
wObjectIndex – [in] Object index
- Returns
EC_E_NOERROR or error code
6.11.3. esClearSlaveCoeObjectDictionary
6.11.4. esResetSlaveCoeObjectDictionary
6.11.5. esSetSlaveCoeObjectTransferCallbacks
-
EC_T_DWORD esSetSlaveCoeObjectTransferCallbacks(EC_T_DWORD dwInstanceId, EC_T_WORD wCfgFixedAddress, EC_T_WORD wObjectIndex, EC_T_PF_COE_READ_CB pfRead, EC_T_PF_COE_WRITE_CB pfWrite, EC_T_VOID *pvContext)
Set SDO upload / download callbacks.
- Parameters
dwInstanceId – [in] Simulator Instance ID
wCfgFixedAddress – [in] Slave’s station address. 0: all slaves
wObjectIndex – [in] Object index. 0xffff: all objects
pfRead – [in] Upload callback function
pfWrite – [in] Download callback function
pvContext – [in] pointer to context passed as first parameters to callback functions
- Returns
EC_E_NOERROR or error code
6.11.6. esCoeSdoDownload
-
EC_T_DWORD esCoeSdoDownload(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, EC_T_WORD wObIndex, EC_T_BYTE byObSubIndex, EC_T_BYTE *pbyData, EC_T_DWORD dwDataLen, EC_T_DWORD dwTimeout, EC_T_DWORD dwFlags)
Execute a CoE SDO download to an EtherCAT slave device.
This function may not be called from within the JobTask’s context.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
dwSlaveId – [in] Slave ID
wObIndex – [in] Object index.
byObSubIndex – [in] Object sub index. 0 or 1 if Complete Access.
pbyData – [in] Buffer containing transfered data
dwDataLen – [in] Buffer length [bytes]
dwTimeout – [in] Timeout [ms]
dwFlags – [in] Mailbox Flags. Bit 0: set if Complete Access (EC_MAILBOX_FLAG_SDO_COMPLETE).
- Returns
EC_E_NOERROR or error code
6.11.7. esCoeSdoUpload
-
EC_T_DWORD esCoeSdoUpload(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, EC_T_WORD wObIndex, EC_T_BYTE byObSubIndex, EC_T_BYTE *pbyData, EC_T_DWORD dwDataLen, EC_T_DWORD *pdwOutDataLen, EC_T_DWORD dwTimeout, EC_T_DWORD dwFlags)
Execute a CoE SDO upload from an EtherCAT slave device to the master.
This function may not be called from within the JobTask’s context.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
dwSlaveId – [in] Slave ID
wObIndex – [in] Object index.
byObSubIndex – [in] Object sub index. 0 or 1 if Complete Access.
pbyData – [out] Buffer receiving transfered data
dwDataLen – [in] Buffer length [bytes]
pdwOutDataLen – [out] Length of received data [byte]
dwTimeout – [in] Timeout [ms]
dwFlags – [in] Mailbox Flags. Bit 0: set if Complete Access (EC_MAILBOX_FLAG_SDO_COMPLETE).
- Returns
EC_E_NOERROR or error code
6.11.8. esCoeGetODList
-
EC_T_DWORD esCoeGetODList(EC_T_DWORD dwInstanceID, EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, EC_T_COE_ODLIST_TYPE eListType, EC_T_DWORD dwTimeout)
Gets a list of object IDs that are available in a slave.
A unique transfer ID must be written into EC_T_MBXTFER.dwTferId. EC_NOTIFY_MBOXRCV is given on completion. This function may not be called from within the JobTask’s context.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
pMbxTfer – [in] Mailbox transfer
dwSlaveId – [in] Slave ID
eListType – [in] which object types shall be transferred
dwTimeout – [in] Timeout [ms] The function will block at most for this time. If the timeout value is set to EC_NOWAIT the function will return immediately.
- Returns
EC_E_NOERROR or error code
6.11.9. esCoeGetObjectDesc
-
EC_T_DWORD esCoeGetObjectDesc(EC_T_DWORD dwInstanceID, EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, EC_T_WORD wObIndex, EC_T_DWORD dwTimeout)
Determines the description of a specific object.
A unique transfer ID must be written into EC_T_MBXTFER.dwTferId. EC_NOTIFY_MBOXRCV is given on completion. This function may not be called from within the JobTask’s context.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
pMbxTfer – [in] Mailbox transfer object
dwSlaveId – [in] Slave ID
wObIndex – [in] Object index
dwTimeout – [in] Timeout [ms] The function will block at most for this time. If the timeout value is set to EC_NOWAIT the function will return immediately.
- Returns
EC_E_NOERROR or error code
6.11.10. esCoeGetEntryDesc
-
EC_T_DWORD esCoeGetEntryDesc(EC_T_DWORD dwInstanceID, EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, EC_T_WORD wObIndex, EC_T_BYTE byObSubIndex, EC_T_BYTE byValueInfo, EC_T_DWORD dwTimeout)
Determines the description of a specific object entry.
A unique transfer ID must be written into EC_T_MBXTFER.dwTferId. EC_NOTIFY_MBOXRCV is given on completion. This function may not be called from within the JobTask’s context.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
pMbxTfer – [in] Mailbox transfer object
dwSlaveId – [in] Slave ID
wObIndex – [in] Object index
byObSubIndex – [in] Object sub-index
byValueInfo – [in] The value info bit mask includes which elements shall be in the response. See Value info flags for available values.
dwTimeout – [in] Timeout [ms] The function will block at most for this time. If the timeout value is set to EC_NOWAIT the function will return immediately
- Returns
EC_E_NOERROR or error code
See szUnitType, szDefaultValue, szMinValue, szMaxValue, szDescription in CoeReadObjectDictionary in EcSdoServices.cpp as an example for evaluating EC_T_COE_ENTRYDESC.pbyData.
6.12. Ethernet over EtherCAT (EoE)
To handle EoE frames within the application, the callback pfnEoeReceive must be registered using esSetSlaveSscApplication()
, e.g. in myAppPrepare()
of EcSimulatorHilDemo / EcSimulatorSilDemo.
See also EoE Ping Example
6.12.1. esEoeSendFrame
6.12.2. esGetCfgSlaveEoeInfo
-
EC_T_DWORD esGetCfgSlaveEoeInfo(EC_T_DWORD dwInstanceID, EC_T_BOOL bFixedAddressing, EC_T_WORD wSlaveAddress, EC_T_CFG_SLAVE_EOE_INFO *pSlaveEoeInfo)
Return EoE information about a configured slave from the ENI file.
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
bFixedAddressing – [in] EC_TRUE: use station address, EC_FALSE: use AutoInc address
wSlaveAddress – [in] Slave address according bFixedAddressing
pSlaveEoeInfo – [out] Information about the slave
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range
EC_E_NOTFOUND if no slave matching bFixedAddressing / wSlaveAddress can be found
EC_E_NO_MBX_SUPPORT if the slave does not support mailbox communication
EC_E_NO_EOE_SUPPORT if the slave supports mailbox communication, but not EoE
Content of EC_T_CFG_SLAVE_EOE_INFO
is subject to be extended.
esGetCfgSlaveEoeInfo Example
EC_T_CFG_SLAVE_EOE_INFO oInfo;
OsMemset(&oInfo, 0, sizeof(EC_T_CFG_SLAVE_EOE_INFO));
dwRes = esGetCfgSlaveEoeInfo(pAppContext->dwInstanceId, EC_TRUE, wSlaveAddress, &oInfo);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "esGetCfgSlaveEoeInfo failed: %s (0x%lx))\n",
esGetText(pAppContext->dwInstanceId, dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
EcLogMsg(EC_LOG_LEVEL_INFO, (pEcLogContext, EC_LOG_LEVEL_INFO, "esGetCfgSlaveEoeInfo(%d): "
"MAC address: %02X:%02X:%02X:%02X:%02X:%02X, IP address: %d.%d.%d.%d, subnet mask: %d.%d.%d.%d, "
"default gateway: %d.%d.%d.%d, DNS server: %d.%d.%d.%d, DNS name: %s\n", wSlaveAddress,
oInfo.abyMacAddr[0], oInfo.abyMacAddr[1], oInfo.abyMacAddr[2],
oInfo.abyMacAddr[3], oInfo.abyMacAddr[4], oInfo.abyMacAddr[5],
oInfo.abyIpAddr[3], oInfo.abyIpAddr[2], oInfo.abyIpAddr[1], oInfo.abyIpAddr[0],
oInfo.abySubnetMask[3], oInfo.abySubnetMask[2], oInfo.abySubnetMask[1], oInfo.abySubnetMask[0],
oInfo.abyDefaultGateway[3], oInfo.abyDefaultGateway[2], oInfo.abyDefaultGateway[1], oInfo.abyDefaultGateway[0],
oInfo.abyDnsServer[3], oInfo.abyDnsServer[2], oInfo.abyDnsServer[1], oInfo.abyDnsServer[0], oInfo.szDnsName));
6.12.3. EoE Ping Example
The following example demonstrates how to customize EoE simulation using esSetSlaveSscApplication()
and esEoeSendFrame()
.
EoE Ping Example
The following code demonstrates how to receive EoE frames from the Master and send answers back.
/********************************************************************************/
/** \brief EoE ARP request and PING request context structure
*/
typedef struct _T_MY_EOE_CONTEXT
{
T_EC_DEMO_APP_CONTEXT* pAppContext;
EC_T_WORD wSlaveAddress;
ETHERNET_ADDRESS oMacAddress;
EC_T_IPADDR oIpV4Address;
EC_T_LINK_FRAMEDESC oSendFrame;
} T_MY_EOE_CONTEXT;
/********************************************************************************/
/** \brief EoE ARP request and PING request handler
*
* \return pReplyFrameDesc->dwSize > 0 if handled with reply
*/
EC_T_VOID myAppProcessEoeFrameArpAndPing(EC_T_LINK_FRAMEDESC* pRequestFrameDesc, EC_T_LINK_FRAMEDESC* pReplyFrameDesc, ETHERNET_ADDRESS MacAddress, EC_T_IPADDR IpV4Address)
{
ETHERNET_FRAME* pRequest = (ETHERNET_FRAME*)pRequestFrameDesc->pbyFrame;
ETHERNET_FRAME* pReply = (ETHERNET_FRAME*)pReplyFrameDesc->pbyFrame;
/* prepare reply */
OsMemcpy(pReply, pRequest, pRequestFrameDesc->dwSize);
pReply->Destination = pRequest->Source;
pReply->Source = MacAddress;
pReplyFrameDesc->dwSize = 0;
/* handle ARP / ping */
switch (EC_ETHFRM_GET_FRAMETYPE(pRequest))
{
case ETHERNET_FRAME_TYPE_ARP:
{
EC_ARP_IP_HEADER* pArpRequest = (EC_ARP_IP_HEADER*)EC_ENDOF(pRequest); /* skip ETHERNET_FRAME header */
EC_ARP_IP_HEADER* pArpReply = (EC_ARP_IP_HEADER*)EC_ENDOF(pReply); /* skip ETHERNET_FRAME header */
/* only Ethernet MAC and IPv4 ARP requests supported */
if ((EC_NTOHS(pArpRequest->wHwAddressType) == EC_ARP_HW_TYPE_ETHERNET)
&& (EC_NTOHS(pArpRequest->wProtocolType) == ETHERNET_FRAME_TYPE_IP)
&& (pArpRequest->byHwAddressLength == ETHERNET_ADDRESS_LEN)
&& (pArpRequest->byProtocolAddressLength == EC_IPv4_ADDRESS_LEN)
&& (EC_NTOHS(pArpRequest->wOpCode) == EC_ARP_OPCODE_REQUEST))
{
/* only answer ARP request if IP address matches */
if ((BroadcastEthernetAddress == pRequest->Destination)
&& (pArpRequest->Address.IpV4.DestinationIp == IpV4Address))
{
pArpReply->Address.IpV4.DestinationMac = pArpRequest->Address.IpV4.SourceMac;
pArpReply->Address.IpV4.SourceMac = MacAddress;
pArpReply->Address.IpV4.DestinationIp = pArpRequest->Address.IpV4.SourceIp;
pArpReply->Address.IpV4.SourceIp = IpV4Address;
pArpReply->wOpCode = EC_HTONS(EC_ARP_OPCODE_REPLY);
/* reply valid */
pReplyFrameDesc->dwSize = ETHERNET_FRAME_LEN + EC_ARP_IPv4_HEADER_LEN;
}
}
} break;
case ETHERNET_FRAME_TYPE_IP:
{
if (((EC_IP_HEADER*)EC_ENDOF(pRequest))->byProtocol == EC_IP_PROTOCOL_ICMP)
{
EC_ICMP_HEADER* pIcmpRequest = (EC_ICMP_HEADER*)EC_ENDOF(pRequest); /* skip ETHERNET_FRAME header */
EC_ICMP_HEADER* pIcmpReply = (EC_ICMP_HEADER*)EC_ENDOF(pReply); /* skip ETHERNET_FRAME header */
/* only answer PING request if MAC address and IP address match */
if ((pIcmpRequest->byType == EC_ICMP_TYPE_ECHO)
&& (pRequest->Destination == MacAddress)
&& (pIcmpRequest->IpHdr.dwDstAddr == IpV4Address))
{
EC_T_WORD wLen = EC_NTOHS(pIcmpRequest->IpHdr.wTotalLength);
/* swap src and dest ip address */
pIcmpReply->IpHdr.dwSrcAddr = pIcmpRequest->IpHdr.dwDstAddr;
pIcmpReply->IpHdr.dwDstAddr = pIcmpRequest->IpHdr.dwSrcAddr;
pIcmpReply->byType = EC_ICMP_TYPE_ECHO_REPLY;
pIcmpReply->IpHdr.wCheckSum = 0;
pIcmpReply->IpHdr.wCheckSum = EC_HTONS(CalculateCrcRfc1071((EC_T_WORD*)&pIcmpReply->IpHdr, EC_IP_HEADER_MINIMUM_LEN));
pIcmpRequest->wCheckSum = 0;
pIcmpRequest->wCheckSum = EC_HTONS(CalculateCrcRfc1071((EC_T_WORD*)&pIcmpReply->byType /* skip IpHdr */, (EC_T_WORD)(wLen - EC_IP_HEADER_MINIMUM_LEN)));
/* reply valid */
pReplyFrameDesc->dwSize = (EC_T_WORD)(ETHERNET_FRAME_LEN + wLen);
}
}
} break;
}
}
EC_T_VOID myAppEoe_APPL_EoeReceive(EC_T_VOID* pvContext, EC_T_WORD* pwFrame, EC_T_WORD wFrameSize)
{
T_MY_EOE_CONTEXT* poContext = (T_MY_EOE_CONTEXT*)pvContext;
EC_T_LINK_FRAMEDESC oReceiveFrame;
oReceiveFrame.pbyFrame = (EC_T_BYTE*)pwFrame;
oReceiveFrame.dwSize = wFrameSize;
/* call ARP request and ping request handler and send reply if filled by handler */
myAppProcessEoeFrameArpAndPing(&oReceiveFrame, &poContext->oSendFrame, poContext->oMacAddress, poContext->oIpV4Address);
if (poContext->oSendFrame.dwSize > 0)
{
esEoeSendFrame(poContext->pAppContext->dwInstanceId, poContext->wSlaveAddress, poContext->oSendFrame.pbyFrame, poContext->oSendFrame.dwSize);
}
}
EC_T_VOID myAppEoe_APPL_EoeSettingInd(EC_T_VOID* pvContext, EC_T_WORD* pwMacAddress, EC_T_WORD* pwIpV4Address,
EC_T_WORD* /* pwIpV4SubNetMask */, EC_T_WORD* /* pwIpV4DefaultGateway */, EC_T_WORD* /* pwDnsIpV4Address */)
{
T_MY_EOE_CONTEXT* poContext = (T_MY_EOE_CONTEXT*)pvContext;
poContext->oMacAddress = *((ETHERNET_ADDRESS*)pwMacAddress);
poContext->oIpV4Address.dwAddr = EC_GETDWORD(pwIpV4Address);
}
EC_T_DWORD myAppEoeInit(T_EC_DEMO_APP_CONTEXT* pAppContext, T_MY_EOE_CONTEXT* poContext, EC_T_WORD wSlaveAddress)
{
EC_T_DWORD dwRetVal = EC_E_ERROR;
EC_T_DWORD dwRes = EC_E_ERROR;
poContext->pAppContext = pAppContext;
poContext->wSlaveAddress = wSlaveAddress;
poContext->oSendFrame.pbyFrame = (EC_T_BYTE*)OsMalloc(ETHERNET_MAX_FRAMEBUF_LEN /* 1536 */);
if (EC_NULL == poContext->oSendFrame.pbyFrame)
{
dwRetVal = EC_E_NOMEMORY;
goto Exit;
}
{
struct _EC_T_SLAVE_SSC_APPL_DESC oSlaveApplDesc;
OsMemset(&oSlaveApplDesc, 0, sizeof(struct _EC_T_SLAVE_SSC_APPL_DESC));
oSlaveApplDesc.dwSignature = SIMULATOR_SIGNATURE;
oSlaveApplDesc.dwSize = sizeof(struct _EC_T_SLAVE_SSC_APPL_DESC);
oSlaveApplDesc.szName = (EC_T_CHAR*)"MyAppEoeSlaveAppl";
oSlaveApplDesc.pvContext = poContext; /* first parameter of static wrapper functions */
oSlaveApplDesc.pfnEoeReceive = myAppEoe_APPL_EoeReceive;
oSlaveApplDesc.pfnEoeSettingInd = myAppEoe_APPL_EoeSettingInd;
/* register callbacks at slave */
dwRes = esSetSlaveSscApplication(pAppContext->dwInstanceId, wSlaveAddress, &oSlaveApplDesc);
if (EC_E_NOERROR != dwRes)
{
dwRetVal = dwRes;
goto Exit;
}
}
dwRetVal = EC_E_NOERROR;
Exit:
if (EC_E_NOERROR != dwRetVal)
{
SafeOsFree(poContext->oSendFrame.pbyFrame);
}
return dwRetVal;
}
The callbacks need a context. Each slave needs its individual context. If there is only one slave to be registered, a global context can be declared and used:
T_MY_EOE_CONTEXT G_oContext;
The callbacks must be registered using esSetSlaveSscApplication()
, e.g. in myAppPrepare()
of EcSimulatorHilDemo / EcSimulatorSilDemo:
OsMemset(&G_oContext, 0, sizeof(G_oContext));
dwRes = myAppEoeInit(pAppContext, &G_oContext, wSlaveAddress);
if (EC_E_NOERROR != dwRes)
{
dwRetVal = dwRes;
goto Exit;
}
6.13. File access over EtherCAT (FoE)
The following examples demonstrate how to customize FoE simulation using esSetSlaveSscApplication()
.
FoE Download Example
The following code demonstrates how to receive FoE from the Master and store it in a buffer.
The data received in this example is stored in T_MY_CONTEXT::abyFileBuf
:
#define MYAPP_FOE_BUFFER_SIZE (35264)
typedef struct
{
EC_T_BYTE abyFileBuf[MYAPP_FOE_BUFFER_SIZE];
EC_T_WORD wFileBufLen;
/* ... */
} T_MY_CONTEXT;
myAppFoeWrite()
handles download requests from the Master, myAppFoeWriteData()
copies the FoE payload from the mailbox to T_MY_CONTEXT::abyFileBuf
:
extern "C" EC_T_WORD myAppFoeWrite(EC_T_VOID* pvContext, EC_T_WORD*, EC_T_WORD, EC_T_DWORD)
{
T_MY_CONTEXT* poContext = (T_MY_CONTEXT*)pvContext;
poContext->wFileBufLen = 0;
return 0; /* accept file download (ECAT_FOE_ERRCODE_... denies download) */
}
extern "C" EC_T_WORD myAppFoeWriteData(
EC_T_VOID* pvContext, EC_T_WORD* pData, EC_T_WORD wSize, EC_T_BYTE bDataFollowing)
{
T_MY_CONTEXT* poContext = (T_MY_CONTEXT*)pvContext;
if (poContext->wFileBufLen + wSize > sizeof(poContext->abyFileBuf))
{
return ECAT_FOE_ERRCODE_DISKFULL; /* abort transfer */
}
OsMemcpy(&poContext->abyFileBuf[poContext->wFileBufLen], pData, wSize);
poContext->wFileBufLen = poContext->wFileBufLen + wSize;
/* FoE ACK segment at Master (more segments follow / download finished) */
return bDataFollowing ? SSC_FOE_ACK : SSC_FOE_ACKFINISHED;
}
The callbacks must be registered using esSetSlaveSscApplication()
, e.g. in myAppPrepare()
of EcSimulatorHilDemo / EcSimulatorSilDemo:
struct _EC_T_SLAVE_SSC_APPL_DESC oSlaveApp;
OsMemset(&oSlaveApp, 0, sizeof(struct _EC_T_SLAVE_SSC_APPL_DESC));
T_MY_CONTEXT* poSlaveApplContext = &G_oSlaveApplContext;
OsMemset(poSlaveApplContext, 0, sizeof(G_oSlaveApplContext));
oSlaveApp.dwSignature = SIMULATOR_SIGNATURE;
oSlaveApp.dwSize = sizeof(struct _EC_T_SLAVE_SSC_APPL_DESC);
oSlaveApp.szName = (EC_T_CHAR*)"mySlaveAppl";
oSlaveApp.pvContext = poSlaveApplContext; /* pvContext of callbacks */
oSlaveApp.pfnFoeWrite = myAppFoeWrite;
oSlaveApp.pfnFoeWriteData = myAppFoeWriteData;
/* register SlaveSscApplication call-backs (Master in INIT) */
dwRes = esSetSlaveSscApplication(dwSimulatorId, wSlaveAddress, &oSlaveApp);
if (dwRes != EC_E_NOERROR)
{
goto Exit;
}
The following code at Master downloads the file to the slave:
/* set Master PREOP */
dwRes = emSetMasterState(dwMasterId, 30000 /* dwTimeout */, eEcatState_PREOP);
if (dwRes != EC_E_NOERROR)
{
goto Exit;
}
/* download file */
dwRes = emFoeFileDownload(dwMasterId, emGetSlaveId(dwMasterId, wSlaveAddress),
(EC_T_CHAR*)"foe.dat", (EC_T_DWORD)OsStrlen((EC_T_CHAR*)"foe.dat"),
G_abyFileBuf, MYAPP_FOE_BUFFER_SIZE, 0 /* dwPassword */, 30000 /* dwTimeout */);
if (dwRes != EC_E_NOERROR)
{
goto Exit;
}
FoE Upload Example
The following code demonstrates how to serve FoE data from a local buffer to the Master.
The data served in this example is stored in T_MY_CONTEXT::abyFileBuf
:
#define MYAPP_FOE_BUFFER_SIZE (35264)
typedef struct
{
EC_T_BYTE abyFileBuf[MYAPP_FOE_BUFFER_SIZE];
EC_T_WORD wFileBufLen;
/* ... */
} T_MY_CONTEXT;
myAppFoeRead()
handles upload requests from the Master, myAppFoeReadData()
copies the FoE payload from T_MY_CONTEXT::abyFileBuf
to the mailbox:
extern "C" EC_T_WORD myAppFoeReadData(
EC_T_VOID* pvContext, EC_T_DWORD dwOffset, EC_T_WORD wMaxBlockSize, EC_T_WORD* pData)
{
T_MY_CONTEXT* poContext = (T_MY_CONTEXT*)pvContext;
if (dwOffset > poContext->wFileBufLen)
{
return 0;
}
if (dwOffset + wMaxBlockSize > poContext->wFileBufLen)
{
wMaxBlockSize = EC_LOWORD(poContext->wFileBufLen - dwOffset);
}
if (wMaxBlockSize > 0)
{
OsMemcpy(pData, &poContext->abyFileBuf[dwOffset], wMaxBlockSize);
}
return wMaxBlockSize; /* amount of data read */
}
extern "C" EC_T_WORD myAppFoeRead(
EC_T_VOID* pvContext, EC_T_WORD*, EC_T_WORD, EC_T_DWORD, EC_T_WORD wMaxBlockSize, EC_T_WORD* pData)
{
/* APPL_FoeRead contains returning first data */
return myAppFoeReadData(pvContext, 0, wMaxBlockSize, pData);
}
The callbacks must be registered using esSetSlaveSscApplication()
, e.g. in myAppPrepare()
of EcSimulatorHilDemo / EcSimulatorSilDemo:
struct _EC_T_SLAVE_SSC_APPL_DESC oSlaveApp;
OsMemset(&oSlaveApp, 0, sizeof(struct _EC_T_SLAVE_SSC_APPL_DESC));
T_MY_CONTEXT* poSlaveApplContext = &G_oSlaveApplContext;
OsMemset(poSlaveApplContext, 0, sizeof(G_oSlaveApplContext));
/* pattern for file content */
OsMemset(poSlaveApplContext->abyFileBuf, 0xAA, MYAPP_FOE_BUFFER_SIZE);
poSlaveApplContext->wFileBufLen = MYAPP_FOE_BUFFER_SIZE;
oSlaveApp.dwSignature = SIMULATOR_SIGNATURE;
oSlaveApp.dwSize = sizeof(struct _EC_T_SLAVE_SSC_APPL_DESC);
oSlaveApp.szName = (EC_T_CHAR*)"mySlaveAppl";
oSlaveApp.pvContext = poSlaveApplContext; /* pvContext of callbacks */
oSlaveApp.pfnFoeRead = myAppFoeRead;
oSlaveApp.pfnFoeReadData = myAppFoeReadData;
/* register SlaveSscApplication call-backs (Master in INIT) */
dwRes = esSetSlaveSscApplication(dwSimulatorId, wSlaveAddress, &oSlaveApp);
if (dwRes != EC_E_NOERROR)
{
goto Exit;
}
The following code at Master uploads the file from the slave:
/* set Master PREOP */
dwRes = emSetMasterState(dwMasterId, 30000 /* dwTimeout */, eEcatState_PREOP);
if (dwRes != EC_E_NOERROR)
{
goto Exit;
}
/* upload file */
dwRes = emFoeFileUpload(dwMasterId, emGetSlaveId(dwMasterId, wSlaveAddress),
(EC_T_CHAR*)"foe.dat", (EC_T_DWORD)OsStrlen((EC_T_CHAR*)"foe.dat"),
G_abyFileBuf, MYAPP_FOE_BUFFER_SIZE, &dwOutDataLen, 0 /* dwPassword */, 30000 /* dwTimeout */);
if (dwRes != EC_E_NOERROR)
{
goto Exit;
}
See also
6.14. Vendor specific access over EtherCAT (VoE)
See also VoE Receive Example
6.14.1. esVoeSend
-
EC_T_DWORD esVoeSend(EC_T_DWORD dwInstanceId, EC_T_WORD wCfgFixedAddress, EC_T_WORD wDstFixedAddress, EC_T_VOID *pvData, EC_T_DWORD dwDataLen)
Fill “Mailbox In” (SM1) with VoE data to be polled by Master. The slave must have VoE enabled, see ESI: /EtherCATInfo/Descriptions/Devices/Device/Mailbox/VoE, ENI/EXI: /EtherCATConfig/Config/Slave/Mailbox/Protocol/VoE.
- Parameters
dwInstanceId – [in] Simulator Instance ID
wCfgFixedAddress – [in] Slave’s station address
wDstFixedAddress – [in] Destination address
pvData – [in] Data
dwDataLen – [in] Data length
- Returns
EC_E_NOERROR or error code
6.14.2. esSetVoeReceiveCallback
-
EC_T_DWORD esSetVoeReceiveCallback(EC_T_DWORD dwInstanceId, EC_T_WORD wCfgFixedAddress, EC_T_BYTE (*pfVoeReceive)(EC_T_VOID *pvContext, EC_T_WORD wFixedAddress, EC_T_WORD wSrcFixedAddress, EC_T_VOID *pvData, EC_T_DWORD dwDataLen), EC_T_VOID *pvContext)
Set VoE data received callback for “Mailbox Out” (SM0) Within the callback, no EC-Simulator API may be called. The slave must have VoE enabled, see ESI: /EtherCATInfo/Descriptions/Devices/Device/Mailbox/VoE, ENI/EXI: /EtherCATConfig/Config/Slave/Mailbox/Protocol/VoE.
- Parameters
dwInstanceId – [in] Simulator Instance ID
wCfgFixedAddress – [in] Slave’s station address
pfVoeReceive – [in] Receive callback function
pvContext – [in] Receive callback function context
- Returns
EC_E_NOERROR or error code
6.14.3. VoE Receive Example
The following examples demonstrate how to register a handler for VoE writes from the Master or from other slaves.
VoE Receive Example
The following code demonstrates how to send VoE from the Master to the slave and store it in a buffer at the Simulator.
The data received in this example is stored in T_MY_CONTEXT::abyVoeBuf
:
#define MYAPP_FOE_BUFFER_SIZE (35264)
typedef struct
{
EC_T_BYTE abyFileBuf[MYAPP_FOE_BUFFER_SIZE];
EC_T_WORD wFileBufLen;
/* ... */
} T_MY_CONTEXT;
myAppVoeReceiveCallback()
handles write requests from the Master and copies the received VoE payload from the mailbox to T_MY_CONTEXT::abyVoeBuf
:
EC_T_BYTE EC_FNCALL myAppVoeReceiveCallback(EC_T_VOID* pvContext,
EC_T_WORD /* wCfgFixedAddress VoE receiver address, e.g. 1001 */,
EC_T_WORD /* wSrcFixedAddress VoE sender address, 0: Master */,
EC_T_VOID* pvData, EC_T_DWORD dwDataLen)
{
T_MY_CONTEXT* poContext = (T_MY_CONTEXT*)pvContext;
OsMemcpy(poContext->abyVoeBuf, pvData, EC_AT_MOST(MYAPP_VOE_BUFFER_SIZE, dwDataLen));
poContext->dwVoeBufLen = dwDataLen;
/* No EC-Simulator APIs may be issued from within the callback context.
Signalize VoE data received for deferred processing in other thread. */
OsSetEvent(poContext->pvEvent);
return 0;
}
The following code shows how to register myAppVoeReceiveCallback()
and send VoE from the Master to the simulated slave:
EC_T_DWORD dwRes = EC_E_ERROR;
EC_T_DWORD dwRetVal = EC_E_ERROR;
#define MYAPP_VOE_SEND_BUF_LEN sizeof(EC_T_DWORD)
EC_T_BYTE abyVoeSendBuf[MYAPP_VOE_SEND_BUF_LEN];
OsMemset(abyVoeSendBuf, 0, MYAPP_VOE_SEND_BUF_LEN);
T_MY_CONTEXT oContext;
OsMemset(&oContext, 0, sizeof(T_MY_CONTEXT));
oContext.pvEvent = OsCreateEvent();
if (EC_NULL == oContext.pvEvent)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "OsCreateEvent failed\n"));
dwRetVal = EC_E_NOMEMORY;
goto Exit;
}
/* EC-Simulator: register VoE handler */
dwRes = esSetVoeReceiveCallback(dwSimulatorId, 1001, myAppVoeReceiveCallback, &oContext);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "esSetVoeReceiveCallback failed: %s (0x%lx))\n", esGetText(dwSimulatorId, dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* EC-Master: set PREOP state */
dwRes = emSetMasterState(dwMasterId, 30000, eEcatState_PREOP);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emSetMasterState failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* send VoE to slave */
EC_SET_FRM_DWORD(abyVoeSendBuf, 0x12345678);
dwRes = emVoeWrite(dwMasterId, emGetSlaveId(dwMasterId, 1001), abyVoeSendBuf, MYAPP_VOE_SEND_BUF_LEN, 5000);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "emVoeWrite failed: %s (0x%lx))\n", ecatGetText(dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
/* wait for slave received data in callback */
dwRes = OsWaitForEvent(oContext.pvEvent, 5000);
if (dwRes != EC_E_NOERROR)
{
EcLogMsg(EC_LOG_LEVEL_ERROR, (pEcLogContext, EC_LOG_LEVEL_ERROR, "OsWaitForEvent failed: %s (0x%lx))\n", esGetText(dwSimulatorId, dwRes), dwRes));
dwRetVal = dwRes;
goto Exit;
}
dwRetVal = EC_E_NOERROR;
Exit:
SafeOsDeleteEvent(oContext.pvEvent);