6.12. File access over EtherCAT (FoE)
The File access over EtherCAT (FoE) mailbox command specifies a standard way to download a firmware or any other files from a client to a server or to upload a firmware or any other files from a server to a client.
Reference:
ETG.1000.5 and ETG.1000.6
6.12.1. Specification
6.12.1.1. FoE file download
Regular download
Segmented download
In case of segmented download the EC-Master raises emNotify - EC_NOTIFY_MBOXRCV in EC-Master Class B documentation to request more data from the application after each ACK from the slave. The notification handler may not block the EC-Master, e.g. due to reading from or writing to the file system, therefore applications typically do not handle EC_NOTIFY_MBOXRCV within the JobTask context. The segments are transferred using the slave’s mailbox, so the maximum size of a segment is known from the configuration. The segment’s size can be calculated as follows:
segment size = mailbox size - 12 (protocol overhead)
See also
Download with busy
Download with error
6.12.1.2. FoE file upload
The names of availables files and their size are slave specific and cannot be retrieved using FoE. It is possible to upload the complete file in segments without the need to know the file size.
The segments are transferred using the slave’s mailbox, so the maximum size of a segment is known from the configuration.
Regular upload
6.12.1.3. Boot State
For the download of firmware the BOOT state in the EtherCAT state machine is defined. In bootstrap mode only FoE Download is possible. A special Mailbox size can be supported by the slave for the Boot state (ETG.2000). This is part of the Init-Commands in the network configuration.
6.12.2. emFoeFileDownload
-
static EC_T_DWORD ecatFoeFileDownload(EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_BYTE *pbyData, EC_T_DWORD dwDataLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
-
EC_T_DWORD emFoeFileDownload(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_BYTE *pbyData, EC_T_DWORD dwDataLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
Execute a FoE File download to an EtherCAT slave device.
This function is used to download a complete file. The function returns after the download has been successfully completed or an error has occurred. 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
achFileName – [in] File name of slave file to write
dwFileNameLen – [in] Length of slave file name in bytes
pbyData – [in] Buffer containing transfered data
dwDataLen – [in] Buffer length [bytes]
dwPassword – [in] slave password
dwTimeout – [in] Timeout [ms] The function will block at most for this time.
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range or maximum file name length of 64 bytes (MAX_FILE_NAME_SIZE) exceeded
EC_E_FOE_ERRCODE_NOTINBOOTSTRAP if slave in BOOTSTRAP and filename not accepted by slave
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
See also
The following example demonstrates how to download files from the Master to the Slave using FoE.
FoE Download Example
This example code shows how to download a file from a buffer at the master to a slave, e.g. in order to update the firmware.
EC_T_DWORD dwRetVal = EC_E_ERROR;
EC_T_DWORD dwRes = EC_E_ERROR;
EC_T_WORD wSlaveAddress = MY_FOE_SLAVE_ADDRESS /* e.g. 1001 */;
EC_T_DWORD dwSlaveId = ecatGetSlaveId(wSlaveAddress);
FILE* pfLocalFile = EC_NULL;
EC_T_BYTE* pbyBuffer = EC_NULL;
EC_T_DWORD dwBufferSize = 0;
/* read file to buffer */
pfLocalFile = OsFopen(MY_FOE_TRANSFER_LOCAL_FILENAME, "rb");
if (EC_NULL == pfLocalFile)
{
dwRetVal = EC_E_OPENFAILED;
goto Exit;
}
dwBufferSize = OsGetFileSize(pfLocalFile);
pbyBuffer = (EC_T_BYTE*)OsMalloc(dwBufferSize);
if (EC_NULL == pbyBuffer)
{
dwRetVal = EC_E_NOMEMORY;
goto Exit;
}
dwRes = (EC_T_DWORD)OsFread(pbyBuffer, 1, dwBufferSize, pfLocalFile);
if (dwRes != dwBufferSize)
{
dwRetVal = EC_E_ERROR;
goto Exit;
}
/* download buffer to slave */
dwRes = ecatFoeFileDownload(dwSlaveId, MY_FOE_TRANSFER_SLAVE_FILENAME,
(EC_T_DWORD)OsStrlen(MY_FOE_TRANSFER_SLAVE_FILENAME),
pbyBuffer, dwBufferSize, 0, 600000 /* 10 minutes */);
if (EC_E_NOERROR != dwRes)
{
dwRetVal = dwRes;
goto Exit;
}
dwRetVal = EC_E_NOERROR;
Exit:
/* free resources */
if (EC_NULL != pfLocalFile)
{
OsFclose(pfLocalFile);
}
SafeOsFree(pbyBuffer);
6.12.3. emFoeFileUpload
-
static EC_T_DWORD ecatFoeFileUpload(EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_BYTE *pbyData, EC_T_DWORD dwDataLen, EC_T_DWORD *pdwOutDataLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
-
EC_T_DWORD emFoeFileUpload(EC_T_DWORD dwInstanceID, EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_BYTE *pbyData, EC_T_DWORD dwDataLen, EC_T_DWORD *pdwOutDataLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
Execute a FoE File upload from an EtherCAT slave device.
This function is used to upload a complete file. The function returns after the upload has been successfully completed or an error has occurred. 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
achFileName – [in] File name of slave file to read.
dwFileNameLen – [in] Length of slave file name in bytes.
pbyData – [out] Buffer receiving transfered data
dwDataLen – [in] Buffer length [bytes]
pdwOutDataLen – [out] Length of received data [byte]
dwPassword – [in] slave password
dwTimeout – [in] Timeout [ms] The function will block at most for this time.
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range or maximum file name length of 64 bytes (MAX_FILE_NAME_SIZE) exceeded
EC_E_TIMEOUT if dwTimeout elapsed during the API call
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
See also
6.12.4. emFoeDownloadReq
-
static EC_T_DWORD ecatFoeDownloadReq(EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
-
EC_T_DWORD emFoeDownloadReq(EC_T_DWORD dwInstanceID, EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
Initiates an FoE File download to an EtherCAT slave device.
This function is used to download a complete file and returns immediately. After the download has been successfully completed or an error has occurred, EC_NOTIFY_MBOXRCV is raised. The progress of the file transfer is also notified with EC_NOTIFY_MBOXRCV.
- Deprecated:
EC_NOWAIT as a timeout is still accepted for reasons of compatibility and sets the timeout to 10 seconds
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
pMbxTfer – [in] Mailbox transfer object
dwSlaveId – [in] Slave ID
achFileName – [in] File name of slave file to write.
dwFileNameLen – [in] Length of slave file name in bytes.
dwPassword – [in] slave password
dwTimeout – [in] Timeout [ms]
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range or maximum file name length of 64 bytes (MAX_FILE_NAME_SIZE) exceeded
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
See also
6.12.5. emFoeSegmentedDownloadReq
-
static EC_T_DWORD ecatFoeSegmentedDownloadReq(EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *szFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwFileSize, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
-
EC_T_DWORD emFoeSegmentedDownloadReq(EC_T_DWORD dwInstanceID, EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *szFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwFileSize, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
Initiates or continues a segmented FoE File download to an EtherCAT slave device.
This function is used to download a file chunk-by-chunk and returns immediately. An EC_NOTIFY_MBOXRCV is raised to request the next chunk from the application or to provide information about the progress and the change in the transfer status.
The slave may have a different mailbox size for BOOTSTRAP than for PREOP, SAFEOP, OP. See
EC_T_CFG_SLAVE_INFO.dwMbxInSize2. The maximum chunk size is the slave’s mailbox size - 12 bytes overhead for EtherCAT’s FoE protocol. The mailbox transfer object’s buffer must be at least as big as the chunks to be transferred.- Deprecated:
EC_NOWAIT as a timeout is still accepted for reasons of compatibility and sets the timeout to 10 seconds
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
pMbxTfer – [in] Pointer to the corresponding mailbox transfer object. EC_T_MBXTFER.pbyMbxTferData: next chunk, EC_T_MBXTFER.dwDataLen: next chunk size.
dwSlaveId – [in] Slave ID
szFileName – [in] File name of slave file to write. Only evaluated when initiating the request.
dwFileNameLen – [in] Length of slave file name in bytes
dwFileSize – [in] Complete file size (mandatory). Used also for progress information. Only evaluated when initiating the request.
dwPassword – [in] Slave password. Only evaluated when initiating the request.
dwTimeout – [in] Timeout [ms] specify the overall timeout of the FoE transfer. Only evaluated when initiating the request.
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range or maximum file name length of 64 bytes (MAX_FILE_NAME_SIZE) exceeded
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
6.12.6. emFoeUploadReq
-
static EC_T_DWORD ecatFoeUploadReq(EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
-
EC_T_DWORD emFoeUploadReq(EC_T_DWORD dwInstanceID, EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *achFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
Initiates an FoE File upload from an EtherCAT slave device.
This function is used to upload a complete file and returns immediately. After the upload has been successfully completed or an error has occurred, EC_NOTIFY_MBOXRCV is raised. The progress of the file transfer is also notified with EC_NOTIFY_MBOXRCV.
- Deprecated:
EC_NOWAIT as a timeout is still accepted for reasons of compatibility and sets the timeout to 10 seconds
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
pMbxTfer – [in] Mailbox transfer object
dwSlaveId – [in] Slave ID
achFileName – [in] File name of slave file to read.
dwFileNameLen – [in] Length of slave file name in bytes.
dwPassword – [in] slave password
dwTimeout – [in] Timeout [ms]
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range or maximum file name length of 64 bytes (MAX_FILE_NAME_SIZE) exceeded
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
See also
6.12.7. emFoeSegmentedUploadReq
-
static EC_T_DWORD ecatFoeSegmentedUploadReq(EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *szFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwFileSize, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
-
EC_T_DWORD emFoeSegmentedUploadReq(EC_T_DWORD dwInstanceID, EC_T_MBXTFER *pMbxTfer, EC_T_DWORD dwSlaveId, const EC_T_CHAR *szFileName, EC_T_DWORD dwFileNameLen, EC_T_DWORD dwFileSize, EC_T_DWORD dwPassword, EC_T_DWORD dwTimeout)
Initiates or continues a segmented FoE File upload from an EtherCAT slave device.
This function is used to upload a file chunk-by-chunk and returns immediately. An EC_NOTIFY_MBOXRCV is raised to provide the next chunk to the application or to get information about the progress and the change in the transfer status.
The slave may have a different mailbox size for BOOTSTRAP than for PREOP, SAFEOP, OP. See
EC_T_CFG_SLAVE_INFO.dwMbxInSize2. The maximum chunk size is the slave’s mailbox size - 12 bytes overhead for EtherCAT’s FoE protocol. The mailbox transfer object’s buffer must be at least as big as the chunks to be transferred.- Deprecated:
EC_NOWAIT as a timeout is still accepted for reasons of compatibility and sets the timeout to 10 seconds
- Parameters
dwInstanceID – [in] Instance ID (Multiple EtherCAT Network Support)
pMbxTfer – [in] Pointer to the corresponding mailbox transfer object. EC_T_MBXTFER.pbyMbxTferData: next chunk, EC_T_MBXTFER.dwDataLen: next chunk size.
dwSlaveId – [in] Slave ID
szFileName – [in] File name of slave file to write. Only evaluated when initiating the request.
dwFileNameLen – [in] Length of slave file name in bytes.
dwFileSize – [in] Used only for progress information.
dwPassword – [in] Slave password. Only evaluated when initiating the request.
dwTimeout – [in] Timeout [ms] specify the overall timeout of the FoE transfer. Only evaluated when initiating the request.
- Returns
EC_E_NOERROR if successful
EC_E_INVALIDSTATE if master isn’t initialized
EC_E_INVALIDPARM if dwInstanceID is out of range or maximum file name length of 64 bytes (MAX_FILE_NAME_SIZE) exceeded
EC_E_MASTER_RED_STATE_INACTIVE if Master Redundancy is configured and master is inactive
The following example demonstrates how to upload a file in segments:
FoE Segmented Upload Example
The following code demonstrates how to receive FoE from the slave with address MY_FOE_SLAVE_ADDRESS and store it in a file. The data uploaded from MY_FOE_TRANSFER_SLAVE_FILENAME of the slave is stored in a file with filename MY_FOE_TRANSFER_LOCAL_FILENAME in this example.
The example code can be placed after the corresponding emSetMasterState()
-call in EcDemoApp.cpp:
EC_T_DWORD dwRetVal = EC_E_ERROR;
EC_T_DWORD dwRes = EC_E_ERROR;
EC_T_WORD wSlaveAddress = MY_FOE_SLAVE_ADDRESS /* e.g. 1001 */;
EC_T_DWORD dwSlaveId = ecatGetSlaveId(wSlaveAddress);
EC_T_CFG_SLAVE_INFO oCfgSlaveInfo;
FILE* pfLocalFile = EC_NULL;
EC_T_DWORD dwFileSize = 0;
EC_T_MBXTFER_DESC oMbxTferDesc;
EC_T_MBXTFER* pMbxTfer = EC_NULL;
EC_T_BYTE* pbyBuffer = EC_NULL;
EC_T_DWORD dwBufferSize = 0;
OsMemset(&oCfgSlaveInfo, 0, sizeof(EC_T_CFG_SLAVE_INFO));
OsMemset(&oMbxTferDesc, 0, sizeof(EC_T_MBXTFER_DESC));
/* get max. FoE segment size */
dwRes = ecatGetCfgSlaveInfo(EC_TRUE, wSlaveAddress, &oCfgSlaveInfo);
if (EC_E_NOERROR != dwRes)
{
dwRetVal = dwRes;
goto Exit;
}
/* mailbox contains mailbox header, FoE header and payload for buffer */
dwBufferSize = oCfgSlaveInfo.dwMbxInSize - ETHERCAT_MAX_FOE_MBOX_HDR_LEN;
/* allocate segment buffer */
pbyBuffer = (EC_T_BYTE*)OsMalloc(dwBufferSize);
if (EC_NULL == pbyBuffer)
{
dwRetVal = EC_E_NOMEMORY;
goto Exit;
}
oMbxTferDesc.pbyMbxTferDescData = pbyBuffer;
oMbxTferDesc.dwMaxDataLen = dwBufferSize;
pMbxTfer = ecatMbxTferCreate(&oMbxTferDesc);
if (EC_NULL == pMbxTfer)
{
dwRetVal = EC_E_NOMEMORY;
goto Exit;
}
pMbxTfer->dwTferId = 0x12345678; /* uniq ID from application */
/* open local file */
pfLocalFile = OsFopen(MY_FOE_TRANSFER_LOCAL_FILENAME /* e.g. (EC_T_CHAR*)"MyFile.dat" */, "wb");
if (EC_NULL == pfLocalFile)
{
dwRetVal = EC_E_OPENFAILED;
goto Exit;
}
/* start upload */
dwRes = ecatFoeSegmentedUploadReq(pMbxTfer, dwSlaveId,
MY_FOE_TRANSFER_SLAVE_FILENAME /* e.g. (EC_T_CHAR*)"MyFile.dat" */, (EC_T_DWORD)OsStrlen(MY_FOE_TRANSFER_SLAVE_FILENAME),
0xffffffff /* unknown file size */, 0, MBX_TIMEOUT /* e.g. 5000 */);
if (EC_E_NOERROR != dwRes)
{
dwRetVal = dwRes;
goto Exit;
}
/* upload file writing segments to disk */
while ((eMbxTferStatus_Pend == pMbxTfer->eTferStatus)
|| (eMbxTferStatus_TferWaitingForContinue == pMbxTfer->eTferStatus))
{
/* wait for master received data from slave */
if (eMbxTferStatus_TferWaitingForContinue == pMbxTfer->eTferStatus)
{
/* write segment */
OsFwrite(pMbxTfer->pbyMbxTferData, pMbxTfer->dwDataLen, 1, pfLocalFile);
dwFileSize = dwFileSize + pMbxTfer->dwDataLen;
/* acknowledge segment so master can receive the next segment */
dwRes = ecatFoeSegmentedUploadReq(pMbxTfer, 0, EC_NULL, 0, 0, 0, 0);
if (EC_E_NOERROR != dwRes)
{
dwRetVal = dwRes;
goto Exit;
}
}
OsSleep(10);
}
if (eMbxTferStatus_TferReqError == pMbxTfer->eTferStatus)
{
dwRetVal = pMbxTfer->dwErrorCode;
goto Exit;
}
/* transfer done */
if (eMbxTferStatus_TferDone == pMbxTfer->eTferStatus)
{
dwRetVal = pMbxTfer->dwErrorCode; /* e.g. EC_E_NOERROR */
pMbxTfer->eTferStatus = eMbxTferStatus_Idle;
}
Exit:
/* free resources */
if (EC_NULL != pfLocalFile)
{
OsFclose(pfLocalFile);
}
if (EC_NULL != pMbxTfer)
{
if (eMbxTferStatus_Pend == pMbxTfer->eTferStatus)
{
CEcTimer oTimeout(MBX_TIMEOUT);
ecatMbxTferAbort(pMbxTfer);
while ((eMbxTferStatus_Pend == pMbxTfer->eTferStatus) && !oTimeout.IsElapsed())
{
OsSleep(100);
}
}
ecatMbxTferDelete(pMbxTfer);
}
SafeOsFree(pbyBuffer);
6.12.8. emConvertEcErrorToFoeError
6.12.9. emNotify - EC_NOTIFY_FOE_MBXSND_WKC_ERROR
This error will be indicated in case the working counter of a FoE mailbox write command was not set to the expected value of 1.
Detailed error information is stored in structure EC_T_WKCERR_DESC
of the union element WkcErrDesc.
-
struct EC_T_WKCERR_DESC
6.12.10. emNotify - EC_NOTIFY_FOE_MBSLAVE_ERROR
This error will be indicated in case a FoE mailbox slave send an error message.
Detailed error information is stored in structure EC_T_MBOX_FOE_ABORT_DESC
of the union element FoeErrorDesc.
-
struct EC_T_MBOX_FOE_ABORT_DESC
Public Members
-
EC_T_SLAVE_PROP SlaveProp
Slave properties
-
EC_T_SLAVE_PROP SlaveProp
6.12.11. Extending EC_T_MBX_DATA
FoE transfer data, e.g. progress information in notification.