fgdb - khalilbendhief/KHALIL GitHub Wiki
new.rs implements MachineNewTrait and handles EtherCAT device discovery, module initialization, and channel binding. It runs once at startup.
Step 1 — Validate the device group
validate_same_machine_identification_unique(&device_identification)?;
validate_no_role_duplicates(&device_identification)?;Ensures all devices assigned in the dashboard share the same serial number and have no duplicate roles. Fails early with a clear error if the assignment is invalid.
Step 2 — Acquire the 750-354 coupler
let _wago_750_354 = get_ethercat_device::<Wago750_354>(
hardware, params, 0, [WAGO_750_354_IDENTITY_A].to_vec(),
).await?;Fetches the coupler handle from the EtherCAT bus by identity. The 0 is the expected position on the bus.
Step 3 — Discover and register slot modules
let modules = Wago750_354::initialize_modules(_wago_750_354.1).await?;
let mut coupler = _wago_750_354.0.write().await;
for module in modules { coupler.set_module(module); }
coupler.init_slot_modules(_wago_750_354.1);The coupler scans its physical slots left-to-right and registers whatever modules it finds. After this, coupler.slot_devices is populated by slot index.
Step 4 — Downcast slot devices to concrete types
// Slot 0 → 750-530 (Digital Output)
let dev = coupler.slot_devices.get(0).unwrap().clone().unwrap();
let wago750_530: Arc<RwLock<Wago750_530>> =
downcast_device::<Wago750_530>(dev).await?;
// Slot 1 → 750-430 (Digital Input)
let dev = coupler.slot_devices.get(1).unwrap().clone().unwrap();
let wago750_430: Arc<RwLock<Wago750_430>> =
downcast_device::<Wago750_430>(dev).await?;downcast_device casts the generic Arc<dyn EthercatDevice> to the concrete module type. If the physical module in a slot doesn't match the expected type, this returns an error at runtime.
⚠️ Physical slot order matters: slot 0 = 750-530 (DO), slot 1 = 750-430 (DI). Mount the modules in this exact order on the DIN rail.
Step 5 — Create per-channel I/O handles
let di1 = DigitalInput::new(wago750_430.clone(), Wago750_430Port::Port1);
// ... di2 through di8
let do1 = DigitalOutput::new(wago750_530.clone(), Wago750_530Port::Port1);
// ... do2 through do8Each DigitalInput / DigitalOutput holds a shared reference (Arc<RwLock<T>>) to its parent module and a port identifier. Multiple channel handles share the same module lock safely.
Step 6 — Construct the machine and emit initial state
let mut machine = Self {
digital_input: [di1, di2, di3, di4, di5, di6, di7, di8],
digital_output: [do1, do2, do3, do4, do5, do6, do7, do8],
inputs: [false; 8],
led_on: [false; 8],
// ...
};
machine.emit_state();
Ok(machine)All channels are bundled into fixed-size arrays. emit_state() is called immediately so any connected frontend receives the initial state without waiting for the first 30 Hz tick.