#![allow(unused)]
use env_logger::Env;
use ethercrab::{
MainDevice, MainDeviceConfig, PduStorage, Timeouts, error::Error, std::ethercat_now,
};
use futures_lite::StreamExt;
use std::time::Duration;
const MAX_SUBDEVICES: usize = 16;
const MAX_PDU_DATA: usize = PduStorage::element_size(1100);
const MAX_FRAMES: usize = 16;
const PDI_LEN: usize = 64;
static PDU_STORAGE: PduStorage<MAX_FRAMES, MAX_PDU_DATA> = PduStorage::new();
#[cfg(not(windows))]
fn main() -> Result<(), Error> {
smol::block_on(async {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let interface = std::env::args()
.nth(1)
.expect("Provide network interface as first argument.");
log::info!("Starting release demo...");
log::info!("Run with RUST_LOG=ethercrab=debug or =trace for debug information");
let (tx, rx, pdu_loop) = PDU_STORAGE.try_split().expect("can only split once");
let maindevice =
MainDevice::new(pdu_loop, Timeouts::default(), MainDeviceConfig::default());
let tx_rx_handle =
smol::spawn(ethercrab::std::tx_rx_task(&interface, tx, rx).expect("spawn TX/RX task"));
process_loop(&maindevice).await;
let pdu_loop = unsafe { maindevice.release() };
log::info!("PduLoop was released, starting new MainDevice...");
let maindevice =
MainDevice::new(pdu_loop, Timeouts::default(), MainDeviceConfig::default());
process_loop(&maindevice).await;
let pdu_loop = unsafe { maindevice.release_all() };
let (tx, rx) = tx_rx_handle.await.expect("Failed to stop TX/RX task");
log::info!(
"PduLoop, PduTx and PduRx were released, starting new TX/RX task and making new MainDevice..."
);
let tx_rx_handle =
smol::spawn(ethercrab::std::tx_rx_task(&interface, tx, rx).expect("spawn TX/RX task"));
let maindevice =
MainDevice::new(pdu_loop, Timeouts::default(), MainDeviceConfig::default());
process_loop(&maindevice).await;
log::info!("Third PDU loop with second TX/RX task shutdown complete");
let pdu_loop = unsafe { maindevice.release_all() };
let (tx, rx) = tx_rx_handle.await.expect("TX/RX task error");
#[cfg(all(target_os = "linux", feature = "io-uring"))]
{
use ethercrab::std::tx_rx_task_io_uring;
log::info!("Linux only: reuse TX/RX with io_uring");
let tx_rx_handle = std::thread::spawn(move || tx_rx_task_io_uring(&interface, tx, rx));
let maindevice =
MainDevice::new(pdu_loop, Timeouts::default(), MainDeviceConfig::default());
process_loop(&maindevice).await;
let _pdu_loop = unsafe { maindevice.release_all() };
let (tx, rx) = tx_rx_handle
.join()
.expect("io_uring TX/RX thread")
.expect("Could not recover TX/RX hadnles");
assert!(!tx.should_exit());
assert!(!rx.should_exit());
}
Ok(())
})
}
async fn process_loop(maindevice: &MainDevice<'_>) {
let group = maindevice
.init_single_group::<MAX_SUBDEVICES, PDI_LEN>(ethercat_now)
.await
.expect("Init")
.into_op(maindevice)
.await
.expect("PRE-OP -> OP");
log::info!("Discovered {} SubDevices", group.len());
for subdevice in group.iter(maindevice) {
let io = subdevice.io_raw();
log::info!(
"-> SubDevice {:#06x} {} inputs: {} bytes, outputs: {} bytes",
subdevice.configured_address(),
subdevice.name(),
io.inputs().len(),
io.outputs().len()
);
}
let mut tick_interval = smol::Timer::interval(Duration::from_millis(5));
for _ in 0..u8::MAX {
group.tx_rx(maindevice).await.expect("TX/RX");
for subdevice in group.iter(maindevice) {
let mut o = subdevice.outputs_raw_mut();
for byte in o.iter_mut() {
*byte = byte.wrapping_add(1);
}
}
tick_interval.next().await;
}
let _ = group
.into_safe_op(maindevice)
.await
.expect("OP -> SAFE-OP")
.into_pre_op(maindevice)
.await
.expect("SAFE-OP -> PRE-OP")
.into_init(maindevice)
.await
.expect("PRE-OP -> INIT");
}
#[cfg(windows)]
fn main() {
eprintln!("This example only supports non-Windows OSes");
}