//! Replay comms between EK1100, EL2828, EL2889. Based on `multiple-groups` demo at time of writing. //! //! Required hardware: //! //! - EK1100 //! - EL2828 //! - EL2889 mod util; use env_logger::Env; use ethercrab::{MainDevice, MainDeviceConfig, PduStorage, SubDeviceGroup, Timeouts, error::Error}; use std::{path::PathBuf, time::Duration}; use tokio::time::MissedTickBehavior; const MAX_SUBDEVICES: usize = 16; const MAX_PDU_DATA: usize = PduStorage::element_size(1100); const MAX_FRAMES: usize = 128; #[derive(Default)] struct Groups { /// EL2889 and EK1100. 2 items, 2 bytes of PDI for 16 output bits. /// /// We'll keep the EK1100 in here as it has no PDI but still needs to live somewhere. slow_outputs: SubDeviceGroup<2, 2>, /// EL2828. 1 item, 1 byte of PDI for 8 output bits. fast_outputs: SubDeviceGroup<1, 1>, } #[tokio::test] #[cfg_attr(miri, ignore)] async fn replay_ek1100_el2828_el2889() -> Result<(), Error> { env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); static PDU_STORAGE: PduStorage = PduStorage::new(); let (tx, rx, pdu_loop) = PDU_STORAGE.try_split().expect("can only split once"); let maindevice = MainDevice::new( pdu_loop, Timeouts::default(), MainDeviceConfig { dc_static_sync_iterations: 100, ..Default::default() }, ); let test_name = PathBuf::from(file!()) .file_stem() .unwrap() .to_string_lossy() .to_string(); util::spawn_tx_rx(&format!("tests/{test_name}.pcapng"), tx, rx); // Read configurations from SubDevice EEPROMs and configure devices. let groups = maindevice .init::( || 0, Groups::default(), |groups: &Groups, subdevice| match subdevice.name() { "EL2889" | "EK1100" => Ok(&groups.slow_outputs), "EL2828" => Ok(&groups.fast_outputs), _ => Err(Error::UnknownSubDevice), }, ) .await .expect("Init"); let Groups { slow_outputs, fast_outputs, } = groups; let slow_outputs = slow_outputs .into_op(&maindevice) .await .expect("Slow into OP"); let fast_outputs = fast_outputs .into_op(&maindevice) .await .expect("Fast into OP"); assert_eq!( slow_outputs.subdevice(&maindevice, 0).unwrap().name(), "EK1100" ); assert_eq!( slow_outputs.subdevice(&maindevice, 1).unwrap().name(), "EL2889" ); assert_eq!( fast_outputs.subdevice(&maindevice, 0).unwrap().name(), "EL2828" ); let mut slow_cycle_time = tokio::time::interval(Duration::from_millis(10)); slow_cycle_time.set_missed_tick_behavior(MissedTickBehavior::Skip); { let el2889 = slow_outputs .subdevice(&maindevice, 1) .expect("EL2889 not present!"); // Set initial output state el2889.outputs_raw_mut()[0] = 0x01; el2889.outputs_raw_mut()[1] = 0x80; } // Animate slow pattern for 8 ticks for _ in 0..8 { slow_outputs.tx_rx(&maindevice).await.expect("TX/RX"); let el2889 = slow_outputs .subdevice(&maindevice, 1) .expect("EL2889 not present!"); let mut o = el2889.outputs_raw_mut(); // Make a nice pattern on EL2889 LEDs o[0] = o[0].rotate_left(1); o[1] = o[1].rotate_right(1); slow_cycle_time.tick().await; } let mut fast_cycle_time = tokio::time::interval(Duration::from_millis(5)); fast_cycle_time.set_missed_tick_behavior(MissedTickBehavior::Skip); // Count up to 255 in binary for _ in 0..255 { fast_outputs.tx_rx(&maindevice).await.expect("TX/RX"); // Increment every output byte for every SubDevice by one for subdevice in fast_outputs.iter(&maindevice) { let mut o = subdevice.outputs_raw_mut(); for byte in o.iter_mut() { *byte = byte.wrapping_add(1); } } fast_cycle_time.tick().await; } Ok(()) }