跳到主要内容

从站诊断

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

从站基础属性

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

配合事件使用

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

主站级诊断

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

功能概览

功能访问方式说明
通信诊断slave.ReadPortErrors()ESC 端口错误计数器
冗余诊断slave.RedundancyActivated() / PrimaryLinkBroken() / SecondaryLinkBroken()冗余激活、主/冗余线路断路检测
DC 同步slave.IsInSync() / SyncTimeDifference() / GetSyncWindowStatus()同步状态、时间差、失步次数
拓扑信息slave.ActivePorts() / ParentStation()端口连接和父节点
链路质量diag.SlaveLinkQuality(slave)从站链路质量
备注

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

通信诊断

ReadPortErrors()

std::optional<EscPortErrors> ReadPortErrors() const;

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

返回值:

  • std::optional<EscPortErrors> — 端口错误计数器, 读取失败返回 std::nullopt

相关结构:

struct EscPortErrors {
uint8_t RxError[4]; // 各端口 RX 错误计数 [Port0-3]
uint8_t InvalidFrame[4]; // 各端口无效帧计数 [Port0-3]
uint8_t LostLink[4]; // 各端口链路丢失计数 [Port0-3]
bool HasErrors; // 是否存在任何错误
};

struct SyncWindowStatus {
int DiffNs; // 当前与参考时钟的时间差 (纳秒)
int MaxDiffNs; // 最大时间差 (纳秒)
int MinDiffNs; // 最小时间差 (纳秒)
bool InSync; // 是否在同步窗口内
uint32_t OutOfSyncCount; // 失步次数
};

示例:

for (int i = 1; i <= master.SlaveCount(); ++i) {
auto& s = master.GetSlave(i);
auto errors = s.ReadPortErrors();
if (errors && errors->HasErrors) {
printf("从站 %d: RX=[%d,%d,%d,%d] 无效帧=[%d,%d,%d,%d] 链路丢失=[%d,%d,%d,%d]\n", i,
errors->RxError[0], errors->RxError[1], errors->RxError[2], errors->RxError[3],
errors->InvalidFrame[0], errors->InvalidFrame[1], errors->InvalidFrame[2], errors->InvalidFrame[3],
errors->LostLink[0], errors->LostLink[1], errors->LostLink[2], errors->LostLink[3]);
}
}

冗余诊断

通过从站对象访问冗余状态。仅在主站启用冗余时有意义。RedundancyActivated() 表示从站未丢失但网络中存在物理断线; PrimaryLinkBroken() / SecondaryLinkBroken() 表示主/副端口路径上存在断线。CRC 故障不触发这些标志。

主站级监控

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

示例:

for (int i = 1; i <= master.SlaveCount(); ++i) {
auto& s = master.GetSlave(i);
if (!s.RedundancyActivated()) continue;

printf("从站 %d: 冗余激活", i);
if (s.PrimaryLinkBroken()) printf(", 主线路断路");
if (s.SecondaryLinkBroken()) printf(", 冗余线路断路");
printf("\n");
}

DC 同步

通过从站对象访问 DC 同步状态。IsInSync() 返回是否在同步窗口内 (阈值由 master.GetDiagnostics().SyncWindowThreshold() 控制); SyncTimeDifference() 返回与参考时钟的纳秒级时间差; GetSyncWindowStatus() 返回完整 SyncWindowStatus 结构。

主站级监控

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

示例:

for (int i = 1; i <= master.SlaveCount(); ++i) {
auto& s = master.GetSlave(i);
if (!s.HasDC()) continue;

auto status = s.GetSyncWindowStatus();
if (status) {
printf("从站 %d: 时间差=%dns 最大=%dns 同步=%s 失步=%u\n", i,
status->DiffNs, status->MaxDiffNs,
status->InSync ? "是" : "否", status->OutOfSyncCount);
}
}

完整示例

#include "ethercat.hpp"
using namespace darra::ethercat;

void slave_diagnostics_report(EtherCATMaster& master) {
auto& diag = master.GetDiagnostics();
for (int i = 1; i <= master.SlaveCount(); ++i) {
auto& s = master.GetSlave(i);
printf("--- 从站 %d: %s ---\n", i, s.Name().c_str());

auto errors = s.ReadPortErrors();
if (errors && errors->HasErrors) {
printf(" 端口错误: RX=[%d,%d,%d,%d]\n",
errors->RxError[0], errors->RxError[1],
errors->RxError[2], errors->RxError[3]);
}

if (s.RedundancyActivated()) {
printf(" 冗余激活: 主线路断=%s 冗余线路断=%s\n",
s.PrimaryLinkBroken() ? "是" : "否",
s.SecondaryLinkBroken() ? "是" : "否");
}

if (s.HasDC()) {
auto sync = s.GetSyncWindowStatus();
if (sync) {
printf(" DC: 时间差=%dns 同步=%s 失步=%u\n",
sync->DiffNs, sync->InSync ? "是" : "否",
sync->OutOfSyncCount);
}
}

printf(" 活动端口=0x%02X 父节点=%u 链路质量=%d\n",
s.ActivePorts(), s.ParentStation(), diag.SlaveLinkQuality(i));
}
}