You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
4.4 KiB

//! 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);
}
}
}
}