【原创】IgH EtherCAT主站详解(十五)--EOE网络桥架与FoE固件升级

一、EoE 网络桥接

4.7 — Ethernet over EtherCAT 虚拟网络接口与桥接配置


概览

什么是 EoE?

EoE (Ethernet over EtherCAT) 是一种通过 EtherCAT 总线隧道传输标准以太网帧的协议。它允许主站与支持 EoE 的从站之间建立虚拟网络连接,使从站像普通网络设备一样收发 TCP/IP 数据。每个支持 EoE 的从站都会在 Linux 系统中创建一个虚拟网络接口 (如 eoe0),可以配置 IP 地址并加入网桥。

EoE 典型应用

从站网络管理: 远程 Telnet/SSH 到从站内部控制器
Web 服务器: 访问从站内嵌的 Web 配置界面
文件传输: 不依赖 FoE 的文件传输方式
远程调试: 通过网络调试从站固件


技术详情

EoE 数据传输架构

flowchart TD subgraph "Linux 网络栈" A["TCP/IP 应用<br/>(ping/ssh/http)"] --> B["Linux 网络协议栈"] B --> C["虚拟网络接口 eoe0<br/>(net_device)"] end subgraph "IgH EtherCAT Master" C --> D["ec_eoe_t 结构体<br/>SKB 发送/接收队列"] D --> E["EoE 请求队列<br/>eoe_request_t"] E --> F["Slave FSM<br/>邮箱 EoE 传输"] end subgraph "EtherCAT 总线" F --> G["EoE 邮箱帧<br/>分片传输"] G --> H["从站 ESC<br/>EoE 解封装"] end H --> I["从站内部<br/>以太网控制器"] style C fill:#ebf8ff,stroke:#90cdf4 style F fill:#fefcbf,stroke:#ecc94b

EoE 帧分片机制

标准以太网帧 (MTU 1500 字节) 需要通过 EtherCAT 邮箱分片传输:

字段 大小 说明
EoE Header 4 字节 包含帧类型、分片偏移、帧号、分片标志
Ethernet Header 14 字节 仅在第一帧中包含
Payload 可变 以太网帧数据(分片)
Last Fragment 1 bit 标志是否为最后一个分片

EoE 配置步骤流程

flowchart TD A["加载主站模块<br/>insmod ec_master.ko<br/>eoe_interfaces=eoe0:0:0"] --> B["EoE 接口自动创建<br/>或手动 ethercat eoe_addif"] B --> C["配置 IP 地址<br/>ip addr add 192.168.1.1/24 dev eoe0"] C --> D["启动接口<br/>ip link set eoe0 up"] D --> E["创建网桥 (可选)<br/>brctl addbr eoebr0<br/>brctl addif eoebr0 eoe0"] E --> F["配置网桥 IP<br/>ip addr add 192.168.1.1/24 dev eoebr0"] F --> G["测试连通性<br/>ping 192.168.1.2"] style A fill:#c6f6d5,stroke:#68d391 style G fill:#c6f6d5,stroke:#68d391

完整配置案例

EoE 桥接配置示例

# ===== 方法 1: 使用 ethercat 命令行工具 =====

# 1. 为从站 0 (alias=0, position=0) 创建 EoE 接口
ethercat eoe_addif 0 0
# 输出: Created EoE interface eoe0 for alias 0, position 0

# 2. 配置 IP 地址
ip addr add 192.168.1.100/24 dev eoe0
ip link set eoe0 up

# 3. 测试连通性
ping 192.168.1.200  # 从站的 IP 地址

# ===== 方法 2: 使用网桥模式 =====

# 1. 创建网桥
brctl addbr eoebr0

# 2. 添加 EoE 接口到网桥
brctl addif eoebr0 eoe0

# 3. 配置网桥 IP
ip addr add 192.168.1.100/24 dev eoebr0
ip link set eoebr0 up

# ===== 方法 3: 模块参数自动创建 =====

# 加载模块时指定 EoE 接口
insmod ec_master.ko \
    main_devices=00:11:22:33:44:55 \
    eoe_interfaces=eoe0:0:0,eoe1:0:1

# 格式: 接口名:主站索引:从站位置

# ===== 删除 EoE 接口 =====
ethercat eoe_delif eoe0

ifup-eoe.sh 自动桥接脚本

IgH 提供的 script/ifup-eoe.sh 可以在网络接口启动时自动将 EoE 接口加入网桥:

script/ifup-eoe.sh

# 自定义配置
BRNAME="eoebr0"              # 网桥名称
INTERFACES=""                 # 要桥接的接口列表

# 检查接口是否在列表中
# 创建网桥(如果不存在)
brctl addbr ${BRNAME}

# 将接口加入网桥
ip link set ${IFNAME} down
ip addr flush dev ${IFNAME}
brctl addif ${BRNAME} ${IFNAME}
ip link set ${IFNAME} up

深入源码

EoE 数据结构

源文件: master/ethernet.h, master/ethernet.c

字段 类型 说明
dev struct net_device * Linux 虚拟网络设备
slave ec_slave_t * 关联的从站
opened unsigned int 接口是否已打开
tx_skb struct sk_buff * 当前发送中的 SKB
tx_queue struct list_head SKB 发送队列
rx_skb struct sk_buff * 当前接收中的 SKB
rx_expected_fragment unsigned int 期望的下一个分片偏移
tx_fragment_number uint16_t 发送帧序号
rx_frame_number uint16_t 接收帧序号
rate_jiffies unsigned long 速率统计

EoE 虚拟网络设备操作

ec_netdev_ops 定义了虚拟网络设备的操作函数:

操作 函数 说明
ndo_open ec_eoedev_open() 打开网络接口
ndo_stop ec_eoedev_stop() 关闭网络接口
ndo_start_xmit ec_eoedev_tx() 发送数据包(从 Linux 网络栈接收)
ndo_get_stats ec_eoedev_stats() 获取接口统计信息

EoE 数据收发流程

sequenceDiagram participant STACK as Linux TCP/IP participant DEV as eoe0 (net_device) participant EOE as ec_eoe_t participant FSM as EoE FSM participant SLAVE as 从站 ESC Note over STACK,SLAVE: === 发送方向 (主站 → 从站) === STACK->>DEV: ip_send_packet() DEV->>EOE: ec_eoedev_tx(skb) EOE->>EOE: 将 SKB 加入 tx_queue EOE->>EOE: 唤醒 EoE 内核线程 loop EoE 线程处理 EOE->>EOE: 从 tx_queue 取出 SKB EOE->>EOE: 将以太网帧分片为 EoE 邮箱帧 EOE->>FSM: 创建 eoe_request FSM->>SLAVE: EoE Write Request (邮箱) SLAVE-->>FSM: EoE Write Response FSM-->>EOE: 分片发送完成 EOE->>EOE: 继续下一个分片 end EOE->>DEV: 发送完成回调 DEV->>STACK: 释放 SKB Note over STACK,SLAVE: === 接收方向 (从站 → 主站) === SLAVE->>FSM: EoE Read Request (从站主动发送) FSM->>EOE: 解析 EoE 分片 EOE->>EOE: 重组以太网帧 EOE->>DEV: netif_rx(skb) DEV->>STACK: 数据包进入 Linux 协议栈

EoE IP 设置 FSM

源文件: master/fsm_eoe.c

EoE FSM 除了数据传输,还负责设置从站的 IP 参数:

状态 行号 说明
set_ip_start 241 开始设置 IP 参数
set_ip_request 275 发送 IP 设置请求
set_ip_check 335 检查响应帧头
set_ip_response 400 读取完整响应
set_ip_response_data 439 解析设置结果
end 527 正常结束
error 516 错误处理

EoE 线程

位置: master/master.c:ec_master_eoe_start() (行 2071)

EoE 处理运行在独立的内核线程 EtherCAT-EoE 中:

  1. 遍历所有 EoE handler
  2. 对每个打开的 handler:
  • 处理发送队列中的 SKB(分片发送)
  • 检查从站的 EoE 接收数据
  • 统计传输速率
  1. 如果没有数据需要处理,休眠等待唤醒

性能提示: EoE 通过邮箱通信,带宽有限(取决于邮箱大小和周期)。不适合大量数据传输,主要用于配置和诊断。典型吞吐量约 1-5 Mbps。

二、固件升级 (FoE)

4.6 — File Access over EtherCAT 固件升级端到端流程


概览

什么是 FoE?

FoE (File Access over EtherCAT) 是 EtherCAT 协议中用于文件传输的协议,类似于 TFTP。它的主要用途是从站固件升级:将固件二进制文件从主站传输到从站的非易失性存储器(Flash)。FoE 通过邮箱通信进行,支持读写两种操作。

FoE 特点

简单可靠: 协议类似 TFTP,请求-确认握手模式
分块传输: 大文件分割为多个数据块逐个传输
错误重传: 传输失败时自动重试
命令行工具: ethercat foe_write / ethercat foe_read


技术详情

FoE 写入流程 (固件升级)

以下是从主站向从站写入固件文件的完整流程:

sequenceDiagram participant TOOL as ethercat tool participant MST as ec_master participant FSM as FoE FSM participant SLAVE as 从站 ESC TOOL->>MST: ecrt_master_write_foe() MST->>FSM: ec_fsm_foe_transfer(WRITE) FSM->>SLAVE: FoE WRQ (Write Request)<br/>OpCode=1, Password, Filename SLAVE-->>FSM: FoE ACK (Acknowledge)<br/>OpCode=2 loop 每个数据块 FSM->>SLAVE: FoE Data<br/>OpCode=3, BlockNumber, Data[0..n] SLAVE-->>FSM: FoE ACK<br/>OpCode=2, BlockNumber+1 end FSM->>SLAVE: FoE Data (最后一个块, 长度>FSM: FoE ACK FSM-->>MST: 传输完成 MST-->>TOOL: 返回成功 Note over FSM,SLAVE: 错误处理 SLAVE-->>FSM: FoE ERROR (OpCode=4) FSM->>FSM: 重试或上报错误

FoE 协议帧格式

OpCode 名称 方向 说明
0x01 WRQ (Write Request) 主站→从站 请求写入文件,携带 Password 和 Filename
0x02 ACK (Acknowledge) 从站→主站 确认收到数据块,携带下一个 BlockNumber
0x03 DATA 主站→从站 数据块,携带 BlockNumber 和文件数据
0x04 ERROR 从站→主站 错误响应,携带错误码和错误文本
0x05 RRQ (Read Request) 主站→从站 请求读取文件
0x06 BUSY 从站→主站 从站繁忙,请求等待

固件升级操作步骤

固件升级命令

# 1. 查看当前从站状态
ethercat slaves

# 2. 确认从站进入 BOOT 状态 (固件升级模式)
ethercat states -p 0 BOOT

# 3. 执行固件写入
ethercat foe_write -p 0 firmware.bin

# 4. 等待传输完成,重启从站
ethercat reboot -p 0

# 5. 验证固件版本
ethercat slaves -v

FoE 读取流程 (文件读取)

从从站读取文件的流程与写入相反:

  1. 主站发送 RRQ (Read Request),携带 Password 和 Filename
  2. 从站响应 DATA 帧,携带文件数据块
  3. 主站发送 ACK 确认,携带下一个期望的 BlockNumber
  4. 重复直到所有数据传输完毕

⚠ 注意事项

从站状态: 固件升级通常需要从站进入 BOOT (Bootstrap) 状态
传输中断: 如果传输中断,从站可能处于不完整固件状态,需要重新传输
密码保护: 部分 ESC 芯片的 FoE 操作需要正确的 Password
块大小: 每个数据块大小受邮箱大小限制(通常 128-512 字节)


深入源码

FoE FSM 状态函数

源文件: master/fsm_foe.c, master/fsm_foe.h

写操作 (Write) 状态转换:

stateDiagram-v2 [*] --> wrq_sent: 发送 WRQ 写请求 wrq_sent --> ack_read_data: 收到 ACK wrq_sent --> error: 收到 ERROR/超时 ack_read_data --> ack_check: 读取完整 ACK ack_check --> data_sent: 准备数据块并发送 ack_check --> end: 最后一个块已确认 data_sent --> ack_read_data: 等待下一个 ACK data_sent --> ack_check: 检查 ACK 内容 data_sent --> error: 收到 ERROR error --> [*]: 上报错误 end --> [*]: 传输完成

状态函数清单

状态函数 行号 职责
state_wrq_sent 525 WRQ 发送后,等待从站 ACK/ERROR 响应
state_rrq_sent 684 RRQ 发送后,等待从站 DATA/ERROR 响应
state_ack_check 329 检查 ACK 帧头,发起读取完整 ACK
state_ack_read 392 读取完整 ACK 响应数据
state_ack_read_data 430 解析 ACK 内容,获取 BlockNumber
state_data_sent 572 Data 帧发送后,等待 ACK 确认
state_data_check — 检查 Data 帧(读操作)
state_data_read — 读取 Data 帧数据(读操作)
state_data_read_data — 处理 Data 帧内容(读操作)
state_sent_ack — ACK 发送后(读操作)

ethercat foe_write 命令实现

源文件: tool/CommandFoeWrite.cpp

命令执行流程:

  1. 解析命令行参数(从站位置、文件名、密码)
  2. 打开固件文件,读取全部内容到内存
  3. 创建 ec_foe_request_t,设置文件名、密码、数据
  4. 通过 ioctl 发送 EC_IOCTL_FOE_WRITE 命令
  5. 内核侧创建 FoE 请求,加入从站请求队列
  6. Slave FSM 在其循环中检测到 FoE 请求,启动 FoE FSM
  7. FoE FSM 执行完整的写入握手流程
  8. 完成后通过 ioctl 返回结果给用户空间

FoE 错误码

错误码 名称 含义
0x0001 NOT_DEFINED 未定义错误
0x0002 NOT_FOUND 文件未找到
0x0003 ACCESS_DENIED 访问被拒绝(密码错误)
0x0004 DISK_FULL 磁盘空间不足
0x0005 ILLEGAL_PACKET 非法数据包
0x0006 PACKET_NUMBER 包序号错误
0x0007 OPERATION 操作不支持
0x0008 UNKNOWN 未知错误
posted @ 2026-04-14 21:57  沐多  阅读(284)  评论(0)    收藏  举报