跳到主要内容

主站诊断

通过 master.Diagnostics 访问所有诊断、监控、统计功能。

配合事件使用

建议通过 事件 驱动异常处理,而非自行轮询。
直接读取诊断属性适用于 UI 显示等场景。

从站诊断

单个从站的状态诊断、链路质量请参考 从站诊断

功能概览

功能说明
通信与性能统计帧计数、丢包、抖动、PDO 丢帧、网口状态、拓扑
DC 同步同步窗口阈值、DCSyncLost 事件
冗余状态冗余激活、故障点检测(断线 + CRC 故障定位)
诊断控制启停数据采集、重置统计

通信与性能统计

类别属性类型访问使能控制说明
帧计数RTcntint只读每秒帧数(Hz),5秒平均
ErrorCntuint只读每秒错误数,5秒平均
PacketLossRatefloat只读丢包率(0.0~1.0)— TX vs RX 5 秒滑窗,pipeline 在途不算丢
LateFrameRatefloat只读过慢帧率(0.0~1.0)— idx 出 8 帧窗 stale, 不计入丢包
周期与抖动CycleTimeSpanint只读实际周期时间(微秒),实时值
AvgJitterUsdouble只读最近5秒平均抖动(微秒),总线抖动
MaxJitterUsdouble只读最近5秒最大抖动(微秒),总线抖动
PDO 丢帧PDO.TotalLostuint只读不可停累计丢帧数(所有组合计)
PDO.ConsecutiveLostuint只读不可停当前连续丢帧数(所有组中最大值)
PDO.GetFrameLossStats(byte group)PDOFrameLossStats只读不可停获取指定组的 PDO 丢帧统计。0-7 返回对应组,不传参数返回所有组汇总。返回值含 TotalLost / ConsecutiveLost / MaxConsecutiveLost
从站异常WorstSlaveIndexushort只读不可停异常率最高的从站索引
WorstLinkQualityshort只读不可停最差从站的通信健康度(%),越低越差
WKCPrimaryWKCushort只读不可停主网口工作计数器(冗余模式下独立跟踪)
SecondaryWKCushort只读不可停副网口工作计数器(冗余模式下独立跟踪)
网口状态PrimaryPortOkbool只读不可停主端口是否正常(有流量且5秒内无错误)
SecondaryPortOkbool只读不可停副端口是否正常(有流量且5秒内无错误,无冗余时始终 false)
PrimaryPortErrorsuint只读不可停主端口最近5秒错误数
SecondaryPortErrorsuint只读不可停副端口最近5秒错误数
拓扑TopologyDescriptionstring只读不可停拓扑模式描述("线性" / "环形" / "环+分支")
TimingModestring只读不可停定时模式("硬件定时器" / "RT就绪" / "降级" / "RT错误")。WDK 驱动必须就绪,不再存在软件定时器路径
DC 同步SyncWindowThresholdint读写不可停同步窗口阈值(纳秒),默认 1000ns。超出阈值触发 DCSyncLost 事件
冗余状态RedundancyActivebool只读不可停冗余是否激活(存在断线但网络仍正常运行)
RingModeRingMode只读不可停环拓扑冗余运行模式(Inactive/Dual/Degraded)
BreakPointBreakPointInfo?只读不可停当前故障点(多个故障只返回第一个)。支持断线和 CRC 故障两种类型,恢复后自动清除,无故障为 null
诊断控制Enabledbool读写诊断数据采集开关(默认关闭)。启用后周期性采样,记录标记为[是]的统计数据
计算公式
指标公式说明
RTcnt采样周期帧数 / 窗口秒数滑动窗口平均帧频
ErrorCnt采样周期错误数 / 窗口秒数滑动窗口平均错误率
PacketLossRate(TX-RX-pipeline) / TX5 秒滑窗丢包率, 全双工 pipeline 在途不算丢
LateFrameRateLateDrop / TX过慢帧率 (idx 出 8 帧窗 stale, 不计入丢包)

Enabled = true

PDOFrameLossStats 结构
属性类型说明
TotalLostuint累计丢帧数
ConsecutiveLostuint当前连续丢帧数
MaxConsecutiveLostuint历史最大连续丢帧数

示例:

var diag = master.Diagnostics;
diag.Enabled = true; // 启用诊断数据采集

// 帧计数
Console.WriteLine($"帧频: {diag.RTcnt} Hz");
Console.WriteLine($"丢包率: {diag.PacketLossRate:P2}");
Console.WriteLine($"错误数: {diag.ErrorCnt}");

// 周期与抖动
Console.WriteLine($"周期时间: {diag.CycleTimeSpan} µs");
Console.WriteLine($"抖动: 平均 {diag.AvgJitterUs:F2} µs, 最大 {diag.MaxJitterUs:F2} µs");

// PDO 丢帧(所有组汇总)
var pdo = diag.PDO;
Console.WriteLine($"PDO 丢帧: 累计={pdo.TotalLost}, 连续={pdo.ConsecutiveLost}");
if (pdo.ConsecutiveLost > 10)
Console.WriteLine("警告: PDO 连续丢帧!");

// 按组查询丢帧(0-7)
var group0Stats = pdo.GetFrameLossStats(0); // 组0(默认组)
var group1Stats = pdo.GetFrameLossStats(1); // 组1
Console.WriteLine($"组0丢帧: {group0Stats.TotalLost}, 组1丢帧: {group1Stats.TotalLost}");

// 从站异常
Console.WriteLine($"最差从站: #{diag.WorstSlaveIndex} ({diag.WorstLinkQuality}%)");

// 网口状态
Console.WriteLine($"主端口: {(diag.PrimaryPortOk ? "正常" : "异常")}");
Console.WriteLine($"副端口: {(diag.SecondaryPortOk ? "正常" : "未连接")}");

// 拓扑信息
Console.WriteLine($"拓扑: {diag.TopologyDescription}");
Console.WriteLine($"定时: {diag.TimingMode}");
从站通信诊断

每个从站的 ESC 端口错误通过 slave.Diagnostics.ReadPortErrors() 获取。详见 从站诊断 - 通信诊断

DC 同步

自动监控(ETG.1500 5.13.3),每秒检查各从站时间偏差。超出 SyncWindowThreshold 阈值时触发 DCSyncLost 事件。

单个从站

单个从站的同步状态请使用 slave.Diagnostics.DC.IsInSyncslave.Diagnostics.DC.SyncTimeDifference

冗余状态

RingMode 反映环拓扑冗余的运行状态。Inactive 表示冗余未初始化,Dual 表示双向冗余正常工作,Degraded 表示 secondary 链路不可用仅 primary 工作。

BreakPoint 统一检测两类物理故障:

类型FaultType检测方式典型场景
断线0DL Status 端口物理链路丢失拔线、线缆断裂
CRC 故障1端口级 RxError + InvalidFrame 持续增长接触不良、线缆老化、连接器氧化

故障线缆段定位: 当相邻从站的对向端口(如从站 N 的 P1 和从站 N+1 的 P0)同时报故障,说明连接线缆有问题。仅单侧报故障则定位到该端口连接器。

RingMode 枚举
名称说明
0Inactive未激活:冗余监控未初始化
1Dual双向冗余:双端口发送,正常工作
2Degraded降级模式:secondary链路不可用,仅primary工作
BreakPointInfo 结构
属性类型说明
SlaveIndexushort故障从站索引 (1-based)
Portbyte故障端口号 (0-3, 对应 P0-P3)
FaultTypebyte故障类型:0=断线,1=CRC 故障
IsLinkDownbool是否为断线故障
IsCrcFaultbool是否为 CRC 故障(线缆/连接器劣化)
从站冗余诊断

单个从站的冗余状态请参考 从站诊断 - 冗余诊断

示例:

var diag = master.Diagnostics;

// 环拓扑冗余模式
Console.WriteLine($"冗余模式: {diag.RingMode}");
if (diag.RingMode == RingMode.Degraded)
Console.WriteLine("警告: secondary链路不可用,仅primary工作");

if (diag.RedundancyActive)
Console.WriteLine("冗余已激活");

var bp = diag.BreakPoint;
if (bp != null)
{
Console.WriteLine($"故障: {bp}"); // 输出: "从站5 P3 断线" 或 "从站3 P1 CRC故障"
if (bp.Value.IsCrcFault)
Console.WriteLine("建议检查线缆/连接器");
}

诊断快照

GetSnapshot()

public DiagnosticsSnapshot GetSnapshot()

一次调用获取所有诊断数据的一致快照,避免多次属性访问导致的数据不一致和性能开销。适合 UI 刷新和日志记录场景。

返回值:

  • DiagnosticsSnapshot — 诊断数据快照对象

相关结构:

public class DiagnosticsSnapshot
{
public int Frequency { get; } // 每秒帧数 (Hz)
public uint ErrorCount { get; } // 每秒错误数
public float PacketLossRate { get; } // 丢包率 (0.0-1.0) — TX vs RX, 5 秒滑窗
public float LateFrameRate { get; } // 过慢帧率 (0.0-1.0) — idx 出 8 帧窗 stale, 不计丢
public double AvgJitterUs { get; } // 平均抖动 (µs)
public double MaxJitterUs { get; } // 最大抖动 (µs)
public int CycleTimeUs { get; } // 实际周期时间 (µs)
public ushort WkcActual { get; } // 当前 WKC
public ushort WkcExpected { get; } // 期望 WKC
public bool PrimaryPortOk { get; } // 主端口正常
public bool SecondaryPortOk { get; } // 副端口正常
public bool RedundancyActive { get; } // 冗余激活
}

示例:

var snap = master.Diagnostics.GetSnapshot();
Console.WriteLine($"频率: {snap.Frequency} Hz, 抖动: {snap.AvgJitterUs:F2} µs");
Console.WriteLine($"WKC: {snap.WkcActual}/{snap.WkcExpected}");
if (snap.RedundancyActive)
Console.WriteLine("冗余已激活");

诊断控制

标记为"是"的属性需先设置 Enabled = true 启动周期性采样,标记为"不可停"的功能始终活跃。

Reset (诊断计数器)

public void Reset()

一次性重置所有诊断统计,包括:

  • 基础诊断统计(帧错误等)
  • PDO 丢帧统计
  • DC 同步窗口统计
  • 所有从站的端口错误计数器

只清空主站层面的统计数据, 不影响 FSoE 安全连接状态机 (slave.FSoE.Reset)。

AL 错误分类

对 AL Status Code 进行分类,帮助快速判断错误性质和处理策略。

ALErrorClassifier.Classify

public static ALErrorCategory Classify(ushort alStatusCode)
public static ALErrorCategory Classify(EcALState alState)

对 AL Status Code(从站返回的错误码)进行分类,帮助快速判断错误性质和处理策略。支持 ushortEcALState 两种参数类型。

参数:

  • alStatusCode (ushort) 或 alState (EcALState) — AL Status Code,从 slave.ErrorCode 或状态转换失败时获取

返回值:

  • ALErrorCategory — 错误分类枚举

相关结构:

  • None (0) — 无错误
  • Transient (1) — 瞬态错误,可重试状态转换,通常自动恢复
  • Configuration (2) — 配置错误,检查 PDO 映射、SM 配置、Startup 参数等
  • Hardware (3) — 硬件错误,检查从站硬件、线缆、电源
  • Unknown (4) — 未知错误,查阅 ETG.1000 或从站手册

示例:

var slave = master.Slaves[1];
if (slave.ErrorCode != EcALState.NoError)
{
var category = ALErrorClassifier.Classify(slave.ErrorCode);
Console.WriteLine($"从站 {slave.SlaveNum} 错误 0x{(ushort)slave.ErrorCode:X4}: {category}");

switch (category)
{
case ALErrorCategory.Transient:
Console.WriteLine("瞬态错误,尝试重新切换状态...");
break;
case ALErrorCategory.Configuration:
Console.WriteLine("配置错误,请检查 PDO/SM 配置");
break;
case ALErrorCategory.Hardware:
Console.WriteLine("硬件错误,请检查从站设备");
break;
}
}
常见 AL Status Code
  • 0x001E 无效输入映射 — Configuration
  • 0x001D 无效输出映射 — Configuration
  • 0x0011 无效邮箱配置 — Configuration
  • 0x002D 同步错误 — Transient
  • 0x0032 DC 同步超时 — Transient
  • 0x0050 EEPROM 错误 — Hardware

从站错误计数器

ReadSlaveErrorCounters(int slaveIndex)

public SlaveErrorCounters ReadSlaveErrorCounters(int slaveIndex)

读取指定从站的错误计数器汇总(CRC 错误、帧错误、丢帧统计)。

参数:

  • slaveIndex (int) — 从站索引(1-based)

返回值:

  • SlaveErrorCounters — 错误计数器汇总

相关结构:

public class SlaveErrorCounters
{
public int SlaveIndex { get; } // 从站编号
public uint Port0CrcErrors { get; } // 端口 0 CRC 错误
public uint Port1CrcErrors { get; } // 端口 1 CRC 错误
public uint Port2CrcErrors { get; } // 端口 2 CRC 错误
public uint Port3CrcErrors { get; } // 端口 3 CRC 错误
public uint FrameErrors { get; } // 帧错误计数
public uint LostFrames { get; } // 丢帧计数
}

示例:

var counters = master.Diagnostics.ReadSlaveErrorCounters(1);
if (counters.Port0CrcErrors + counters.FrameErrors + counters.LostFrames > 0)
{
Console.WriteLine($"从站 1 错误计数:");
Console.WriteLine($" CRC 错误: P0={counters.Port0CrcErrors}, P1={counters.Port1CrcErrors}, P2={counters.Port2CrcErrors}, P3={counters.Port3CrcErrors}");
Console.WriteLine($" 帧错误: {counters.FrameErrors}");
Console.WriteLine($" 丢帧: {counters.LostFrames}");
}

诊断消息

slave.CoE.ReadDiagnosticMessages()

public List<DiagnosticMessage> ReadDiagnosticMessages()

通过 CoE 读取从站对象 0x10F3(诊断历史对象,ETG.1020)中的诊断消息。返回从站记录的诊断事件列表,包含时间戳、错误码和描述信息。

访问路径: slave.CoE.ReadDiagnosticMessages()

返回值:

  • List<DiagnosticMessage> — 诊断消息列表,无消息时返回空列表

示例:

foreach (var slave in master.Slaves)
{
var messages = slave.CoE?.ReadDiagnosticMessages();
if (messages == null || messages.Count == 0) continue;

foreach (var msg in messages)
{
Console.WriteLine($"[从站 {slave.SlaveNum}] " +
$"代码=0x{msg.DiagCode:X8}, {msg}");
}
}
备注

并非所有从站都支持 0x10F3 诊断历史对象。不支持的从站调用时返回空列表。此方法通过 SDO 读取,不建议在实时路径中高频调用。