Skip to main content

autocore_std/
lib.rs

1//! # AutoCore Standard Library
2//!
3//! The standard library for writing AutoCore control programs. This crate provides
4//! everything you need to build real-time control applications that integrate with
5//! the AutoCore server ecosystem.
6//!
7//! ## Overview
8//!
9//! AutoCore control programs run as separate processes that communicate with the
10//! autocore-server via shared memory and IPC. This library handles all the low-level
11//! details, allowing you to focus on your control logic.
12//!
13//! ```text
14//! ┌─────────────────────────┐     ┌─────────────────────────┐
15//! │   autocore-server       │     │   Your Control Program  │
16//! │                         │     │                         │
17//! │  ┌─────────────────┐    │     │  ┌─────────────────┐    │
18//! │  │ Shared Memory   │◄───┼─────┼──│ ControlRunner   │    │
19//! │  │ (GlobalMemory)  │    │     │  │                 │    │
20//! │  └─────────────────┘    │     │  │ ┌─────────────┐ │    │
21//! │                         │     │  │ │ Your Logic  │ │    │
22//! │  ┌─────────────────┐    │     │  │ └─────────────┘ │    │
23//! │  │ Tick Signal     │────┼─────┼──│                 │    │
24//! │  └─────────────────┘    │     │  └─────────────────┘    │
25//! └─────────────────────────┘     └─────────────────────────┘
26//! ```
27//!
28//! ## Quick Start
29//!
30//! 1. Create a new control project using `acctl`:
31//!    ```bash
32//!    acctl clone <server-ip> <project-name>
33//!    ```
34//!
35//! 2. Implement the [`ControlProgram`] trait:
36//!    ```ignore
37//!    use autocore_std::{ControlProgram, RTrig};
38//!
39//!    // GlobalMemory is generated from your project.json
40//!    mod gm;
41//!    use gm::GlobalMemory;
42//!
43//!    pub struct MyProgram {
44//!        start_button: RTrig,
45//!    }
46//!
47//!    impl MyProgram {
48//!        pub fn new() -> Self {
49//!            Self {
50//!                start_button: RTrig::new(),
51//!            }
52//!        }
53//!    }
54//!
55//!    impl ControlProgram for MyProgram {
56//!        type Memory = GlobalMemory;
57//!
58//!        fn process_tick(&mut self, mem: &mut GlobalMemory, _cycle: u64) {
59//!            // Detect rising edge on start button
60//!            if self.start_button.call(mem.inputs.start_button) {
61//!                mem.outputs.motor_running = true;
62//!                autocore_std::log::info!("Motor started!");
63//!            }
64//!        }
65//!    }
66//!    ```
67//!
68//! 3. Use the [`autocore_main!`] macro for the entry point:
69//!    ```ignore
70//!    autocore_std::autocore_main!(MyProgram, "my_project_shm", "tick");
71//!    ```
72//!
73//! ## Function Blocks (IEC 61131-3 Inspired)
74//!
75//! This library includes standard function blocks commonly used in PLC programming:
76//!
77//! - [`RTrig`] - Rising edge detector (false→true transition)
78//! - [`FTrig`] - Falling edge detector (true→false transition)
79//! - [`Ton`] - Timer On Delay (output after delay)
80//! - [`SimpleTimer`] - Simple one-shot timer (NOT IEC 61131-3, for imperative use)
81//! - [`StateMachine`] - State machine helper with automatic timer management
82//!
83//! ### Example: Edge Detection
84//!
85//! ```
86//! use autocore_std::RTrig;
87//!
88//! let mut trigger = RTrig::new();
89//!
90//! // First call with false - no edge
91//! assert_eq!(trigger.call(false), false);
92//!
93//! // Rising edge detected!
94//! assert_eq!(trigger.call(true), true);
95//!
96//! // Still true, but no edge (already high)
97//! assert_eq!(trigger.call(true), false);
98//!
99//! // Back to false
100//! assert_eq!(trigger.call(false), false);
101//!
102//! // Another rising edge
103//! assert_eq!(trigger.call(true), true);
104//! ```
105//!
106//! ### Example: Timer
107//!
108//! ```
109//! use autocore_std::Ton;
110//! use std::time::Duration;
111//!
112//! let mut timer = Ton::new();
113//! let delay = Duration::from_millis(100);
114//!
115//! // Timer not enabled - output is false
116//! assert_eq!(timer.call(false, delay), false);
117//!
118//! // Enable timer - starts counting
119//! assert_eq!(timer.call(true, delay), false);
120//!
121//! // Still counting...
122//! std::thread::sleep(Duration::from_millis(50));
123//! assert_eq!(timer.call(true, delay), false);
124//! assert!(timer.et < delay); // Elapsed time < preset
125//!
126//! // After delay elapsed
127//! std::thread::sleep(Duration::from_millis(60));
128//! assert_eq!(timer.call(true, delay), true); // Output is now true!
129//! ```
130//!
131//! ## Logging
132//!
133//! Control programs can send log messages to the autocore-server for display in the
134//! web console. Logging is handled automatically when using [`ControlRunner`].
135//!
136//! ```ignore
137//! use autocore_std::log;
138//!
139//! log::trace!("Detailed trace message");
140//! log::debug!("Debug information");
141//! log::info!("Normal operation message");
142//! log::warn!("Warning condition detected");
143//! log::error!("Error occurred!");
144//! ```
145//!
146//! See the [`logger`] module for advanced configuration.
147//!
148//! ## Memory Synchronization
149//!
150//! The [`ControlRunner`] handles all shared memory synchronization automatically:
151//!
152//! 1. **Wait for tick** - Blocks until the server signals a new cycle
153//! 2. **Read inputs** - Copies shared memory to local buffer (atomic snapshot)
154//! 3. **Execute logic** - Your `process_tick` runs on the local buffer
155//! 4. **Write outputs** - Copies local buffer back to shared memory
156//!
157//! This ensures your control logic always sees a consistent view of the data,
158//! even when other processes are modifying shared memory.
159
160#![warn(missing_docs)]
161#![warn(rustdoc::missing_crate_level_docs)]
162#![doc(html_root_url = "https://docs.rs/autocore-std/3.3.0")]
163
164use anyhow::{anyhow, Result};
165use futures_util::{SinkExt, StreamExt};
166use log::LevelFilter;
167use mechutil::ipc::{CommandMessage, MessageType};
168use raw_sync::events::{Event, EventInit, EventState};
169use raw_sync::Timeout;
170use shared_memory::ShmemConf;
171use std::collections::HashMap;
172use std::sync::atomic::{fence, Ordering, AtomicBool};
173use std::sync::Arc;
174use std::time::{Duration, Instant};
175use tokio_tungstenite::{connect_async, tungstenite::Message};
176
177/// UDP logger for sending log messages to autocore-server.
178///
179/// This module provides a non-blocking logger implementation that sends log messages
180/// via UDP to the autocore-server. Messages are batched and sent asynchronously to
181/// avoid impacting the control loop timing.
182///
183/// # Example
184///
185/// ```ignore
186/// use autocore_std::logger;
187/// use log::LevelFilter;
188///
189/// // Initialize the logger (done automatically by ControlRunner)
190/// logger::init_udp_logger("127.0.0.1", 39101, LevelFilter::Info, "control")?;
191///
192/// // Now you can use the log macros
193/// log::info!("System initialized");
194/// ```
195pub mod logger;
196
197// Re-export log crate for convenience - control programs can use autocore_std::log::info!() etc.
198pub use log;
199
200// ============================================================================
201// Standard Library Function Blocks (IEC 61131-3 Inspired)
202// ============================================================================
203
204/// Rising Edge Trigger (R_TRIG)
205///
206/// Detects a rising edge (false → true transition) on the input signal.
207/// The output `q` is `true` for exactly one cycle when the input `clk`
208/// transitions from `false` to `true`.
209///
210/// This is equivalent to the IEC 61131-3 R_TRIG function block.
211///
212/// # Example
213///
214/// ```
215/// use autocore_std::RTrig;
216///
217/// let mut trigger = RTrig::new();
218///
219/// // No edge yet
220/// assert_eq!(trigger.call(false), false);
221///
222/// // Rising edge detected!
223/// assert_eq!(trigger.call(true), true);
224///
225/// // Signal still high, but edge already passed
226/// assert_eq!(trigger.call(true), false);
227/// assert_eq!(trigger.call(true), false);
228///
229/// // Signal goes low
230/// assert_eq!(trigger.call(false), false);
231///
232/// // Another rising edge
233/// assert_eq!(trigger.call(true), true);
234/// ```
235///
236/// # Timing Diagram
237///
238/// ```text
239/// clk: _____|‾‾‾‾‾‾‾‾‾|_____|‾‾‾‾‾
240///   q: _____|‾|_____________|‾|____
241/// ```
242///
243/// # Use Cases
244///
245/// - Detecting button presses (trigger on press, not hold)
246/// - Counting events (increment counter on each rising edge)
247/// - State machine transitions
248#[derive(Debug, Clone)]
249pub struct RTrig {
250    /// Current input value
251    pub clk: bool,
252    /// Output: true for one cycle on rising edge
253    pub q: bool,
254    /// Internal memory of previous input state
255    m: bool,
256}
257
258impl RTrig {
259    /// Creates a new rising edge trigger with all values initialized to `false`.
260    ///
261    /// # Example
262    ///
263    /// ```
264    /// use autocore_std::RTrig;
265    ///
266    /// let trigger = RTrig::new();
267    /// assert_eq!(trigger.q, false);
268    /// ```
269    pub fn new() -> Self {
270        Self {
271            clk: false,
272            q: false,
273            m: false,
274        }
275    }
276
277    /// Executes the rising edge detection logic.
278    ///
279    /// Call this method once per control cycle with the current input value.
280    /// Returns `true` for exactly one cycle when a rising edge is detected.
281    ///
282    /// # Arguments
283    ///
284    /// * `clk` - The current state of the input signal
285    ///
286    /// # Returns
287    ///
288    /// `true` if a rising edge (false → true transition) was detected, `false` otherwise.
289    ///
290    /// # Example
291    ///
292    /// ```
293    /// use autocore_std::RTrig;
294    ///
295    /// let mut trigger = RTrig::new();
296    ///
297    /// let button_pressed = true;
298    /// if trigger.call(button_pressed) {
299    ///     println!("Button was just pressed!");
300    /// }
301    /// ```
302    pub fn call(&mut self, clk: bool) -> bool {
303        self.clk = clk;
304        self.q = self.clk && !self.m;
305        self.m = self.clk;
306        self.q
307    }
308}
309
310impl Default for RTrig {
311    fn default() -> Self {
312        Self::new()
313    }
314}
315
316
317/// Falling Edge Trigger (F_TRIG)
318///
319/// Detects a falling edge (true → false transition) on the input signal.
320/// The output `q` is `true` for exactly one cycle when the input `clk`
321/// transitions from `true` to `false`.
322///
323/// This is equivalent to the IEC 61131-3 F_TRIG function block.
324///
325/// # Example
326///
327/// ```
328/// use autocore_std::FTrig;
329///
330/// let mut trigger = FTrig::new();
331///
332/// // Signal starts low
333/// assert_eq!(trigger.call(false), false);
334///
335/// // Signal goes high
336/// assert_eq!(trigger.call(true), false);
337///
338/// // Falling edge detected!
339/// assert_eq!(trigger.call(false), true);
340///
341/// // Signal still low, edge already passed
342/// assert_eq!(trigger.call(false), false);
343/// ```
344///
345/// # Timing Diagram
346///
347/// ```text
348/// clk: _____|‾‾‾‾‾‾‾‾‾|_____|‾‾‾‾‾
349///   q: _______________|‾|________
350/// ```
351///
352/// # Use Cases
353///
354/// - Detecting button releases
355/// - Detecting signal loss
356/// - Triggering actions when a condition ends
357#[derive(Debug, Clone)]
358pub struct FTrig {
359    /// Current input value
360    pub clk: bool,
361    /// Output: true for one cycle on falling edge
362    pub q: bool,
363    /// Internal memory of previous input state
364    m: bool,
365}
366
367impl FTrig {
368    /// Creates a new falling edge trigger with all values initialized to `false`.
369    ///
370    /// # Example
371    ///
372    /// ```
373    /// use autocore_std::FTrig;
374    ///
375    /// let trigger = FTrig::new();
376    /// assert_eq!(trigger.q, false);
377    /// ```
378    pub fn new() -> Self {
379        Self {
380            clk: false,
381            q: false,
382            m: false,
383        }
384    }
385
386    /// Executes the falling edge detection logic.
387    ///
388    /// Call this method once per control cycle with the current input value.
389    /// Returns `true` for exactly one cycle when a falling edge is detected.
390    ///
391    /// # Arguments
392    ///
393    /// * `clk` - The current state of the input signal
394    ///
395    /// # Returns
396    ///
397    /// `true` if a falling edge (true → false transition) was detected, `false` otherwise.
398    ///
399    /// # Example
400    ///
401    /// ```
402    /// use autocore_std::FTrig;
403    ///
404    /// let mut trigger = FTrig::new();
405    ///
406    /// // Simulate button release
407    /// trigger.call(true);  // Button held
408    /// if trigger.call(false) {  // Button released
409    ///     println!("Button was just released!");
410    /// }
411    /// ```
412    pub fn call(&mut self, clk: bool) -> bool {
413        self.clk = clk;
414        self.q = !self.clk && self.m;
415        self.m = self.clk;
416        self.q
417    }
418}
419
420impl Default for FTrig {
421    fn default() -> Self {
422        Self::new()
423    }
424}
425
426
427/// Timer On Delay (TON)
428///
429/// A timer that delays turning on the output. The output `q` becomes `true`
430/// after the enable input `en` has been continuously `true` for the preset
431/// time `pt`. The elapsed time is available in `et`.
432///
433/// This is equivalent to the IEC 61131-3 TON function block.
434///
435/// # Behavior
436///
437/// - When `en` becomes `true`, the timer starts counting from zero
438/// - While counting, `et` shows the elapsed time and `q` is `false`
439/// - When `et` reaches `pt`, `q` becomes `true` and `et` is clamped to `pt`
440/// - When `en` becomes `false`, the timer resets: `q` = `false`, `et` = 0
441///
442/// # Example
443///
444/// ```
445/// use autocore_std::Ton;
446/// use std::time::Duration;
447///
448/// let mut timer = Ton::new();
449/// let delay = Duration::from_secs(5);
450///
451/// // Timer disabled - output is false
452/// assert_eq!(timer.call(false, delay), false);
453/// assert_eq!(timer.et, Duration::ZERO);
454///
455/// // Enable timer - starts counting
456/// timer.call(true, delay);
457/// assert_eq!(timer.q, false);  // Not done yet
458/// // timer.et is now counting up...
459///
460/// // Disable resets the timer
461/// timer.call(false, delay);
462/// assert_eq!(timer.et, Duration::ZERO);
463/// ```
464///
465/// # Timing Diagram
466///
467/// ```text
468///  en: _____|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|_____
469///   q: _____________|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|_____
470///  et: 0---|++++++++|PT----------------|0----
471///          ^        ^                  ^
472///          |        |                  |
473///      en rises   et=pt             en falls
474/// ```
475///
476/// # Use Cases
477///
478/// - Motor start delay (allow contactors to engage)
479/// - Debouncing switches (ignore brief transitions)
480/// - Timeout detection (alarm if condition persists too long)
481#[derive(Debug, Clone)]
482pub struct Ton {
483    /// Input: Enable the timer (true = counting, false = reset)
484    pub en: bool,
485    /// Input: Preset time (duration before output activates)
486    pub pt: Duration,
487    /// Output: Timer done (true when elapsed time >= preset time)
488    pub q: bool,
489    /// Output: Elapsed time since timer was enabled
490    pub et: Duration,
491
492    start_time: Option<Instant>,
493    active: bool,
494}
495
496impl Ton {
497    /// Creates a new timer with default values.
498    ///
499    /// The timer starts in the disabled state with zero elapsed time.
500    ///
501    /// # Example
502    ///
503    /// ```
504    /// use autocore_std::Ton;
505    ///
506    /// let timer = Ton::new();
507    /// assert_eq!(timer.q, false);
508    /// assert_eq!(timer.et, std::time::Duration::ZERO);
509    /// ```
510    pub fn new() -> Self {
511        Self {
512            en: false,
513            pt: Duration::default(),
514            q: false,
515            et: Duration::default(),
516            start_time: None,
517            active: false,
518        }
519    }
520
521    /// Executes the timer logic.
522    ///
523    /// Call this method once per control cycle. The timer counts real elapsed
524    /// time (not cycles), so the output timing is independent of scan rate.
525    ///
526    /// # Arguments
527    ///
528    /// * `en` - Enable input: `true` to run timer, `false` to reset
529    /// * `pt` - Preset time: duration before output activates
530    ///
531    /// # Returns
532    ///
533    /// The current state of the output `q` (true if timer has elapsed).
534    ///
535    /// # Example
536    ///
537    /// ```
538    /// use autocore_std::Ton;
539    /// use std::time::Duration;
540    ///
541    /// let mut timer = Ton::new();
542    ///
543    /// // Use in a control loop
544    /// let motor_request = true;
545    /// let start_delay = Duration::from_millis(500);
546    ///
547    /// let motor_enabled = timer.call(motor_request, start_delay);
548    /// // motor_enabled will be true after 500ms of motor_request being true
549    /// ```
550    pub fn call(&mut self, en: bool, pt: Duration) -> bool {
551        self.en = en;
552        self.pt = pt;
553
554        if !self.en {
555            // Reset
556            self.q = false;
557            self.et = Duration::ZERO;
558            self.start_time = None;
559            self.active = false;
560        } else {
561            if !self.active {
562                // Rising edge of EN - start timing
563                self.start_time = Some(Instant::now());
564                self.active = true;
565                self.et = Duration::ZERO;
566                self.q = false;
567            } else {
568                // Timer running
569                if let Some(start) = self.start_time {
570                    self.et = start.elapsed();
571                    if self.et >= self.pt {
572                        self.et = self.pt; // Clamp ET to PT
573                        self.q = true;
574                    }
575                }
576            }
577        }
578        self.q
579    }
580
581    /// Resets the timer to its initial state.
582    ///
583    /// This is equivalent to calling `call(false, ...)`.
584    ///
585    /// # Example
586    ///
587    /// ```
588    /// use autocore_std::Ton;
589    /// use std::time::Duration;
590    ///
591    /// let mut timer = Ton::new();
592    /// timer.call(true, Duration::from_secs(1));
593    /// // ... timer is running ...
594    ///
595    /// timer.reset();
596    /// assert_eq!(timer.q, false);
597    /// assert_eq!(timer.et, Duration::ZERO);
598    /// ```
599    pub fn reset(&mut self) {
600        self.q = false;
601        self.et = Duration::ZERO;
602        self.start_time = None;
603        self.active = false;
604    }
605}
606
607impl Default for Ton {
608    fn default() -> Self {
609        Self::new()
610    }
611}
612
613
614/// Simple One-Shot Timer
615///
616/// A simple timer for one-shot timing operations. Unlike [`Ton`], this timer
617/// does NOT follow the IEC 61131-3 standard and is designed for imperative
618/// "start then check" patterns rather than cyclic function block calls.
619///
620/// **Note:** For standard PLC timer patterns (delay while condition is true),
621/// use [`Ton`] instead. `SimpleTimer` is intended for one-shot use cases
622/// like "do X, wait, then do Y".
623///
624/// # Safety
625///
626/// This timer uses [`Instant`] (monotonic clock) internally, making it immune
627/// to system clock adjustments (NTP sync, manual changes, DST). This is
628/// critical for reliable timing in industrial control applications.
629///
630/// # Example
631///
632/// ```
633/// use autocore_std::SimpleTimer;
634/// use std::time::Duration;
635///
636/// let mut timer = SimpleTimer::new(Duration::from_millis(100));
637///
638/// // Timer hasn't started yet
639/// assert_eq!(timer.is_done(), false);
640/// assert_eq!(timer.elapsed(), Duration::ZERO);
641///
642/// // Start the timer
643/// timer.start();
644///
645/// // Check if done (will be false initially)
646/// assert_eq!(timer.is_done(), false);
647///
648/// // After waiting...
649/// std::thread::sleep(Duration::from_millis(110));
650/// assert_eq!(timer.is_done(), true);
651///
652/// // Reset for reuse
653/// timer.reset();
654/// assert_eq!(timer.is_done(), false);
655/// ```
656///
657/// # Use Cases
658///
659/// - One-shot delays ("wait 500ms then continue")
660/// - Tracking time since an event occurred
661/// - Non-cyclic async contexts
662/// - Simple timeout checks
663///
664/// # Comparison with Ton
665///
666/// | Aspect | `Ton` | `SimpleTimer` |
667/// |--------|-------|---------------|
668/// | IEC 61131-3 | Yes | No |
669/// | Pattern | Cyclic `call()` | Imperative `start()`/`is_done()` |
670/// | Auto-reset on disable | Yes | No (explicit `reset()`) |
671/// | Best for | PLC-style control | One-shot operations |
672#[derive(Debug, Clone)]
673pub struct SimpleTimer {
674    start_time: Option<Instant>,
675    preset: Duration,
676}
677
678impl SimpleTimer {
679    /// Creates a new simple timer with the specified preset duration.
680    ///
681    /// The timer starts in the stopped state and must be explicitly started
682    /// with [`start()`](Self::start).
683    ///
684    /// # Arguments
685    ///
686    /// * `preset` - The duration after which [`is_done()`](Self::is_done) returns `true`
687    ///
688    /// # Example
689    ///
690    /// ```
691    /// use autocore_std::SimpleTimer;
692    /// use std::time::Duration;
693    ///
694    /// let timer = SimpleTimer::new(Duration::from_secs(5));
695    /// assert_eq!(timer.is_done(), false);
696    /// ```
697    pub fn new(preset: Duration) -> Self {
698        Self {
699            start_time: None,
700            preset,
701        }
702    }
703
704    /// Starts (or restarts) the timer.
705    ///
706    /// Records the current time as the start time. If the timer was already
707    /// running, this restarts it from zero.
708    ///
709    /// # Example
710    ///
711    /// ```
712    /// use autocore_std::SimpleTimer;
713    /// use std::time::Duration;
714    ///
715    /// let mut timer = SimpleTimer::new(Duration::from_millis(100));
716    /// timer.start();
717    /// // Timer is now counting...
718    /// ```
719    pub fn start(&mut self) {
720        self.start_time = Some(Instant::now());
721    }
722
723    /// Checks if the preset time has elapsed since the timer was started.
724    ///
725    /// Returns `false` if the timer hasn't been started yet.
726    ///
727    /// # Returns
728    ///
729    /// `true` if the timer was started and the preset duration has elapsed,
730    /// `false` otherwise.
731    ///
732    /// # Example
733    ///
734    /// ```
735    /// use autocore_std::SimpleTimer;
736    /// use std::time::Duration;
737    ///
738    /// let mut timer = SimpleTimer::new(Duration::from_millis(50));
739    ///
740    /// // Not started yet
741    /// assert_eq!(timer.is_done(), false);
742    ///
743    /// timer.start();
744    /// std::thread::sleep(Duration::from_millis(60));
745    /// assert_eq!(timer.is_done(), true);
746    /// ```
747    pub fn is_done(&self) -> bool {
748        self.start_time
749            .map(|t| t.elapsed() >= self.preset)
750            .unwrap_or(false)
751    }
752
753    /// Returns the elapsed time since the timer was started.
754    ///
755    /// Returns [`Duration::ZERO`] if the timer hasn't been started yet.
756    ///
757    /// # Returns
758    ///
759    /// The elapsed time since [`start()`](Self::start) was called, or
760    /// `Duration::ZERO` if not started.
761    ///
762    /// # Example
763    ///
764    /// ```
765    /// use autocore_std::SimpleTimer;
766    /// use std::time::Duration;
767    ///
768    /// let mut timer = SimpleTimer::new(Duration::from_secs(10));
769    ///
770    /// // Not started
771    /// assert_eq!(timer.elapsed(), Duration::ZERO);
772    ///
773    /// timer.start();
774    /// std::thread::sleep(Duration::from_millis(50));
775    /// assert!(timer.elapsed() >= Duration::from_millis(50));
776    /// ```
777    pub fn elapsed(&self) -> Duration {
778        self.start_time
779            .map(|t| t.elapsed())
780            .unwrap_or(Duration::ZERO)
781    }
782
783    /// Resets the timer to its initial (stopped) state.
784    ///
785    /// After calling this, [`is_done()`](Self::is_done) will return `false`
786    /// and [`elapsed()`](Self::elapsed) will return zero until
787    /// [`start()`](Self::start) is called again.
788    ///
789    /// # Example
790    ///
791    /// ```
792    /// use autocore_std::SimpleTimer;
793    /// use std::time::Duration;
794    ///
795    /// let mut timer = SimpleTimer::new(Duration::from_millis(50));
796    /// timer.start();
797    /// std::thread::sleep(Duration::from_millis(60));
798    /// assert_eq!(timer.is_done(), true);
799    ///
800    /// timer.reset();
801    /// assert_eq!(timer.is_done(), false);
802    /// assert_eq!(timer.elapsed(), Duration::ZERO);
803    /// ```
804    pub fn reset(&mut self) {
805        self.start_time = None;
806    }
807
808    /// Returns the preset duration for this timer.
809    ///
810    /// # Example
811    ///
812    /// ```
813    /// use autocore_std::SimpleTimer;
814    /// use std::time::Duration;
815    ///
816    /// let timer = SimpleTimer::new(Duration::from_secs(5));
817    /// assert_eq!(timer.preset(), Duration::from_secs(5));
818    /// ```
819    pub fn preset(&self) -> Duration {
820        self.preset
821    }
822
823    /// Sets a new preset duration.
824    ///
825    /// This does not reset or restart the timer. If the timer is running,
826    /// the new preset takes effect immediately for [`is_done()`](Self::is_done)
827    /// checks.
828    ///
829    /// # Arguments
830    ///
831    /// * `preset` - The new duration after which `is_done()` returns `true`
832    ///
833    /// # Example
834    ///
835    /// ```
836    /// use autocore_std::SimpleTimer;
837    /// use std::time::Duration;
838    ///
839    /// let mut timer = SimpleTimer::new(Duration::from_secs(5));
840    /// timer.set_preset(Duration::from_secs(10));
841    /// assert_eq!(timer.preset(), Duration::from_secs(10));
842    /// ```
843    pub fn set_preset(&mut self, preset: Duration) {
844        self.preset = preset;
845    }
846
847    /// Returns whether the timer is currently running (has been started but not reset).
848    ///
849    /// # Example
850    ///
851    /// ```
852    /// use autocore_std::SimpleTimer;
853    /// use std::time::Duration;
854    ///
855    /// let mut timer = SimpleTimer::new(Duration::from_secs(5));
856    /// assert_eq!(timer.is_running(), false);
857    ///
858    /// timer.start();
859    /// assert_eq!(timer.is_running(), true);
860    ///
861    /// timer.reset();
862    /// assert_eq!(timer.is_running(), false);
863    /// ```
864    pub fn is_running(&self) -> bool {
865        self.start_time.is_some()
866    }
867}
868
869impl Default for SimpleTimer {
870    /// Creates a timer with a preset of zero (will be immediately done when started).
871    fn default() -> Self {
872        Self::new(Duration::ZERO)
873    }
874}
875
876
877/// State Machine Helper (FB_StateMachine)
878///
879/// A state machine helper with automatic timer management and error tracking.
880/// Provides two timers that automatically reset when the state index changes:
881///
882/// - **Timer** (`timer_done()`) - General purpose timer for delays and debouncing
883/// - **Timeout** (`timed_out()`) - For detecting stuck states
884///
885/// This is equivalent to the IEC 61131-3 FB_StateMachine function block.
886///
887/// # Automatic Timer Reset
888///
889/// Both timers automatically reset when `index` changes. This eliminates a
890/// common source of bugs in state machines where timers are not properly reset.
891///
892/// The pattern is:
893/// 1. Set `timer_preset` (and optionally `timeout_preset`) in state N
894/// 2. Change `index` to state N+1 (timers reset and start counting)
895/// 3. In state N+1, check `timer_done()` or `timed_out()`
896///
897/// # Example
898///
899/// ```
900/// use autocore_std::StateMachine;
901/// use std::time::Duration;
902///
903/// let mut state = StateMachine::new();
904///
905/// // Simulate a control loop
906/// loop {
907///     match state.index {
908///         0 => { // Reset
909///             state.clear_error();
910///             state.index = 10;
911///         }
912///         10 => { // Idle - wait for start signal
913///             // For demo, just proceed
914///             state.timer_preset = Duration::from_millis(100);
915///             state.index = 20;
916///         }
917///         20 => { // Debounce
918///             if state.timer_done() {
919///                 state.timeout_preset = Duration::from_secs(10);
920///                 state.index = 30;
921///             }
922///         }
923///         30 => { // Wait for operation (simulated)
924///             // In real code: check operation_complete
925///             // For demo, check timeout
926///             if state.timed_out() {
927///                 state.set_error(30, "Operation timeout");
928///                 state.index = 0;
929///             }
930///             // Exit demo loop
931///             break;
932///         }
933///         _ => { state.index = 0; }
934///     }
935///
936///     state.call(); // Call at end of each scan cycle
937///     # break; // Exit for doctest
938/// }
939/// ```
940///
941/// # Timer Presets Persist
942///
943/// Timer presets persist until you change them. This allows setting a preset
944/// once and using it across multiple states:
945///
946/// ```ignore
947/// 100 => {
948///     state.timer_preset = Duration::from_millis(300);
949///     state.index = 110;
950/// }
951/// 110 => {
952///     // Uses 300ms preset set in state 100
953///     if some_condition && state.timer_done() {
954///         state.index = 120;
955///     }
956/// }
957/// 120 => {
958///     // Still uses 300ms preset (timer reset on state change)
959///     if state.timer_done() {
960///         state.index = 10;
961///     }
962/// }
963/// ```
964///
965/// # Error Handling Pattern
966///
967/// ```ignore
968/// 200 => {
969///     state.timeout_preset = Duration::from_secs(7);
970///     start_operation();
971///     state.index = 210;
972/// }
973/// 210 => {
974///     if operation_complete {
975///         state.index = 1000; // Success
976///     } else if state.timed_out() {
977///         state.set_error(210, "Operation timed out");
978///         state.index = 5000; // Error handler
979///     }
980/// }
981/// 5000 => {
982///     // Error recovery
983///     state.index = 0;
984/// }
985/// ```
986#[derive(Debug, Clone)]
987pub struct StateMachine {
988    /// Current state index.
989    pub index: i32,
990
991    /// Timer preset. `timer_done()` returns true when time in current state >= this value.
992    /// Defaults to `Duration::MAX` (timer never triggers unless you set a preset).
993    pub timer_preset: Duration,
994
995    /// Timeout preset. `timed_out()` returns true when time in current state >= this value.
996    /// Defaults to `Duration::MAX` (timeout never triggers unless you set a preset).
997    pub timeout_preset: Duration,
998
999    /// Error code. A value of 0 indicates no error.
1000    /// When non-zero, `is_error()` returns true.
1001    pub error_code: i32,
1002
1003    /// Status message for UI display. Content does not indicate an error.
1004    pub message: String,
1005
1006    /// Error message for UI display. Should only have content when `error_code != 0`.
1007    pub error_message: String,
1008
1009    // Internal state
1010    last_index: Option<i32>,
1011    state_entered_at: Option<Instant>,
1012}
1013
1014impl StateMachine {
1015    /// Creates a new state machine starting at state 0.
1016    ///
1017    /// Timer presets default to `Duration::MAX`, meaning timers won't trigger
1018    /// until you explicitly set a preset.
1019    ///
1020    /// # Example
1021    ///
1022    /// ```
1023    /// use autocore_std::StateMachine;
1024    ///
1025    /// let state = StateMachine::new();
1026    /// assert_eq!(state.index, 0);
1027    /// assert_eq!(state.error_code, 0);
1028    /// assert!(!state.is_error());
1029    /// ```
1030    pub fn new() -> Self {
1031        Self {
1032            index: 0,
1033            timer_preset: Duration::MAX,
1034            timeout_preset: Duration::MAX,
1035            error_code: 0,
1036            message: String::new(),
1037            error_message: String::new(),
1038            last_index: None,
1039            state_entered_at: None,
1040        }
1041    }
1042
1043    /// Call once per scan cycle at the END of your state machine logic.
1044    ///
1045    /// This method:
1046    /// - Detects state changes (when `index` differs from the previous call)
1047    /// - Resets internal timers on state change
1048    /// - Updates internal tracking for `elapsed()`, `timer_done()`, and `timed_out()`
1049    ///
1050    /// # Example
1051    ///
1052    /// ```
1053    /// use autocore_std::StateMachine;
1054    ///
1055    /// let mut state = StateMachine::new();
1056    ///
1057    /// // Your state machine logic here...
1058    /// match state.index {
1059    ///     0 => { state.index = 10; }
1060    ///     _ => {}
1061    /// }
1062    ///
1063    /// state.call(); // Always call at the end
1064    /// ```
1065    pub fn call(&mut self) {
1066        if self.last_index != Some(self.index) {
1067            self.state_entered_at = Some(Instant::now());
1068        }
1069        self.last_index = Some(self.index);
1070    }
1071
1072    /// Returns true when time in current state >= `timer_preset`.
1073    ///
1074    /// The timer automatically resets when the state index changes.
1075    ///
1076    /// # Example
1077    ///
1078    /// ```
1079    /// use autocore_std::StateMachine;
1080    /// use std::time::Duration;
1081    ///
1082    /// let mut state = StateMachine::new();
1083    /// state.timer_preset = Duration::from_millis(50);
1084    /// state.call(); // Start tracking
1085    ///
1086    /// assert!(!state.timer_done()); // Not enough time elapsed
1087    ///
1088    /// std::thread::sleep(Duration::from_millis(60));
1089    /// assert!(state.timer_done()); // Now it's done
1090    /// ```
1091    pub fn timer_done(&self) -> bool {
1092        self.elapsed() >= self.timer_preset
1093    }
1094
1095    /// Returns true when time in current state >= `timeout_preset`.
1096    ///
1097    /// Use this for detecting stuck states. The timeout automatically
1098    /// resets when the state index changes.
1099    ///
1100    /// # Example
1101    ///
1102    /// ```
1103    /// use autocore_std::StateMachine;
1104    /// use std::time::Duration;
1105    ///
1106    /// let mut state = StateMachine::new();
1107    /// state.timeout_preset = Duration::from_millis(50);
1108    /// state.call();
1109    ///
1110    /// assert!(!state.timed_out());
1111    ///
1112    /// std::thread::sleep(Duration::from_millis(60));
1113    /// assert!(state.timed_out());
1114    /// ```
1115    pub fn timed_out(&self) -> bool {
1116        self.elapsed() >= self.timeout_preset
1117    }
1118
1119    /// Returns elapsed time since entering the current state.
1120    ///
1121    /// Returns `Duration::ZERO` if `call()` has never been called.
1122    ///
1123    /// # Example
1124    ///
1125    /// ```
1126    /// use autocore_std::StateMachine;
1127    /// use std::time::Duration;
1128    ///
1129    /// let mut state = StateMachine::new();
1130    /// state.call();
1131    ///
1132    /// std::thread::sleep(Duration::from_millis(10));
1133    /// assert!(state.elapsed() >= Duration::from_millis(10));
1134    /// ```
1135    pub fn elapsed(&self) -> Duration {
1136        self.state_entered_at
1137            .map(|t| t.elapsed())
1138            .unwrap_or(Duration::ZERO)
1139    }
1140
1141    /// Returns true if `error_code != 0`.
1142    ///
1143    /// # Example
1144    ///
1145    /// ```
1146    /// use autocore_std::StateMachine;
1147    ///
1148    /// let mut state = StateMachine::new();
1149    /// assert!(!state.is_error());
1150    ///
1151    /// state.error_code = 100;
1152    /// assert!(state.is_error());
1153    /// ```
1154    pub fn is_error(&self) -> bool {
1155        self.error_code != 0
1156    }
1157
1158    /// Set error state with code and message.
1159    ///
1160    /// This is a convenience method equivalent to setting `error_code`
1161    /// and `error_message` directly.
1162    ///
1163    /// # Example
1164    ///
1165    /// ```
1166    /// use autocore_std::StateMachine;
1167    ///
1168    /// let mut state = StateMachine::new();
1169    /// state.set_error(110, "Failed to home X axis");
1170    ///
1171    /// assert_eq!(state.error_code, 110);
1172    /// assert_eq!(state.error_message, "Failed to home X axis");
1173    /// assert!(state.is_error());
1174    /// ```
1175    pub fn set_error(&mut self, code: i32, message: impl Into<String>) {
1176        self.error_code = code;
1177        self.error_message = message.into();
1178    }
1179
1180    /// Clear error state.
1181    ///
1182    /// Sets `error_code` to 0 and clears `error_message`.
1183    ///
1184    /// # Example
1185    ///
1186    /// ```
1187    /// use autocore_std::StateMachine;
1188    ///
1189    /// let mut state = StateMachine::new();
1190    /// state.set_error(100, "Some error");
1191    /// assert!(state.is_error());
1192    ///
1193    /// state.clear_error();
1194    /// assert!(!state.is_error());
1195    /// assert_eq!(state.error_code, 0);
1196    /// assert!(state.error_message.is_empty());
1197    /// ```
1198    pub fn clear_error(&mut self) {
1199        self.error_code = 0;
1200        self.error_message.clear();
1201    }
1202
1203    /// Returns the current state index.
1204    ///
1205    /// This is equivalent to reading `state.index` directly but provided
1206    /// for API consistency.
1207    pub fn state(&self) -> i32 {
1208        self.index
1209    }
1210}
1211
1212impl Default for StateMachine {
1213    fn default() -> Self {
1214        Self::new()
1215    }
1216}
1217
1218
1219// ============================================================================
1220// Core Framework
1221// ============================================================================
1222
1223/// Marker trait for generated GlobalMemory structs.
1224///
1225/// This trait is implemented by the auto-generated `GlobalMemory` struct
1226/// that represents the shared memory layout. It serves as a marker for
1227/// type safety in the control framework.
1228///
1229/// You don't need to implement this trait yourself - it's automatically
1230/// implemented by the code generator.
1231pub trait AutoCoreMemory {}
1232
1233/// Trait for detecting changes in memory structures.
1234pub trait ChangeTracker {
1235    /// Compare self with a previous state and return a list of changed fields.
1236    /// Returns a vector of (field_name, new_value).
1237    fn get_changes(&self, prev: &Self) -> Vec<(&'static str, serde_json::Value)>;
1238}
1239
1240/// The trait that defines a control program's logic.
1241///
1242/// Implement this trait to create your control program. The associated `Memory`
1243/// type should be the generated `GlobalMemory` struct from your project.
1244///
1245/// # Memory Type Requirements
1246///
1247/// The `Memory` type must implement `Copy` to allow efficient synchronization
1248/// between shared memory and local buffers. This is automatically satisfied
1249/// by the generated `GlobalMemory` struct.
1250///
1251/// # Lifecycle
1252///
1253/// 1. `initialize` is called once at startup
1254/// 2. `process_tick` is called repeatedly in the control loop
1255///
1256/// # Example
1257///
1258/// ```ignore
1259/// use autocore_std::ControlProgram;
1260///
1261/// mod gm;
1262/// use gm::GlobalMemory;
1263///
1264/// pub struct MyController {
1265///     cycle_counter: u64,
1266/// }
1267///
1268/// impl MyController {
1269///     pub fn new() -> Self {
1270///         Self { cycle_counter: 0 }
1271///     }
1272/// }
1273///
1274/// impl ControlProgram for MyController {
1275///     type Memory = GlobalMemory;
1276///
1277///     fn initialize(&mut self, mem: &mut GlobalMemory) {
1278///         // Set initial output states
1279///         mem.outputs.ready = true;
1280///         log::info!("Controller initialized");
1281///     }
1282///
1283///     fn process_tick(&mut self, mem: &mut GlobalMemory, cycle: u64) {
1284///         self.cycle_counter = cycle;
1285///
1286///         // Your control logic here
1287///         if mem.inputs.start && !mem.inputs.estop {
1288///             mem.outputs.running = true;
1289///         }
1290///     }
1291/// }
1292/// ```
1293pub trait ControlProgram {
1294    /// The shared memory structure type (usually the generated `GlobalMemory`).
1295    ///
1296    /// Must implement `Copy` to allow efficient memory synchronization.
1297    type Memory: Copy + ChangeTracker;
1298
1299    /// Called once when the control program starts.
1300    ///
1301    /// Use this to initialize output states, reset counters, or perform
1302    /// any one-time setup. The default implementation does nothing.
1303    ///
1304    /// # Arguments
1305    ///
1306    /// * `mem` - Mutable reference to the shared memory. Changes are written
1307    ///           back to shared memory after this method returns.
1308    fn initialize(&mut self, _mem: &mut Self::Memory) {}
1309
1310    /// The main control loop - called once per scan cycle.
1311    ///
1312    /// This is where your control logic lives. Read inputs from `mem`,
1313    /// perform calculations, and write outputs back to `mem`.
1314    ///
1315    /// # Arguments
1316    ///
1317    /// * `mem` - Mutable reference to a local copy of the shared memory.
1318    ///           Changes made here are written back to shared memory after
1319    ///           this method returns.
1320    /// * `cycle` - The current cycle number (increments each tick, starting at 1).
1321    ///
1322    /// # Timing
1323    ///
1324    /// This method should complete within the scan cycle time. Long-running
1325    /// operations will cause cycle overruns.
1326    fn process_tick(&mut self, mem: &mut Self::Memory, cycle: u64);
1327}
1328
1329/// Configuration for the [`ControlRunner`].
1330///
1331/// Specifies connection parameters, shared memory names, and logging settings.
1332/// Use [`Default::default()`] for typical configurations.
1333///
1334/// # Example
1335///
1336/// ```
1337/// use autocore_std::RunnerConfig;
1338/// use log::LevelFilter;
1339///
1340/// let config = RunnerConfig {
1341///     server_host: "192.168.1.100".to_string(),
1342///     module_name: "my_controller".to_string(),
1343///     shm_name: "my_project_shm".to_string(),
1344///     tick_signal_name: "tick".to_string(),
1345///     busy_signal_name: Some("busy".to_string()),
1346///     log_level: LevelFilter::Debug,
1347///     ..Default::default()
1348/// };
1349/// ```
1350#[derive(Debug, Clone)]
1351pub struct RunnerConfig {
1352    /// Server host address (default: "127.0.0.1")
1353    pub server_host: String,
1354    /// WebSocket port for commands (default: 11969)
1355    pub ws_port: u16,
1356    /// Module name for identification (default: "control")
1357    pub module_name: String,
1358    /// Shared memory segment name (must match server configuration)
1359    pub shm_name: String,
1360    /// Name of the tick signal in shared memory (triggers each scan cycle)
1361    pub tick_signal_name: String,
1362    /// Optional name of the busy signal (set when cycle completes)
1363    pub busy_signal_name: Option<String>,
1364    /// Minimum log level to send to the server (default: Info)
1365    pub log_level: LevelFilter,
1366    /// UDP port for sending logs to the server (default: 39101)
1367    pub log_udp_port: u16,
1368}
1369
1370/// Default WebSocket port for autocore-server
1371pub const DEFAULT_WS_PORT: u16 = 11969;
1372
1373impl Default for RunnerConfig {
1374    fn default() -> Self {
1375        Self {
1376            server_host: "127.0.0.1".to_string(),
1377            ws_port: DEFAULT_WS_PORT,
1378            module_name: "control".to_string(),
1379            shm_name: "autocore_cyclic".to_string(),
1380            tick_signal_name: "tick".to_string(),
1381            busy_signal_name: None,
1382            log_level: LevelFilter::Info,
1383            log_udp_port: logger::DEFAULT_LOG_UDP_PORT,
1384        }
1385    }
1386}
1387
1388
1389/// The main execution engine for control programs.
1390///
1391/// `ControlRunner` handles all the infrastructure required to run a control program:
1392///
1393/// - Reading memory layout from the server's layout file
1394/// - Opening and mapping shared memory
1395/// - Setting up synchronization signals
1396/// - Running the real-time control loop
1397/// - Sending log messages to the server
1398///
1399/// # Usage
1400///
1401/// ```ignore
1402/// use autocore_std::{ControlRunner, RunnerConfig};
1403///
1404/// let config = RunnerConfig {
1405///     shm_name: "my_project_shm".to_string(),
1406///     tick_signal_name: "tick".to_string(),
1407///     ..Default::default()
1408/// };
1409///
1410/// ControlRunner::new(MyProgram::new())
1411///     .config(config)
1412///     .run()?;  // Blocks forever
1413/// ```
1414///
1415/// # Control Loop
1416///
1417/// The runner executes a synchronous control loop:
1418///
1419/// 1. **Wait** - Blocks until the tick signal is set by the server
1420/// 2. **Read** - Copies shared memory to a local buffer (acquire barrier)
1421/// 3. **Execute** - Calls your `process_tick` method
1422/// 4. **Write** - Copies local buffer back to shared memory (release barrier)
1423/// 5. **Signal** - Sets the busy signal (if configured) to indicate completion
1424///
1425/// This ensures your code always sees a consistent snapshot of the data
1426/// and that your writes are atomically visible to other processes.
1427pub struct ControlRunner<P: ControlProgram> {
1428    config: RunnerConfig,
1429    program: P,
1430}
1431
1432impl<P: ControlProgram> ControlRunner<P> {
1433    /// Creates a new runner for the given control program.
1434    ///
1435    /// Uses default configuration. Call [`.config()`](Self::config) to customize.
1436    ///
1437    /// # Arguments
1438    ///
1439    /// * `program` - Your control program instance
1440    ///
1441    /// # Example
1442    ///
1443    /// ```ignore
1444    /// let runner = ControlRunner::new(MyProgram::new());
1445    /// ```
1446    pub fn new(program: P) -> Self {
1447        Self {
1448            config: RunnerConfig::default(),
1449            program,
1450        }
1451    }
1452
1453    /// Sets the configuration for this runner.
1454    ///
1455    /// # Arguments
1456    ///
1457    /// * `config` - The configuration to use
1458    ///
1459    /// # Example
1460    ///
1461    /// ```ignore
1462    /// ControlRunner::new(MyProgram::new())
1463    ///     .config(RunnerConfig {
1464    ///         shm_name: "custom_shm".to_string(),
1465    ///         ..Default::default()
1466    ///     })
1467    ///     .run()?;
1468    /// ```
1469    pub fn config(mut self, config: RunnerConfig) -> Self {
1470        self.config = config;
1471        self
1472    }
1473
1474    /// Starts the control loop.
1475    ///
1476    /// This method blocks indefinitely, running the control loop until
1477    /// an error occurs or the process is terminated.
1478    ///
1479    /// # Returns
1480    ///
1481    /// Returns `Ok(())` only if the loop exits cleanly (which typically
1482    /// doesn't happen). Returns an error if:
1483    ///
1484    /// - IPC connection fails
1485    /// - Shared memory cannot be opened
1486    /// - Signal offsets cannot be found
1487    /// - A critical error occurs during execution
1488    ///
1489    /// # Example
1490    ///
1491    /// ```ignore
1492    /// fn main() -> anyhow::Result<()> {
1493    ///     ControlRunner::new(MyProgram::new())
1494    ///         .config(config)
1495    ///         .run()
1496    /// }
1497    /// ```
1498    pub fn run(mut self) -> Result<()> {
1499        // Initialize UDP logger FIRST (before any log statements)
1500        if let Err(e) = logger::init_udp_logger(
1501            &self.config.server_host,
1502            self.config.log_udp_port,
1503            self.config.log_level,
1504            "control",
1505        ) {
1506            eprintln!("Warning: Failed to initialize UDP logger: {}", e);
1507            // Continue anyway - logging will just go nowhere
1508        }
1509
1510        // We use a dedicated runtime for the setup phase
1511        let rt = tokio::runtime::Builder::new_current_thread()
1512            .enable_all()
1513            .build()?;
1514
1515        rt.block_on(async {
1516            log::info!("AutoCore Control Runner Starting...");
1517
1518            // 1. Connect to server via WebSocket and get layout
1519            let ws_url = format!("ws://{}:{}/ws/", self.config.server_host, self.config.ws_port);
1520            log::info!("Connecting to server at {}", ws_url);
1521
1522            let (ws_stream, _) = connect_async(&ws_url).await
1523                .map_err(|e| anyhow!("Failed to connect to server at {}: {}", ws_url, e))?;
1524
1525            let (mut write, mut read) = ws_stream.split();
1526
1527            // Send gm.get_layout request
1528            let request = CommandMessage::request("gm.get_layout", serde_json::Value::Null);
1529            let transaction_id = request.transaction_id;
1530            let request_json = serde_json::to_string(&request)?;
1531
1532            write.send(Message::Text(request_json)).await
1533                .map_err(|e| anyhow!("Failed to send layout request: {}", e))?;
1534
1535            // Wait for response with matching transaction_id
1536            let timeout = Duration::from_secs(10);
1537            let start = std::time::Instant::now();
1538            let mut layout: Option<HashMap<String, serde_json::Value>> = None;
1539
1540            while start.elapsed() < timeout {
1541                match tokio::time::timeout(Duration::from_secs(1), read.next()).await {
1542                    Ok(Some(Ok(Message::Text(text)))) => {
1543                        if let Ok(response) = serde_json::from_str::<CommandMessage>(&text) {
1544                            if response.transaction_id == transaction_id {
1545                                if !response.success {
1546                                    return Err(anyhow!("Server error: {}", response.error_message));
1547                                }
1548                                layout = Some(serde_json::from_value(response.data)?);
1549                                break;
1550                            }
1551                            // Skip broadcasts and other messages
1552                            if response.message_type == MessageType::Broadcast {
1553                                continue;
1554                            }
1555                        }
1556                    }
1557                    Ok(Some(Ok(_))) => continue,
1558                    Ok(Some(Err(e))) => return Err(anyhow!("WebSocket error: {}", e)),
1559                    Ok(None) => return Err(anyhow!("Server closed connection")),
1560                    Err(_) => continue, // Timeout on single read, keep trying
1561                }
1562            }
1563
1564            let layout = layout.ok_or_else(|| anyhow!("Timeout waiting for layout response"))?;
1565            log::info!("Layout received with {} entries.", layout.len());
1566
1567            // We keep the WebSocket open for sending updates
1568            // let _ = write.close().await;
1569
1570            // 2. Find Signal Offsets
1571            let tick_offset = self.find_offset(&layout, &self.config.tick_signal_name)?;
1572            let busy_offset = if let Some(name) = &self.config.busy_signal_name {
1573                Some(self.find_offset(&layout, name)?)
1574            } else {
1575                None
1576            };
1577
1578            // 4. Open Shared Memory
1579            let shmem = ShmemConf::new().os_id(&self.config.shm_name).open()?;
1580            let base_ptr = shmem.as_ptr();
1581            log::info!("Shared Memory '{}' mapped.", self.config.shm_name);
1582
1583            // 5. Setup Pointers
1584            // SAFETY: We trust the server's layout matches the generated GlobalMemory struct.
1585            let gm = unsafe { &mut *(base_ptr as *mut P::Memory) };
1586
1587            // Get tick event from shared memory
1588            log::info!("Setting up tick event at offset {} (base_ptr: {:p})", tick_offset, base_ptr);
1589            let (tick_event, _) = unsafe {
1590                Event::from_existing(base_ptr.add(tick_offset))
1591            }.map_err(|e| anyhow!("Failed to open tick event: {:?}", e))?;
1592            log::info!("Tick event ready");
1593
1594            // Busy signal event (optional)
1595            let busy_event = busy_offset.map(|offset| {
1596                unsafe { Event::from_existing(base_ptr.add(offset)) }
1597                    .map(|(event, _)| event)
1598                    .ok()
1599            }).flatten();
1600
1601            // 6. Initialize local memory buffer and user program
1602            // We use a local copy for the control loop to ensure:
1603            // - Consistent snapshot of inputs at start of cycle
1604            // - Atomic commit of outputs at end of cycle
1605            // - Proper memory barriers for cross-process visibility
1606            let mut local_mem: P::Memory = unsafe { std::ptr::read_volatile(gm) };
1607            let mut prev_mem: P::Memory = local_mem; // Snapshot for change detection
1608
1609            fence(Ordering::Acquire); // Ensure we see all prior writes from other processes
1610
1611            self.program.initialize(&mut local_mem);
1612
1613            // Write back any changes from initialize
1614            fence(Ordering::Release);
1615            unsafe { std::ptr::write_volatile(gm, local_mem) };
1616
1617            // Set up signal handler for graceful shutdown
1618            let running = Arc::new(AtomicBool::new(true));
1619            let r = running.clone();
1620            
1621            // Only set handler if not already set
1622            if let Err(e) = ctrlc::set_handler(move || {
1623                r.store(false, Ordering::SeqCst);
1624            }) {
1625                log::warn!("Failed to set signal handler: {}", e);
1626            }
1627
1628            log::info!("Entering Control Loop - waiting for first tick...");
1629            let mut cycle_count: u64 = 0;
1630
1631            while running.load(Ordering::SeqCst) {
1632                // Wait for Tick - Event-based synchronization
1633                // Use a timeout (1s) to allow checking the running flag periodically
1634                match tick_event.wait(Timeout::Val(Duration::from_secs(1))) {
1635                    Ok(_) => {},
1636                    Err(e) => {
1637                        // Check for timeout
1638                        let err_str = format!("{:?}", e);
1639                        if err_str.contains("Timeout") {
1640                            continue;
1641                        }
1642                        return Err(anyhow!("Tick wait failed: {:?}", e));
1643                    }
1644                }
1645
1646                if !running.load(Ordering::SeqCst) {
1647                    log::info!("Shutdown signal received, exiting control loop.");
1648                    break;
1649                }
1650
1651                cycle_count += 1;
1652                if cycle_count == 1 {
1653                    log::info!("First tick received!");
1654                }
1655
1656                // === INPUT PHASE ===
1657                // Read all variables from shared memory into local buffer.
1658                // This gives us a consistent snapshot of inputs for this cycle.
1659                // Acquire fence ensures we see all writes from other processes (server, modules).
1660                local_mem = unsafe { std::ptr::read_volatile(gm) };
1661                
1662                // Update prev_mem before execution to track changes made IN THIS CYCLE
1663                // Actually, we want to know what changed in SHM relative to what we last knew,
1664                // OR what WE changed relative to what we read?
1665                // The user wants "writes on shared variables" to be broadcast.
1666                // Typically outputs.
1667                // If inputs changed (from other source), broadcasting them again is fine too.
1668                // Let's capture state BEFORE execution (which is what we just read from SHM).
1669                prev_mem = local_mem;
1670
1671                fence(Ordering::Acquire);
1672
1673                // === EXECUTE PHASE ===
1674                // Execute user logic on the local copy.
1675                // All reads/writes during process_tick operate on local_mem.
1676                self.program.process_tick(&mut local_mem, cycle_count);
1677
1678                // === OUTPUT PHASE ===
1679                // Write all variables from local buffer back to shared memory.
1680                // Release fence ensures our writes are visible to other processes.
1681                fence(Ordering::Release);
1682                unsafe { std::ptr::write_volatile(gm, local_mem) };
1683
1684                // === CHANGE DETECTION & NOTIFICATION ===
1685                let changes = local_mem.get_changes(&prev_mem);
1686                if !changes.is_empty() {
1687                    // Construct bulk write message
1688                    let mut data_map = serde_json::Map::new();
1689                    for (key, val) in changes {
1690                        data_map.insert(key.to_string(), val);
1691                    }
1692                    
1693                    let msg = CommandMessage::request("gm.write", serde_json::Value::Object(data_map));
1694                    let msg_json = serde_json::to_string(&msg).unwrap_or_default();
1695                    
1696                    // Send via WebSocket (fire and forget, don't block)
1697                    // Note: WebSocket send is async. We are in block_on.
1698                    // We can await it. If it takes too long, it might delay the cycle.
1699                    // Ideally we should spawn this? But spawn requires 'static or Arc.
1700                    // For now, let's await with a very short timeout or just await.
1701                    // write is Sink.
1702                    if let Err(e) = write.send(Message::Text(msg_json)).await {
1703                        log::error!("Failed to send updates: {}", e);
1704                    }
1705                }
1706
1707                // Signal Busy/Done event
1708                if let Some(ref busy_ev) = busy_event {
1709                    let _ = busy_ev.set(EventState::Signaled);
1710                }
1711            }
1712
1713            Ok(())
1714        })
1715    }
1716
1717    fn find_offset(&self, layout: &HashMap<String, serde_json::Value>, name: &str) -> Result<usize> {
1718        let info = layout.get(name).ok_or_else(|| anyhow!("Signal '{}' not found in layout", name))?;
1719        info.get("offset")
1720            .and_then(|v| v.as_u64())
1721            .map(|v| v as usize)
1722            .ok_or_else(|| anyhow!("Invalid offset for '{}'", name))
1723    }
1724}
1725
1726/// Generates the standard `main` function for a control program.
1727///
1728/// This macro reduces boilerplate by creating a properly configured `main`
1729/// function that initializes and runs your control program.
1730///
1731/// # Arguments
1732///
1733/// * `$prog_type` - The type of your control program (must implement [`ControlProgram`])
1734/// * `$shm_name` - The shared memory segment name (string literal)
1735/// * `$tick_signal` - The tick signal name in shared memory (string literal)
1736///
1737/// # Example
1738///
1739/// ```ignore
1740/// mod gm;
1741/// use gm::GlobalMemory;
1742///
1743/// pub struct MyProgram;
1744///
1745/// impl MyProgram {
1746///     pub fn new() -> Self { Self }
1747/// }
1748///
1749/// impl autocore_std::ControlProgram for MyProgram {
1750///     type Memory = GlobalMemory;
1751///
1752///     fn process_tick(&mut self, mem: &mut GlobalMemory, _cycle: u64) {
1753///         // Your logic here
1754///     }
1755/// }
1756///
1757/// // This generates the main function
1758/// autocore_std::autocore_main!(MyProgram, "my_project_shm", "tick");
1759/// ```
1760///
1761/// # Generated Code
1762///
1763/// The macro expands to:
1764///
1765/// ```ignore
1766/// fn main() -> anyhow::Result<()> {
1767///     let config = autocore_std::RunnerConfig {
1768///         server_host: "127.0.0.1".to_string(),
1769///         ws_port: autocore_std::DEFAULT_WS_PORT,
1770///         module_name: "control".to_string(),
1771///         shm_name: "my_project_shm".to_string(),
1772///         tick_signal_name: "tick".to_string(),
1773///         busy_signal_name: None,
1774///         log_level: log::LevelFilter::Info,
1775///         log_udp_port: autocore_std::logger::DEFAULT_LOG_UDP_PORT,
1776///     };
1777///
1778///     autocore_std::ControlRunner::new(MyProgram::new())
1779///         .config(config)
1780///         .run()
1781/// }
1782/// ```
1783#[macro_export]
1784macro_rules! autocore_main {
1785    ($prog_type:ty, $shm_name:expr, $tick_signal:expr) => {
1786        fn main() -> anyhow::Result<()> {
1787            let config = autocore_std::RunnerConfig {
1788                server_host: "127.0.0.1".to_string(),
1789                ws_port: autocore_std::DEFAULT_WS_PORT,
1790                module_name: "control".to_string(),
1791                shm_name: $shm_name.to_string(),
1792                tick_signal_name: $tick_signal.to_string(),
1793                busy_signal_name: None,
1794                log_level: log::LevelFilter::Info,
1795                log_udp_port: autocore_std::logger::DEFAULT_LOG_UDP_PORT,
1796            };
1797
1798            autocore_std::ControlRunner::new(<$prog_type>::new())
1799                .config(config)
1800                .run()
1801        }
1802    };
1803}
1804
1805#[cfg(test)]
1806mod tests {
1807    use super::*;
1808
1809    #[test]
1810    fn test_rtrig_rising_edge() {
1811        let mut trigger = RTrig::new();
1812
1813        // No edge initially
1814        assert_eq!(trigger.call(false), false);
1815
1816        // Rising edge
1817        assert_eq!(trigger.call(true), true);
1818
1819        // No edge while high
1820        assert_eq!(trigger.call(true), false);
1821        assert_eq!(trigger.call(true), false);
1822
1823        // No edge on falling
1824        assert_eq!(trigger.call(false), false);
1825
1826        // Rising edge again
1827        assert_eq!(trigger.call(true), true);
1828    }
1829
1830    #[test]
1831    fn test_ftrig_falling_edge() {
1832        let mut trigger = FTrig::new();
1833
1834        // No edge initially
1835        assert_eq!(trigger.call(false), false);
1836
1837        // No edge on rising
1838        assert_eq!(trigger.call(true), false);
1839
1840        // Falling edge
1841        assert_eq!(trigger.call(false), true);
1842
1843        // No edge while low
1844        assert_eq!(trigger.call(false), false);
1845
1846        // Rising, then falling edge
1847        assert_eq!(trigger.call(true), false);
1848        assert_eq!(trigger.call(false), true);
1849    }
1850
1851    #[test]
1852    fn test_ton_basic() {
1853        let mut timer = Ton::new();
1854        let pt = Duration::from_millis(50);
1855
1856        // Disabled
1857        assert_eq!(timer.call(false, pt), false);
1858        assert_eq!(timer.et, Duration::ZERO);
1859
1860        // Enable
1861        assert_eq!(timer.call(true, pt), false);
1862        assert!(timer.et < pt);
1863
1864        // Wait for timer
1865        std::thread::sleep(Duration::from_millis(60));
1866        assert_eq!(timer.call(true, pt), true);
1867        assert_eq!(timer.et, pt);
1868
1869        // Reset
1870        timer.reset();
1871        assert_eq!(timer.q, false);
1872        assert_eq!(timer.et, Duration::ZERO);
1873    }
1874
1875    #[test]
1876    fn test_simple_timer_basic() {
1877        let mut timer = SimpleTimer::new(Duration::from_millis(50));
1878
1879        // Not started yet
1880        assert_eq!(timer.is_done(), false);
1881        assert_eq!(timer.is_running(), false);
1882        assert_eq!(timer.elapsed(), Duration::ZERO);
1883
1884        // Start
1885        timer.start();
1886        assert_eq!(timer.is_running(), true);
1887        assert_eq!(timer.is_done(), false);
1888
1889        // Wait for timer
1890        std::thread::sleep(Duration::from_millis(60));
1891        assert_eq!(timer.is_done(), true);
1892        assert!(timer.elapsed() >= Duration::from_millis(50));
1893
1894        // Reset
1895        timer.reset();
1896        assert_eq!(timer.is_done(), false);
1897        assert_eq!(timer.is_running(), false);
1898        assert_eq!(timer.elapsed(), Duration::ZERO);
1899    }
1900
1901    #[test]
1902    fn test_simple_timer_restart() {
1903        let mut timer = SimpleTimer::new(Duration::from_millis(100));
1904
1905        timer.start();
1906        std::thread::sleep(Duration::from_millis(30));
1907
1908        // Restart resets the timer
1909        timer.start();
1910        assert!(timer.elapsed() < Duration::from_millis(20));
1911    }
1912
1913    #[test]
1914    fn test_simple_timer_preset() {
1915        let mut timer = SimpleTimer::new(Duration::from_secs(5));
1916
1917        assert_eq!(timer.preset(), Duration::from_secs(5));
1918
1919        timer.set_preset(Duration::from_secs(10));
1920        assert_eq!(timer.preset(), Duration::from_secs(10));
1921    }
1922
1923    #[test]
1924    fn test_simple_timer_default() {
1925        let mut timer = SimpleTimer::default();
1926
1927        // Default preset is zero, so immediately done when started
1928        assert_eq!(timer.preset(), Duration::ZERO);
1929
1930        timer.start();
1931        assert_eq!(timer.is_done(), true);
1932    }
1933
1934    #[test]
1935    fn test_state_machine_basic() {
1936        let state = StateMachine::new();
1937
1938        assert_eq!(state.index, 0);
1939        assert_eq!(state.error_code, 0);
1940        assert!(!state.is_error());
1941        assert_eq!(state.timer_preset, Duration::MAX);
1942        assert_eq!(state.timeout_preset, Duration::MAX);
1943    }
1944
1945    #[test]
1946    fn test_state_machine_timer() {
1947        let mut state = StateMachine::new();
1948        state.timer_preset = Duration::from_millis(50);
1949        state.call();
1950
1951        // Timer shouldn't be done yet
1952        assert!(!state.timer_done());
1953
1954        // Wait for timer
1955        std::thread::sleep(Duration::from_millis(60));
1956        assert!(state.timer_done());
1957        assert!(state.elapsed() >= Duration::from_millis(50));
1958    }
1959
1960    #[test]
1961    fn test_state_machine_timeout() {
1962        let mut state = StateMachine::new();
1963        state.timeout_preset = Duration::from_millis(50);
1964        state.call();
1965
1966        assert!(!state.timed_out());
1967
1968        std::thread::sleep(Duration::from_millis(60));
1969        assert!(state.timed_out());
1970    }
1971
1972    #[test]
1973    fn test_state_machine_timer_reset_on_state_change() {
1974        let mut state = StateMachine::new();
1975        state.timer_preset = Duration::from_millis(50);
1976        state.call();
1977
1978        // Wait a bit
1979        std::thread::sleep(Duration::from_millis(30));
1980        let elapsed_before = state.elapsed();
1981        assert!(elapsed_before >= Duration::from_millis(30));
1982
1983        // Change state
1984        state.index = 10;
1985        state.call();
1986
1987        // Timer should have reset
1988        assert!(state.elapsed() < Duration::from_millis(20));
1989        assert!(!state.timer_done());
1990    }
1991
1992    #[test]
1993    fn test_state_machine_error_handling() {
1994        let mut state = StateMachine::new();
1995
1996        assert!(!state.is_error());
1997
1998        state.set_error(110, "Failed to home axis");
1999        assert!(state.is_error());
2000        assert_eq!(state.error_code, 110);
2001        assert_eq!(state.error_message, "Failed to home axis");
2002
2003        state.clear_error();
2004        assert!(!state.is_error());
2005        assert_eq!(state.error_code, 0);
2006        assert!(state.error_message.is_empty());
2007    }
2008
2009    #[test]
2010    fn test_state_machine_preset_persists() {
2011        let mut state = StateMachine::new();
2012
2013        // Set preset in state 0
2014        state.timer_preset = Duration::from_millis(50);
2015        state.index = 10;
2016        state.call();
2017
2018        // Preset should still be 50ms
2019        assert_eq!(state.timer_preset, Duration::from_millis(50));
2020
2021        // Change to state 20 without changing preset
2022        state.index = 20;
2023        state.call();
2024
2025        // Preset still 50ms
2026        assert_eq!(state.timer_preset, Duration::from_millis(50));
2027    }
2028
2029    #[test]
2030    fn test_state_machine_default_presets_never_trigger() {
2031        let mut state = StateMachine::new();
2032        state.call();
2033
2034        // Default presets are Duration::MAX, so timers should never trigger
2035        std::thread::sleep(Duration::from_millis(10));
2036        assert!(!state.timer_done());
2037        assert!(!state.timed_out());
2038    }
2039}