跳到主要内容

AoE (ADS over EtherCAT)

AoE 协议实现了 ADS (Automation Device Specification) over EtherCAT 通信,支持与实现 ADS 协议的设备进行通信。

通过 slave.AoE() 访问。子对象延迟创建,始终返回实例(不会为 null);从站是否支持 AoE 用 slave.AoE().isSupported() 判断。​

默认超时

AoE 各方法的不带 timeoutUs 参数重载使用内置默认超时 500000 微秒(0.5 秒)。该默认值为 SDK 内部常量,不作为公开属性暴露;需要自定义超时请使用带 timeoutUs 参数的重载。

数据读写​

Read(int indexGroup, int indexOffset, int length, int timeoutUs)​

public byte[] Read(int indexGroup, int indexOffset, int length, int timeoutUs)
public byte[] Read(int indexGroup, int indexOffset, int length) // 默认超时

读取 ADS 数据。

参数:

  • indexGroup (int) — 索引组
  • indexOffset (int) — 索引偏移
  • length (int) — 读取长度
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • byte[] — 读取的数据,失败返回 null

示例:

byte[] status = slave.AoE().Read(0x4020, 0, 4);
if (status != null) {
int value = (status[0] & 0xFF) | ((status[1] & 0xFF) << 8)
| ((status[2] & 0xFF) << 16) | ((status[3] & 0xFF) << 24);
System.out.printf("状态值: 0x%08X%n", value);
}

异步重载:

public CompletableFuture<byte[]> readAsync(int indexGroup, int indexOffset, int length, int timeoutUs)
public CompletableFuture<byte[]> readAsync(int indexGroup, int indexOffset, int length)

异步读取 ADS 数据。底层失败时 future 以 AoE.AoEProtocolException 异常完成。

slave.AoE().readAsync(0x4020, 0, 4)
.thenAccept(data -> System.out.printf("状态长度: %d%n", data.length))
.exceptionally(ex -> { System.err.println("失败: " + ex.getMessage()); return null; });

Write(int indexGroup, int indexOffset, byte[] data, int timeoutUs)​

public boolean Write(int indexGroup, int indexOffset, byte[] data, int timeoutUs)
public boolean Write(int indexGroup, int indexOffset, byte[] data) // 默认超时

写入 ADS 数据。

参数:

  • indexGroup (int) — 索引组
  • indexOffset (int) — 索引偏移
  • data (byte[]) — 写入数据
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • boolean — 成功返回 true

示例:

byte[] data = { 0x06, 0x00, 0x00, 0x00 };
slave.AoE().Write(0x4020, 0, data);

异步重载:

public CompletableFuture<Boolean> writeAsync(int indexGroup, int indexOffset, byte[] data, int timeoutUs)
public CompletableFuture<Boolean> writeAsync(int indexGroup, int indexOffset, byte[] data)

ReadWrite(int indexGroup, int indexOffset, int readLength, byte[] writeData, int timeoutUs)​

public byte[] ReadWrite(int indexGroup, int indexOffset, int readLength, byte[] writeData, int timeoutUs)

同时读写数据(ADS ReadWrite 命令)。

参数:

  • indexGroup (int) — 索引组
  • indexOffset (int) — 索引偏移
  • readLength (int) — 读取长度
  • writeData (byte[]) — 写入数据(可为 null)
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • byte[] — 读取的数据,失败返回 null

异步重载:

public CompletableFuture<byte[]> readWriteAsync(int indexGroup, int indexOffset, int readLength,
byte[] writeData, int timeoutUs)

设备信息​

ReadDeviceInfo(int timeoutUs)​

public DeviceInfo ReadDeviceInfo(int timeoutUs)
public DeviceInfo ReadDeviceInfo()

读取 ADS 设备信息。

返回值:

相关结构:

DeviceInfo​

public static class DeviceInfo {
public boolean Success; // 是否成功
public byte MajorVer; // 主版本号
public byte MinorVer; // 次版本号
public short Build; // 编译号
public String DeviceName; // 设备名称
}

示例:

AoE.DeviceInfo info = slave.AoE().ReadDeviceInfo();
if (info.Success)
System.out.printf("设备: %s v%d.%d.%d%n",
info.DeviceName, info.MajorVer, info.MinorVer, info.Build);

ReadState(int timeoutUs)​

public AdsState ReadState(int timeoutUs)
public AdsState ReadState()

读取 ADS 状态。

返回值:

相关结构:

AdsState​

public static class AdsState {
public boolean Success; // 是否成功
public short AdsState; // ADS 状态
public short DeviceState; // 设备状态
}

ADS 状态码含义:

  • 0 — Invalid 无效状态
  • 1 — Idle 空闲
  • 2 — Reset 复位
  • 3 — Init 初始化
  • 4 — Start 启动
  • 5 — Run 运行
  • 6 — Stop 停止
  • 7 — SaveConfig 保存配置
  • 8 — LoadConfig 加载配置
  • 9 — PowerFailure 电源故障
  • 10 — PowerGood 电源正常
  • 11 — Error 错误
  • 15 — Config 配置

示例:

AoE.AdsState state = slave.AoE().ReadState();
if (state.Success)
System.out.println("ADS 状态: " + AoE.GetAdsStateDescription(state.AdsState));

WriteControl(short adsState, short deviceState, byte[] data, int timeoutUs)​

public boolean WriteControl(short adsState, short deviceState, byte[] data, int timeoutUs)
public boolean WriteControl(short adsState, short deviceState)

写入控制命令(切换设备状态)。

参数:

  • adsState (short) — 目标 ADS 状态
  • deviceState (short) — 目标设备状态
  • data (byte[]) — 附加数据(可选)
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • boolean — 成功返回 true

示例:

slave.AoE().WriteControl((short) 5, (short) 0);  // 切换到 Run 状态

GetAdsStateDescription(int adsState)​

public static String GetAdsStateDescription(int adsState)

获取 ADS 状态码的中文描述。

数据订阅​

Subscribe(int indexGroup, int indexOffset, int dataLength, NotificationCallback callback, int cycleTimeMs)​

public int Subscribe(int indexGroup, int indexOffset, int dataLength,
NotificationCallback callback, int cycleTimeMs)

订阅数据变化通知。

参数:

  • indexGroup (int) — 索引组
  • indexOffset (int) — 索引偏移
  • dataLength (int) — 数据长度
  • callback (NotificationCallback) — 数据变化回调
  • cycleTimeMs (int) — 检查周期(毫秒)

返回值:

  • int — 通知句柄,失败返回 -1

相关结构:

NotificationCallback​

@FunctionalInterface
public interface NotificationCallback {
void onNotification(short slave, int handle, byte[] data, long timestamp);
}

示例:

int handle = slave.AoE().Subscribe(0x4020, 0, 4, (slaveNo, h, data, ts) -> {
int value = (data[0] & 0xFF) | ((data[1] & 0xFF) << 8)
| ((data[2] & 0xFF) << 16) | ((data[3] & 0xFF) << 24);
System.out.printf("数据变化: 0x%08X%n", value);
}, 100);

Unsubscribe(int handle)​

public boolean Unsubscribe(int handle)

取消指定订阅。

UnsubscribeAll()​

public void UnsubscribeAll()

取消所有订阅。

GetActiveSubscriptions()​

public int[] GetActiveSubscriptions()

获取所有活跃订阅的句柄列表。

SendCommand(short targetPort, short commandId, byte[] commandData, int timeoutUs)​

public byte[] SendCommand(short targetPort, short commandId, byte[] commandData, int timeoutUs)

发送原始 ADS 命令(高级 API,常规场景请使用 Read/Write/Subscribe)。

参数:

  • targetPort (short) — 目标端口
  • commandId (short) — 命令 ID
  • commandData (byte[]) — 命令数据
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • byte[] — 响应数据,失败返回 null

AoE 配置​

SetConfig(byte[] targetNetId, short targetPort, byte[] sourceNetId, short sourcePort)​

public boolean SetConfig(byte[] targetNetId, short targetPort, byte[] sourceNetId, short sourcePort)

设置 AoE 路由配置(AMS NetID 和端口)。

参数:

  • targetNetId (byte[]) — 目标 AMS NetID(6 字节)
  • targetPort (short) — 目标 AMS 端口
  • sourceNetId (byte[]) — 源 AMS NetID(6 字节)
  • sourcePort (short) — 源 AMS 端口

返回值:

  • boolean — 成功返回 true

示例:

byte[] targetNetId = { 5, 80, (byte)187, (byte)177, 1, 1 };
byte[] sourceNetId = { (byte)192, (byte)168, 1, 100, 1, 1 };
slave.AoE().SetConfig(targetNetId, (short) 851, sourceNetId, (short) 32768);

InitializeSlaveNetId(byte[] netId, int timeoutUs)​

public boolean InitializeSlaveNetId(byte[] netId, int timeoutUs)
public boolean InitializeSlaveNetId(byte[] netId)

初始化从站 AoE Net ID(ETG.1020 §9.4)。在 INIT→PreOp 状态切换期间调用,将 Net ID 写入从站 ADS 路由表。

参数:

  • netId (byte[]) — 6 字节的 AMS Net ID
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • boolean — 成功返回 true

示例:

byte[] netId = { 5, 80, (byte)187, (byte)177, 1, 1 };
slave.AoE().InitializeSlaveNetId(netId);

GetConfig()​

public AoEConfig GetConfig()

获取当前 AoE 路由配置。

返回值:

相关结构:

AoEConfig​

public static class AoEConfig {
public boolean Success; // 是否成功
public byte[] TargetNetId; // 目标 AMS NetID (6 字节)
public short TargetPort; // 目标 AMS 端口
public byte[] SourceNetId; // 源 AMS NetID (6 字节)
public short SourcePort; // 源 AMS 端口
}

跨协议网关​

通过 AoE 路由访问其他邮箱协议(ETG.1020),支持 CoE 和 SoE 协议的透明转发。

ReadCoEViaAoE(int index, int subindex, int readLength, int timeoutUs)​

public byte[] ReadCoEViaAoE(int index, int subindex, int readLength, int timeoutUs)
public byte[] ReadCoEViaAoE(int index, int subindex, int readLength)

通过 AoE 路由读取 CoE 对象(IndexGroup=0xF302)。

参数:

  • index (int) — CoE 对象索引
  • subindex (int) — CoE 子索引
  • readLength (int) — 期望读取长度
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • byte[] — 读取的数据,失败返回 null

示例:

// 通过 AoE 网关读取 CoE 对象 0x6041:0(状态字)
byte[] data = slave.AoE().ReadCoEViaAoE(0x6041, 0, 2);
if (data != null) {
int statusWord = (data[0] & 0xFF) | ((data[1] & 0xFF) << 8);
System.out.printf("状态字: 0x%04X%n", statusWord);
}

WriteCoEViaAoE(int index, int subindex, byte[] data, int timeoutUs)​

public boolean WriteCoEViaAoE(int index, int subindex, byte[] data, int timeoutUs)
public boolean WriteCoEViaAoE(int index, int subindex, byte[] data)

通过 AoE 路由写入 CoE 对象(IndexGroup=0xF302)。

参数:

  • index (int) — CoE 对象索引
  • subindex (int) — CoE 子索引
  • data (byte[]) — 写入数据
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • boolean — 成功返回 true

示例:

// 通过 AoE 网关写入 CoE 对象 0x6040:0(控制字)
byte[] ctrlWord = { 0x0F, 0x00 };
slave.AoE().WriteCoEViaAoE(0x6040, 0, ctrlWord);

ReadSoEViaAoE(int idn, int readLength, int timeoutUs)​

public byte[] ReadSoEViaAoE(int idn, int readLength, int timeoutUs)
public byte[] ReadSoEViaAoE(int idn, int readLength)

通过 AoE 路由读取 SoE IDN(IndexGroup=0xF420)。

参数:

  • idn (int) — SoE IDN 编号
  • readLength (int) — 期望读取长度
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • byte[] — 读取的数据,失败返回 null

WriteSoEViaAoE(int idn, byte[] data, int timeoutUs)​

public boolean WriteSoEViaAoE(int idn, byte[] data, int timeoutUs)
public boolean WriteSoEViaAoE(int idn, byte[] data)

通过 AoE 路由写入 SoE IDN(IndexGroup=0xF420)。

参数:

  • idn (int) — SoE IDN 编号
  • data (byte[]) — 写入数据
  • timeoutUs (int) — 超时时间(微秒)

返回值:

  • boolean — 成功返回 true

路由 IndexGroup 常量​

public static final int COE_INDEX_GROUP = 0xF302;  // CoE over AoE 路由
public static final int SOE_INDEX_GROUP = 0xF420; // SoE over AoE 路由

ReadCoEViaAoE / WriteCoEViaAoE 内部使用 COE_INDEX_GROUP,IndexOffset 编码为 (index << 16) | subindex;ReadSoEViaAoE / WriteSoEViaAoE 使用 SOE_INDEX_GROUP,IndexOffset = IDN 编号。

错误码与异常​

AoEResultCode(枚举)​

ETG.1020 Table 16 定义的 AoE/ADS 结果码,数值与标准定义一致:高字节 = 错误类(0x0700 = ADS 设备错误,0x0740 = 客户端错误),低字节 = 具体错误码。

public enum AoEResultCode {
NO_ERROR(0x0000),
INTERNAL_ERROR(0x0001),
NO_REALTIME(0x0002),
INSERT_MAILBOX_ERROR(0x0004),
TARGET_PORT_NOT_FOUND(0x0006),
TARGET_MACHINE_NOT_FOUND(0x0007),
UNKNOWN_COMMAND_ID(0x0008),
INVALID_AMS_LENGTH(0x000E),
INVALID_AMS_NET_ID(0x000F),
PORT_DISABLED(0x0012),
AMS_SYNC_TIMEOUT(0x0015),
DEVICE_INVALID_GROUP(0x0700),
DEVICE_INVALID_OFFSET(0x0701),
DEVICE_NOT_READY(0x0705),
DEVICE_TIMEOUT(0x0712),
DEVICE_ACCESS_DENIED(0x071C),
CLIENT_ERROR(0x0740),
CLIENT_INVOKE_TIMEOUT(0x0744),
CLIENT_QUEUE_FULL(0x0750);
// 完整列表(共约 60 个常量)见 SDK 源码 AoE.AoEResultCode (ETG.1020 Table 16)

public int getValue(); // 数值
public static AoEResultCode fromValue(int code); // 数值反查,未匹配返回 null
}
  • getValue() (int) — 数值(只读):枚举常量对应的 ADS 结果码
  • fromValue(int code) (AoEResultCode) — 反查(静态,只读):由数值匹配枚举常量,未匹配返回 null

AoEProtocolException​

AoE 异步方法(readAsync / writeAsync / readWriteAsync)底层失败时,返回的 CompletableFuture 以该异常完成。

public static class AoEProtocolException extends RuntimeException {
public AoEProtocolException(String message);
public AoEProtocolException(String message, Throwable cause);
}

示例:

slave.AoE().readAsync(0x4020, 0, 4)
.thenAccept(data -> System.out.printf("长度: %d%n", data.length))
.exceptionally(ex -> {
if (ex.getCause() instanceof AoE.AoEProtocolException)
System.err.println("AoE 读取失败: " + ex.getCause().getMessage());
return null;
});

邮箱统计​

AoE 实现统一的 IMailboxProtocol 接口。2.5.x 起,getStatistics() / resetStatistics() 经真实导出的 native EcxMbxGetStats / EcxMbxResetStats 拉取(此前为占位空快照)。

类别方法类型读写说明
协议标识getProtocolType()byte只读协议类型常量(AoE=0x01)
getProtocolName()String只读协议名称("AoE")
isSupported()boolean只读从站是否支持本协议
事务状态getLastStatus()MailboxStatus只读最近一次邮箱事务的统一状态
getLastErrorCode()long只读最近一次协议层错误码(0=无错误)
统计getStatistics()MailboxStatistics只读邮箱统计快照
resetStatistics()void只写重置邮箱统计计数器
MailboxStatistics 结构字段与 MailboxStatus 枚举详见 CoE — 邮箱统计。

完整示例​

数据读写​

AoE aoe = slave.AoE();

// 读取数据
byte[] status = aoe.Read(0x4020, 0, 4);
if (status != null) {
int value = (status[0] & 0xFF) | ((status[1] & 0xFF) << 8)
| ((status[2] & 0xFF) << 16) | ((status[3] & 0xFF) << 24);
System.out.printf("状态: 0x%08X%n", value);
}

// 写入数据
byte[] writeData = { 0x06, 0x00, 0x00, 0x00 };
aoe.Write(0x4020, 0, writeData);

// 设备信息
AoE.DeviceInfo info = aoe.ReadDeviceInfo();
if (info.Success)
System.out.printf("设备: %s v%d.%d.%d%n",
info.DeviceName, info.MajorVer, info.MinorVer, info.Build);

数据订阅​

AoE aoe = slave.AoE();

int handle = aoe.Subscribe(0x4020, 0, 4, (slaveNo, h, data, ts) -> {
System.out.println("数据变化");
}, 100);

Thread.sleep(10000);
aoe.UnsubscribeAll();

跨协议网关​

AoE aoe = slave.AoE();

// 通过 AoE 读取 CoE 对象
byte[] statusWord = aoe.ReadCoEViaAoE(0x6041, 0, 2);
if (statusWord != null) {
int value = (statusWord[0] & 0xFF) | ((statusWord[1] & 0xFF) << 8);
System.out.printf("状态字: 0x%04X%n", value);
}

// 通过 AoE 写入 CoE 对象
byte[] ctrlWord = { 0x0F, 0x00 };
aoe.WriteCoEViaAoE(0x6040, 0, ctrlWord);

// 通过 AoE 读取 SoE IDN
byte[] idnData = aoe.ReadSoEViaAoE(32, 4);
if (idnData != null) {
int value = (idnData[0] & 0xFF) | ((idnData[1] & 0xFF) << 8)
| ((idnData[2] & 0xFF) << 16) | ((idnData[3] & 0xFF) << 24);
System.out.printf("IDN 32 值: %d%n", value);
}