跳到主要内容

主站诊断

配合事件使用

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

从站诊断

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

功能概览

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

通信与性能统计

类别函数类型读写说明
帧计数GetPacketLossRate(mi)float只读丢包率(0.0~1.0),TX vs RX 5 秒滑窗
帧计数GetLateFrameRate(mi)float只读过慢帧率(0.0~1.0),idx 出 8 帧窗 stale
WKCGetExpectedWKC(mi) / SetExpectedWKC(mi, wkc)uint16_t读写期望工作计数器
WKCGetPrimaryWKC()uint16_t只读主网口 WKC(冗余模式独立跟踪)
WKCGetSecondaryWKC()uint16_t只读副网口 WKC(冗余模式独立跟踪)
从站异常GetSlaveLinkQuality(mi, si)int16_t只读从站链路质量 0-100%
网口帧计数GetWdkPrimaryFrameTx(mi) / GetWdkPrimaryFrameRx(mi)uint32_t只读主网卡发送/接收累计帧数
网口帧计数GetWdkSecondaryFrameTx(mi) / GetWdkSecondaryFrameRx(mi)uint32_t只读副网卡发送/接收累计帧数(冗余有效)
网口帧计数GetWdkPdoIdxDropCount(mi)uint32_t只读PDO idx 槽位被覆盖丢弃次数
详细诊断GetDetailedDiagnostics(mi)void*只读详细诊断数据指针(无需释放)
通信统计GetCommunicationStats(mi) / ResetCommunicationStats(mi)void*读写通信统计指针 + 重置

详细诊断数据结构:

typedef struct {
uint32_t FrameErrors;
uint32_t LostFrames;
uint32_t OutOfOrderFrames;
uint32_t ChecksumErrors;
uint32_t TimeoutFrames;
uint32_t RxErrorCount[EC_MAXSLAVE];
uint32_t TxErrorCount[EC_MAXSLAVE];
uint16_t LostLinkCount[EC_MAXSLAVE];
uint16_t InvalidFrameCount[EC_MAXSLAVE];
uint16_t WorkingCounterErrors;
uint16_t ConsecutiveWkcErrors;
uint32_t TotalWkcMismatches;
uint32_t PdoLostFrames[EC_MAXGROUP];
uint32_t PdoConsecutiveLost[EC_MAXGROUP];
uint32_t PdoMaxConsecutiveLost[EC_MAXGROUP];
int16_t LinkQualityPercent[EC_MAXSLAVE];
uint32_t PrimaryPortTxCount;
uint32_t PrimaryPortRxCount;
uint32_t SecondaryPortTxCount;
uint32_t SecondaryPortRxCount;
uint32_t PrimaryPortErrors;
uint32_t SecondaryPortErrors;
} ec_diagnostics_data_t;

PDO 丢帧统计

void GetPDOFrameLossStats(uint16_t master_index, uint8_t group,
uint32_t* total_lost, uint32_t* consecutive_lost,
uint32_t* max_consecutive_lost);
void ResetPDOFrameLossStats(uint16_t master_index, uint8_t group);

按组(0-7)查询 PDO 丢帧统计:累计丢帧、当前连续丢帧、历史最大连续丢帧。

DC 同步

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

void SetSyncWindowThreshold(uint16_t master_index, int threshold_ns);
int GetSyncWindowThreshold(uint16_t master_index);

threshold_ns 默认 1000ns。

单个从站

单个从站的同步状态请使用 GetSlaveSyncWindowStatus(),详见 从站 DC 同步

冗余状态

int  GetBreakPoints(uint16_t master_index,
uint16_t* out_slaves, uint8_t* out_ports,
uint8_t* out_types, uint16_t max_results);
int GetRingMode(uint16_t master_index);
BOOL GetSecondaryLinkStatus(uint16_t master_index);

GetBreakPoints() 检测当前所有故障点,统一覆盖两类物理故障:

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

GetRingMode() 返回值: 0=Inactive(未激活), 1=Dual(双向冗余), 2=Degraded(secondary 链路不可用,仅 primary 工作)。

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

从站冗余诊断

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

诊断快照

BOOL GetDiagnosticsSnapshot(uint16_t master_index, ec_diagnostics_snapshot_t* snapshot);

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

typedef struct {
int frequency; /* 每秒帧数 (Hz) */
uint32_t error_count; /* 每秒错误数 */
float packet_loss_rate; /* 丢包率 (0.0-1.0) */
float late_frame_rate; /* 过慢帧率 (0.0-1.0) */
double avg_jitter_us; /* 平均抖动 (微秒) */
double max_jitter_us; /* 最大抖动 (微秒) */
int cycle_time_us; /* 实际周期时间 (微秒) */
uint16_t wkc_actual; /* 当前 WKC */
uint16_t wkc_expected; /* 期望 WKC */
uint32_t bus_cycle_hz; /* 总线频率 (Hz) */
double bus_max_jitter_us; /* 总线最大抖动 (微秒) */
double bus_avg_jitter_us; /* 总线平均抖动 (微秒) */
double bus_roundtrip_us; /* 总线往返延迟 (微秒) */
int primary_port_ok; /* 主端口正常 (BOOL) */
int secondary_port_ok; /* 副端口正常 (BOOL) */
int redundancy_active; /* 冗余激活 (BOOL) */
} ec_diagnostics_snapshot_t;

示例:

ec_diagnostics_snapshot_t snap;
if (dll.GetDiagnosticsSnapshot(master, &snap)) {
printf("频率: %d Hz, 抖动: %.2f us, WKC: %d/%d, 丢包: %.4f\n",
snap.frequency, snap.max_jitter_us,
snap.wkc_actual, snap.wkc_expected, snap.packet_loss_rate);
}

诊断控制

void SetDiagnosticsEnabled(uint16_t master_index, BOOL enable);
BOOL GetDiagnosticsEnabled(uint16_t master_index);
void ResetDiagnostics(uint16_t master_index);

SetDiagnosticsEnabled() 启用/禁用诊断数据采集(默认关闭,启用后周期性采样)。ResetDiagnostics() 一次性重置所有诊断统计:基础诊断统计、PDO 丢帧统计、DC 同步窗口统计、所有从站的端口错误计数器。只清空主站层面的统计数据, 不影响 FSoE 安全连接状态机。

AL 错误分类

typedef enum {
AL_ERROR_NONE = 0, /* 无错误 */
AL_ERROR_TRANSIENT = 1, /* 瞬态: 同步丢失 / DC 超时 / 看门狗 */
AL_ERROR_CONFIGURATION = 2, /* 配置错误: PDO 映射 / SM / 邮箱 */
AL_ERROR_HARDWARE = 3, /* 硬件错误: EEPROM / 端口 / 物理层 */
AL_ERROR_UNKNOWN = 4 /* 未在已知列表中 */
} DarraAlErrorClass;

DarraAlErrorClass diagnostics_classify_al_error(uint16_t al_status_code);

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

分类处理建议
Transient瞬态错误,可重试状态转换,通常自动恢复
Configuration检查 PDO 映射、SM 配置、Startup 参数
Hardware检查从站硬件、线缆、电源
Unknown查阅 ETG.1000 或从站手册
常见 AL Status Code
  • 0x001E 无效输入映射 — Configuration
  • 0x001D 无效输出映射 — Configuration
  • 0x0011 无效邮箱配置 — Configuration
  • 0x002D 同步错误 — Transient
  • 0x0032 DC 同步超时 — Transient
  • 0x0050 EEPROM 错误 — Hardware

从站错误计数器

BOOL ResetSlavePortErrorCounters(uint16_t master_index, uint16_t slave_index);
BOOL ReadSlavePortErrorCounters(uint16_t master_index, uint16_t slave_index,
uint8_t* rx_error, uint8_t* invalid_frame, uint8_t* lost_link);
int ReadAllSlavePortErrorCounters(uint16_t master_index);
void* GetSlavePortErrorStats(uint16_t master_index, uint16_t slave_index);

读取/重置从站 ESC 端口错误计数器(ETG.1000.4)。rx_error/invalid_frame/lost_link 各为 4 字节数组,对应 P0-P3 端口。

示例:

uint8_t rx[4], inv[4], lost[4];
if (dll.ReadSlavePortErrorCounters(master, 1, rx, inv, lost)) {
for (int p = 0; p < 4; p++) {
if (rx[p] || inv[p] || lost[p])
printf("从站1 P%d: rx=%u inv=%u lost=%u\n", p, rx[p], inv[p], lost[p]);
}
}

配置预检查

int ValidateConfig(uint16_t master_index, char* error_buf, int buf_size);

Build 前预检查主站配置是否完整(网络适配器、从站发现、PDO 映射等)。返回 0 表示配置有效,非 0 表示配置问题数量;error_buf 接收错误描述(可为 NULL)。

主站身份与诊断对象

BOOL GetMasterIdentity(uint16_t master_index, ec_master_identity_t* identity);
BOOL GetMasterDiagData(uint16_t master_index, ec_master_diag_data_t* diag);

读取主站 ETG.1510 标准对象:身份对象 0x1018(VendorID/ProductCode/RevisionNumber/SerialNumber)和诊断数据对象 0xF120。

诊断消息

int coe_read_diagnostic_messages(uint16_t master_index, uint16_t slave_index,
ec_diag_message_t* out_messages, int max_count);

通过 CoE 读取从站对象 0x10F3(诊断历史对象,ETG.1020)中的诊断消息。返回从站记录的诊断事件数量。

备注

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

紧急控制与中止

void AbortScan(void);
void ResetScanAbort(void);
void AbortNetwork(void);
void ResetAbortNetwork(void);
void EmergencyCloseNics(void);

终止正在进行的网络扫描或紧急关闭网卡,避免长操作卡死调用方。

警告

EmergencyCloseNics 不走标准 Stop / Dispose 流程, 仅在死锁兜底场景使用. 正常退出请用 Stop + Dispose + EcClose.

完整示例

#define DYNAMIC_LOAD
#include "ethercat.h"
#include <stdio.h>

int main(void) {
dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");

uint16_t master = dll.Initialize();
dll.SetNetwork(master, "\\Device\\NPF_{GUID}", "");
dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
dll.Start(master);

dll.SetDiagnosticsEnabled(master, TRUE);

/* 一致快照 */
ec_diagnostics_snapshot_t snap;
if (dll.GetDiagnosticsSnapshot(master, &snap)) {
printf("频率: %d Hz, 抖动: %.2f us, 丢包: %.4f\n",
snap.frequency, snap.max_jitter_us, snap.packet_loss_rate);
}

/* PDO 丢帧 */
uint32_t total, cur, max;
dll.GetPDOFrameLossStats(master, 0, &total, &cur, &max);
if (cur > 10) printf("警告: PDO 连续丢帧 %u\n", cur);

/* 故障点 */
uint16_t bp_s[8]; uint8_t bp_p[8], bp_t[8];
int n = dll.GetBreakPoints(master, bp_s, bp_p, bp_t, 8);
for (int i = 0; i < n; i++) {
printf("故障: 从站%d P%d %s\n", bp_s[i], bp_p[i],
bp_t[i] == 0 ? "断线" : "CRC故障");
}

/* AL 错误分类 */
uint16_t al = dll.GetSlaveALStatusCode(master, 1);
if (al) {
DarraAlErrorClass c = diagnostics_classify_al_error(al);
printf("从站1 错误 0x%04X: 分类=%d\n", al, c);
}

dll.ResetDiagnostics(master);
dll.Stop(master);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}