//! Steuerung für die Ventilinseln //! //! Verbindet sich dynamisch mit einer Ventilinsel, die am Bus unter beliebiger Adresse gefunden //! wurde. Es wird eine bekannte Parametrierung vorausgesetzt. //! //! Zur demo ist hier eine CPV14 mit CPV14-GE-DI02-8 Anschaltung vorgesehen. use profirust::dp; // "Festo CPV-DI02" by "Festo AG&Co." const VALVE_TERMINAL_IDENT_NUMBER: u16 = 0x0a35; pub struct ValveTerminal { peripheral: dp::PeripheralHandle, address: profirust::Address, valve_states: [bool; 8], } impl ValveTerminal { pub fn new(dp_master: &mut dp::DpMaster, baudrate: profirust::Baudrate) -> Self { // Als erstes wird die Ventilinsel mit einer Standard-Adresse parametriert. Die Adresse // wird dann später geändert, sobald ein tatsächliches Gerät auf dem Bus gefunden wurde. let default_address = 42; // Options generated by `gsdtool` using "cpv_0A35.gse" let options = profirust::dp::PeripheralOptions { // "Festo CPV-DI02" by "Festo AG&Co." ident_number: 0x0a35, // Global Parameters: // (none) // // Selected Modules: // [0] Base module:16DO // - monitor U-Load.........: active // - monitor failure CP-Line: inactive // - fault mode.............: reset outputs // - fault state 2 byte.....: 0 user_parameters: Some(&[0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00]), config: Some(&[0x21]), // Set max_tsdr depending on baudrate and assert // that a supported baudrate is used. max_tsdr: match baudrate { profirust::Baudrate::B9600 => 20, profirust::Baudrate::B19200 => 20, profirust::Baudrate::B93750 => 20, profirust::Baudrate::B187500 => 20, profirust::Baudrate::B500000 => 20, profirust::Baudrate::B1500000 => 25, profirust::Baudrate::B3000000 => 50, profirust::Baudrate::B6000000 => 100, profirust::Baudrate::B12000000 => 200, b => panic!("Peripheral \"Festo CPV-DI02\" does not support baudrate {b:?}!"), }, fail_safe: false, ..Default::default() }; let buffer_inputs = vec![0u8; 0].leak(); let buffer_outputs = vec![0u8; 2].leak(); let buffer_diagnostics = vec![0u8; 16].leak(); let handle = dp_master.add( dp::Peripheral::new(default_address, options, buffer_inputs, buffer_outputs) .with_diag_buffer(buffer_diagnostics), ); Self { peripheral: handle, address: default_address, valve_states: [false; 8], } } /// Überprüfen ob ein gefundenes Gerät eine Ventilinsel von unserem Typ ist pub fn check_ident(&self, ident: u16) -> bool { ident == VALVE_TERMINAL_IDENT_NUMBER } /// Gibt `true` zurück wenn die Ventilinsel an der aktuell parametrierten Adresse erfolgreich /// kommuniziert. pub fn is_running(&self, dp_master: &mut dp::DpMaster) -> bool { let peripheral = dp_master.get_mut(self.peripheral); peripheral.is_running() } pub fn init_at_address(&mut self, address: profirust::Address, dp_master: &mut dp::DpMaster) { if address != self.address { let peripheral = dp_master.get_mut(self.peripheral); peripheral.reset_address(address); peripheral.pi_q_mut().fill(0u8); self.valve_states = [false; 8]; } } pub fn update_valve_states(&mut self, valve_states: &[bool]) { if self.valve_states != valve_states { self.valve_states.copy_from_slice(valve_states); log::info!("Ventile: {:?}", valve_states); } } pub fn update(&mut self, dp_master: &mut dp::DpMaster, events: &dp::DpEvents) { let peripheral = dp_master.get_mut(self.peripheral); if peripheral.is_running() && events.cycle_completed { let pi_q = peripheral.pi_q_mut(); pi_q.fill(0); for (i, valve) in self.valve_states.iter().enumerate() { let bit_index = i * 2; let bit_value = if *valve { 1 } else { 0 }; pi_q[bit_index / 8] |= bit_value << (bit_index % 8); } } } }