跳到主要内容

主站诊断

通过 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) / TX5 秒滑窗, pipeline 在途不算丢
LateFrameRateLateDrop / TXidx 出 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检测方式典型场景
断线0DL 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;
}
}
常见 AL Status Code
  • 0x001E 无效输入映射 — Configuration
  • 0x001D 无效输出映射 — Configuration
  • 0x0011 无效邮箱配置 — Configuration
  • 0x002D 同步错误 — Transient
  • 0x0032 DC 同步超时 — Transient
  • 0x0050 EEPROM 错误 — 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 读取,不建议在实时路径中高频调用。