darra-ethercat-master 2.6.0

Commercial EtherCAT master protocol stack, real-time kernel driver integration, Windows and Linux support, multi-language SDKs, complex topology and hot-plug support.
Documentation

#![cfg(feature = "async-tokio")]

use crate::data::error::{DarraError, EcState, Result};
use crate::master::async_isolation::{
    self, run_exclusive_async, run_exclusive_async_unit, run_static_exclusive_async,
    safe_abort, CancelToken, ProgressFn,
};
use crate::master::core::{BuildResult, EtherCATMaster, MasterBuilder};
use crate::slave::core::Slave;
use crate::statics::network::{get_scanned_slaves, ScannedSlaveInfo};

#[inline]
fn report(progress: &Option<ProgressFn>, msg: &str) {
    if let Some(p) = progress {
        p(msg);
    }
}

impl MasterBuilder {

    pub async fn build_async(
        self,
        progress: Option<ProgressFn>,
        cancel: Option<CancelToken>,
    ) -> Result<BuildResult> {

        run_static_exclusive_async("Build", cancel, move || {
            report(&progress, "开始构建 EtherCAT 主站 (连接→扫描→配置)…");
            let r = self.build();
            match &r {
                Ok(br) => report(
                    &progress,
                    &format!("主站构建完成 (从站数: {}, success={})", br.slave_count, br.success),
                ),
                Err(e) => report(&progress, &format!("主站构建失败: {}", e)),
            }
            r
        })
        .await
    }
}

impl EtherCATMaster {

    pub async fn set_state_async_isolated(
        &mut self,
        state: EcState,
        progress: Option<ProgressFn>,
        cancel: Option<CancelToken>,
    ) -> Result<()> {
        let index = self.index();

        let was_started = self.started_flag();
        let started_after = run_exclusive_async(
            index,
            "SetState",
            progress,
            cancel,
            safe_abort,
            move |progress| {
                report(&progress, &format!("正在切换状态 → {:?}", state));
                let r = EtherCATMaster::set_state_at(index, state, was_started);
                match &r {
                    Ok(_) => report(&progress, &format!("已切换到 {:?}", state)),
                    Err(e) => report(&progress, &format!("切换到 {:?} 失败: {}", state, e)),
                }
                r
            },
        )
        .await?;

        self.set_started_flag(started_after);
        Ok(())
    }

    pub async fn scan_async(
        adapter: &str,
        secondary: Option<&str>,
        cancel: Option<CancelToken>,
    ) -> Result<Vec<ScannedSlaveInfo>> {
        if adapter.is_empty() {
            return Err(DarraError::InvalidParameter("适配器名称不能为空".into()));
        }
        let adapter = adapter.to_string();
        let _secondary = secondary.map(|s| s.to_string());
        run_static_exclusive_async("Scan", cancel, move || {

            EtherCATMaster::read_slave_info(&adapter)?;

            Ok(get_scanned_slaves())
        })
        .await
    }

    pub async fn dispose_async(&mut self) -> Result<()> {
        let index = self.index();

        async_isolation::mark_shutdown(index);
        let was_started = self.started_flag();
        run_exclusive_async_unit(
            index,
            "Dispose",
            None,
            None,
            safe_abort,
            move |_progress| {

                EtherCATMaster::dispose_at(index, was_started);
                Ok(())
            },
        )
        .await?;

        self.mark_disposed();
        async_isolation::release_state(index);
        Ok(())
    }
}

impl Slave {

    pub async fn sdo_read_isolated(
        &self,
        index: u16,
        subindex: u8,
        complete_access: bool,
        cancel: Option<CancelToken>,
    ) -> Result<Vec<u8>> {
        let mi = self.master_index();
        let si = self.index();
        run_exclusive_async(
            mi,
            "SDOReadIsolated",
            None,
            cancel,
            move || safe_abort(),
            move |_progress| {
                let coe = crate::slave::coe::CoEInstance::new(mi, si);
                coe.sdo_read(index, subindex, complete_access)
            },
        )
        .await
    }

    pub async fn sdo_write_isolated(
        &self,
        index: u16,
        subindex: u8,
        complete_access: bool,
        data: Vec<u8>,
        cancel: Option<CancelToken>,
    ) -> Result<()> {
        let mi = self.master_index();
        let si = self.index();
        run_exclusive_async_unit(
            mi,
            "SDOWriteIsolated",
            None,
            cancel,
            move || safe_abort(),
            move |_progress| {
                let coe = crate::slave::coe::CoEInstance::new(mi, si);
                coe.sdo_write(index, subindex, complete_access, &data)
            },
        )
        .await
    }
}