darra-ethercat-master 0.5.0

Darra EtherCAT Master SDK - Rust 绑定 (封装 Darra.Core.dll/libDarraCore.so)
Documentation
darra-ethercat-master-0.5.0 has been yanked.

Darra EtherCAT — Rust SDK

Rust 1.70+ 平台的 Darra EtherCAT Master 封装. 安全的 Rust API, FFI 绑定 Darra.Core.dll (Windows) / libDarraCore.so (Linux), 对齐 C#/Java/Python 语义.

安装

crates.io

[dependencies]
darra-ethercat = "0.4"

可选 feature

darra-ethercat = { version = "0.4", features = ["async-tokio", "redundancy", "udp", "wdk"] }
Feature 作用
async-tokio 启用 *_async 方法 (基于 tokio::task::spawn_blocking)
redundancy 双网口 Cable Redundancy 支持
udp UDP 传输层 (非 Raw Ethernet)
wdk WDK 内核 PDO Offload (仅 Windows)

默认无 feature: 纯同步 + Raw Ethernet.

系统依赖

  • Windows: 需 Darra.Core.dll 在可执行目录 / PATH
  • Linux: 需 libDarraCore.soLD_LIBRARY_PATH

快速 Hello World

use darra_ethercat::{EtherCATMaster, EcState};
use darra_ethercat::statics::network;

fn main() -> darra_ethercat::Result<()> {
    // 1. 扫描网卡
    let adapters = network::get_network_info(true)?;
    for nic in &adapters {
        println!("{}  slaves={}", nic.description, nic.slave_count);
    }

    let target = adapters.iter().find(|n| n.slave_count > 0)
        .ok_or_else(|| darra_ethercat::DarraError::Other("未找到带从站的网卡".into()))?;

    // 2. 构建主站 (builder)
    let master = EtherCATMaster::builder()
        .set_network(&target.name, "")
        .enable_auto_startup()
        .build()?;

    // 3. 扫描从站
    println!("主站 #{} 发现从站 {}",
        master.master_number(), master.slave_count());
    for s in master.slaves() {
        println!("  [{}] {}  State={:?}", s.index(), s.name(), s.state());
    }

    // 4. 进入 OP
    master.set_state_sequence(EcState::Operational, 10_000)?;

    // 5. 读取第一个从站 Statusword
    if master.slave_count() > 0 {
        let slave = master.slave(1);  // 1-based
        let data = slave.coe().sdo_read(0x6041, 0x00, false)?;
        let sw = u16::from_le_bytes([data[0], data[1]]);
        println!("Statusword=0x{:04X}", sw);
    }

    // 6. 退出 (master drop 时自动释放)
    master.set_state(EcState::Init)?;
    Ok(())
}

API 要点

  • 入口: EtherCATMaster::new() / EtherCATMaster::builder().set_network(...).build() / EtherCATMaster::from_json_file("config.xml")
  • 从站: master.slave(idx) (1-based) / master.slaves() (Vec) / master.slaves_in_group(g)
  • 协议实例: slave.coe() / .foe() / .soe() / .eoe() / .aoe() / .voe() / .fsoe() / .dc() / .pdo()
  • 诊断: master.diagnostics()
  • 状态机: master.set_state_sequence(EcState::Operational, 10_000)master.set_state(target)
  • 错误: Result<T, DarraError>, DarraError 携带 ETG abort code

异步模型

启用 async-tokio feature:

darra-ethercat = { version = "0.4", features = ["async-tokio"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
#[tokio::main]
async fn main() -> Result<()> {
    let data = slave.coe().sdo_read_async(0x6041, 0x00, false).await?;
    slave.coe().sdo_write_async(0x6040, 0x00, false, &[0x0F, 0x00]).await?;

    // 并发
    let (s1, s2, s3) = tokio::join!(
        slave.coe().sdo_read_async(0x6041, 0x00, false),
        slave.coe().sdo_read_async(0x6064, 0x00, false),
        slave.coe().sdo_read_async(0x606C, 0x00, false),
    );
    Ok(())
}

未启用 async-tokio 时, 使用 *_blocking 版本 (基于 std::thread):

let handle = slave.coe().sdo_read_blocking(0, 1, 0x6041, 0x00);
let data = handle.join().unwrap()?;  // JoinHandle

与 C# 对齐

C# Rust
DarraEtherCAT EtherCATMaster
SDORead(0x6041, 0x00) sdo_read(0x6041, 0x00, false)
SetState(EcState.OP) set_state_sequence(EcState::Operational, 10_000)
slave.CoE.LastSdoError slave.coe().last_error()
master.Dispose() drop(master) (自动)

命名风格: Rust snake_case (类型名 PascalCase).

错误处理

use darra_ethercat::{DarraError, SDOError};

match slave.coe().sdo_read(0x6041, 0x00, false) {
    Ok(data) => { /* use data */ }
    Err(DarraError::Sdo(SDOError::AccessDenied)) => { /* ETG 0x06010000 */ }
    Err(DarraError::Timeout) => { /* 网络超时 */ }
    Err(e) => eprintln!("SDO 失败: {}", e),
}

DarraError 实现 thiserror::Error, 可与 anyhow / eyre 无缝集成.

日志

SDK 通过 DLL callback 上报日志, 默认写到 stderr. 可接入 log / tracing:

use darra_ethercat::logging;
logging::set_callback(|level, module, msg| {
    tracing::info!(target: module, "[{}] {}", level, msg);
});

协议支持

以 C# SDK 为对齐基准, 通过 extern "C" FFI 直调 Darra Core DLL. 详细对比见 ../SDK_ALIGNMENT.md.

协议 / 能力 状态 说明
CoE ✓ 完整 SDO sdo_read/sdo_write, async-tokio, PDO, OD, CiA402
EoE ✓ 完整 IP/MAC 配置
FoE ✓ 完整 上下载, Cancel, 进度回调
SoE ✓ 完整 IDN 读写
AoE ✓ 完整 ADS 透传
VoE ✓ 完整 厂商邮箱透传
FSoE ✓ 完整 SIL3, 多连接
DC ✓ 完整 sync0/sync1, drift 补偿
Cable Redundancy ✓ 完整 feature redundancy 启用, 双网口 failover
Hot-Connect ✓ 完整 热插拔
Mailbox Gateway ✓ 完整 ETG.8200 TCP 网关
ESI 解析 ✓ 完整 XML 自动加载
ENI 配置 ✓ 完整 ETG.1510 ENI init
ETG.1510 Diagnostics ✓ 完整 0x10F3 历史 + 聚合状态 + Emergency Recorder tokio::Stream 适配 (master.emergency_stream())

对齐度: 100% vs C# (Phase 4 后, tokio::Stream 适配在 managed 层实装).

字节级一致性保证

Rust SDK 通过 extern "C" FFI 转发到 Darra.Core.dll, 与 C# 基准做字节级对齐:

  • CRC16 (FSoE): darra_ethercat::fsoe::crc16(data: &[u8]) -> u16 直调 C ABI, byte-by-byte 与 C# 输出一致
  • IDN 编码 (SoE): SoeIdn::encode(set, type_, block) -> u16 与 C# SoeIdn.Encode() 同值, to_le_bytes() 与线缆字节序一致
  • 枚举值: #[repr(u8)] enum EcState { Init = 0x01, ..., Operational = 0x08 } 与 C/C#/Java/Python 同值, bytemuck::Pod 派生保证内存布局
  • 结构体: #[repr(C, packed)] 与 C #pragma pack(1) / C# Pack=1 字段偏移一致
  • &[u8] 语义: SDO 数据按 EtherCAT 帧字节序透传, FFI 边界不做字节交换 (利用 Pin<&[u8]> 防止移动)
  • Result<T, DarraError>: 错误码值与 C EC_ERR_* / C# EtgAbortCode 同值, From<i32> 转换无信息损失

字节级一致性由 Darra_EtherCAT_SDKTest_Rust 测试套件 + cargo test 与 C# 基准每次 CI 比对.

已知限制

下列能力在 Darra.Core.dll 中未导出 native symbol, Rust SDK 在 managed (safe Rust) 层提供 fallback, 用户 API 不变:

  • ENI 回写 (master.export_eni(path)): DLL 无 export, fallback 用 quick-xml 序列化 MasterConfig 重建 ENI XML
  • Emergency Recorder 历史深度: DLL 默认 256 项, fallback 用 VecDeque<EmergencyEntry> 容量可配
  • Diagnostics 变化推送: DLL 仅支持轮询, fallback 用 tokio::time::interval + tokio::sync::watch 推送, 暴露为 impl Stream<Item = DiagnosticsChange>
  • MailboxGateway 会话上限: DLL 默认 16 路, fallback 用 tokio::sync::Semaphore 限流

Rust fallback 全部 safe Rust 实现, 不引入 unsafe, 字节输出与 native 一致. 启用 async-tokio feature 时延迟 < 100 ms, 可通过 MasterBuilder::poll_interval(Duration) 调整.

如何升级到完整功能

DLL 端补以下 export 后, FFI 绑定切换为 native 路径, managed fallback 自动停用 (通过 cfg!(feature = "native-<x>") 切换):

待补 export Rust SDK 受益
Master_ExportENI master.export_eni() 走 native, 移除 quick-xml 依赖
EmergencyRecorder_SetMaxHistory 历史下沉 DLL, 释放 VecDeque heap
Diagnostics_RegisterChangeCallback extern "C" fn 回调推送, 延迟从 100 ms 降至 < 1 ms (注意 Send + Sync)
MailboxGateway_SetSessionLimit DLL 限流, 移除 tokio::sync::Semaphore

切换无需修改用户代码: build.rs 探测 native symbol, 自动启用 cfg(native_<feature>), fallback 模块由 cfg(not(native_<feature>)) 编译.

相关文档

License

Proprietary — Darra Technology.