Lely canopen:用 EDS 和 master.yml 生成 CANopen 主站 DCF

在这里插入图片描述

本文以 Lely CANopen 2.4.0、Ubuntu 20.04 和 CANopenNode 从站为例,演示如何在开发机上安装 dcf-tools,编写原生 Lely master.yml,并从 EDS 生成可供主站程序使用的 master.dcf

本文要解决的问题

在嵌入式 CANopen 项目中,经常会同时存在两套运行环境:

  • 目标板运行交叉编译后的 Lely C/C++ 库;
  • 开发机运行 Python 版 dcf-tools,用于检查 EDS/DCF 和生成主站配置。

这两部分相互配合,但不需要安装到同一个系统,也不要求使用同一种架构。目标板可以继续使用 --disable-python --disable-cython 构建 Lely;dcf-tools 只安装在 Ubuntu 开发机上即可。

完成本文后,你将得到:

1
2
3
4
5
6
7
8
9
config/
├── project.eds # 原始从站 EDS
├── master.yml # Lely 主站生成配置
└── generated/
├── project.dcfgen.eds # 供 dcf-tools 使用的兼容副本
├── master.dcf # 主站运行时 DCF
├── master.bin # 可选:主站 concise DCF
├── mcu_node_1.bin # 可选:从站配置 concise DCF
└── SHA256SUMS # 生成物校验值

示例环境

本文命令基于以下环境整理。路径、CAN 接口和 Node-ID 可按实际项目替换。

项目 示例值
开发机 Ubuntu 20.04
Lely 源码 /home/embedsky/share/lely-imx8p/lely-core
Lely 版本 2.4.0
目标架构 AArch64 / i.MX8P
CAN 接口 can1
CAN 位速率 1000 kbit/s
从站 CANopenNode,Node-ID 1
主站 Node-ID 127

本文使用的示例 EDS 描述了一个 RT-Thread CANopenNode 设备,包含 4 个 RPDO、5 个 TPDO,并声明支持 LSS。后文将使用其中的默认 PDO 配置进行说明。

先理解 dcf-tools 在系统中的位置

Lely 工程中的核心组件可以分为两类:

1
2
3
4
5
6
7
8
9
10
11
12
flowchart LR
A[开发机 Ubuntu] --> B[dcfchk]
A --> C[dcfgen]
A --> D[dcf2dev]
E[从站 EDS] --> B
E --> C
F[master.yml] --> C
C --> G[master.dcf]
C --> H[可选 concise DCF .bin]
G --> I[目标板 Lely 主站程序]
H --> I
J[AArch64 Lely C/C++ 库] --> I

三个命令的职责如下:

命令 用途
dcfchk 检查 EDS/DCF 的语法和对象字典一致性
dcfgen 根据从站 EDS 和 master.yml 生成主站 DCF 及可选 concise DCF
dcf2dev 将 DCF 转换为设备相关源码或数据,具体用途取决于项目集成方式

关键点是:dcf-tools 是主机侧生成工具,不参与目标板运行,也不受目标板 ABI 约束。


第一步:固定 Lely 源码版本

不要在生成环境中无条件跟随 master 分支。dcf-tools 的 YAML 字段、模板和生成行为都可能随源码变化,因此应先记录当前 commit。

1
2
3
4
5
6
7
8
export WORK_ROOT=/home/embedsky/share/lely-imx8p
export LELY_SRC=${WORK_ROOT}/lely-core
export TESTER_ROOT=${WORK_ROOT}/canopen-slave-tester

cd "$LELY_SRC"
git status --short
git rev-parse HEAD
git describe --always --dirty

建议满足以下条件后再继续:

  1. 工作区没有未确认修改;
  2. 已保存完整 40 字符 commit SHA;
  3. 目标板 Lely C/C++ 库和开发机 dcf-tools 尽量来自同一个 commit;
  4. 自动化构建脚本不再直接执行 git pull

保存版本信息:

1
2
3
4
5
6
mkdir -p "$TESTER_ROOT/docs/baseline"
{
echo "repository=https://gitlab.com/lely_industries/lely-core.git"
echo "commit=$(git -C "$LELY_SRC" rev-parse HEAD)"
echo "describe=$(git -C "$LELY_SRC" describe --always --dirty)"
} > "$TESTER_ROOT/docs/baseline/LELY_SOURCE_VERSION.txt"

这样做的目的不是增加流程,而是确保未来能够回答两个问题:

  • 当前 master.dcf 是由哪一版工具生成的?
  • 升级 Lely 后,生成结果为什么发生变化?

第二步:在开发机安装 dcf-tools

2.1 安装 Python 环境

1
2
3
4
5
6
7
sudo apt update
sudo apt install -y \
python3 \
python3-venv \
python3-pip \
python3-setuptools \
python3-wheel

这里不需要安装 AArch64 交叉编译器,也不需要启用 Lely Cython bindings。

2.2 创建项目专用虚拟环境

不要把工具直接安装到系统 Python。项目专用虚拟环境可以避免不同 Lely 版本之间互相污染。

1
2
3
4
5
mkdir -p "$TESTER_ROOT"
python3 -m venv "$TESTER_ROOT/.venv-dcf-tools"
source "$TESTER_ROOT/.venv-dcf-tools/bin/activate"

python -m pip install --upgrade pip wheel setuptools

确认当前 Python 和 pip 均来自虚拟环境:

1
2
command -v python
command -v pip

输出路径应位于:

1
/home/embedsky/share/lely-imx8p/canopen-slave-tester/.venv-dcf-tools/bin/

2.3 从当前 Lely 源码安装

python/dcf-tools/setup.py 声明的主要依赖是 PyYAML 和 EmPy。对于已经验证过的工程,可以固定版本以提高复现性:

1
2
3
4
5
python -m pip install \
'PyYAML==6.0.3' \
'empy==4.2.1' \
'setuptools==75.3.2' \
wheel

然后从本地 Lely 源码安装,而不是从 PyPI 获取另一份版本:

1
python -m pip install --no-deps "$LELY_SRC/python/dcf-tools"

如果正在调试 dcf-tools 本身,可以改用 editable 模式:

1
2
python -m pip uninstall -y dcf-tools
python -m pip install --no-deps -e "$LELY_SRC/python/dcf-tools"

正式生成环境更适合普通安装。editable 模式会让源码目录中的临时修改立即影响生成结果,不利于复现。

依赖版本应以实际 Lely commit 和项目验证结果为准。升级 Lely 或 Python 后,应重新执行本文后面的生成与语义检查。

2.4 验证安装来源

1
2
3
4
5
6
7
8
9
10
command -v dcfchk
command -v dcfgen
command -v dcf2dev

python -m pip show dcf-tools
python -m pip freeze

dcfchk --help
dcfgen --help
dcf2dev --help

检查以下项目:

  • 三个命令都来自项目虚拟环境;
  • pip show 的安装位置在项目虚拟环境内;
  • dcf-tools 版本与当前源码中的 setup.py 一致;
  • dcfgen --help 至少能看到 -d-r-S-v

保存 Python 依赖基线:

1
2
3
4
5
6
7
python -m pip freeze > "$TESTER_ROOT/docs/baseline/DCF_TOOL_VERSION.txt"

{
echo
echo "source=$LELY_SRC/python/dcf-tools"
echo "lely_commit=$(git -C "$LELY_SRC" rev-parse HEAD)"
} >> "$TESTER_ROOT/docs/baseline/DCF_TOOL_VERSION.txt"

第三步:准备 EDS、YAML 和输出目录

推荐目录如下:

1
mkdir -p "$TESTER_ROOT/config/generated"
1
2
3
4
${TESTER_ROOT}/config/
├── project.eds
├── master.yml
└── generated/

为什么要保留一份 EDS 兼容副本

工程中的原始 EDS 是设备描述和测试证据,不建议为了适配某个工具版本直接修改。更稳妥的做法是:

  1. 保留 project.eds 原文件;
  2. 复制为 generated/project.dcfgen.eds
  3. 只在兼容副本中修正当前 dcf-tools 无法接受的字段;
  4. 对原始 EDS 和兼容副本分别记录 SHA256。

示例工程曾遇到两类兼容问题:

  • DeviceInfo.NG_Slave 不被当前工具识别;
  • DeviceInfo.RevisionNumber 与对象 0x1018:03 不一致。

可以先创建副本:

1
2
cd "$TESTER_ROOT/config"
cp project.eds generated/project.dcfgen.eds

随后只在 generated/project.dcfgen.eds 中处理兼容项,并保留变更说明。不要把工具兼容性修正伪装成设备固件真实配置的变化。


第四步:编写最小可控的 master.yml

本教程的目标是让测试程序显式控制 NMT、SDO 和 PDO,而不是让主站在启动时自动重配置从站。因此先使用一份“安全、最小、可观察”的配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Native Lely dcfgen 2.4.0 configuration.
# NMT/SDO/PDO operations are controlled explicitly by the test program.

options:
dcf_path: ""
heartbeat_multiplier: 3.0
retry_factor: 3

master:
node_id: 127
baudrate: 1000

vendor_id: 0x00000000
product_code: 0x00000000
revision_number: 0x00000000
serial_number: 0x00000000

sync_period: 0
sync_window: 0
sync_overflow: 0
time_cob_id: 0x00000100
emcy_inhibit_time: 0

heartbeat_multiplier: 3.0
heartbeat_consumer: false
heartbeat_producer: 0

error_behavior:
1: 0x00
nmt_inhibit_time: 0

start: false
start_nodes: false
start_all_nodes: false
reset_all_nodes: false
stop_all_nodes: false
boot_time: 0

mcu_node_1:
dcf: "generated/project.dcfgen.eds"
node_id: 1

heartbeat_consumer: false
heartbeat_producer: 0

boot: false
mandatory: false
reset_communication: false

顶层结构必须使用原生 Lely 格式

Lely 2.4.0 原生 dcfgen 使用以下结构:

1
2
3
4
5
6
7
8
options:
# 全局默认项

master:
# 主站配置

mcu_node_1:
# 从站配置

optionsmaster 和以点开头的模板 section 外,其他顶层 section 都会被当作从站。

不要直接使用某些 ROS 2 或 downstream 项目中的格式:

1
2
3
4
# 不适用于本文所用的原生 dcfgen 2.4.0

defaults: {}
nodes: []

原生工具可能把 defaultsnodes 误认为两个从站 section。

YAML 中最容易出错的类型

布尔值必须使用真正的 YAML boolean:

1
boot: false

不要写成字符串:

1
boot: "false"

当前源码会对配置值执行 Python bool() 转换,非空字符串即使内容是 "false",也会被判定为 true。

其他规则:

  • 十六进制整数不要加引号;
  • PDO 编号使用数字键;
  • cob_id: auto 是特殊字符串;
  • dcf 是生成阶段读取的 EDS/DCF 路径;
  • dcf_path 是生成物在运行环境中的目录前缀,两者含义不同。

第五步:检查 EDS 并生成 DCF

5.1 从正确目录执行

原生 dcfgen 会直接打开 dcf 字段中的路径。相对路径通常以命令执行时的当前目录为基准,而不是自动以 YAML 文件所在目录为基准。

因此建议始终进入 config/ 后执行:

1
2
cd "$TESTER_ROOT/config"
source "$TESTER_ROOT/.venv-dcf-tools/bin/activate"

5.2 清理旧生成物

1
2
3
4
rm -f generated/master.dcf \
generated/master.bin \
generated/mcu_node_1.bin \
generated/SHA256SUMS

不要依赖旧 .bin 是否还在来判断本次是否生成。先清理再生成,结果更容易解释。

5.3 检查从站 EDS

1
dcfchk -n 1 -p generated/project.dcfgen.eds

这里的 -n 1 用于按 Node-ID 1 解析 $NODEID 表达式。检查失败时应先处理 EDS 一致性问题,不建议直接使用跳过错误的方式进入正式生成。

5.4 生成主站 DCF

1
2
3
4
5
dcfgen \
-r \
-v \
-d generated \
master.yml

常用参数:

参数 作用
-d generated 指定输出目录
-r 在主站 DCF 中生成 remote PDO 对象和参数映射
-v 输出生成的 SDO 配置请求,便于检查隐式写操作
-S lint 失败时继续;正式生成不建议使用

5.5 检查主站 DCF

1
dcfchk -n 127 generated/master.dcf

生成命令成功只说明文件被写出,不代表主站行为符合测试目标。后面还需要进行语义检查。


第六步:理解生成结果

dcfgen 可能生成以下文件:

文件 是否必定生成 作用
master.dcf Lely 主站运行时设备描述、NMT 和 PDO 配置
master.bin 主站自身的 concise DCF 数据
<slave-name>.bin 主站在 boot/configuration 阶段写入对应从站的 concise DCF

是否生成 .bin 由配置内容决定。不要在脚本中假定它们始终存在。

对于显式测试型主站,第一版配置通常希望:

  • 一定生成 master.dcf
  • 尽量不生成 mcu_node_1.bin
  • 即使存在从站 .bin,主站也不自动 boot/configure 从站。

如果生成了意外的从站 .bin,重点检查这些字段是否与 EDS 默认值不同:

  • heartbeat_producer
  • guard_timelife_time_factor
  • error_behavior
  • rpdo / tpdo
  • sdo
  • TIME、SYNC 或 EMCY 相关覆盖项。

dcfgen -v 会打印对应的 SDO 写请求,是定位问题的首选手段。


第七步:检查主站是否会自动控制从站

7.1 检查 0x1F80 NMT 启动行为

当前示例配置为:

1
2
3
4
5
start: false
start_nodes: false
start_all_nodes: false
reset_all_nodes: false
stop_all_nodes: false

按照 Lely 2.4.0 的生成逻辑,0x1F80 应得到:

1
0x0000000D

这表示主站不会在启动阶段自动进入 operational,也不会自动启动从站。测试程序可以显式发送 NMT 命令,并独立验证状态转换。

0x1F80 的主要生成规则如下:

配置 0x1F80 的影响
初始值 bit 0 置 1
start_all_nodes: true bit 1 置 1
start: false bit 2 置 1
start_nodes: false bit 3 置 1
reset_all_nodes: true bit 4 置 1
stop_all_nodes: true bit 6 置 1

7.2 检查 0x1F81 从站 assignment

从站 section 的以下配置决定主站是否自动管理该节点:

1
2
3
boot: false
mandatory: false
reset_communication: false

主要位定义:

条件 assignment 位
节点存在 bit 0
boot: true bit 2
mandatory: true bit 3
reset_communication: false bit 4
software_version != 0 bit 5
software_file 非空 bit 6
restore_configuration != 0 bit 7
retry_factor bits 8..15
guard_time bits 16..31

对于协议功能测试,建议先关闭自动 boot 和自动 reset communication。否则主站程序的后台行为可能改变从站状态,导致测试结果难以归因。


第八步:验证示例 EDS 中的默认 PDO

本文示例 EDS 的默认 PDO 可用于验证 -r 生成结果是否合理。

RPDO1

示例 EDS 中 RPDO1 的关键配置为:

1
2
3
4
COB-ID:$NODEID + 0x200
Node-ID 1 时 CAN-ID:0x201
Transmission type:254
Mapping:0x2200:00,32 bit

对应的 YAML 覆盖写法如下,但在第一阶段不建议覆盖 EDS 默认配置:

1
2
3
4
5
6
7
8
9
mcu_node_1:
rpdo:
1:
enabled: true
cob_id: 0x201
transmission: 254
mapping:
- index: 0x2200
sub_index: 0

TPDO1

示例 EDS 中 TPDO1 的关键配置为:

1
2
3
4
5
线上的 CAN-ID:0x181
Transmission type:254
Event timer:1000 ms
Mapping:0x2100:00,32 bit
0x2101:00,32 bit

对应 YAML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mcu_node_1:
tpdo:
1:
enabled: true
cob_id: 0x181
transmission: 254
inhibit_time: 0
event_timer: 1000
sync_start: 0
mapping:
- index: 0x2100
sub_index: 0
- index: 0x2101
sub_index: 0

第一阶段更推荐让 dcfgen 直接读取 EDS 默认 PDO,并通过 -r 在主站侧生成 remote PDO。这样可以验证设备原始配置,而不是先由主站改写设备再测试。

PDO 配置注意事项

  • 只能引用 EDS 中已经存在的 PDO 编号;
  • 映射对象必须存在于对象字典;
  • 映射对象应声明支持 PDO mapping;
  • 一个经典 CAN PDO 的总映射长度不能超过 64 bit;
  • inhibit_time 单位为 100 μs;
  • event_timerevent_deadline 单位为 ms;
  • -rdcfgen 命令行参数,不是 YAML 字段。

第九步:按需启用 heartbeat、SYNC 和 SDO 配置

最小配置通过后,再逐项启用自动化功能。每次只增加一类配置,并比较 verbose SDO 输出和生成物差异。

9.1 Heartbeat

主站监控从站 heartbeat:

1
2
3
master:
heartbeat_consumer: true
heartbeat_multiplier: 3.0

从站生产 heartbeat:

1
2
mcu_node_1:
heartbeat_producer: 1000

如果 EDS 中 0x1017 默认值不是 1000,该配置通常会生成一条 SDO 写请求,并可能生成从站 .bin

不要同时启用有效 heartbeat producer 和 node guarding。当前源码检测到以下组合时会发出警告并清除 guarding:

1
2
3
guard_time != 0
life_time_factor != 0
heartbeat_producer != 0

9.2 SYNC

主站产生 10 ms 周期的 SYNC:

1
2
3
4
master:
sync_period: 10000
sync_window: 0
sync_overflow: 0

sync_period 单位为 μs,对应对象 0x1006。启用前需要确认从站 PDO transmission type 与同步策略匹配。

9.3 显式 SDO 写入

可以在从站 section 中追加配置阶段 SDO:

1
2
3
4
5
6
7
8
mcu_node_1:
sdo:
- index: 0x1017
sub_index: 0
value: 1000
- index: 0x2200
sub_index: 0
value: 0x12345678

字段含义:

字段 是否必填 默认值
index
sub_index 0
value 0

对于自动化测试框架,不建议把测试值固化在 master.yml。更清晰的做法是让测试用例运行时写入、验证并清理对象值,避免生成阶段的隐式配置掩盖协议行为。


master.yml 常用字段速查

options

字段 类型 默认值 说明
dcf_path string "" 运行时查找 .bin 的目录前缀
heartbeat_multiplier float 3.0 heartbeat consumer timeout 倍数
retry_factor int 3 NMT boot 重试因子

master

字段 说明
node_id 主站 Node-ID
baudrate 位速率,单位 kbit/s
vendor_id 0x1018:01
product_code 0x1018:02
revision_number 0x1018:03
serial_number 0x1018:04
sync_period 0x1006,单位 μs
sync_window 0x1007,单位 μs
sync_overflow 0x1019
time_cob_id 0x1012
emcy_inhibit_time 0x1015,单位 100 μs
heartbeat_consumer 是否生成从站 heartbeat consumer 配置
heartbeat_producer 主站 heartbeat 周期,单位 ms
error_behavior 0x1029
nmt_inhibit_time 0x102A,单位 100 μs
start 主站是否自行进入 operational
start_nodes 是否启动从站
start_all_nodes 是否广播启动所有节点
reset_all_nodes mandatory 节点异常时是否 reset all
stop_all_nodes mandatory 节点异常时是否 stop all
boot_time mandatory 从站 boot timeout,单位 ms

从站 section

字段 说明
dcf 生成阶段读取的 EDS/DCF 文件,必填
node_id 从站 Node-ID
dcf_path 运行时 .bin 目录前缀
revision_number 覆盖或校验 0x1018:03
serial_number 覆盖或校验 0x1018:04
heartbeat_consumer 从站是否监控主站 heartbeat
heartbeat_producer 从站 heartbeat 周期
retry_factor boot 重试因子
guard_time node guarding 周期
life_time_factor node guarding life time factor
error_behavior 从站 0x1029
rpdo / tpdo 覆盖从站 PDO 并生成主站对应映射
boot 是否由主站 boot/configure
mandatory 是否为 mandatory 节点
reset_communication boot 时是否允许 reset communication
software_file firmware 文件
software_version 期望软件版本
configuration_file concise DCF 文件路径
restore_configuration 恢复配置策略
sdo 配置阶段 SDO 写请求列表

当前原生 Lely 2.4.0 不支持某些 downstream 文档中常见的字段,例如:

1
2
3
4
5
6
7
8
boot_timeout
sdo_timeout_ms
driver
package
namespace
enable_lazy_load
defaults
nodes

使用字段前应以当前 commit 中 python/dcf-tools/dcfgen/cli.py 为准。


生成后建立可复现基线

生成完成后记录哈希:

1
2
3
4
5
6
7
cd "$TESTER_ROOT/config/generated"

sha256sum master.dcf project.dcfgen.eds > SHA256SUMS
[ ! -f master.bin ] || sha256sum master.bin >> SHA256SUMS
[ ! -f mcu_node_1.bin ] || sha256sum mcu_node_1.bin >> SHA256SUMS

sha256sum -c SHA256SUMS

建议提交或归档以下内容:

1
2
3
4
5
6
7
8
master.yml
project.eds 的 SHA256
project.dcfgen.eds
master.dcf
实际生成的 .bin
SHA256SUMS
LELY_SOURCE_VERSION.txt
DCF_TOOL_VERSION.txt

生成物比较不能只看文件是否变化,还应检查语义:

  • 主站 Node-ID 是否为 127;
  • 位速率是否为 1000 kbit/s;
  • 0x1F80 是否为预期值;
  • 从站 assignment 是否关闭自动 boot;
  • remote PDO 是否存在;
  • dcfgen -v 是否出现非预期 SDO 写请求。

常见问题排查

dcfgen: command not found

通常是虚拟环境未激活:

1
2
source "$TESTER_ROOT/.venv-dcf-tools/bin/activate"
command -v dcfgen

调用了错误的系统版本或 PyPI 版本

1
2
type -a dcfgen
python -m pip show dcf-tools

应确保命令路径和安装位置均指向项目虚拟环境。

找不到 EDS 文件

通常是从错误目录执行,导致相对路径解析失败:

1
2
cd "$TESTER_ROOT/config"
dcfgen -r -v -d generated master.yml

NG_Slave lint 警告

保留原始 EDS,仅在 project.dcfgen.eds 兼容副本中处理当前工具不识别的字段,并记录变更原因。

RevisionNumber 不一致

使兼容副本中的 DeviceInfo.RevisionNumber0x1018:03 一致。原始 EDS 继续作为设备输入证据保留。

生成了意外的从站 .bin

重新执行:

1
dcfgen -r -v -d generated master.yml

根据 verbose 输出定位是 heartbeat、PDO、guarding、error behavior 还是 sdo 产生了写请求。

主站启动后自动改变从站状态

检查:

1
2
3
4
5
6
7
8
master:
start: false
start_nodes: false

mcu_node_1:
boot: false
mandatory: false
reset_communication: false

同时检查生成后的 0x1F800x1F81,不要只检查 YAML 文本。

boot: "false" 仍然启用了 boot

原因是 quoted boolean 实际为字符串。改为:

1
boot: false

Lely 2.4.0 源码中的三个注意点

以下问题来自当前版本 dcfgen/cli.py 的实现细节。升级 Lely 后应重新核对,不应永久视为所有版本都存在。

1. configuration_file

当前源码读取 configuration_file 时,赋值目标与字段命名的直观含义不完全一致。建议:

  • 第一阶段不要主动覆盖该字段;
  • 优先使用自动生成的 <dcf_path>/<section-name>.bin
  • 如必须自定义路径,应增加生成结果测试。

2. event_deadline

当前源码处理 RPDO event_deadline 时存在变量引用风险。仅配置该字段可能导致异常或错误编码。

在修复和增加针对 0x140x:05 的测试之前,不建议在正式配置中使用它。

3. time_cob_id

当前从站解析路径中出现过 time_cob_idtime_cobid 命名不一致。第一阶段可保留 EDS 中 0x1012 的默认值,不通过 YAML 覆盖从站 TIME COB-ID。

升级时可使用以下命令审计字段和模板变化:

1
2
3
4
5
6
7
grep -nE 'if "[A-Za-z0-9_]+" in cfg' \
"$LELY_SRC/python/dcf-tools/dcfgen/cli.py"

git -C "$LELY_SRC" diff <old-commit>..<new-commit> -- \
python/dcf-tools/dcfgen/cli.py \
python/dcf-tools/dcfgen/data/master.dcf.em \
python/dcf-tools/setup.py

推荐的日常维护流程

EDS 或 master.yml 发生变化时:

1
2
3
4
5
6
7
8
flowchart TD
A[校验原始 EDS SHA256] --> B[生成兼容 EDS]
B --> C[dcfchk 检查从站]
C --> D[dcfgen -r -v]
D --> E[dcfchk 检查主站]
E --> F[检查 0x1F80 / 0x1F81 / PDO]
F --> G[生成 SHA256SUMS]
G --> H[提交配置、生成物和版本记录]

Lely commit 发生变化时:

1
2
3
4
5
6
重建或重装 dcf-tools 虚拟环境
-> 比较 cli.py、master.dcf.em 和 setup.py
-> 重新生成 DCF
-> 比较 verbose SDO 和对象字典语义
-> 重跑主站基础测试
-> 确认无回归后更新项目基线

完整执行命令汇总

下面给出一次完整生成流程,适合整理为项目脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
set -eu

export WORK_ROOT=/home/embedsky/share/lely-imx8p
export LELY_SRC=${WORK_ROOT}/lely-core
export TESTER_ROOT=${WORK_ROOT}/canopen-slave-tester

source "$TESTER_ROOT/.venv-dcf-tools/bin/activate"
cd "$TESTER_ROOT/config"

cp project.eds generated/project.dcfgen.eds
# 在这里执行项目定义的 EDS 兼容处理。

rm -f generated/master.dcf \
generated/master.bin \
generated/mcu_node_1.bin \
generated/SHA256SUMS

dcfchk -n 1 -p generated/project.dcfgen.eds
dcfgen -r -v -d generated master.yml
dcfchk -n 127 generated/master.dcf

cd generated
sha256sum master.dcf project.dcfgen.eds > SHA256SUMS
[ ! -f master.bin ] || sha256sum master.bin >> SHA256SUMS
[ ! -f mcu_node_1.bin ] || sha256sum mcu_node_1.bin >> SHA256SUMS
sha256sum -c SHA256SUMS

实际项目中,EDS 兼容处理不应依赖人工编辑,建议固化为可审查的脚本,并对修改前后的 SHA256 和差异内容进行记录。


总结

使用 Lely dcf-tools 时,最重要的不是“生成出一个 master.dcf”,而是保证生成过程可复现、生成行为可解释:

  1. 固定 Lely commit 和 Python 依赖;
  2. 把主机侧 dcf-tools 与目标板 C/C++ 库分开管理;
  3. 保留原始 EDS,只对兼容副本做工具适配;
  4. 从最小、禁止自动 boot 的 master.yml 开始;
  5. 使用 dcfgen -v 检查所有隐式 SDO 写入;
  6. 检查 0x1F800x1F81 和 remote PDO,而不是只看命令返回值;
  7. 将版本、配置、生成物和 SHA256 一起纳入项目基线。

按这个流程建立基线后,再逐项启用 heartbeat、SYNC、PDO 重映射或 concise DCF,问题会更容易定位,也更适合自动化测试和持续集成。

参考资料

  • Lely CANopen 安装文档:https://opensource.lely.com/canopen/docs/installation/
  • Lely dcf-tools 文档:https://opensource.lely.com/canopen/docs/dcf-tools/
  • Lely dcf-tools 源码:https://gitlab.com/lely_industries/lely-core/-/tree/master/python/dcf-tools
  • 当前项目重点源码:
    • python/dcf-tools/setup.py
    • python/dcf-tools/dcfgen/cli.py
    • python/dcf-tools/dcfgen/data/master.dcf.em