#![allow(clippy::print_stdout, clippy::enum_glob_use)]
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use ready_active_safe::prelude::*;
#[derive(Debug, Clone, PartialEq, Eq)]
enum Mode {
Initializing,
Sampling,
Safe,
}
impl core::fmt::Display for Mode {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{self:?}")
}
}
#[derive(Debug)]
enum Event {
Tick,
Measurement(u32),
Fault,
}
#[derive(Debug, PartialEq)]
enum Command {
RecordSample(u32),
TriggerAlarm,
LogTick,
}
struct SensorSystem;
impl Machine for SensorSystem {
type Mode = Mode;
type Event = Event;
type Command = Command;
fn initial_mode(&self) -> Mode {
Mode::Initializing
}
fn on_event(&self, mode: &Mode, event: &Event) -> Decision<Mode, Command> {
use Command::*;
use Event::*;
use Mode::*;
match (mode, event) {
(Initializing, Tick) => transition(Sampling),
(Sampling, Measurement(val)) => stay().emit(RecordSample(*val)),
(Sampling, Tick) => stay().emit(LogTick),
(Sampling, Fault) => transition(Safe).emit(TriggerAlarm),
_ => ignore(),
}
}
}
fn spawn_timer(tx: mpsc::Sender<Event>) {
thread::spawn(move || {
for _ in 0..6 {
thread::sleep(Duration::from_millis(50));
if tx.send(Event::Tick).is_err() {
return;
}
}
});
}
fn spawn_sensor(tx: mpsc::Sender<Event>) {
thread::spawn(move || {
for i in 0..4 {
thread::sleep(Duration::from_millis(80));
if tx.send(Event::Measurement(100 + i)).is_err() {
return;
}
}
});
}
fn spawn_fault_injector(tx: mpsc::Sender<Event>) {
thread::spawn(move || {
thread::sleep(Duration::from_millis(350));
let _ = tx.send(Event::Fault);
});
}
fn main() {
let system = SensorSystem;
let mut runner = Runner::new(&system);
let (tx, rx) = mpsc::channel();
spawn_timer(tx.clone());
spawn_sensor(tx.clone());
spawn_fault_injector(tx);
println!("Starting in {:?}", runner.mode());
loop {
match rx.recv_timeout(Duration::from_millis(500)) {
Ok(event) => {
let before = runner.mode().clone();
runner.feed_and_dispatch(&event, |cmd| {
println!(" dispatch: {cmd:?}");
});
let after = runner.mode();
println!("{before:?} + {event:?} => {after:?}");
if *after == Mode::Safe {
println!("Reached Safe mode, shutting down.");
break;
}
}
Err(mpsc::RecvTimeoutError::Timeout) => {
println!("No events for 500ms, shutting down.");
break;
}
Err(mpsc::RecvTimeoutError::Disconnected) => {
println!("All senders dropped, shutting down.");
break;
}
}
}
println!("Final mode: {:?}", runner.mode());
}