Wireshark Packet Capture of EtherCAT Frames
When testing EtherCAT EOE functionality using TwinCAT, we often find that it’s not possible to capture EtherCAT packets directly with Wireshark under normal conditions. Today, this article will guide you through how to perform packet capturing for EtherCAT.
Preparation Environment
Hardware Setup:
● EtherKit Development Board
● One Ethernet cable
● One Type-C USB cable
Software Setup:
● TwinCAT 3
● RT-Thread Studio
● Wireshark
EtherCAT EOE Project Download
First, install the EtherKit SDK package in RT-Thread Studio. Then, create a new example project: `etherkit_ethercat_eoe`. Compile and download the program.
Connect one end of the Ethernet cable from your computer to EtherKit’s ETH0 port. Additionally, modify the Ethernet adapter’s IP address to be in the same subnet as the slave device’s IP.
Observe the serial port status on the development board. At this point, you should see that the EOE app is running normally.
TwinCAT3 Simulation of EtherCAT Master Startup
During the startup process of TwinCAT3, it is also necessary to configure the ESI file and install the TwinCAT driver. For detailed instructions, please refer to the EtherKit user manual (https://gitee.com/RT-Thread-Studio-Mirror/sdk-bsp-rzn2l-etherkit/raw/master/docs/EtherKit_User_Manual.pdf). These steps will not be elaborated here.
Next, the master scans for slave devices and activates the slave:
After activating the slave device, you will see that the EtherKit development board’s onboard Ethernet indicator light is functioning normally. Additionally, the default slave operates in DC mode with SM-Synchron:
TwinCAT3 Configuration of DC-Synchron
First, we need to enable packet capturing support in Wireshark. Right-click on the device, then in the Adapter settings, check “Promiscuous Mode (use with Wireshark only)” to enable promiscuous mode.
Next, switch the device from the default SM-Synchron mode to DC-Synchron mode.
Finally, click on the top navigation bar: TwinCAT -> Restart TwinCAT (Config Mode).
Prompted with “Restart TwinCAT system in config mode,” click OK.
Next, click on “Activate.”
After that, switch back to SM-Synchron mode, open Wireshark, and select the corresponding network interface. At this point, you should be able to see the EtherCAT (ECAT) packets.
EtherCAT Data Frame Structure
EtherCAT data is transmitted directly using Ethernet frames, with a frame type of 0x88A4. An EtherCAT data frame consists of a 2-byte header and 44 to 1498 bytes of data. The data area is made up of one or more EtherCAT subframes, each corresponding to an individual device or slave station’s memory area.
EtherCAT Frame Structure Definition
Each EtherCAT subframe includes a subframe header, a data field, and the corresponding Working Counter (WKC). The WKC records the number of times the slave station has successfully processed the subframe. The master sets an expected WKC for each communication service subframe. The initial value of the working counter in the transmitted subframe is 0. After the slave correctly processes the subframe, the working counter increments by one. The master compares the WKC returned in the response subframe with the expected WKC to determine if the subframe was processed correctly. The EtherCAT Slave Controller (ESC) updates the WKC during data frame processing, and different communication services have varying methods of incrementing the WKC.
EtherCAT Subframe Structure Definition
EtherCAT Packet Analysis
1. Request Packet
First, we set up a filter rule:
ecat.cmd==BRD && ecat.ado==0x130
We randomly capture a BRD (Broadcast Read) packet. The master sends a packet to the slave with an offset address of 0x130, indicating a read of specific slave registers (such as device identifiers, status words, etc.). Such packets are commonly used during system initialization or status monitoring.
2. Response Packet
Slave Startup Process:
The master sequentially sends commands to offset addresses 0x120 with values 1, 2, 4, and 8, controlling the slave to transition through the following states in order:
● Initialization (INIT)
● Pre-Operation (PRE-OP)
● Safe-Operational (SAFE-OP)
● Operational (OP)
ecat.ado==0x120 && (ecat.adp==0x03e9 ||ecat.adp==0xffff)
Where `ecat.adp == 0xffff` indicates broadcast mode, meaning the master sends commands to all slaves; whereas `ecat.adp == 0x03e9` (for example) specifies a command directed to a particular slave address (which can be modified based on the actual address).
3. Control Commands and EOE Packet Filtering
We use the following filter rules to capture EtherCAT control commands and Ethernet over EtherCAT (EOE) related packets:
(ecat.ado==0x120 || ecat_mailbox.eoe) && (ecat.adp==0x03e9 || ecat.adp==0xffff)
Analysis Explanation
● `ecat.ado == 0x120`: Captures commands accessing the register at offset address 0x120, which is the slave status control register. The master uses it to send mode switch commands (such as INIT, PRE-OP, SAFE-OP, OP) to the slave.
● `ecat_mailbox.eoe`: Captures all Ethernet data encapsulated with the EOE protocol, which allows transferring standard Ethernet frames (like TCP/IP, UDP) over EtherCAT.
● `ecat.adp == 0x03e9`: Specifies a target slave address of 0x03e9 (decimal 1001), used for point-to-point communication with a specific slave.
● `ecat.adp == 0xffff`: Indicates a broadcast command, where the master simultaneously issues commands to all slaves.
Application Scenarios
This filtering rule can be used to monitor:
● The master’s control behavior over a specific slave (or all slaves) regarding operational mode changes.
● Data frames transmitted via EOE protocol (commonly used in EtherCAT slaves with TCP/IP interfaces, such as remote I/O modules or industrial cameras).
Below is an example of actual packet capture using Wireshark:
4. EtherCAT EOE Packet Capture of TCP Frames
First, modify the `src/hal_entry.c` file in your project directory by replacing its entire content with the following code:
/* * Copyright (c) 2006-2024, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024-03-11 Wangyuqiang first version */#include <rtthread.h>#include "hal_data.h"#include <rtdevice.h>#include <board.h>#include <sys/socket.h>#include <netdb.h>#include <string.h>#include <finsh.h>#define BUFSZ (1024)static const char send_data[] = "This is TCP Server from RT-Thread.";void hal_entry(void){ rt_kprintf("\nHello RT-Thread!\n"); rt_kprintf("==================================================\n"); rt_kprintf("This example project is an ethercat eoe routine!\n"); rt_kprintf("==================================================\n");}static void tcpserv(void *parameter){ char *recv_data; /* 用于接收的指针,后面会做一次动态分配以请求可用内存 */ socklen_t sin_size; int sock, connected, bytes_received; struct sockaddr_in server_addr, client_addr; rt_bool_t stop = RT_FALSE; /* 停止标志 */ int ret; recv_data = rt_malloc(BUFSZ + 1); /* 分配接收用的数据缓冲 */ if (recv_data == RT_NULL) { rt_kprintf("No memory\n"); return; } /* 一个socket在使用前,需要预先创建出来,指定SOCK_STREAM为TCP的socket */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { /* 创建失败的错误处理 */ rt_kprintf("Socket error\n"); /* 释放已分配的接收缓冲 */ rt_free(recv_data); return; } /* 初始化服务端地址 */ server_addr.sin_family = AF_INET; server_addr.sin_port = htons(5000); /* 服务端工作的端口 */ server_addr.sin_addr.s_addr = INADDR_ANY; rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); /* 绑定socket到服务端地址 */ if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) { /* 绑定失败 */ rt_kprintf("Unable to bind\n"); /* 释放已分配的接收缓冲 */ rt_free(recv_data); return; } /* 在socket上进行监听 */ if (listen(sock, 5) == -1) { rt_kprintf("Listen error\n"); /* release recv buffer */ rt_free(recv_data); return; } rt_kprintf("\nTCPServer Waiting for client on port 5000...\n"); while (stop != RT_TRUE) { sin_size = sizeof(struct sockaddr_in); /* 接受一个客户端连接socket的请求,这个函数调用是阻塞式的 */ connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size); /* 返回的是连接成功的socket */ if (connected < 0) { rt_kprintf("accept connection failed! errno = %d\n", errno); continue; } /* 接受返回的client_addr指向了客户端的地址信息 */ rt_kprintf("I got a connection from (%s , %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); /* 客户端连接的处理 */ while (1) { /* 发送数据到connected socket */ ret = send(connected, send_data, strlen(send_data), 0); if (ret < 0) { /* 发送失败,关闭这个连接 */ closesocket(connected); rt_kprintf("\nsend error,close the socket.\r\n"); break; } else if (ret == 0) { /* 打印send函数返回值为0的警告信息 */ rt_kprintf("\n Send warning,send function return 0.\r\n"); } /* 从connected socket中接收数据,接收buffer是1024大小,但并不一定能够收到1024大小的数据 */ bytes_received = recv(connected, recv_data, BUFSZ, 0); if (bytes_received < 0) { /* 接收失败,关闭这个connected socket */ closesocket(connected); break; } else if (bytes_received == 0) { /* 打印recv函数返回值为0的警告信息 */ rt_kprintf("\nReceived warning,recv function return 0.\r\n"); closesocket(connected); break; } /* 有接收到数据,把末端清零 */ recv_data[bytes_received] = '\0'; if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0) { /* 如果是首字母是q或Q,关闭这个连接 */ closesocket(connected); break; } else if (strcmp(recv_data, "exit") == 0) { /* 如果接收的是exit,则关闭整个服务端 */ closesocket(connected); stop = RT_TRUE; break; } else { /* 在控制终端显示收到的数据 */ rt_kprintf("RECEIVED DATA = %s \n", recv_data); } } } /* 退出服务 */ closesocket(sock); /* 释放接收缓冲 */ rt_free(recv_data); return ;}static int tcpserv_app(void){ rt_thread_t tcps = rt_thread_create("tcpserv", tcpserv, RT_NULL, 2048, 18, 10); if(tcps != RT_NULL) { rt_thread_startup(tcps); } return 0;}MSH_CMD_EXPORT(tcpserv_app, a tcp server sample);
After compiling, downloading, and reprogramming the device, and once the slave successfully connects to the master, execute the `tcpserv_app` command to start a TCP server:
Meanwhile, open your TCP testing software and configure the TCP client with the following settings:
● Target IP: 192.168.10.100 (slave’s IP)
● Target Port: 5000
Also, open Wireshark and monitor the network. You should be able to successfully capture TCP packets within the EtherCAT EOE network.
Appendix 1: EtherCAT Communication Service Commands
All EtherCAT subframe services are described from the master’s perspective. The data link layer defines the services for internal storage, reading, writing, and exchanging data within the slave device. The type of communication service provided by a subframe — such as read, write, or address access — is determined by the command byte in the subframe header:
When the master receives a response data frame, it inspects the Working Counter (WKC) within the subframe. If the WKC does not match the expected value, it indicates that the subframe was not processed correctly. The expected WKC value depends on the type of communication service and the addressing used.
For each slave processing the subframe:
● If it is a read or write operation performed individually, the WKC increments by 1 upon completion.
● For a combined read/write operation:
● WKC increments by 1 if the read was successful.
● WKC increments by 2 if the write was successful.
● WKC increments by 3 when both read and write are completed successfully.
● When multiple slaves process the same subframe, the WKC is the sum of each slave’s individual processing results.
This mechanism ensures the master can verify the successful processing of each subframe across the network.