// eqpalg/utility/fb_state_machine.h #pragma once #include #include #include using TimePoint = std::chrono::system_clock::time_point; using TimeDur = std::chrono::milliseconds; /** * @brief 反馈动作状态枚举 */ enum class FbState { Idle, // 空闲(无活动动作) Started, // 刚启动(首周期检测到触发条件,下次检查反馈) InProgress, // 进行中(等待反馈条件满足或超时) Done, // 反馈条件满足,动作完成 NotHold, // keep_mode 下触发条件丢失 Timeout // 超时 }; /** * @brief FbStateMachine::update() 的返回结构 */ struct FbUpdateResult { FbState state; bool funVarsNeedReset; // 本周期是否需要标记 fun_vars 重置 }; /** * @brief 反馈动作状态机 * * 替代 ExpBase 中分散的 4 个方法(act_start_done/act_not_hold/act_done/act_timeout) * 和 4 个布尔标志(act_started_/act_triggered_/feedback_triggered_/feedback_done_)。 * * 管理反馈动作的完整生命周期: * Idle → Started → InProgress → Done/NotHold/Timeout → Idle * * 同时负责动作期间的变量快照和累积更新(通过 VarManager 引用)。 */ class FbStateMachine { public: FbStateMachine() = default; ~FbStateMachine() = default; // ========== 配置 ========== /** * @param keepMode 是否保持模式(触发条件丢失时退出动作) * @param timeout 超时时间(-32768ms 表示无限制,仅防溢出) */ void configure(bool keepMode, TimeDur timeout); // ========== 每周期调用 ========== /** * @brief 更新状态机(每个 mon 周期调用一次) * * @param actTriggered 前提表达式结果(exp_act_->evaluate() 的布尔值) * @param now 当前时间 * @param mm_vars 变量映射(用于快照/累积更新) * @param tag_count tag 点数量 * * @return FbUpdateResult — 新状态 + 是否需要重置 fun_vars */ FbUpdateResult update(bool actTriggered, TimePoint now, std::map& mm_vars, size_t tag_count); /** * @brief 检查反馈条件(在 update() 返回 InProgress 后调用) * * @param fbCondition 反馈表达式结果(exp_feedback_->evaluate() 的布尔值) * @param now 当前时间 * @param mm_vars 变量映射 * * @return true → 反馈条件满足,转为 Done * @return false → 继续保持 InProgress */ bool checkFeedback(bool fbCondition, TimePoint now, std::map& mm_vars); // ========== 查询 ========== bool isActive() const; // Started 或 InProgress bool isKeepMode() const { return keep_mode_; } TimePoint actionStartTime() const { return start_time_; } FbState currentState() const { return state_; } // ========== 外部强制重置(PRR=false 时调用)========== void forceReset(); // ========== 获取 m_timemode(供外部判断报警消息格式)========== bool isTimeMode() const { return time_mode_; } void setTimeMode(bool v) { time_mode_ = v; } private: bool keep_mode_ = false; TimeDur timeout_ = std::chrono::minutes(10); FbState state_ = FbState::Idle; TimePoint start_time_; bool time_mode_ = false; // 原 ExpBase::m_timemode // ========== 内部变量操作(替代分散在 act_* 方法中的变量更新)========== void snapshotActionStart(TimePoint now, std::map& mm_vars, size_t tag_count); void updateActionVars(TimePoint now, std::map& mm_vars, size_t tag_count); void recordActionEnd(TimePoint now, std::map& mm_vars); void clearActionAccumulators(std::map& mm_vars, size_t tag_count); bool isAccumulatorNearOverflow( const std::map& mm_vars, size_t tag_count) const; };