/** * @file TriggerEngine.h * @brief Hub-side trigger FSM with web-oscilloscope semantics. * * Mirrors the web client's trigger logic (Client/udpstreamer/static/app.js): * * IDLE --Arm()--> ARMED * ARMED --edge fires--> COLLECTING (trigTime + pre/post window latched) * COLLECTING -capture done-> TRIGGERED (StreamHub broadcasts the capture) * TRIGGERED --Arm()--> ARMED (auto after ~200 ms in normal mode, * manual "rearm" in single mode) * any --Disarm()--> IDLE * * Configuration is the web client's: full signal key ("src:sig" or * "src:sig[i]"), edge rising/falling/both, threshold, capture window length * windowSec, pre-trigger percentage, and acquisition mode normal/single with * a "stopped" flag pausing auto-rearm. * * CheckSample() is called from the UDPSClient receive thread for every decoded * sample of the configured signal. All state is protected by a * FastPollingMutexSem so the StreamHub push thread can poll it safely. */ #ifndef STREAMHUB_TRIGGER_ENGINE_H_ #define STREAMHUB_TRIGGER_ENGINE_H_ #include "CompilerTypes.h" #include "FastPollingMutexSem.h" #include "StreamString.h" namespace StreamHub { using MARTe::uint32; using MARTe::float64; using MARTe::StreamString; using MARTe::FastPollingMutexSem; /** Trigger FSM states (badge mapping: idle/armed/collecting/triggered). */ enum TrigState { kTrigIdle = 0, kTrigArmed = 1, kTrigCollecting = 2, kTrigTriggered = 3 }; /** Edge selection. */ enum TrigEdge { kEdgeRising = 0, kEdgeFalling = 1, kEdgeBoth = 2 }; /** Acquisition mode. */ enum TrigAcqMode { kTrigNormal = 0, ///< Auto-rearm after each capture (unless stopped) kTrigSingle = 1 ///< Stay TRIGGERED until an explicit rearm }; /** @brief Trigger configuration (web client semantics). */ struct TriggerConfig { TriggerConfig(); StreamString signalKey; ///< Full key: "src:sig" or "src:sig[i]" TrigEdge edge; ///< Rising / falling / both float64 threshold; ///< Trigger threshold (physical units) float64 windowSec; ///< Capture window length [1e-4 .. 10] s float64 prePercent; ///< Pre-trigger part of the window [0 .. 100] % TrigAcqMode mode; ///< Normal (auto-rearm) or single }; /** * @brief Hub-side trigger FSM. */ class TriggerEngine { public: TriggerEngine(); /** @brief Replace the configuration (bumps the config epoch). */ void SetConfig(const TriggerConfig &cfg); /** @return Copy of the current configuration. */ TriggerConfig GetConfig() const; /** * @return Monotonic configuration epoch. UDPSourceSession caches the * resolved (signal idx, element idx) per epoch and re-resolves on change. */ uint32 GetConfigEpoch() const; /** @brief Arm: any state → ARMED (resets edge detection). */ void Arm(); /** @brief Disarm: any state → IDLE; clears the stopped flag. */ void Disarm(); /** @brief Set/clear the stopped flag (pauses normal-mode auto-rearm). */ void SetStopped(bool stopped); /** @return Current stopped flag. */ bool GetStopped() const; /** * @brief Edge-detect one decoded sample of the configured signal. * Receive-thread context. Only acts in ARMED state; on a matching edge * latches trigTime and the pre/post window and moves to COLLECTING. */ void CheckSample(float64 t, float64 v); /** @return Current FSM state. */ TrigState GetState() const; /** * @brief Get the latched capture window of the last fired trigger. * @return false if no trigger has fired since the last Disarm(). */ bool GetFiredWindow(float64 &trigTime, float64 &preSec, float64 &postSec) const; /** @brief COLLECTING → TRIGGERED (push thread, after the capture frame). */ void MarkTriggered(); private: mutable FastPollingMutexSem mutex_; TriggerConfig config_; uint32 epoch_; TrigState state_; bool stopped_; float64 prevValue_; ///< Last sample (edge detection) bool prevValid_; ///< First-sample guard in ARMED state float64 trigTime_; ///< Latched trigger time (Unix s) float64 firedPreSec_; ///< Window pre-part latched at fire time float64 firedPostSec_; ///< Window post-part latched at fire time bool firedValid_; ///< true after a fire, until Disarm() }; inline TriggerConfig::TriggerConfig() : edge(kEdgeRising), threshold(0.0), windowSec(1.0), prePercent(20.0), mode(kTrigNormal) { } } /* namespace StreamHub */ #endif /* STREAMHUB_TRIGGER_ENGINE_H_ */