pub struct StateMachine {
pub index: i32,
pub timer_preset: Duration,
pub timeout_preset: Duration,
pub error_code: i32,
pub message: String,
pub error_message: String,
/* private fields */
}Expand description
State Machine Helper (FB_StateMachine)
A state machine helper with automatic timer management and error tracking. Provides two timers that automatically reset when the state index changes:
- Timer (
timer_done()) - General purpose timer for delays and debouncing - Timeout (
timed_out()) - For detecting stuck states
This is equivalent to the IEC 61131-3 FB_StateMachine function block.
§Automatic Timer Reset
Both timers automatically reset when index changes. This eliminates a
common source of bugs in state machines where timers are not properly reset.
The pattern is:
- Set
timer_preset(and optionallytimeout_preset) in state N - Change
indexto state N+1 (timers reset and start counting) - In state N+1, check
timer_done()ortimed_out()
§Example
use autocore_std::fb::StateMachine;
use std::time::Duration;
let mut state = StateMachine::new();
// Simulate a control loop
loop {
match state.index {
0 => { // Reset
state.clear_error();
state.index = 10;
}
10 => { // Idle - wait for start signal
// For demo, just proceed
state.timer_preset = Duration::from_millis(100);
state.index = 20;
}
20 => { // Debounce
if state.timer_done() {
state.timeout_preset = Duration::from_secs(10);
state.index = 30;
}
}
30 => { // Wait for operation (simulated)
// In real code: check operation_complete
// For demo, check timeout
if state.timed_out() {
state.set_error(30, "Operation timeout");
state.index = 0;
}
// Exit demo loop
break;
}
_ => { state.index = 0; }
}
state.call(); // Call at end of each scan cycle
}§Timer Presets Persist
Timer presets persist until you change them. This allows setting a preset once and using it across multiple states:
100 => {
state.timer_preset = Duration::from_millis(300);
state.index = 110;
}
110 => {
// Uses 300ms preset set in state 100
if some_condition && state.timer_done() {
state.index = 120;
}
}
120 => {
// Still uses 300ms preset (timer reset on state change)
if state.timer_done() {
state.index = 10;
}
}§Error Handling Pattern
200 => {
state.timeout_preset = Duration::from_secs(7);
start_operation();
state.index = 210;
}
210 => {
if operation_complete {
state.index = 1000; // Success
} else if state.timed_out() {
state.set_error(210, "Operation timed out");
state.index = 5000; // Error handler
}
}
5000 => {
// Error recovery
state.index = 0;
}Fields§
§index: i32Current state index.
timer_preset: DurationTimer preset. timer_done() returns true when time in current state >= this value.
Defaults to Duration::MAX (timer never triggers unless you set a preset).
timeout_preset: DurationTimeout preset. timed_out() returns true when time in current state >= this value.
Defaults to Duration::MAX (timeout never triggers unless you set a preset).
error_code: i32Error code. A value of 0 indicates no error.
When non-zero, is_error() returns true.
message: StringStatus message for UI display. Content does not indicate an error.
error_message: StringError message for UI display. Should only have content when error_code != 0.
Implementations§
Source§impl StateMachine
impl StateMachine
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new state machine starting at state 0.
Timer presets default to Duration::MAX, meaning timers won’t trigger
until you explicitly set a preset.
§Example
use autocore_std::fb::StateMachine;
let state = StateMachine::new();
assert_eq!(state.index, 0);
assert_eq!(state.error_code, 0);
assert!(!state.is_error());Sourcepub fn call(&mut self)
pub fn call(&mut self)
Call once per scan cycle at the END of your state machine logic.
This method:
- Detects state changes (when
indexdiffers from the previous call) - Resets internal timers on state change
- Updates internal tracking for
elapsed(),timer_done(), andtimed_out()
§Example
use autocore_std::fb::StateMachine;
let mut state = StateMachine::new();
// Your state machine logic here...
match state.index {
0 => { state.index = 10; }
_ => {}
}
state.call(); // Always call at the endSourcepub fn timer_done(&self) -> bool
pub fn timer_done(&self) -> bool
Returns true when time in current state >= timer_preset.
The timer automatically resets when the state index changes.
§Example
use autocore_std::fb::StateMachine;
use std::time::Duration;
let mut state = StateMachine::new();
state.timer_preset = Duration::from_millis(50);
state.call(); // Start tracking
assert!(!state.timer_done()); // Not enough time elapsed
std::thread::sleep(Duration::from_millis(60));
assert!(state.timer_done()); // Now it's doneSourcepub fn timed_out(&self) -> bool
pub fn timed_out(&self) -> bool
Returns true when time in current state >= timeout_preset.
Use this for detecting stuck states. The timeout automatically resets when the state index changes.
§Example
use autocore_std::fb::StateMachine;
use std::time::Duration;
let mut state = StateMachine::new();
state.timeout_preset = Duration::from_millis(50);
state.call();
assert!(!state.timed_out());
std::thread::sleep(Duration::from_millis(60));
assert!(state.timed_out());Sourcepub fn elapsed(&self) -> Duration
pub fn elapsed(&self) -> Duration
Returns elapsed time since entering the current state.
Returns Duration::ZERO if call() has never been called.
§Example
use autocore_std::fb::StateMachine;
use std::time::Duration;
let mut state = StateMachine::new();
state.call();
std::thread::sleep(Duration::from_millis(10));
assert!(state.elapsed() >= Duration::from_millis(10));Sourcepub fn is_error(&self) -> bool
pub fn is_error(&self) -> bool
Returns true if error_code != 0.
§Example
use autocore_std::fb::StateMachine;
let mut state = StateMachine::new();
assert!(!state.is_error());
state.error_code = 100;
assert!(state.is_error());Sourcepub fn set_error(&mut self, code: i32, message: impl Into<String>)
pub fn set_error(&mut self, code: i32, message: impl Into<String>)
Set error state with code and message.
This is a convenience method equivalent to setting error_code
and error_message directly.
§Example
use autocore_std::fb::StateMachine;
let mut state = StateMachine::new();
state.set_error(110, "Failed to home X axis");
assert_eq!(state.error_code, 110);
assert_eq!(state.error_message, "Failed to home X axis");
assert!(state.is_error());Sourcepub fn clear_error(&mut self)
pub fn clear_error(&mut self)
Clear error state.
Sets error_code to 0 and clears error_message.
§Example
use autocore_std::fb::StateMachine;
let mut state = StateMachine::new();
state.set_error(100, "Some error");
assert!(state.is_error());
state.clear_error();
assert!(!state.is_error());
assert_eq!(state.error_code, 0);
assert!(state.error_message.is_empty());Trait Implementations§
Source§impl Clone for StateMachine
impl Clone for StateMachine
Source§fn clone(&self) -> StateMachine
fn clone(&self) -> StateMachine
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more