初始化
强烈建议使用 Darra 配置工具导出的 DENI 文件进行初始化。 DENI 文件包含完整的网络配置(网口、从站、PDO 映射、DC 设置等),可确保配置的一致性和正确性。 使用 DENI 文件管理设备硬件设施将获得更好的兼容性与通用性。
工厂方法
EtherCATMaster 通过静态工厂方法创建实例,不使用 new 构造函数。
EtherCATMaster.create()
public static EtherCATMaster create()
public static EtherCATMaster create(short masterIndex)
创建主站实例,流式 API 入口。无参版本自动分配编号,带参版本指定编号。必须通过 setENI() 或 SetNetwork() 设置配置,然后调用 build() 初始化。
返回值:
EtherCATMaster— 主站实例
示例:
EtherCATMaster master = EtherCATMaster.create()
.setENI("C:\\EtherCAT\\MyProject.xml")
.build()
.master;
if (master == null) {
System.out.println("初始化失败");
return;
}
master.setState(EcState.OP);
EtherCATMaster.createFromJsonFile(String jsonFilePath)
public static EtherCATMaster createFromJson(String jsonConfig)
public static EtherCATMaster createFromJsonFile(String jsonFilePath)
通过 JSON 配置一步完成主站初始化。内部自动执行初始化、网络配置和状态转换全流程。
示例:
try (EtherCATMaster master = EtherCATMaster.createFromJsonFile("C:\\config.json")) {
System.out.println("从站数量: " + master.SlaveCount());
}
流式配置
setENI(String path)
public EtherCATMaster setENI(String path)
加载 DENI/ENI 配置文件(延迟配置,build 时生效)。
参数:
path(String) — DENI 或 ENI 配置文件路径
示例:
EtherCATMaster master = EtherCATMaster.create()
.setENI("C:\\EtherCAT\\MyProject.xml");
SetNetwork(String primary, String secondary)
public EtherCATMaster SetNetwork(String primary)
public EtherCATMaster SetNetwork(String primary, String secondary)
public int setNetwork(String adapter) // 返回从站数
public int setNetwork(String adapter, String redundantAdapter) // 返回从站数
通过网口名称设置主网口和可选的冗余网口(链式调用版延迟配置;setNetwork 立即设置并返回扫描到的从站数量)。
示例:
EtherCATMaster master = EtherCATMaster.create()
.SetNetwork("\\Device\\NPF_{...}");
// 冗余模式
EtherCATMaster master = EtherCATMaster.create()
.SetNetwork("\\Device\\NPF_{primary}", "\\Device\\NPF_{secondary}");
setEsiFile(String path)
public EtherCATMaster setEsiFile(String path)
加载单个 ESI 文件(延迟配置,build 时生效)。可多次调用。
如果使用 DENI 文件,通常不需要单独加载 ESI。
setEsiFiles(String path)
public EtherCATMaster setEsiFiles(String path)
加载 ESI 文件目录(延迟配置,build 时生效)。可多次调用。
enableAutoStartup()
public EtherCATMaster enableAutoStartup()
标记需要自动配置从站(build 时执行)。
如果使用 ENI/DENI 文件,通常不需要调用此方法。已有启动参数的从站会被完整跳过,不会被覆盖或补充。此方法仅对未配置的从站生效(自动从 ESI/MDP/SM 生成 PDO/DC/启动参数)。
setENI 和 SetNetwork 都可以设置网口。当两者同时使用时,后调用的方法覆盖前面的冲突配置:
// setENI 在后 -> 使用 ENI 文件中的网口配置
EtherCATMaster master = EtherCATMaster.create()
.SetNetwork("以太网 1")
.setENI("C:\\config.xml"); // <- ENI 中的网口覆盖 SetNetwork
// SetNetwork 在后 -> SetNetwork 的网口覆盖 ENI
EtherCATMaster master = EtherCATMaster.create()
.setENI("C:\\config.xml")
.SetNetwork("以太网 1"); // <- 覆盖 ENI 中的网口
ENI/DENI 文件中的从站配置、PDO 映射、DC 设置等始终保留,仅网口配置受覆盖规则影响。enableAutoStartup() 仅对未配置的从站生效,ENI/DENI 已配置的从站会被完整跳过。
构建
build()
public BuildResult build()
构建并初始化主站(终结方法)。执行流程:验证配置 → 加载 ENI → 设置网口 → 扫描从站 → 自动配置。
返回值:
BuildResult— 包含主站实例、从站数量、成功标志和消息
BuildResult 结构:
public static class BuildResult {
public final boolean success; // 是否成功
public final int slaveCount; // 从站数量
public final short masterIndex; // 主站索引
public final String message; // 成功/失败消息
public final EtherCATMaster master; // 主站实例(成功时非空,失败时为 null)
}
示例:
BuildResult result = EtherCATMaster.create()
.setENI("C:\\EtherCAT\\config.xml")
.SetNetwork("\\Device\\NPF_{...}")
.enableAutoStartup()
.build();
if (!result.success) {
System.out.println("初始化失败: " + result.message);
return;
}
EtherCATMaster master = result.master;
master.setState(EcState.OP);
Validate()
public ValidationResult Validate()
build 前配置预检查,不执行实际构建。检查 ENI 文件存在性、主站实例上限等。
返回值:
ValidationResult— 包含IsValid(boolean) 和Errors(List<String>) 字段
示例:
EtherCATMaster master = EtherCATMaster.create().setENI("config.xml");
EtherCATMaster.ValidationResult result = master.Validate();
if (!result.IsValid) {
for (String error : result.Errors) {
System.out.println("配置错误: " + error);
}
return;
}
master.build();
资源释放
close()
@Override
public void close()
关闭并清空内存,停止主站和数据采集线程。实现 AutoCloseable 接口,支持 try-with-resources。
try (EtherCATMaster master = EtherCATMaster.create()) {
master.SetNetwork("\\Device\\NPF_{...}");
master.setState(EcState.OP);
master.Start();
// ...
} // 自动释放
Stop()
public void Stop()
停止主站和 PDO 线程,但保留实例(可后续重新启动)。
emergencyCloseNics()
public static void emergencyCloseNics()
紧急清理所有主站资源 / 释放网卡句柄。在进程异常退出时调用,避免资源泄漏。
示例:
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
EtherCATMaster.emergencyCloseNics();
}));
多实例管理
getActiveInstanceCount()
public static int getActiveInstanceCount()
当前活跃的主站实例数量。
getMaxInstanceCount()
public static int getMaxInstanceCount()
允许的最大主站实例数量。
网络扫描
NetworkInfo.getAvailableNetworks(boolean isRedundant, boolean needSlavesNum)
public static List<NetworkInfo> getAvailableNetworks(boolean isRedundant, boolean needSlavesNum)
public static List<NetworkInfo> getAvailableNetworks()
获取系统中可用的网络适配器列表。needSlavesNum=true 时同时扫描每张 NIC 的从站数 + 自动识别冗余对。
参数:
isRedundant(boolean) — 是否筛选冗余网络适配器needSlavesNum(boolean) — 是否检测每个网卡上的从站数量(需扫描,较慢)
返回值:
List<NetworkInfo>— 网络适配器信息列表
NetworkInfo 结构:
public class NetworkInfo {
public String getName() // 适配器系统名称(用于 SetNetwork)
public String getDescription() // 适配器描述(用户可读)
public String getMacAddress() // MAC 地址
public Integer getSlaveCount() // 从站数量(需 needSlavesNum=true)
public Integer getRedundantSlaveCount() // 受冗余保护的从站数量
public boolean isUp() // 网卡是否在线
}
示例:
List<NetworkInfo> adapters = NetworkInfo.getAvailableNetworks(false, true);
for (NetworkInfo a : adapters) {
Integer count = a.getSlaveCount();
if (count == null || count == 0) continue;
int branch = count - (a.getRedundantSlaveCount() != null ? a.getRedundantSlaveCount() : 0);
System.out.println(a.getDescription() + ": " + count + " 个从站 (分支 " + branch + ")");
}
NetworkInfo.quickSlaveCount(String adapterName)
public static int quickSlaveCount(String adapterName)
快速从站计数(不读取 EEPROM,仅使用广播读取)。比完整扫描更快,适合快速检测从站数量。
返回值:
int— 检测到的从站数量
NetworkInfo.quickSlaveCountRedundant(String primary, String secondary)
public static int quickSlaveCountRedundant(String primary, String secondary)
冗余模式快速从站计数(不读取 EEPROM)。
NetworkInfo.getRingSlaveCount()
public static int getRingSlaveCount()
获取上一次冗余扫描中环形路径上的从站数。
EtherCATMaster.readSlaveInfo(String adapterName)
public static int readSlaveInfo(String adapterName)
public static int readSlaveInfo(String adapterName, String redundantAdapter)
一键扫描从站,扫描结果通过 NetworkInfo.getScannedSlaveInfoList() 获取。传入 redundantAdapter 时自动使用冗余模式扫描。
ScannedSlaveInfo 结构:
public static class ScannedSlaveInfo {
public int vendorId; // 厂商 ID
public int productCode; // 产品代码
public int revision; // 修订版本号
public int serialNumber; // 序列号
public String name; // 设备名称
public short configAddr; // 配置地址
public short aliasAddr; // 别名地址
public short parent; // 父从站编号(0=主站是父节点)
public byte topology; // 拓扑类型 (0~4)
public byte activePorts; // 活动端口位图
public byte entryPort; // 入口端口
public byte parentPort; // 父从站上的端口号
public byte physicalType; // 物理端口类型
}
示例:
// 1. 执行扫描
EtherCATMaster.readSlaveInfo("\\Device\\NPF_{...}");
// 2. 获取扫描结果
List<NetworkInfo.ScannedSlaveInfo> slaves = NetworkInfo.getScannedSlaveInfoList();
for (NetworkInfo.ScannedSlaveInfo s : slaves) {
System.out.printf("[%d] %s (VID=0x%08X, PID=0x%08X)%n",
s.configAddr & 0xFFFF, s.name, s.vendorId, s.productCode);
}
NetworkInfo.abortScan()
public static void abortScan()
中止所有正在进行的扫描操作。用于关闭窗口或取消操作时快速中断阻塞的网络扫描。
示例:
// 在后台线程中扫描
Thread scanThread = new Thread(() -> EtherCATMaster.readSlaveInfo(adapterName));
scanThread.start();
// 用户点击取消
NetworkInfo.abortScan();
版本与授权
getSerialNumber()
public static String getSerialNumber()
获取当前设备的序列号(用于授权验证)。
返回值:
String— 设备序列号,获取失败时返回空字符串
完整示例
使用 DENI 文件(推荐)
EtherCATMaster.BuildResult result = EtherCATMaster.create()
.setENI("C:\\EtherCAT\\MyProject.xml")
.build();
if (!result.success) {
System.out.println("初始化失败: " + result.message);
return;
}
EtherCATMaster master = result.master;
master.setState(EcState.OP);
master.Start();
动态扫描网口
List<NetworkInfo> adapters = NetworkInfo.getAvailableNetworks(false, true);
NetworkInfo target = adapters.stream()
.filter(a -> a.getSlaveCount() != null && a.getSlaveCount() > 0)
.findFirst().orElse(null);
if (target == null) return;
EtherCATMaster.BuildResult result = EtherCATMaster.create()
.SetNetwork(target.getName())
.setEsiFiles("C:\\ESI")
.enableAutoStartup()
.build();
if (!result.success) return;
EtherCATMaster master = result.master;
冗余模式 (自动识别冗余对)
List<NetworkInfo> adapters = NetworkInfo.getAvailableNetworks(false, true);
List<NetworkInfo> pair = new java.util.ArrayList<>();
for (NetworkInfo a : adapters) {
if (a.getRedundantSlaveCount() != null && a.getRedundantSlaveCount() > 0) pair.add(a);
}
if (pair.size() < 2) return; // 没找到冗余对
try (EtherCATMaster master = EtherCATMaster.create()) {
master.SetNetwork(pair.get(0).getName(), pair.get(1).getName());
master.setENI("C:\\config.xml");
master.build();
master.setState(EcState.OP);
master.Start();
}
多实例(多网卡独立总线)
每个主站实例管理一条独立的 EtherCAT 总线,使用不同的网卡。创建新实例无需重启,即时生效。
- 每个实例必须使用不同的网卡 — 同一网卡不能被多个实例同时使用,SDK 会自动检测并阻止重复绑定
- CPU 核心自动分配 — 每个实例自动占用不同的 CPU 核心,无需手动设置
- Mailbox Gateway 端口自动偏移 — 每个实例自动分配不同的端口号
- 授权与日志共享 — 所有实例共享同一授权状态和日志系统,无冲突
// 实例 1 — 绑定第一张网卡
EtherCATMaster master1 = EtherCATMaster.create();
master1.SetNetwork("\\Device\\NPF_{nic1}");
master1.setState(EcState.OP);
master1.Start();
// 实例 2 — 绑定第二张网卡(即时生效,无需重启)
EtherCATMaster master2 = EtherCATMaster.create();
master2.SetNetwork("\\Device\\NPF_{nic2}");
master2.setState(EcState.OP);
master2.Start();
System.out.println("活跃主站数: " + EtherCATMaster.getActiveInstanceCount());
// 释放时自动归还网卡和端口
master2.close(); // 释放后该网卡可被新实例使用