跳到主要内容

AoE (ADS over EtherCAT)

AoE 协议实现了 ADS (Automation Device Specification) over EtherCAT 通信,支持 Beckhoff TwinCAT 和类似设备的 ADS 通信。

通过 slave.AoE 访问。从站不支持 AoE 时为 null

属性

属性类型访问说明
DefaultTimeoutint只读默认超时时间(微秒),500000

数据读写

Read(uint indexGroup, uint indexOffset, uint length, int timeoutUs = DefaultTimeout)

public byte[]? Read(uint indexGroup, uint indexOffset, uint length, int timeoutUs = DefaultTimeout)

读取 ADS 数据。

参数:

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

返回值:

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

示例:

byte[]? status = slave.AoE.Read(0x4020, 0, 4);
if (status != null)
{
uint value = BitConverter.ToUInt32(status, 0);
Console.WriteLine($"状态值: 0x{value:X8}");
}

Write(uint indexGroup, uint indexOffset, byte[] data, int timeoutUs = DefaultTimeout)

public bool Write(uint indexGroup, uint indexOffset, byte[] data, int timeoutUs = DefaultTimeout)

写入 ADS 数据。

参数:

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

返回值:

  • bool — 成功返回 true

示例:

slave.AoE.Write(0x4020, 0, BitConverter.GetBytes((uint)0x0006));

ReadWrite(uint indexGroup, uint indexOffset, uint readLength, byte[]? writeData = null, int timeoutUs = DefaultTimeout)

public byte[]? ReadWrite(uint indexGroup, uint indexOffset, uint readLength, byte[]? writeData = null, int timeoutUs = DefaultTimeout)

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

参数:

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

返回值:

  • byte[]? — 读取的数据

设备信息

ReadDeviceInfo(int timeoutUs = DefaultTimeout)

public (bool success, byte majorVer, byte minorVer, ushort build, string deviceName) ReadDeviceInfo(int timeoutUs = DefaultTimeout)

读取 ADS 设备信息。

返回值:

  • success (bool) — 是否成功
  • majorVer (byte) — 主版本号
  • minorVer (byte) — 次版本号
  • build (ushort) — 编译号
  • deviceName (string) — 设备名称

示例:

var (success, major, minor, build, name) = slave.AoE.ReadDeviceInfo();
if (success)
Console.WriteLine($"设备: {name} v{major}.{minor}.{build}");

ReadState(int timeoutUs = DefaultTimeout)

public (bool success, ushort adsState, ushort deviceState) ReadState(int timeoutUs = DefaultTimeout)

读取 ADS 状态。

返回值:

  • success (bool) — 是否成功
  • adsState (ushort) — ADS 状态
  • deviceState (ushort) — 设备状态

相关结构:

  • 0Invalid 无效状态
  • 1Idle 空闲
  • 2Reset 复位
  • 3Init 初始化
  • 4Start 启动
  • 5Run 运行
  • 6Stop 停止
  • 7SaveConfig 保存配置
  • 8LoadConfig 加载配置
  • 9PowerFailure 电源故障
  • 10PowerGood 电源正常
  • 11Error 错误
  • 12Shutdown 关闭
  • 13Suspend 挂起
  • 14Resume 恢复
  • 15Config 配置
  • 16Reconfig 重新配置

示例:

var (success, adsState, deviceState) = slave.AoE.ReadState();
if (success)
Console.WriteLine($"ADS 状态: {slave.AoE.GetAdsStateName(adsState)} ({adsState})");

WriteControl(ushort adsState, ushort deviceState, byte[]? data = null, int timeoutUs = DefaultTimeout)

public bool WriteControl(ushort adsState, ushort deviceState, byte[]? data = null, int timeoutUs = DefaultTimeout)

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

参数:

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

返回值:

  • bool — 成功返回 true

示例:

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

GetAdsStateName(ushort adsState)

public string GetAdsStateName(ushort adsState)

获取 ADS 状态名称。

数据订阅

Subscribe(...)

public AoESubscription? Subscribe(
uint indexGroup, uint indexOffset, uint dataLength,
Action<AoENotificationEventArgs> callback,
AoETransmissionMode mode = AoETransmissionMode.OnChange,
int cycleTimeMs = 100)

订阅数据变化通知。

参数:

  • indexGroup (uint) — 索引组
  • indexOffset (uint) — 索引偏移
  • dataLength (uint) — 数据长度
  • callback (Action<AoENotificationEventArgs>) — 数据变化回调
  • mode (AoETransmissionMode) — 传输模式(默认 OnChange
  • cycleTimeMs (int) — 检查周期(毫秒,默认 100)

返回值:

  • AoESubscription? — 订阅对象,失败返回 null

相关结构:

public enum AoETransmissionMode : uint
{
NoTransmission = 0, // 无通知
Cyclic = 1, // 循环通知 - 按指定周期发送
OnChange = 2, // 变化通知 - 数据变化时发送
CyclicInDevice = 3, // 设备端循环通知
OnChangeInDevice = 4 // 设备端变化通知
}

示例:

var sub = slave.AoE.Subscribe(0x4020, 0, 4, e =>
{
uint value = BitConverter.ToUInt32(e.Data, 0);
Console.WriteLine($"数据变化: 0x{value:X8}");
});

Unsubscribe(AoESubscription subscription)

public bool Unsubscribe(AoESubscription subscription)

取消订阅。

UnsubscribeAll()

public void UnsubscribeAll()

取消所有订阅。

DelNotification(uint notificationHandle, int timeoutUs = DefaultTimeout)

public bool DelNotification(uint notificationHandle, int timeoutUs = DefaultTimeout)

底层删除从站设备通知句柄 (ADS Command 0x07)。常规场景应使用 Unsubscribe / UnsubscribeAll,此方法仅在持有原始 handle 且需手动清理时调用。

参数:

  • notificationHandle (uint) — 由 ADS AddNotification 返回的句柄
  • timeoutUs (int) — 超时时间(微秒),默认 DefaultTimeout

返回值:

  • bool — 成功返回 true

示例:

// 已知 handle 的低层清理路径
slave.AoE.DelNotification(handle);

DelNotificationAsync(uint notificationHandle, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

public Task<bool> DelNotificationAsync(uint notificationHandle, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

异步版本的 DelNotification,用于 UI / 后台线程清理设备通知。

参数:

  • notificationHandle (uint) — 由 ADS AddNotification 返回的句柄
  • timeoutUs (int) — 超时时间(微秒),默认 DefaultTimeout
  • cancellationToken (CancellationToken) — 取消令牌

返回值:

  • Task<bool> — 成功返回 true

示例:

await slave.AoE.DelNotificationAsync(handle, cancellationToken: ct);

AoE 配置

SetConfig(byte[] targetNetId, ushort targetPort, byte[] sourceNetId, ushort sourcePort)

public bool SetConfig(byte[] targetNetId, ushort targetPort, byte[] sourceNetId, ushort sourcePort)

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

参数:

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

返回值:

  • bool — 成功返回 true

示例:

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

InitializeSlaveNetId(byte[] netId, int timeoutUs = DefaultTimeout)

public bool InitializeSlaveNetId(byte[] netId, int timeoutUs = DefaultTimeout)

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

参数:

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

返回值:

  • bool — 成功返回 true

示例:

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

InitializeSlaveNetIdAsync(byte[] netId, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

public Task<bool> InitializeSlaveNetIdAsync(byte[] netId, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

异步版本的 InitializeSlaveNetId,避免阻塞调用线程。

参数:

  • netId (byte[]) — 6 字节的 AMS Net ID
  • timeoutUs (int) — 超时时间(微秒)
  • cancellationToken (CancellationToken) — 取消令牌

返回值:

  • Task<bool> — 成功返回 true

示例:

byte[] netId = { 5, 80, 187, 177, 1, 1 };
await slave.AoE.InitializeSlaveNetIdAsync(netId, cancellationToken: ct);

跨协议网关

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

ReadCoEViaAoE(ushort index, byte subindex, uint readLength, int timeoutUs = DefaultTimeout)

public byte[]? ReadCoEViaAoE(ushort index, byte subindex, uint readLength, int timeoutUs = DefaultTimeout)

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

参数:

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

返回值:

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

示例:

// 通过 AoE 网关读取 CoE 对象 0x6041:0(状态字)
byte[]? data = slave.AoE.ReadCoEViaAoE(0x6041, 0, 2);
if (data != null)
{
ushort statusWord = BitConverter.ToUInt16(data, 0);
Console.WriteLine($"状态字: 0x{statusWord:X4}");
}

WriteCoEViaAoE(ushort index, byte subindex, byte[] data, int timeoutUs = DefaultTimeout)

public bool WriteCoEViaAoE(ushort index, byte subindex, byte[] data, int timeoutUs = DefaultTimeout)

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

参数:

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

返回值:

  • bool — 成功返回 true

示例:

// 通过 AoE 网关写入 CoE 对象 0x6040:0(控制字)
slave.AoE.WriteCoEViaAoE(0x6040, 0, BitConverter.GetBytes((ushort)0x000F));

WriteCoEViaAoEAsync(ushort index, byte subindex, byte[] data, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

public Task<bool> WriteCoEViaAoEAsync(ushort index, byte subindex, byte[] data, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

异步版本的 WriteCoEViaAoE,适合 UI 主线程发起的远程 CoE 写入。

参数:

  • index (ushort) — CoE 对象索引
  • subindex (byte) — CoE 子索引
  • data (byte[]) — 写入数据
  • timeoutUs (int) — 超时时间(微秒)
  • cancellationToken (CancellationToken) — 取消令牌

返回值:

  • Task<bool> — 成功返回 true

示例:

await slave.AoE.WriteCoEViaAoEAsync(0x6040, 0,
BitConverter.GetBytes((ushort)0x000F), cancellationToken: ct);

ReadSoEViaAoE(uint idn, uint readLength, int timeoutUs = DefaultTimeout)

public byte[]? ReadSoEViaAoE(uint idn, uint readLength, int timeoutUs = DefaultTimeout)

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

参数:

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

返回值:

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

WriteSoEViaAoE(uint idn, byte[] data, int timeoutUs = DefaultTimeout)

public bool WriteSoEViaAoE(uint idn, byte[] data, int timeoutUs = DefaultTimeout)

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

参数:

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

返回值:

  • bool — 成功返回 true

WriteSoEViaAoEAsync(uint idn, byte[] data, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

public Task<bool> WriteSoEViaAoEAsync(uint idn, byte[] data, int timeoutUs = DefaultTimeout, CancellationToken cancellationToken = default)

异步版本的 WriteSoEViaAoE,可与 await / CancellationToken 协作。

参数:

  • idn (uint) — SoE IDN 编号
  • data (byte[]) — 写入数据
  • timeoutUs (int) — 超时时间(微秒)
  • cancellationToken (CancellationToken) — 取消令牌

返回值:

  • Task<bool> — 成功返回 true

示例:

await slave.AoE.WriteSoEViaAoEAsync(idn: 32,
BitConverter.GetBytes((uint)1500), cancellationToken: ct);

完整示例

数据读写

if (slave.AoE != null)
{
// 读取数据
byte[]? status = slave.AoE.Read(0x4020, 0, 4);
if (status != null)
Console.WriteLine($"状态: 0x{BitConverter.ToUInt32(status, 0):X8}");

// 写入数据
slave.AoE.Write(0x4020, 0, BitConverter.GetBytes((uint)0x0006));

// 设备信息
var (ok, major, minor, build, name) = slave.AoE.ReadDeviceInfo();
if (ok) Console.WriteLine($"设备: {name} v{major}.{minor}.{build}");
}

数据订阅

if (slave.AoE != null)
{
var sub = slave.AoE.Subscribe(0x4020, 0, 4, e =>
{
Console.WriteLine($"数据变化, 订阅 ID: {e.SubscriptionId}");
});

Thread.Sleep(10000);
slave.AoE.UnsubscribeAll();
}

跨协议网关

if (slave.AoE != null)
{
// 通过 AoE 读取 CoE 对象
byte[]? statusWord = slave.AoE.ReadCoEViaAoE(0x6041, 0, 2);
if (statusWord != null)
Console.WriteLine($"状态字: 0x{BitConverter.ToUInt16(statusWord, 0):X4}");

// 通过 AoE 写入 CoE 对象
slave.AoE.WriteCoEViaAoE(0x6040, 0, BitConverter.GetBytes((ushort)0x000F));

// 通过 AoE 读取 SoE IDN
byte[]? idnData = slave.AoE.ReadSoEViaAoE(32, 4);
if (idnData != null)
Console.WriteLine($"IDN 32 值: {BitConverter.ToUInt32(idnData, 0)}");
}

AoE 订阅子系统

ADS DeviceNotification (Command 0x06/0x07/0x08) 的托管包装. slave.AoE.Subscriptions 入口, 内部跨主站路由 native callback. 订阅后从设备主动推送数据变化, 不再依赖轮询.

Subscriptions

public AoESubscriptionManager Subscriptions { get; }

订阅管理器单例, 首次访问惰性创建. 同一主站的所有 slave 共享 native 回调线程.

Subscribe(uint indexGroup, uint indexOffset, uint dataLength, AoETransmissionMode, int maxDelayMs, int cycleTimeMs)

public AoESubscription? Subscribe(uint indexGroup, uint indexOffset, uint dataLength,
AoETransmissionMode mode = AoETransmissionMode.OnChange,
int maxDelayMs = 100,
int cycleTimeMs = 100)

创建并注册一个新订阅. 内部依次: 启动监听器 → AddDeviceNotification (0x06) → 注册 DLL 回调 → 加入订阅表. 失败返回 null.

参数:

  • indexGroup (uint) — ADS 索引组
  • indexOffset (uint) — ADS 索引偏移
  • dataLength (uint) — 数据长度 (字节)
  • mode (AoETransmissionMode) — 传输模式
  • maxDelayMs (int) — 最大延迟 (毫秒), 默认 100
  • cycleTimeMs (int) — 循环周期 (毫秒), 默认 100

返回值:

  • AoESubscription? — 订阅对象 (含 Id / NotificationHandle / IsActive)

相关结构:

public enum AoETransmissionMode
{
NoTransmission = 0,
Cyclic = 1,
OnChange = 2,
CyclicInDevice = 3,
OnChangeInDevice = 4
}

Unsubscribe(Guid id) / Unsubscribe(AoESubscription)

public bool Unsubscribe(Guid subscriptionId)
public bool Unsubscribe(AoESubscription subscription)

取消单个订阅: 移除事件处理器 → 注销 DLL 回调 → DeleteDeviceNotification (0x07).

UnsubscribeAll() / GetActiveSubscriptions() / GetSubscription(Guid)

public void UnsubscribeAll()
public AoESubscription[] GetActiveSubscriptions()
public AoESubscription? GetSubscription(Guid subscriptionId)

批量管理 API. UnsubscribeAll 在 master 退出前必须调用以避免设备侧句柄泄漏.

订阅事件

public event EventHandler<AoENotificationEventArgs>? DataNotification;
public event EventHandler<AoESubscriptionErrorEventArgs>? Error;
public event EventHandler<AoESubscription>? SubscriptionStateChanged;

相关结构:

public class AoENotificationEventArgs : EventArgs
{
public Guid SubscriptionId { get; }
public uint NotificationHandle { get; }
public ushort SlaveIndex { get; }
public uint IndexGroup { get; }
public uint IndexOffset { get; }
public byte[] Data { get; }
public DateTime Timestamp { get; }
public ulong DeviceTimestamp { get; } // 100ns 单位
}

public class AoESubscriptionErrorEventArgs : EventArgs
{
public Guid SubscriptionId { get; }
public string ErrorMessage { get; }
public Exception? Exception { get; }
public DateTime Timestamp { get; }
}

public class AoESubscription
{
public Guid Id { get; }
public uint NotificationHandle { get; }
public ushort SlaveIndex { get; }
public uint IndexGroup { get; }
public uint IndexOffset { get; }
public uint DataLength { get; }
public AoETransmissionMode TransmissionMode { get; }
public bool IsActive { get; }
public DateTime CreatedAt { get; }
public object? Tag { get; set; }
}

订阅管理器属性

public int SubscriptionCount { get; }      // 当前订阅数量
public bool IsListenerRunning { get; } // native 监听线程是否运行
public int DefaultTimeoutMs { get; set; } // 订阅注册默认超时 (默认 500)

示例:

var sub = slave.AoE.Subscriptions.Subscribe(
indexGroup: 0xF021,
indexOffset: 0x1000,
dataLength: 4,
mode: AoETransmissionMode.OnChange,
maxDelayMs: 50,
cycleTimeMs: 100);

slave.AoE.Subscriptions.DataNotification += (s, e) =>
Console.WriteLine($"slave={e.SlaveIndex} data={BitConverter.ToInt32(e.Data,0)}");

slave.AoE.Subscriptions.Error += (s, e) =>
Console.WriteLine($"订阅错误: {e.ErrorMessage}");

// 退出前清理
slave.AoE.Subscriptions.UnsubscribeAll();

AoE 错误处理

AoEResultCode

public enum AoEResultCode : uint
{
NoError = 0x00,
InternalError = 0x01,
NoRealTime = 0x02,
InsertMailboxError = 0x04,
TargetPortNotFound = 0x06,
TargetMachineNotFound = 0x07,
UnknownCommandId = 0x08,
InvalidAmsLength = 0x0E,
InvalidAmsNetId = 0x0F,
PortDisabled = 0x12,
AmsSyncTimeout = 0x15,
DeviceInvalidGroup = 0x0700,
DeviceInvalidOffset = 0x0701,
DeviceNotReady = 0x0705,
DeviceTimeout = 0x0712,
DeviceAccessDenied = 0x071C,
// 更多见源码 (ETG.1020 Table 16)
}

ETG.1020 Table 16 定义的 AoE/ADS 结果码. 由 LastAoEError 暴露.

AoELastError

public struct AoELastError
{
public uint ResultCode; // 完整 32-bit
public ushort ErrorClass; // High word
public ushort ErrorCode; // Low word
public ushort LastCommand; // 失败的 ADS command id
public bool HasError;
public AoEResultCode ResultCodeEnum { get; }
public string Message { get; }
}

最近一次 AoE 调用失败的完整记录.

主请求接口

InitAllSlavesNetId(byte[]? masterNetId = null, int timeoutUs = 1_000_000)

public int InitAllSlavesNetId(byte[]? masterNetId = null, int timeoutUs = 1_000_000)

为所有支持 AoE 的从站派发 InitializeSlaveNetId. 返回成功初始化的从站数. masterNetId == null 时使用默认 1.1.1.1.1.1.

InitializeSlaveNetId(byte[] netId, int timeoutUs)

public bool InitializeSlaveNetId(byte[] netId, int timeoutUs = DefaultTimeout)

设置当前 slave 的 AMS NetID (6 字节).

SendFragmented(byte[] payload, ushort packetNumber, int timeoutUs)

public bool SendFragmented(byte[] payload, ushort packetNumber, int timeoutUs = DefaultTimeout)

ADS Fragmentation 发送 (ETG.1020 §9.3). 大数据自动分片, 配合 ReadWrite 内部触发使用.

SetConfig(byte[] targetNetId, ushort targetPort, byte[] sourceNetId, ushort sourcePort)

public bool SetConfig(byte[] targetNetId, ushort targetPort, byte[] sourceNetId, ushort sourcePort)

设置 AoE 通信路由 (源/目标 NetID + Port).

WriteControl(ushort adsState, ushort deviceState, byte[]? data = null, int timeoutUs)

public bool WriteControl(ushort adsState, ushort deviceState, byte[]? data = null, int timeoutUs = DefaultTimeout)

ADS WriteControl (Command 0x05): 切换 ADS 状态机 (Run/Stop/Reset/Config).

AddNotification / DelNotification (低层接口)

public uint? AddNotification(uint indexGroup, uint indexOffset, uint length,
uint transMode, uint maxDelay, uint cycleTime, int timeoutUs = DefaultTimeout)
public bool DelNotification(uint notificationHandle, int timeoutUs = DefaultTimeout)

直接注册/注销设备通知. Subscriptions 内部调用; 用户代码一般使用上层 Subscribe API. maxDelay / cycleTime 单位为 100ns.

ReadCoEViaAoE / WriteCoEViaAoE / ReadSoEViaAoE / WriteSoEViaAoE

public byte[]? ReadCoEViaAoE(ushort index, byte subindex, uint readLength, int timeoutUs = DefaultTimeout)
public bool WriteCoEViaAoE(ushort index, byte subindex, byte[] data, int timeoutUs = DefaultTimeout)
public byte[]? ReadSoEViaAoE(uint idn, uint readLength, int timeoutUs = DefaultTimeout)
public bool WriteSoEViaAoE(uint idn, byte[] data, int timeoutUs = DefaultTimeout)

跨协议网关. 通过 AoE 调用 CoE/SoE 对象, 用于多层 ADS 路由场景.

异步全套

每个同步方法都有对应 Async 版本, 后缀 Async, 多接 CancellationToken cancellationToken = default:

同步异步
WriteControlWriteControlAsync
AddNotificationAddNotificationAsync
DelNotificationDelNotificationAsync
ReadCoEViaAoEReadCoEViaAoEAsync
WriteCoEViaAoEWriteCoEViaAoEAsync
ReadSoEViaAoEReadSoEViaAoEAsync
WriteSoEViaAoEWriteSoEViaAoEAsync
InitializeSlaveNetIdInitializeSlaveNetIdAsync

示例:

var ct = new CancellationTokenSource(TimeSpan.FromSeconds(2)).Token;
byte[]? data = await slave.AoE.ReadCoEViaAoEAsync(0x6041, 0, 2, cancellationToken: ct);