主站诊断
通过 master.Diagnostics() 访问所有诊断、监控、统计功能。
建议通过 事件 驱动异常处理,而非自行轮询。 直接读取诊断属性适用于 UI 显示等场景。
单个从站的状态诊断、链路质量请参考 从站诊断。
功能概览
| 功能 | 说明 |
|---|---|
| 通信与性能统计 | 帧计数、丢包、抖动、PDO 丢帧、网口状态、拓扑 |
| DC 同步 | 同步窗口阈值、DCSyncLost 事件 |
| 冗余状态 | 冗余激活、故障点检测(断线 + CRC 故障定位) |
| 诊断快照 | 一次取所有诊断指标的一致快照 |
| 诊断控制 | 启停数据采集、重置统计 |
通信与性能统计
| 类别 | 方法 | 类型 | 需启用 | 说明 |
|---|---|---|---|---|
| 帧计数 | getRTcnt() | int | 是 | 每秒帧数(Hz),5 秒平均 |
| getErrorCnt() | long | 是 | 每秒错误数,5 秒平均 | |
| getPacketLossRate() | float | 是 | 最近 5 秒丢包率(TX vs RX 滑窗, 0.0~1.0) | |
| getLateFrameRate() | float | 是 | 过慢帧率(idx 出 8 帧窗 stale, 不计丢, 0.0~1.0) | |
| 周期与抖动 | getCycleTimeSpan() | int | 是 | 实际周期时间(微秒) |
| getAvgJitterUs() | double | 是 | 最近 5 秒平均抖动(微秒) | |
| getMaxJitterUs() | double | 是 | 最近 5 秒最大抖动(微秒) | |
| 总线实时性能 | getBusCycleHz() | long | 不可停 | 总线频率(Hz) |
| getBusMaxJitterUs() | double | 不可停 | 总线最大抖动(微秒) | |
| getBusAvgJitterUs() | double | 不可停 | 总线平均抖动(微秒) | |
| getBusRoundtripUs() | double | 不可停 | 报文往返延迟(微秒) | |
| getBusLoadPercent() | double | 不可停 | 通讯负载(%)-- RTT/周期×100 | |
| getSmiCount() | long | 不可停 | SMI 累计次数 | |
| getSmiPeakUs() | double | 不可停 | SMI 峰值抖动(微秒) | |
| PDO 丢帧 | getPDO().getTotalLost() | int | 不可停 | 累计丢帧数(所有组合计) |
| getPDO().getConsecutiveLost() | int | 不可停 | 当前连续丢帧数(所有组中最大值) | |
| getPDO().getFrameLossStats(int) | int[] | 不可停 | 指定组丢帧统计 [累计, 连续, 最大连续] | |
| 从站异常 | getWorstSlaveIndex() | int | 不可停 | 异常率最高的从站索引 |
| getWorstLinkQuality() | short | 不可停 | 最差从站健康度(%) | |
| 网口状态 | isPrimaryPortOk() | boolean | 不可停 | 主端口是否正常 |
| isSecondaryPortOk() | boolean | 不可停 | 副端口是否正常 | |
| getPrimaryPortErrors() | long | 不可停 | 主端口最近 5 秒错误数 | |
| getSecondaryPortErrors() | long | 不可停 | 副端口最近 5 秒错误数 | |
| 拓扑 | getTopologyDescription() | String | 不可停 | 拓扑描述(线性/环形) |
| getTimingMode() | String | 不可停 | 定时模式描述("硬件定时器" / "RT就绪" / "降级" / "RT错误"),WDK 驱动必须就绪 |
| 指标 | 公式 | 说明 |
|---|---|---|
| RTcnt | 采样周期帧数 / 窗口秒数 | 滑动窗口平均帧频 |
| ErrorCnt | 采样周期错误数 / 窗口秒数 | 滑动窗口平均错误率 |
| PacketLossRate | (TX-RX-pipeline) / TX | 5 秒滑窗, pipeline 在途不算丢 |
| LateFrameRate | LateDrop / TX | idx 出 8 帧窗 stale, 不计入丢包 |
需 setEnabled(true)。
示例:
MasterDiagnosticsInfo diag = master.Diagnostics();
diag.setEnabled(true); // 启用诊断数据采集
// 帧计数
System.out.println("帧频: " + diag.getRTcnt() + " Hz");
System.out.printf("丢包率: %.2f%%%n", diag.getPacketLossRate() * 100);
// 周期与抖动
System.out.println("周期时间: " + diag.getCycleTimeSpan() + " us");
System.out.printf("抖动: 平均 %.2f us, 最大 %.2f us%n",
diag.getAvgJitterUs(), diag.getMaxJitterUs());
// PDO 丢帧
MasterDiagnosticsInfo.MasterPDODiagnostics pdo = diag.getPDO();
System.out.printf("PDO 丢帧: 累计=%d, 连续=%d%n",
pdo.getTotalLost(), pdo.getConsecutiveLost());
// 从站异常
System.out.printf("最差从站: #%d (%d%%)%n",
diag.getWorstSlaveIndex(), diag.getWorstLinkQuality());
// 网口状态
System.out.println("主端口: " + (diag.isPrimaryPortOk() ? "正常" : "异常"));
System.out.println("副端口: " + (diag.isSecondaryPortOk() ? "正常" : "未连接"));
// 拓扑信息
System.out.println("拓扑: " + diag.getTopologyDescription());
System.out.println("定时: " + diag.getTimingMode());
每个从站的 ESC 端口错误通过 readSlaveErrorCounters() 获取。详见 从站错误计数器。
DC 同步
自动监控(ETG.1500 5.13.3),每秒检查各从站时间偏差。超出同步窗口阈值时触发 DCSyncLost 事件。
通过 getSyncWindowThreshold() / setSyncWindowThreshold(int thresholdNs) 读写同步窗口阈值(纳秒),默认 1000ns。
示例:
MasterDiagnosticsInfo diag = master.Diagnostics();
diag.setSyncWindowThreshold(500); // 500ns 阈值
单个从站的同步状态请使用从站级 DC 诊断方法。
冗余状态
getRingMode() 反映环拓扑冗余的运行状态("无冗余" / "双向冗余" / "降级(仅primary)")。
getBreakPoint() / getAllBreakPoints() 统一检测两类物理故障:
| 类型 | faultType | 检测方式 | 典型场景 |
|---|---|---|---|
| 断线 | 0 | DL Status 端口物理链路丢失 | 拔线、线缆断裂 |
| CRC 故障 | 1 | 端口级 RxError + InvalidFrame 持续增长 | 接触不良、线缆老化、连接器氧化 |
故障线缆段定位: 当相邻从站的对向端口(如从站 N 的 P1 和从站 N+1 的 P0)同时报故障,说明连接线缆有问题。仅单侧报故障则定位到该端口连接器。
BreakPointInfo 结构:
public static class BreakPointInfo {
public final int slaveIndex; // 故障从站索引 (1-based)
public final int port; // 故障端口号 (0-3, 对应 P0-P3)
public final int faultType; // 故障类型: 0=断线, 1=CRC故障
public boolean isLinkDown(); // 是否为断线故障
public boolean isCrcFault(); // 是否为 CRC 故障
}
单个从站的冗余状态请参考 从站诊断 - 冗余诊断。
示例:
MasterDiagnosticsInfo diag = master.Diagnostics();
// 环拓扑冗余模式
System.out.println("冗余模式: " + diag.getRingMode());
if (diag.isRedundancyActive()) {
System.out.println("冗余已激活");
}
MasterDiagnosticsInfo.BreakPointInfo bp = diag.getBreakPoint();
if (bp != null) {
System.out.println("故障: " + bp);
if (bp.isCrcFault()) {
System.out.println("建议检查线缆/连接器");
}
}
// 获取所有故障点
for (MasterDiagnosticsInfo.BreakPointInfo b : diag.getAllBreakPoints()) {
System.out.println("故障点: " + b);
}
诊断快照
GetSnapshot()
public DiagnosticsSnapshot GetSnapshot()
一次调用获取所有诊断数据的一致快照,避免多次属性访问导致的数据不一致和性能开销。适合 UI 刷新和日志记录场景。
返回值:
DiagnosticsSnapshot— 诊断数据快照对象
相关结构:
public static class DiagnosticsSnapshot {
public final int Frequency; // 应用频率 (Hz)
public final long ErrorCount; // 每秒错误数
public final float PacketLossRate; // 丢包率 (0.0~1.0) — TX vs RX 5s 滑窗
public final float LateFrameRate; // 过慢帧率 (0.0~1.0)
public final double AvgJitterUs; // 平均抖动 (微秒)
public final double MaxJitterUs; // 最大抖动 (微秒)
public final int CycleTimeUs; // 实际周期时间 (微秒)
public final short WkcActual; // WKC 实际值
public final short WkcExpected; // WKC 期望值
public final long BusCycleHz; // 总线频率 (Hz)
public final double BusMaxJitterUs; // 总线最大抖动 (微秒)
public final double BusAvgJitterUs; // 总线平均抖动 (微秒)
public final double BusRoundtripUs; // 报文往返延迟 (微秒)
public final double BusLoadPercent; // 通讯负载 (%) — RTT/周期×100
public final long SmiCount; // SMI 累计次数
public final double SmiPeakUs; // SMI 峰值抖动 (微秒)
public final boolean PrimaryPortOk; // 主端口是否正常
public final boolean SecondaryPortOk; // 副端口是否正常
public final boolean RedundancyActive; // 冗余是否激活
}
示例:
MasterDiagnosticsInfo diag = master.Diagnostics();
diag.setEnabled(true);
MasterDiagnosticsInfo.DiagnosticsSnapshot snap = diag.GetSnapshot();
System.out.printf("频率: %d Hz, 丢包: %.2f%%, 抖动: %.2f us%n",
snap.Frequency, snap.PacketLossRate * 100, snap.AvgJitterUs);
System.out.printf("WKC: %d/%d, 总线: %d Hz%n",
snap.WkcActual, snap.WkcExpected, snap.BusCycleHz);
if (snap.RedundancyActive) {
System.out.println("冗余已激活");
}
诊断控制
标记为"是"的属性需先设置 setEnabled(true) 启动周期性采样,标记为"不可停"的功能始终活跃。
reset (诊断计数器)
public void reset()
一次性重置所有诊断统计,包括:
- 基础诊断统计(帧错误等)
- PDO 丢帧统计(所有组)
- DC 同步窗口统计
- 所有从站的端口错误计数器
只清空主站层面的统计数据, 不影响 FSoE 安全连接状态机(slave.FSoE.Reset)。
示例:
MasterDiagnosticsInfo diag = master.Diagnostics();
diag.setEnabled(true); // 启用采集
// ... 运行一段时间 ...
diag.reset(); // 重置统计
AL 错误分类
对 AL Status Code 进行分类,帮助快速判断错误性质和处理策略。
EtherCATTypes.classifyALError
public static EtherCATTypes.ALErrorCategory classifyALError(int errorCode)
对 AL Status Code(从站返回的错误码)进行分类,帮助快速判断错误性质和处理策略。
参数:
errorCode(int) — AL Status Code,从slave.ErrorCode()或状态转换失败时获取
返回值:
ALErrorCategory— 错误分类枚举
相关结构:
public enum ALErrorCategory {
None, // 无错误
Transient, // 瞬态错误,可重试状态转换,通常自动恢复
Configuration, // 配置错误,检查 PDO 映射、SM 配置、Startup 参数等
Hardware, // 硬件错误,检查从站硬件、线缆、电源
Unknown // 未知错误,查阅 ETG.1000 或从站手册
}
示例:
Slave slave = master.getSlave(1);
short errorCode = slave.ErrorCode();
if (errorCode != 0) {
EtherCATTypes.ALErrorCategory category = EtherCATTypes.classifyALError(errorCode);
System.out.printf("从站 1 错误 0x%04X: %s%n", errorCode, category);
switch (category) {
case Transient:
System.out.println("瞬态错误,尝试重新切换状态...");
break;
case Configuration:
System.out.println("配置错误,请检查 PDO/SM 配置");
break;
case Hardware:
System.out.println("硬件错误,请检查从站设备");
break;
default:
break;
}
}
0x001E无效输入映射 — Configuration0x001D无效输出映射 — Configuration0x0011无效邮箱配置 — Configuration0x002D同步错误 — Transient0x0032DC 同步超时 — Transient0x0050EEPROM 错误 — Hardware
从站错误计数器
readSlaveErrorCounters(int slaveIndex)
public EtherCATTypes.SlaveErrorCounters readSlaveErrorCounters(int slaveIndex)
读取指定从站的错误计数器汇总(CRC 错误、帧错误、丢帧统计)。
参数:
slaveIndex(int) — 从站索引(1-based)
返回值:
SlaveErrorCounters— 错误计数器汇总
相关结构:
public class SlaveErrorCounters {
public int slaveIndex; // 从站编号
public long port0CrcErrors; // 端口 0 CRC 错误
public long port1CrcErrors; // 端口 1 CRC 错误
public long port2CrcErrors; // 端口 2 CRC 错误
public long port3CrcErrors; // 端口 3 CRC 错误
public long frameErrors; // 帧错误计数
public long lostFrames; // 丢帧计数
}
示例:
EtherCATTypes.SlaveErrorCounters counters = master.Diagnostics().readSlaveErrorCounters(1);
if (counters.port0CrcErrors + counters.frameErrors + counters.lostFrames > 0) {
System.out.println("从站 1 错误计数:");
System.out.printf(" CRC 错误: P0=%d, P1=%d, P2=%d, P3=%d%n",
counters.port0CrcErrors, counters.port1CrcErrors,
counters.port2CrcErrors, counters.port3CrcErrors);
System.out.println(" 帧错误: " + counters.frameErrors);
System.out.println(" 丢帧: " + counters.lostFrames);
}
诊断消息
slave.CoE().readDiagnosticMessages()
public List<DiagnosticMessage> readDiagnosticMessages()
通过 CoE 读取从站对象 0x10F3(诊断历史对象,ETG.1020)中的诊断消息。返回从站记录的诊断事件列表,包含时间戳、错误码和描述信息。
访问路径: slave.CoE().readDiagnosticMessages()
返回值:
List<DiagnosticMessage>— 诊断消息列表,无消息时返回空列表
相关结构:
public static class DiagnosticMessage {
public byte SubIndex; // 子索引
public int DiagCode; // 诊断码
public short Flags; // 标志位
public short TextIndex; // 文本索引
public byte[] RawData; // 原始数据
}
示例:
for (Slave slave : master.Slaves()) {
CoE coe = slave.CoE();
if (coe == null) continue;
List<CoE.DiagnosticMessage> messages = coe.readDiagnosticMessages();
if (messages.isEmpty()) continue;
for (CoE.DiagnosticMessage msg : messages) {
System.out.printf("[从站 %d] 代码=0x%08X, %s%n",
slave.SlaveNum(), msg.DiagCode, msg);
}
}
并非所有从站都支持 0x10F3 诊断历史对象。不支持的从站调用时返回空列表。此方法通过 SDO 读取,不建议在实时路径中高频调用。