跳到主要内容

主站对象字典 (Master OD)

符合 ETG.1510 标准的主站对象字典,提供主站身份信息和诊断数据。

ETG.1510 标准

主站对象字典按照 ETG.1510 规范实现,使用标准 CoE 索引约定。配合邮箱网关使用,可实现远程诊断工具对主站的标准访问。

C SDK 实际能读到哪些对象

master/diagnostics_ext.h 只把两个快路径接了出来:0x1018 子索引 1..4(GetMasterIdentity)与 0xF120 子索引 0(GetMasterDiagData)。其余索引在 C SDK 上没有可用实现,读取直接返回 -4;native 的 dx_sdo_read / dx_sdo_write 入口无条件拒绝 slave_index == 0,所以经它转发到主站 OD 的路由恒失败。

因此下表描述的是主站对象字典本身(配合邮箱网关,外部 CoE 诊断工具可按标准访问),其中 0x8nnn / 0x9nnn / 0xAnnn 无法用 C SDK 读到。把这套 ETG.1510 对象实装成 SDK API 的是 C# 与 Python 两腿,需要程序内读取从站配置 / 信息 / 诊断对象时请用它们。

另外 0x1009(Hardware Version)的取值以 native 主站对象字典为准,是常量 "1.0"(native mailbox_gateway.c;Java 的 MasterObjectDictionary 同样返回 "1.0")。只有 C# 与 Python 例外,返回进程位宽 "x64" / "x86"(MasterDiagnostics_ETG1510.cs / master_od.py),属少数派实现。

对象索引总览​

索引名称类别子索引数读写说明
0x1000Device Type标准对象0只读0x00001389(EtherCAT Master)
0x1008Device Name标准对象0只读"Darra EtherCAT Master"
0x1009Hardware Version标准对象0只读"1.0"
0x100ASoftware Version标准对象0只读SDK 版本号
0x1018Identity Object标准对象4只读主站身份信息
0x8nnnConfiguration Data从站配置40只读第 n 个从站的配置数据(地址、名称、厂商、邮箱等)
0x9nnnInformation Data从站信息32只读第 n 个从站的检测信息(实际地址、厂商 ID、DL Status)
0xAnnnDiagnosis Data从站诊断19部分可写第 n 个从站的诊断数据(AL Status、错误计数、链路等)
0xF002Detect Modules检测命令3只读从站扫描状态
0xF120Master Diag Data主站诊断16只读主站诊断数据(丢帧计数、帧频、状态)

Identity Object (0x1018)​

子索引名称类别类型读写说明
0x01Vendor ID标准对象uint32只读厂商 ID
0x02Product Code标准对象uint32只读产品代码
0x03Revision Number标准对象uint32只读修订号
0x04Serial Number标准对象uint32只读序列号

Configuration Data (0x8nnn) — 从站配置​

地址计算

从站 n 的配置数据索引为 0x8000 | n(n = 1..slave_count,从站号 1-based 直接落在低 12 位)。例如从站 1 = 0x8001,从站 2 = 0x8002。

子索引名称类别类型读写说明
0x00Number of Entries从站配置byte只读固定 40
0x01Fixed Station Address从站配置uint16只读配置地址(ConfigAddr)
0x02Type从站配置string只读设备类型字符串
0x03Name从站配置string只读设备名称
0x04Device Type从站配置uint32只读设备类型编码
0x05Vendor ID从站配置uint32只读厂商 ID
0x06Product Code从站配置uint32只读产品代码
0x07Revision Number从站配置uint32只读修订号
0x08Serial Number从站配置uint32只读序列号
0x21Mailbox Out Size从站配置uint16只读SM0 邮箱输出大小
0x22Mailbox In Size从站配置uint16只读SM1 邮箱输入大小
0x23Link Status从站配置byte只读端口链路状态
0x24Link Preset从站配置byte只读端口链路预设
0x25Flags从站配置byte只读从站标志(Bit3: 热连接组成员)
0x26Port Physics从站配置uint16只读端口物理类型
0x27Mailbox Protocols从站配置uint16只读支持的邮箱协议(CoE=0x04, FoE=0x08 等)
0x28Diag History Supported从站配置byte只读是否支持 0x10F3 诊断历史对象

Information Data (0x9nnn) — 从站检测信息​

每个从站对应一个 0x9nnn 对象,包含运行时检测到的实际信息。

地址计算

从站 n 的检测信息索引为 0x9000 | n(n = 1..slave_count,从站号 1-based 直接落在低 12 位)。例如从站 1 = 0x9001,从站 2 = 0x9002。

子索引名称类别类型读写说明
0x00Number of Entries从站信息byte只读固定 32
0x01Station Address从站信息uint16只读实际配置地址
0x05Vendor ID从站信息uint32只读检测到的厂商 ID
0x06Product Code从站信息uint32只读检测到的产品代码
0x07Revision Number从站信息uint32只读检测到的修订号
0x08Serial Number从站信息uint32只读检测到的序列号
0x20DL Status从站信息uint16只读DL Status 寄存器(ESC 0x0110-0x0111)

Diagnosis Data (0xAnnn) — 从站诊断​

每个从站对应一个 0xAnnn 对象,包含实时诊断数据。每次读取时自动更新。

地址计算

从站 n 的诊断数据索引为 0xA000 | n(n = 1..slave_count,从站号 1-based 直接落在低 12 位)。例如从站 1 = 0xA001,从站 2 = 0xA002。

子索引名称类别类型读写说明
0x00Number of Entries从站诊断byte只读固定 19
0x01AL Status从站诊断uint16只读当前 AL 状态
0x02AL Control从站诊断uint16可写写入时同步到从站
0x03Last AL Status Code从站诊断uint16只读最近一次 AL 错误码(ESC 0x0134)
0x04Link Conn. Status从站诊断byte只读端口链路连接状态
0x05Link Control从站诊断byte只读链路控制(DL Control 寄存器 0x0101)
0x06Fixed Addr Conn. Port 0从站诊断uint16只读Port 0 连接的从站配置地址
0x07Fixed Addr Conn. Port 1从站诊断uint16只读Port 1 连接的从站配置地址
0x08Fixed Addr Conn. Port 2从站诊断uint16只读Port 2 连接的从站配置地址
0x09Fixed Addr Conn. Port 3从站诊断uint16只读Port 3 连接的从站配置地址
0x0AFrame Error Port 0从站诊断uint32只读Port 0 帧错误计数
0x0BFrame Error Port 1从站诊断uint32只读Port 1 帧错误计数
0x0CFrame Error Port 2从站诊断uint32只读Port 2 帧错误计数
0x0DFrame Error Port 3从站诊断uint32只读Port 3 帧错误计数
0x0ECyclic WC Error Counter从站诊断uint32只读周期性工作计数器错误
0x0FSlave Not Present Counter从站诊断uint32只读从站不在线计数
0x10Abnormal State Change Counter从站诊断uint32只读异常状态变化计数
0x11Disable Auto Link Control从站诊断byte只读自动链路控制禁用标志
0x12Last CoE/SoE Protocol Error从站诊断uint32只读最近一次 CoE/SoE 协议错误码
0x13New Diag Messages从站诊断byte只读是否有新诊断消息(通过 0x10F3 检测)

主站身份​

GetMasterIdentity()​

BOOL GetMasterIdentity(uint16_t master_index, ec_master_identity_t* identity);

获取主站身份信息。

参数:

  • master_index (uint16_t) — 主站索引
  • identity (ec_master_identity_t*) — 输出身份信息

返回值:

  • BOOL — 成功返回 TRUE

ec_master_identity_t​

typedef struct {
uint32_t VendorId; /* 厂商 ID */
uint32_t ProductCode; /* 产品代码 */
uint32_t RevisionNo; /* 修订号 */
uint32_t SerialNo; /* 序列号 */
char DeviceName[64]; /* 设备名称 */
char HwVersion[32]; /* 硬件版本 */
char SwVersion[32]; /* 软件版本 */
} ec_master_identity_t;

主站诊断数据 (0xF120)​

C SDK 只在子索引 0 上接了快路径:diagnostics_etg1510_read() 读 0xF120:00 时调用 GetMasterDiagData(),一次性返回整个 ec_master_diag_data_t(20 字节 = 4 个 uint32 + uint16 + 2 字节对齐填充),不按子索引拆分;其余子索引没有可用实现,读取返回 -4。结构字段与 ETG.1510 子索引的对应关系:

偏移字段类别类型读写ETG.1510 子索引说明
0CyclicLostFrames主站诊断uint32只读01周期性丢帧计数(内核 5 秒滑动窗口值,不是百分比)
4AcyclicLostFrames主站诊断uint32只读02非周期性丢帧计数(内核按超时帧统计,同为 5 秒滑动窗口值)
8CyclicFramesPerSec主站诊断uint32只读03每秒周期帧数
12AcyclicFramesPerSec主站诊断uint32只读04每秒非周期帧数(内核不填该字段,读数恒 0)
16MasterState主站诊断uint16只读16主站当前 EtherCAT 状态

GetMasterDiagData()​

BOOL GetMasterDiagData(uint16_t master_index, ec_master_diag_data_t* diag);

获取主站诊断数据(ETG.1510 0xF120)。

参数:

  • master_index (uint16_t) — 主站索引
  • diag (ec_master_diag_data_t*) — 输出诊断数据

返回值:

  • BOOL — 成功返回 TRUE

ec_master_diag_data_t​

typedef struct {
uint32_t CyclicLostFrames; /* 周期帧丢失计数 (内核 5 秒滑动窗口值) */
uint32_t AcyclicLostFrames; /* 非周期帧丢失计数 (内核按超时帧统计, 同为 5 秒滑动窗口值) */
uint32_t CyclicFramesPerSec; /* 每秒周期帧数 */
uint32_t AcyclicFramesPerSec; /* 每秒非周期帧数 (内核不填该字段, 读数恒 0) */
uint16_t MasterState; /* 主站当前状态 */
} ec_master_diag_data_t;

0xF200 — 诊断接口控制​

子索引名称类别类型读写说明
0x00Number of Entries诊断控制byte只读固定 16
0x10Reset Diag Info诊断控制byte可写写入 1 复位所有从站和主站的诊断计数器(上升沿触发)

ETG.1510 索引常量​

master/diagnostics_ext.h 中定义的对象索引宏:

宏值对象
ETG1510_DEVICE_TYPE0x1000Device Type
ETG1510_DEVICE_NAME0x1008Manufacturer Device Name
ETG1510_HW_VERSION0x1009Hardware Version
ETG1510_SW_VERSION0x100ASoftware Version
ETG1510_IDENTITY0x1018Identity Object
ETG1510_CONFIG_DATA_BASE0x8000从站配置数据基地址
ETG1510_INFO_DATA_BASE0x9000从站信息数据基地址
ETG1510_DIAG_DATA_BASE0xA000从站诊断数据基地址
ETG1510_DETECT_MODULES0xF002Detect Modules Command
ETG1510_MASTER_DIAG_DATA0xF120Master Diag Data
ETG1510_DIAG_INTERFACE_CTRL0xF200Diag Interface Control

通用 OD 访问​

下列函数 (声明于 master/diagnostics_ext.h) 只转发两个快路径: 0x1018 子索引 1..4 路由到 GetMasterIdentity, 0xF120 子索引 0 路由到 GetMasterDiagData。 其余索引在 C SDK 上没有可用实现: native 的 dx_sdo_read / dx_sdo_write 入口无条件拒绝 slave_index == 0, 经它路由到主站 OD 恒失败, 读写分别返回 -4 与 -2/-4, 不会与"从站没响应 / 索引不存在"混在一起。 这两个 SDK 层函数直接以主站索引调用,不需要任何上下文句柄。

diagnostics_etg1510_read()​

int diagnostics_etg1510_read(uint16_t master_index, uint16_t index, uint8_t subindex,
uint8_t* outBuf, int bufSize);

通过 ETG.1510 OD 读取主站对象 (SDO Upload 包装).

参数:

  • master_index (uint16_t) — 主站索引
  • index (uint16_t) — OD 索引 (0x1000-0xFFFF)
  • subindex (uint8_t) — OD 子索引
  • outBuf (uint8_t*) — 输出缓冲区
  • bufSize (int) — 缓冲区大小

返回值:

  • int — 实际写入字节数; -1=参数错误; -3=缓冲区不足; -4=该索引无可用实现(除 0x1018:1..4 与 0xF120:0 外的全部索引)

diagnostics_etg1510_write()​

int diagnostics_etg1510_write(uint16_t master_index, uint16_t index, uint8_t subindex,
const uint8_t* data, int len);

通过 ETG.1510 OD 写入主站对象 (SDO Download 包装). 目标本来是 0xF200 Diag Interface Control, 0xF002 Detect Modules 等可写主站对象; 但 native 拒绝 slave_index == 0, 当前 C SDK 上留不出可用的写通道(见下返回值)。

返回值:

  • int — 0 成功(当前没有索引能走到,见下); -1 参数错误; -2 SDO 失败 (native 拒绝 / Abort / 超时); -4 薄壳不可用 (入口未就绪,未下发)。
  • 当前没有任何索引能走到成功分支: native 的 dx_sdo_write 入口无条件拒绝 slave_index == 0。

示例:

/* 写 0xF200:0x10 = 1 复位主站诊断计数 */
uint8_t one = 1;
diagnostics_etg1510_write(mi, 0xF200, 0x10, &one, 1);

/* 读 0x100A 软件版本字符串 */
uint8_t buf[32] = {0};
int n = diagnostics_etg1510_read(mi, 0x100A, 0x00, buf, sizeof(buf));
if (n > 0) printf("SW Version: %s\n", buf);

AL 状态码分类​

diagnostics_classify_al_error()​

DarraAlErrorClass diagnostics_classify_al_error(uint16_t alStatusCode);

按 ETG.1020 把 AL Status Code 归到大类, 方便 UI 分组展示告警。

返回值:

  • DarraAlErrorClass — 错误大类枚举

相关结构:

typedef enum {
AL_ERR_NONE = 0,
AL_ERR_GENERAL = 1, /* 0x0001-0x000F 通用错误 */
AL_ERR_STARTUP = 2, /* 0x0010-0x001F 启动 */
AL_ERR_MAILBOX = 3, /* 0x0020-0x002F 邮箱 */
AL_ERR_WATCHDOG = 4, /* 0x0030-0x003F 看门狗 */
AL_ERR_SYNC = 5, /* 0x0040-0x004F 同步 */
AL_ERR_DC = 6, /* 0x0050-0x005F DC */
AL_ERR_MBX_EOE = 7, /* 0x0060-0x006F EoE 邮箱 */
AL_ERR_UNKNOWN = 99
} DarraAlErrorClass;

完整示例​

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

int main(void)
{
uint16_t master = Initialize();
uint16_t slave_count = SetNetwork(master, "\\Device\\NPF_{...}", "");
SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
Start(master);

/* ===== 读取主站身份 (0x1018) ===== */
ec_master_identity_t id;
if (GetMasterIdentity(master, &id)) {
printf("=== 主站信息 (0x1018) ===\n");
printf("设备名称: %s\n", id.DeviceName);
printf("软件版本: %s\n", id.SwVersion);
printf("硬件版本: %s\n", id.HwVersion);
printf("VendorId: 0x%08X\n", id.VendorId);
printf("ProductCode: 0x%08X\n", id.ProductCode);
printf("RevisionNo: 0x%08X\n", id.RevisionNo);
printf("SerialNo: 0x%08X\n", id.SerialNo);
}

/* ===== 读取主站诊断数据 (0xF120) ===== */
/* 字段对应 ETG.1510 子索引 01/02/03/04/16; 丢帧计数是内核 5 秒滑动窗口值, 不是百分比 */
ec_master_diag_data_t diag;
if (GetMasterDiagData(master, &diag)) {
printf("\n=== 主站诊断 (0xF120) ===\n");
printf("周期帧频率: %u Hz\n", diag.CyclicFramesPerSec);
printf("非周期帧频率: %u Hz\n", diag.AcyclicFramesPerSec);
printf("周期帧丢失计数: %u\n", diag.CyclicLostFrames);
printf("主站状态: 0x%04X\n", diag.MasterState);
}

/* ===== 遍历所有从站诊断数据 (0xAnnn) ===== */
/* slave_count 来自 SetNetwork 返回值 */
printf("\n=== 从站诊断 (0xAnnn) ===\n");

for (uint16_t i = 1; i <= slave_count; i++) {
char name[128];
GetSlaveName(master, i, name, sizeof(name));

/* 读取 AL Status 和错误码 */
uint16_t al_status = GetSlaveState(master, i);
uint16_t al_code = GetSlaveALStatusCode(master, i);

/* 读取链路质量 */
int16_t link_quality = GetSlaveLinkQuality(master, i);

printf("从站 %d [%s]: AL=0x%04X, Code=0x%04X, 链路=%d%%\n",
i, name, al_status, al_code, link_quality);
}

/* ===== PDO 丢帧统计(按组) ===== */
printf("\n=== PDO 丢帧统计 ===\n");
for (uint8_t g = 0; g < 8; g++) {
uint32_t total = 0, consecutive = 0, max_consecutive = 0;
GetPDOFrameLossStats(master, g, &total, &consecutive, &max_consecutive);
if (total > 0 || GetGroupSlaveCount(master, g) > 0) {
printf("组 %d: 累计=%u, 连续=%u, 最大连续=%u\n",
g, total, consecutive, max_consecutive);
}
}

Stop(master);
Dispose(master);
return 0;
}