1
0
Fork 0
This commit is contained in:
rahix 2024-05-31 20:46:43 +02:00
commit b53b37845d
4 changed files with 544 additions and 0 deletions

208
src/main.rs Normal file
View file

@ -0,0 +1,208 @@
use process_image as pi;
use profirust::dp;
use profirust::fdl;
use profirust::phy;
// Bus Parameters
const MASTER_ADDRESS: u8 = 3;
const BUS_DEVICE: &'static str = "/dev/ttyUSB0";
const BAUDRATE: profirust::Baudrate = profirust::Baudrate::B500000;
// Device Addresses
const RIO_ADDRESS: u8 = 42;
// Parameters
const CYCLE_TIME: u64 = 5000;
pi::process_image! {
struct Pii: 1024 {
pub bgb1: (X, 0, 0), // Left Limit Switch
pub bgb2: (X, 0, 1), // Right Limit Switch
pub bpb1: (X, 0, 2), // Pressure > 1.5 barg
pub want_run: (X, 0, 4), // Start/Stop Switch
pub connection_alive: (X, 64, 0),
}
}
pi::process_image! {
struct mut PiqMut: 1024 {
pub mbb1: (X, 0, 0), // Coil for turning cylinder to the left
pub mbb2: (X, 0, 1), // Coil for turning cylinder to the right
pub pza1_white: (X, 0, 2), // White status indicator light
pub pza1_blue: (X, 0, 3), // Blue status indicator light
pub pza1_orange: (X, 0, 4), // Orange status indicator light
pub pza1_alarm: (X, 0, 5), // Alarm buzzer
pub timer: (L, 104),
pub fault_time: (L, 112),
pub counter: (L, 120),
pub running: (X, 200, 0),
pub faulted: (X, 200, 1),
pub state: (X, 200, 2),
}
}
fn program(inp: Pii, mut out: PiqMut, now: profirust::time::Instant) {
let now = u64::try_from(now.total_millis()).unwrap();
let running = inp.want_run() && (*out.running() || inp.bpb1());
let mut faulted = *out.faulted() && running;
*out.pza1_orange() = faulted;
*out.pza1_blue() = !running && !faulted;
*out.pza1_white() = running && !faulted;
*out.pza1_alarm() = faulted && (now - *out.fault_time()) < 1000;
if running && !inp.connection_alive() {
faulted = true;
}
if running && !inp.bpb1() {
faulted = true;
}
if running && (inp.bgb1() | inp.bgb2()) {
faulted = true;
}
if !running || faulted {
*out.timer() = now;
*out.counter() = 0;
}
if (now - *out.timer()) > CYCLE_TIME && *out.state() {
*out.timer() = now;
*out.state() = false;
*out.counter() += 1;
log::info!("Load cycles: {}", *out.counter());
}
if (now - *out.timer()) > CYCLE_TIME && !*out.state() {
*out.timer() = now;
*out.state() = true;
*out.counter() += 1;
log::info!("Load cycles: {}", *out.counter());
}
let mbb1 = *out.state() && running && !faulted;
let mbb2 = !*out.state() && running && !faulted;
*out.mbb1() = mbb1;
*out.mbb2() = mbb2;
if !*out.faulted() && faulted {
*out.fault_time() = now;
}
*out.running() = running;
*out.faulted() = faulted;
}
fn main() {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
.format_timestamp_micros()
.init();
let mut dp_master = dp::DpMaster::new(vec![]);
// Options generated by `gsdtool` using "B751_P39.GSD"
let options = profirust::dp::PeripheralOptions {
// "WAGO 750-303 (FW: 01 ... 06) PRO" by "WAGO Kontakttechnik GmbH"
ident_number: 0xb751,
// Global Parameters:
// - Register-Interface.............: is not used
// - RESET on terminalbus failure...: POWER ON RESET
// - Terminalbus diagnostics........: disabled
// - Evaluation of Clear_Data.......: enabled
// - Diagnostics of binary modules..: is not mapped into PI
// - Extended PI-Update.............: according to PI-Update
// - Evaluation of complex modules..: process data only
// - Data format....................: MOTOROLA
// - Process image update...........: free running
// - Response to PROFIBUS failure...: Output image is cleared
// - Response to terminalbus failure: PROFIBUS communication stops
// - Maximum length of diagnostics..: 16 Byte
//
// Selected Modules:
// [0] 8 Bit binary inputs
// [1] 8 Bit binary outputs
user_parameters: Some(&[
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x0a,
0x00,
]),
config: Some(&[0x10, 0x20]),
// Set max_tsdr depending on baudrate and assert
// that a supported baudrate is used.
max_tsdr: match BAUDRATE {
profirust::Baudrate::B9600 => 60,
profirust::Baudrate::B19200 => 60,
profirust::Baudrate::B93750 => 60,
profirust::Baudrate::B187500 => 60,
profirust::Baudrate::B500000 => 100,
profirust::Baudrate::B1500000 => 150,
profirust::Baudrate::B3000000 => 250,
profirust::Baudrate::B6000000 => 350,
profirust::Baudrate::B12000000 => 550,
b => panic!(
"Peripheral \"WAGO 750-303 (FW: 01 ... 06) PRO\" does not support baudrate {b:?}!"
),
},
fail_safe: false,
..Default::default()
};
let mut buffer_inputs = [0u8; 1];
let mut buffer_outputs = [0u8; 1];
let mut buffer_diagnostics = [0u8; 64];
let rio_handle = dp_master.add(
dp::Peripheral::new(
RIO_ADDRESS,
options,
&mut buffer_inputs,
&mut buffer_outputs,
)
.with_diag_buffer(&mut buffer_diagnostics),
);
let mut fdl_master = fdl::FdlMaster::new(
fdl::ParametersBuilder::new(MASTER_ADDRESS, BAUDRATE)
// We use a rather large T_slot time because USB-RS485 converters
// can induce large delays at times.
.slot_bits(2500)
.watchdog_timeout(profirust::time::Duration::from_secs(2))
.build_verified(&dp_master),
);
// We must not poll() too often or to little. T_slot / 2 seems to be a good compromise.
let sleep_time: std::time::Duration = (fdl_master.parameters().slot_time() / 2).into();
let mut phy = phy::LinuxRs485Phy::new(BUS_DEVICE, fdl_master.parameters().baudrate);
let start = profirust::time::Instant::now();
let mut pii = [0u8; 1024];
let mut piq = [0u8; 1024];
fdl_master.set_online();
dp_master.enter_operate();
loop {
let now = profirust::time::Instant::now();
let events = fdl_master.poll(now, &mut phy, &mut dp_master);
if events.cycle_completed {
let remoteio = dp_master.get_mut(rio_handle);
let rio_running = remoteio.is_running();
let rio_pii = remoteio.pi_i();
pii[0..rio_pii.len()].copy_from_slice(rio_pii);
*pi::tag_mut!(&mut pii, X, 64, 0) = rio_running;
program(Pii::from(&pii), PiqMut::from(&mut piq), now);
let remoteio = dp_master.get_mut(rio_handle);
let rio_piq = remoteio.pi_q_mut();
rio_piq.copy_from_slice(&piq[0..rio_piq.len()]);
}
std::thread::sleep(sleep_time);
}
}