跳到主要内容

从站诊断

每个从站提供独立的诊断属性和子对象,可查询端口错误、冗余、DC 同步等信息。

从站基础属性

从站状态(StateErrorCodeIsLost)等基础属性请参考 属性与方法

配合事件使用

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

主站级诊断

全局通信统计、丢包率、PDO 丢帧汇总请参考 主站诊断

功能概览

功能访问路径说明
WKC 与健康镜像slave.*per-slave WcState/AL/邮箱健康内核镜像(薄读零帧,实时)
通信诊断slave.Diagnostics.ReadPortErrors()ESC 端口错误计数器
冗余诊断slave.Diagnostics.*冗余激活、主/冗余线路断路检测
DC 同步slave.Diagnostics.DC.*同步状态、时间差
类别属性类型访问使能控制说明
WKC 与健康镜像WcContributedWcContribution只读不可停该从站对工作计数器(WKC)的贡献状态——内核 per-slave WcState 诊断缓存镜像的薄读(零帧实时)。NotContributed ≠ master 故障,是该从站此刻没在响应(疑似掉站/热插拔恢复中)
AlStatusMirrorEcSlaveStatus只读不可停该从站 AL 状态镜像(内核诊断缓存薄读,零帧实时)。低字节 = AL State,含 Error 位时可 .HasFault()
AlStatusCodeEcALState只读不可停该从站当前 AL Status Code(内核 AL 镜像高字节解码)。仅当 AlStatusMirror 含 Error 位时有意义,无 Error 返回 NoError。薄读零帧,实时
MailboxHealthEcMailboxHealth只读不可停该从站邮箱健康度(内核每秒更新的镜像薄读)。Degraded 表示在 OP 但邮箱半失效(CoE/SDO 可能阻塞),如实反映不参与 WKC 篡改
IsFreeRunDemotedbool只读不可停该从站是否被迫降级到 FreeRun 同步模式(薄读零帧)。true 仅当“配置期要 DC 但运行中被迫退到 FreeRun”——半失效根源观测点
HealthDegradedCountuint只读不可停邮箱半失效连续累计计数(≈秒数,内核每秒评估)。0 = 健康或未评估;持续累加表示半失效未恢复,内核在 >=3 时触发自动修复
RecoverMailboxHealth()bool只读不可停手动触发邮箱半失效修复(内核自愈流程)。通常无需手动调用——内核 >=3 秒后自动修复。通讯异常时返回 false 不抛异常
通信诊断ReadPortErrors()EscPortErrors?只读读取 ESC 端口错误计数器。实时读取从站寄存器,失败返回 null
冗余诊断RedundancyActivatedbool只读不可停冗余被激活。从站未丢失,但网络中存在断线(物理链路丢失),冗余机制正在工作。CRC 故障不触发此标志
PrimaryLinkBrokenbool只读不可停主线路断路。从主端口 (Port0) 到该从站的路径上存在断线。仅检测物理断线,不含 CRC 故障
SecondaryLinkBrokenbool只读不可停冗余线路断路。从副端口 (Port1) 反向到该从站的路径上存在断线。仅检测物理断线,不含 CRC 故障
DC 同步DC.IsInSyncbool只读不可停是否在同步窗口内(阈值由 master.Diagnostics.SyncWindowThreshold 控制)
DC.SyncTimeDifferenceint只读不可停当前与参考时钟的时间差(纳秒)
EscPortErrors 结构体
字段类型说明
RxErrorbyte[]各端口 RX 错误计数 [Port0-3]
InvalidFramebyte[]各端口无效帧计数 [Port0-3]
LostLinkbyte[]各端口链路丢失计数 [Port0-3]
HasErrorsbool是否存在任何错误(只读派生)
备注

WKC/健康镜像、冗余和 DC 属性为"不可停"(始终活跃),无需启用 master.Diagnostics.EnabledReadPortErrors() 需实时读取从站,不建议高频调用。

WKC 与健康镜像

这些属性直接在 slave 上访问(不在 slave.Diagnostics 子对象下),全部为内核 per-slave 诊断缓存的薄读零帧——内核每周期(WKC 异常时立即)维护缓存,读到即此刻真实总线现实,无需调任何刷新。配合主站级 master.Diagnostics.WcDeficit 可在掉站时定位到具体从站。

WcContributed(从站 WKC 贡献)

public WcContribution WcContributed { get; }

该从站对工作计数器(WKC)的贡献状态。

R1 可观测性约定: NotContributed 不是 master 故障,而是该从站此刻没在响应(疑似掉站 / 热插拔恢复中);修复后自动回 Contributed。内核未填充时诚实返回 Unknown0xFF),不臆造。

WcContribution 枚举
名称说明
0x00NotContributed该从站此刻没在贡献 WKC(疑似掉站 / 热插拔恢复中)
0x01Contributed该从站正常贡献 WKC(在总线上响应)
0xFFUnknown内核镜像未填充(尚未运行 PDO 循环 / 索引越界)— 诚实暴露,不臆造

AlStatusMirror / AlStatusCode

public EcSlaveStatus AlStatusMirror { get; }
public EcALState AlStatusCode { get; }

AlStatusMirror 为该从站 AL 状态镜像(低字节 = AL State,bit4 = Error 位,可 .HasFault())。当 Error 位置位时,AlStatusCode 给出 EcALState 错误码;无 Error 时返回 EcALState.NoError

MailboxHealth / IsFreeRunDemoted / HealthDegradedCount / RecoverMailboxHealth()

让"在 OP 但邮箱半失效"(CoE/SDO 阻塞)这种隐性故障对上层可见。MailboxHealth == Degraded 表示从站仍在 OP 但邮箱通道半失效。HealthDegradedCount 持续累加表示半失效未恢复(内核 >=3 秒自动修复),也可 RecoverMailboxHealth() 手动介入。R1:全部如实反映,不参与任何 WKC 篡改

EcMailboxHealth 枚举
名称说明
0Unknown未知 / 无邮箱 / 不在 OP — 邮箱健康度此时无意义
1Healthy健康 — 在 OP 且邮箱可用
2Degraded降级 — 在 OP 但邮箱半失效(handler 丢失 / DC 降级伴 0x001F)

示例:

foreach (var slave in master.Slaves)
{
// WKC 贡献:掉站定位
if (slave.WcContributed == WcContribution.NotContributed)
Console.WriteLine($"从站 {slave.SlaveNum} 未贡献 WKC, AL={slave.AlStatusCode}");

// 邮箱半失效(在 OP 但 CoE 可能阻塞)
if (slave.MailboxHealth == EcMailboxHealth.Degraded)
{
Console.WriteLine($"从站 {slave.SlaveNum} 邮箱半失效 {slave.HealthDegradedCount}s" +
(slave.IsFreeRunDemoted ? " (被迫 FreeRun)" : ""));
if (slave.HealthDegradedCount >= 5)
slave.RecoverMailboxHealth(); // 通常内核已自动修复,此为手动介入
}
}

通信诊断

ReadPortErrors()

public EscPortErrors? ReadPortErrors()

读取从站 ESC 端口错误计数器,返回各端口的物理层错误统计。

返回值:

  • EscPortErrors? — 端口错误计数器,读取失败返回 null

示例:

foreach (var slave in master.Slaves)
{
var errors = slave.Diagnostics.ReadPortErrors();
if (errors?.HasErrors == true)
{
var e = errors.Value;
Console.WriteLine($"从站 {slave.SlaveNum}: " +
$"RX错误=[{string.Join(",", e.RxError)}], " +
$"无效帧=[{string.Join(",", e.InvalidFrame)}], " +
$"链路丢失=[{string.Join(",", e.LostLink)}]");
}
}

冗余诊断

通过 slave.Diagnostics 访问从站的冗余状态。仅在主站启用冗余时有意义。

主站级监控

全局冗余状态和断线点请参考 主站诊断 - 冗余状态

示例:

foreach (var slave in master.Slaves)
{
if (!slave.Diagnostics.RedundancyActivated) continue;

Console.Write($"从站 {slave.SlaveNum}: 冗余激活");
if (slave.Diagnostics.PrimaryLinkBroken)
Console.Write(", 主线路断路");
if (slave.Diagnostics.SecondaryLinkBroken)
Console.Write(", 冗余线路断路");
Console.WriteLine();
}

DC 同步

通过 slave.Diagnostics.DC 访问从站的 DC 同步状态。

主站级监控

全局阈值和事件请参考 主站诊断 - DC 同步

示例:

foreach (var slave in master.Slaves)
{
if (!slave.HasDC) continue;

var dc = slave.Diagnostics.DC;
Console.WriteLine($"从站 {slave.SlaveNum}: " +
$"时间差={dc.SyncTimeDifference}ns, " +
$"同步={dc.IsInSync}");
}

完整示例

foreach (var slave in master.Slaves)
{
Console.WriteLine($"--- 从站 {slave.SlaveNum}: {slave.Name} ---");

// 端口错误
var errors = slave.Diagnostics.ReadPortErrors();
if (errors?.HasErrors == true)
{
var e = errors.Value;
Console.WriteLine($" 端口错误: RX=[{string.Join(",", e.RxError)}], " +
$"无效帧=[{string.Join(",", e.InvalidFrame)}], " +
$"链路丢失=[{string.Join(",", e.LostLink)}]");
}

// 冗余(仅冗余模式下有意义)
if (slave.Diagnostics.RedundancyActivated)
{
Console.WriteLine($" 冗余激活: 主线路断={slave.Diagnostics.PrimaryLinkBroken}, " +
$"冗余线路断={slave.Diagnostics.SecondaryLinkBroken}");
}

// DC 同步
if (slave.HasDC)
{
Console.WriteLine($" DC: 时间差={slave.Diagnostics.DC.SyncTimeDifference}ns, " +
$"同步={slave.Diagnostics.DC.IsInSync}");
}
}