#![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
}
}