Reimplement control logic
Move logic into its own module and implement it using nicer programming patterns
This commit is contained in:
parent
a92f0c45f2
commit
ebff378b0a
4 changed files with 162 additions and 9 deletions
|
|
@ -45,6 +45,21 @@ impl Display {
|
||||||
self.inner.signal.notify_one();
|
self.inner.signal.notify_one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_all(&mut self, texts: &[String; 4]) {
|
||||||
|
let mut shared = self.inner.shared.lock().unwrap();
|
||||||
|
for (i, text) in texts.iter().enumerate() {
|
||||||
|
let line = &mut shared.lines[i];
|
||||||
|
if line != text {
|
||||||
|
line.clear();
|
||||||
|
line.push_str(text);
|
||||||
|
shared.pending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if shared.pending {
|
||||||
|
self.inner.signal.notify_one();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_thread(display_data: Arc<DisplayInner>) {
|
fn display_thread(display_data: Arc<DisplayInner>) {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,15 @@ impl Fieldbus {
|
||||||
pii.copy_from_slice(&data.pii);
|
pii.copy_from_slice(&data.pii);
|
||||||
data.piq.copy_from_slice(piq);
|
data.piq.copy_from_slice(piq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_process_images<F, R>(&mut self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&[u8; PII_SIZE], &mut [u8; PIQ_SIZE]) -> R,
|
||||||
|
{
|
||||||
|
let mut data = self.inner.lock().unwrap();
|
||||||
|
let data = &mut *data;
|
||||||
|
f(&data.pii, &mut data.piq)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PeripheralInfo {
|
struct PeripheralInfo {
|
||||||
|
|
|
||||||
114
src/logic.rs
Normal file
114
src/logic.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
use crate::util::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct LogicInputs {
|
||||||
|
pub left_limit: bool,
|
||||||
|
pub right_limit: bool,
|
||||||
|
pub pressure_switch: bool,
|
||||||
|
|
||||||
|
pub switch_run_continuous: bool,
|
||||||
|
pub switch_run_once: bool,
|
||||||
|
|
||||||
|
pub rio_online: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct LogicOutputs {
|
||||||
|
pub cylinder_left: bool,
|
||||||
|
pub cylinder_right: bool,
|
||||||
|
|
||||||
|
pub signal_operate: bool,
|
||||||
|
pub signal_ready: bool,
|
||||||
|
pub signal_fault: bool,
|
||||||
|
pub signal_alarm: bool,
|
||||||
|
|
||||||
|
pub display: [String; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
|
||||||
|
enum MachineState {
|
||||||
|
#[default]
|
||||||
|
Stopped,
|
||||||
|
Idle,
|
||||||
|
ExecuteContinuous,
|
||||||
|
ExecuteOnce,
|
||||||
|
Aborted,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
enum CylinderState {
|
||||||
|
#[default]
|
||||||
|
Unknown,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Logic {
|
||||||
|
inp: LogicInputs,
|
||||||
|
out: LogicOutputs,
|
||||||
|
|
||||||
|
counter: usize,
|
||||||
|
running: bool,
|
||||||
|
faulted: bool,
|
||||||
|
pressure_ok: bool,
|
||||||
|
cylinder_state: CylinderState,
|
||||||
|
state: MachineState,
|
||||||
|
|
||||||
|
t_alarm: PulseTimer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Logic {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inputs_mut(&mut self) -> &mut LogicInputs {
|
||||||
|
&mut self.inp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn outputs(&self) -> &LogicOutputs {
|
||||||
|
&self.out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Logic {
|
||||||
|
pub fn run(&mut self, now: profirust::time::Instant) {
|
||||||
|
self.out.signal_fault = matches!(self.state, MachineState::Stopped | MachineState::Aborted);
|
||||||
|
self.out.signal_ready = matches!(self.state, MachineState::Idle);
|
||||||
|
self.out.signal_operate = matches!(
|
||||||
|
self.state,
|
||||||
|
MachineState::ExecuteContinuous | MachineState::ExecuteOnce
|
||||||
|
);
|
||||||
|
self.out.signal_alarm = self
|
||||||
|
.t_alarm
|
||||||
|
.run(
|
||||||
|
now,
|
||||||
|
matches!(self.state, MachineState::Aborted),
|
||||||
|
500.millis(),
|
||||||
|
)
|
||||||
|
.done;
|
||||||
|
|
||||||
|
self.state = match self.state {
|
||||||
|
MachineState::Stopped if !self.inp.pressure_switch => MachineState::Stopped,
|
||||||
|
_ if !self.inp.pressure_switch => MachineState::Aborted,
|
||||||
|
|
||||||
|
// Reset aborted state when no run mode is requested
|
||||||
|
MachineState::Aborted
|
||||||
|
if !self.inp.switch_run_once && !self.inp.switch_run_continuous =>
|
||||||
|
{
|
||||||
|
MachineState::Stopped
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go to idle state once pressure is okay
|
||||||
|
MachineState::Stopped if self.inp.pressure_switch => MachineState::Idle,
|
||||||
|
|
||||||
|
// Start from idle state when one of the modes is requested
|
||||||
|
MachineState::Idle if self.inp.switch_run_continuous => MachineState::ExecuteContinuous,
|
||||||
|
MachineState::Idle if self.inp.switch_run_once => MachineState::ExecuteOnce,
|
||||||
|
|
||||||
|
// Stay in current state if when no transition is active
|
||||||
|
state => state,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/main.rs
33
src/main.rs
|
|
@ -2,6 +2,7 @@ use process_image as pi;
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
mod fieldbus;
|
mod fieldbus;
|
||||||
|
mod logic;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
// Parameters
|
// Parameters
|
||||||
|
|
@ -103,21 +104,35 @@ fn main() {
|
||||||
display.update_line(0, &format!("{:^20}", "torque tester"));
|
display.update_line(0, &format!("{:^20}", "torque tester"));
|
||||||
|
|
||||||
let mut fieldbus = fieldbus::Fieldbus::new();
|
let mut fieldbus = fieldbus::Fieldbus::new();
|
||||||
|
let mut logic = logic::Logic::new();
|
||||||
let mut pii = [0u8; fieldbus::PII_SIZE];
|
|
||||||
let mut piq = [0u8; fieldbus::PIQ_SIZE];
|
|
||||||
|
|
||||||
fieldbus.enter_state(fieldbus::OperatingState::Operate);
|
fieldbus.enter_state(fieldbus::OperatingState::Operate);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
fieldbus.update_process_images(&mut pii, &piq);
|
fieldbus.with_process_images(|pii, piq| {
|
||||||
let pii = Pii::from(&pii);
|
use process_image::{tag, tag_mut};
|
||||||
let piq = PiqMut::from(&mut piq);
|
|
||||||
|
|
||||||
display.update_line(2, &format!("Switch: {}", pii.want_run()));
|
*tag_mut!(piq, X, 0, 0) = logic.outputs().cylinder_left; // -MBB1
|
||||||
display.update_line(3, &format!("Button: {}", pii.want_run_once()));
|
*tag_mut!(piq, X, 0, 1) = logic.outputs().cylinder_right; // -MBB2
|
||||||
|
//
|
||||||
|
*tag_mut!(piq, X, 0, 2) = logic.outputs().signal_operate; // -PZA1:WHITE
|
||||||
|
*tag_mut!(piq, X, 0, 3) = logic.outputs().signal_ready; // -PZA1:BLUE
|
||||||
|
*tag_mut!(piq, X, 0, 4) = logic.outputs().signal_fault; // -PZA1:ORANGE
|
||||||
|
*tag_mut!(piq, X, 0, 5) = logic.outputs().signal_alarm; // -PZA1:BUZZER (VIOLET)
|
||||||
|
|
||||||
program(pii, piq, profirust::time::Instant::now());
|
logic.inputs_mut().left_limit = tag!(pii, X, 0, 0); // -BGB2
|
||||||
|
logic.inputs_mut().right_limit = tag!(pii, X, 0, 1); // -BGB2
|
||||||
|
logic.inputs_mut().pressure_switch = tag!(pii, X, 0, 2); // -BPB1
|
||||||
|
|
||||||
|
logic.inputs_mut().switch_run_continuous = tag!(pii, X, 0, 4);
|
||||||
|
logic.inputs_mut().switch_run_once = tag!(pii, X, 0, 5);
|
||||||
|
|
||||||
|
logic.inputs_mut().rio_online = tag!(pii, X, 64, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
logic.run(profirust::time::Instant::now());
|
||||||
|
|
||||||
|
display.update_all(&logic.outputs().display);
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(20));
|
std::thread::sleep(std::time::Duration::from_millis(20));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue