eis/TestProject/play_gruond/main.cpp

879 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// #include <iostream>
// #include <vector>
// #include <memory>
// #include <mutex>
// #include <algorithm>
// #include <unordered_map>
// #include <functional>
// // ==================== 观察者接口 ====================
// class IObserver {
// public:
// virtual ~IObserver() = default;
// virtual void update(const std::string& eventType, void* data) = 0; //
// 支持事件类型区分
// };
// // ==================== 主题基类 (线程安全) ====================
// class Observable {
// public:
// virtual ~Observable() = default;
// // 注册观察者(支持事件类型过滤)
// void addObserver(const std::string& eventType, std::weak_ptr<IObserver>
// observer) {
// std::lock_guard<std::mutex> lock(mtx_);
// observers_[eventType].push_back(observer);
// }
// // 移除观察者
// void removeObserver(std::weak_ptr<IObserver> target) {
// std::lock_guard<std::mutex> lock(mtx_);
// for (auto& [type, list] : observers_) {
// list.erase(
// std::remove_if(list.begin(), list.end(),
// [&](const auto& weakObserver) {
// if (auto observer = weakObserver.lock()) {
// return observer == target.lock();
// }
// return false; // 自动清理失效指针
// }),
// list.end()
// );
// }
// }
// protected:
// // 通知特定事件类型的所有观察者(推模型)
// void notify(const std::string& eventType, void* data = nullptr) {
// std::vector<std::weak_ptr<IObserver>> toNotify;
// {
// std::lock_guard<std::mutex> lock(mtx_);
// if (observers_.find(eventType) != observers_.end()) {
// toNotify = observers_[eventType];
// }
// }
// // 遍历通知(自动清理失效观察者)
// auto it = toNotify.begin();
// while (it != toNotify.end()) {
// if (auto observer = it->lock()) {
// observer->update(eventType, data);
// ++it;
// } else {
// it = toNotify.erase(it);
// }
// }
// }
// private:
// std::unordered_map<std::string, std::vector<std::weak_ptr<IObserver>>>
// observers_; mutable std::mutex mtx_;
// };
// // ==================== 具体主题:温度传感器 ====================
// class TemperatureSensor : public Observable {
// public:
// void setTemperature(float temp) {
// temperature_ = temp;
// notify("TEMP_UPDATE", &temperature_); // 推模型传递数据
// }
// // 拉模型支持
// float getTemperature() const { return temperature_; }
// private:
// float temperature_ = 0.0f;
// };
// // ==================== 具体观察者:显示设备 ====================
// class DisplayDevice : public IObserver, public
// std::enable_shared_from_this<DisplayDevice> { public:
// explicit DisplayDevice(const std::string& name) : name_(name) {}
// void subscribeTo(Observable& subject, const std::string& eventType) {
// subject.addObserver(eventType, weak_from_this());
// }
// void update(const std::string& eventType, void* data) override {
// if (eventType == "TEMP_UPDATE") {
// float* temp = static_cast<float*>(data);
// std::cout << "[" << name_ << "] 温度更新: " << *temp << "°C\n";
// }
// }
// private:
// std::string name_;
// };
// // ==================== 具体观察者:报警器(拉模型示例)====================
// class TemperatureAlarm : public IObserver, public
// std::enable_shared_from_this<TemperatureAlarm> { public:
// explicit TemperatureAlarm(float threshold) : threshold_(threshold) {}
// void subscribeTo(TemperatureSensor& sensor) {
// sensor.addObserver("TEMP_UPDATE", weak_from_this());
// }
// void update(const std::string& eventType, void* data) override {
// if (eventType == "TEMP_UPDATE") {
// // 拉模型示例:主动从主题获取数据
// TemperatureSensor* sensor =
// static_cast<TemperatureSensor*>(data); if
// (sensor->getTemperature() > threshold_) {
// std::cout << "! 警报 ! 温度超过阈值: " << threshold_ <<
// "°C\n";
// }
// }
// }
// private:
// float threshold_;
// };
// // ==================== 主函数 ====================
// int main() {
// // 创建主题
// TemperatureSensor sensor;
// // 创建观察者(使用智能指针)
// auto display1 = std::make_shared<DisplayDevice>("主控屏");
// auto display2 = std::make_shared<DisplayDevice>("备用屏");
// auto alarm = std::make_shared<TemperatureAlarm>(35.0f);
// // 注册观察者
// display1->subscribeTo(sensor, "TEMP_UPDATE");
// display2->subscribeTo(sensor, "TEMP_UPDATE");
// alarm->subscribeTo(sensor);
// // 模拟温度变化
// std::cout << "---- 第一次更新 ----\n";
// sensor.setTemperature(25.5f);
// std::cout << "\n---- 第二次更新 ----\n";
// sensor.setTemperature(37.2f); // 触发警报
// // 动态移除观察者
// sensor.removeObserver(std::weak_ptr<IObserver>(display2));
// std::cout << "\n---- 第三次更新(移除备用屏后)----\n";
// sensor.setTemperature(38.0f);
// return 0;
// }
// #include <model/Model2SliceI.h>
// #include <Ice/Ice.h>
// #include <Ice/OutputStream.h>
// #include <Ice/Proxy.h>
// #include <arpa/inet.h>
// #include <dirent.h>
// #include <log4cplus/LOG.h>
// #include <map>
// #include <pace/P99Component.h>
// #include <pace/pace.h>
// #include <string>
// #include <sys/stat.h>
// #include <vector>
// //#include "UDT1.h"
// //#include <boost/type_index.hpp>
// #include "incFileName.h"
// #include <cstdlib>
// #include <ctime>
// //#include "STD/UDT_1.h"
// using namespace iPlature;
// namespace iPlature {
// class EventCallBck : public virtual EventReceiverI {
// public:
// EventCallBck() {}
// ~EventCallBck() {}
// virtual void recvCallBack(const ::Ice::StringSeq &tagNames,
// const ::AP::ByteSeqSeq &tagValues,
// const Ice::Current &current) {
// LOG log("recvCallBack");
// // STD::DSC_MTR::MTR ab;
// short ab = 0;
// for (int i = 0; i < tagNames.size(); i++) {
// log.Info() << "tagName = " << tagNames.at(i) << endl;
// }
// for (int i = 0; i < tagValues.size(); i++) {
// log.DebugHex((void *)&tagValues.at(i).front(),
// (int)tagValues.at(i).size());
// memset(&ab, 0, tagValues.at(i).size());
// memcpy(&ab, &tagValues.at(i).front(), sizeof(2));
// }
// }
// };
// } // namespace iPlature
// using namespace iPlature;
// using namespace std;
// class EventReceiverComponent : public Component {
// public:
// virtual int start() {
// // 创建日志对象
// LOG log("EventReceiverMain");
// // 创建指针
// ptr = new iPlature::EventCallBck();
// std::cout << "ptr" << ptr << endl;
// // 添加指针
// this->add("iPlature/EventCallBck", ptr);
// log.Info() << "add ok " << endl;
// DRSdkConnectParam con;
// // con.szServerIp = "10.25.101.165";
// // con.nServerPort =10087 ;
// con.szServerIp = "192.168.0.12";
// con.nServerPort = 1234;
// con.szServerIpBak = "192.168.0.13";
// con.nServerPortBak = 1234;
// con.flag = 1;
// con.nConnectTimeoutMs = 1000;
// con.nHeartbeatTimeoutMs = 3000;
// DRSdkOption op;
// op.nThreadPoolNum = 10;
// op.nRequestWaitTimeoutMs = 1000;
// const ::Ice::Current &current = ::Ice::emptyCurrent;
// //初始化连接
// ptr->Init(con, op, current);
// log.Info() << "Init ok " << endl;
// ::AP::ByteSeqSeq seq;
// // STD::MTR ab;
// // STD::DSC_MTR::MTR er;
// // log.Debug() << "er size" << sizeof(er) << endl;
// // DSF Name STD.DSC_MTR::MTR
// // C++ Name STD::DSC_MTR::MTR
// std::string objName = "STD::DSC_MTR::MTR";
// Ice::StringSeq ss;
// ss.push_back("STD::TEST1");
// ss.push_back("STD::TEST2");
// ss.push_back("STD::TEST3");
// ss.push_back("STD::TEST4");
// ss.push_back("STD::TEST5");
// // ss.push_back(objName);
// //ͬ同步读
// seq = ptr->readData(ss, current);
// log.Debug() << "readData" << endl;
// short a = 0;
// for (int i = 0; i < seq.size(); i++) {
// ::Ice::ByteSeq sq(sizeof(seq.at(i).size()));
// sq = seq.at(i);
// log.DebugHex((void *)&sq.front(), (int)sq.size());
// memcpy(&a, (void *)&sq.front(), 2);
// std::cout << "a = " << a << endl;
// }
// std::cout << "seq size = " << seq.size() << endl;
// log.Debug() << "seq size = " << seq.size() << endl;
// // ::Ice::ByteSeq sq(sizeof(STD::DSC_MTR::MTR));
// // memcpy((void*)&sq.front(),&er,sizeof(STD::DSC_MTR::MTR));
// // std::cout << "sizeof(STD::DSC_MTR::MTR) =
// "<<sizeof(STD::DSC_MTR::MTR)
// //<< endl;
// //异步读
// ss.clear();
// // ss.push_back("STD::DSC_MTR::MTR");
// ss.push_back("STD::TEST1");
// ss.push_back("STD::TEST2");
// ss.push_back("STD::TEST3");
// ss.push_back("STD::TEST4");
// ss.push_back("STD::TEST5");
// int batchid = ptr->regist(ss, 100, current);
// // short
// a = 5;
// ::AP::ByteSeqSeq tagValues;
// ::Ice::ByteSeq sq1; //(sizeof(aa.O_HMI_STAT_RDY));
// // STD::DSC_MTR::MTR ee;
// int count = 0;
// std::srand(static_cast<unsigned int>(std::time(0))); // Seed for
// randomness while (1) {
// a += count + 1;
// ss.clear();
// tagValues.clear();
// sq1.clear();
// a = static_cast<short>(rand()) / 1000;
// sq1.resize(2);
// memcpy((void *)&sq1.front(), &a, 2);
// tagValues.push_back(sq1);
// sq1.clear();
// sq1.resize(2);
// memcpy((void *)&sq1.front(), &a, 2);
// tagValues.push_back(sq1);
// sq1.clear();
// sq1.resize(2);
// memcpy((void *)&sq1.front(), &a, 2);
// tagValues.push_back(sq1);
// sq1.clear();
// sq1.resize(2);
// memcpy((void *)&sq1.front(), &a, 2);
// tagValues.push_back(sq1);
// sq1.clear();
// sq1.resize(2);
// memcpy((void *)&sq1.front(), &a, 2);
// tagValues.push_back(sq1);
// sq1.clear();
// ss.clear();
// ss.push_back("STD::TEST1");
// ss.push_back("STD::TEST2");
// ss.push_back("STD::TEST3");
// ss.push_back("STD::TEST4");
// ss.push_back("STD::TEST5");
// log.Debug() << "tagValues size = " << tagValues.size() << endl;
// //下发
// int b = ptr->setControlData(ss, tagValues, 5, current);
// log.Info() << "setControlData ok b = " << b << endl;
// log.Info() << "1111" << endl;
// sleep(1);
// count++;
// }
// std::cout << "setControlData ok " << endl;
// }
// private:
// iPlature::EventCallBck *ptr;
// };
// PACE_SERVER_INSTALL(EventReceiverComponent)
// #include "exp_extract.hpp"
// #include "mix_cc/ihyper_db.h"
// #include "mix_cc/json.h"
// #include "mix_cc/matheval/matheval.hpp"
// #include <iomanip>
// #include <iostream>
// #include <map>
// #include <memory>
// #include <string>
// int main() {
// std::map<std::string, double> mm_vars;
// mm_vars["tag1"] = 0;
// std::string exp_str = "ln(3)";
// // std::string exp_str = "XOR(0,0)";
// std::unique_ptr<mix_cc::matheval::Expression> exp_ptr =
// std::make_unique<mix_cc::matheval::Expression>(exp_str, &mm_vars);
// std::cout << "tag1:" << mm_vars["tag1"] << ",exp str:" << exp_str
// << ",exp value:" << exp_ptr->evaluate() << std::endl;
// }
// #include <regex>
// #include <string>
// #include <iostream>
// int extractCTaskNumberRegex(const std::string& input) {
// std::regex pattern(R"(_(\d+)_task$)");
// std::smatch matches;
// if (std::regex_search(input, matches, pattern)) {
// if (matches.size() > 1) { // 索引0是完整匹配索引1是第一个捕获组
// try {
// return std::stoi(matches[1].str());
// } catch (...) {
// return 0;
// }
// }
// }
// return 0;
// }
// // 增强版,可以匹配更多情况
// int extractCTaskNumberRegexEnhanced(const std::string& input) {
// // 匹配任意字符串中的最后一个数字(该数字后面跟下划线和"task"
// std::regex pattern(R"((\d+)(?=_task$))");
// std::smatch matches;
// if (std::regex_search(input, matches, pattern)) {
// try {
// return std::stoi(matches[1].str());
// } catch (...) {
// return 0;
// }
// }
// return 0;
// }
// // 或者更通用的版本,提取最后一个数字部分
// int extractCTaskNumberRegexGeneric(const std::string& input) {
// // 匹配任意位置的数字部分,但通过贪婪匹配获取最后一个
// std::regex pattern(R"((\d+))");
// std::sregex_iterator begin(input.begin(), input.end(), pattern);
// std::sregex_iterator end;
// std::string lastMatch;
// for (auto it = begin; it != end; ++it) {
// lastMatch = (*it)[1].str();
// }
// if (!lastMatch.empty()) {
// try {
// return std::stoi(lastMatch);
// } catch (...) {
// return 0;
// }
// }
// return 0;
// }
// int main() {
// std::string test1 = "12_4_5_task";
// std::string test2 = "a_b_123_task";
// std::string test3 = "test_45_678_task";
// std::cout << extractCTaskNumberRegex(test1) << std::endl; // 输出:
// 5 std::cout << extractCTaskNumberRegexEnhanced(test1) << std::endl; //
// 输出: 5 std::cout << extractCTaskNumberRegexGeneric(test1) << std::endl;
// // 输出: 5
// std::cout << extractCTaskNumberRegex(test2) << std::endl; // 输出:
// 123 std::cout << extractCTaskNumberRegexGeneric(test3) << std::endl; //
// 输出: 678
// return 0;
// }
// #include "VarsCache.hpp"
// #include <iostream>
// #include <string>
// #include <vector>
// using std::cout;
// using std::endl;
// using std::string;
// using std::vector;
// int main() {
// vector<string> m_tag = {"tag1", "tag2", "tag3", "tag5"};
// VarsCache var_cache;
// var_cache.init(5, 30);
// cout << var_cache.dumps() << std::endl;
// return 0;
// }
// #include <chrono>
// #include <ctime>
// #include <iomanip> // 对于 std::setfill 和 std::setw
// #include <iostream>
// #include <sstream> // 对于 std::stringstream
// #include <thread>
// // 方案1使用CLOCK_MONOTONIC_RAW不受NTP和VMware调整
// class MonotonicRawClock {
// public:
// using duration = std::chrono::nanoseconds;
// using rep = duration::rep;
// using period = duration::period;
// using time_point = std::chrono::time_point<MonotonicRawClock>;
// static constexpr bool is_steady = true;
// static time_point now() noexcept {
// timespec ts;
// // CLOCK_MONOTONIC_RAW基于硬件TSC不受时间同步影响
// clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
// return time_point(std::chrono::seconds(ts.tv_sec) +
// std::chrono::nanoseconds(ts.tv_nsec));
// }
// };
// // 方案2混合时钟检测并补偿跳跃
// class RobustTimer {
// private:
// using SteadyClock = std::chrono::steady_clock;
// using SystemClock = std::chrono::system_clock;
// SteadyClock::time_point last_steady_;
// SystemClock::time_point last_system_;
// double estimated_drift_;
// public:
// RobustTimer() : estimated_drift_(0.0) {
// last_steady_ = SteadyClock::now();
// last_system_ = SystemClock::now();
// }
// // 获取经过的时间,自动补偿跳跃
// double elapsed_seconds() {
// auto now_steady = SteadyClock::now();
// auto now_system = SystemClock::now();
// auto steady_diff =
// std::chrono::duration<double>(now_steady - last_steady_).count();
// auto system_diff =
// std::chrono::duration<double>(now_system - last_system_).count();
// // 检测跳跃差异超过10ms
// if (std::abs(steady_diff - system_diff) > 0.01) {
// std::cerr << "检测到时间跳跃: " << (steady_diff - system_diff) * 1000
// << "ms" << std::endl;
// // 使用steady_clock但记录跳跃
// estimated_drift_ += system_diff - steady_diff;
// }
// last_steady_ = now_steady;
// last_system_ = now_system;
// return steady_diff + estimated_drift_;
// }
// };
// // 辅助函数:格式化当前系统时间
// std::string current_time_string(bool with_ms = true) {
// auto now = std::chrono::system_clock::now();
// auto time_t_now = std::chrono::system_clock::to_time_t(now);
// std::tm tm_buf;
// localtime_r(&time_t_now, &tm_buf);
// char buffer[80];
// strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_buf);
// std::stringstream ss;
// ss << buffer;
// if (with_ms) {
// auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
// now.time_since_epoch()) %
// 1000;
// ss << "." << std::setfill('0') << std::setw(3) << ms.count();
// }
// return ss.str();
// }
// int main() {
// // 使用MonotonicRawClock
// auto start = MonotonicRawClock::now();
// RobustTimer timer;
// double total_elapsed = 0.0;
// while (total_elapsed < 3600.0) { // 运行1小时
// // 你的业务逻辑
// // 获取经过的时间
// double elapsed = timer.elapsed_seconds();
// total_elapsed += elapsed;
// std::cout << current_time_string(true) << "|总运行时间: " <<
// total_elapsed
// << "s, 本次间隔: " << elapsed << "s" << std::endl;
// // 精确等待50ms
// auto target =
// start + std::chrono::duration_cast<MonotonicRawClock::duration>(
// std::chrono::duration<double>(total_elapsed + 0.05));
// while (MonotonicRawClock::now() < target) {
// // 忙等待,更高精度
// }
// }
// return 0;
// }
// #include <chrono>
// #include <ctime>
// #include <iomanip> // 对于 std::setfill 和 std::setw
// #include <iostream>
// #include <sstream> // 对于 std::stringstream
// #include <thread>
// // 辅助函数:格式化当前系统时间
// std::string current_time_string(bool with_ms = true) {
// auto now = std::chrono::system_clock::now();
// auto time_t_now = std::chrono::system_clock::to_time_t(now);
// std::tm tm_buf;
// localtime_r(&time_t_now, &tm_buf);
// char buffer[80];
// strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm_buf);
// std::stringstream ss;
// ss << buffer;
// if (with_ms) {
// auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
// now.time_since_epoch()) %
// 1000;
// ss << "." << std::setfill('0') << std::setw(3) << ms.count();
// }
// return ss.str();
// }
// int main() {
// // 1. 检查标准库是否把 steady_clock 声明为单调的
// std::cout << "is_steady: " << std::chrono::steady_clock::is_steady
// << std::endl;
// // 2. 测试差值是否跳变
// auto start = std::chrono::steady_clock::now();
// std::this_thread::sleep_for(std::chrono::seconds(2)); //
// 等待系统时间跳变发生 auto end = std::chrono::steady_clock::now(); auto
// duration =
// std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
// std::cout << current_time_string(true) << "|耗时: " << duration.count()
// << " ms" << std::endl;
// return 0;
// }
// // 检查你的系统如何实现 steady_clock
// #include <iostream>
// #include <chrono>
// int main() {
// auto start = std::chrono::steady_clock::now();
// // 检查 steady_clock 的底层实现
// std::cout << "steady_clock is_steady: " <<
// std::chrono::steady_clock::is_steady << std::endl;
// // 对比实现
// struct timespec ts;
// clock_gettime(CLOCK_MONOTONIC, &ts);
// auto t1 = std::chrono::steady_clock::now();
// auto t2 = std::chrono::time_point<std::chrono::steady_clock>(
// std::chrono::nanoseconds(ts.tv_sec * 1000000000LL + ts.tv_nsec)
// );
// std::cout << "Diff: " <<
// std::chrono::duration_cast<std::chrono::nanoseconds>(t1 - t2).count() <<
// " ns" << stdendl;
// return 0;
// }
#include <chrono>
#include <iostream>
#include <optional>
// 报警信息结构
struct AlarmInfo {
enum Type { None, Alarm, Timeout } type;
std::string message;
};
// 状态机类
class ExprMonitorSM {
public:
// 构造函数
// hold_mode: 动作表达式是否需要保持为真
// timeout: 超时时间0 表示无超时)
ExprMonitorSM(bool hold_mode, std::chrono::milliseconds timeout =
std::chrono::milliseconds::zero())
: hold_mode_(hold_mode), timeout_(timeout), state_(State::Idle) {}
// 重置状态机(清除所有内部状态)
void reset() {
state_ = State::Idle;
act_trigger_time_ = std::chrono::steady_clock::time_point();
}
// 每个周期调用一次,更新表达式值并获取报警信息
// act: 动作表达式结果
// fb: 反馈表达式结果
// mon: 监控表达式结果
// now: 当前时间(可选,便于测试)
std::optional<AlarmInfo> update(bool act, bool fb, bool mon,
std::chrono::steady_clock::time_point now =
std::chrono::steady_clock::now()) {
// 超时检测(仅当不在空闲状态时)
if (state_ != State::Idle && timeout_.count() > 0) {
if (now - act_trigger_time_ >= timeout_) {
reset();
return AlarmInfo{AlarmInfo::Timeout, "动作触发后超时未收到反馈"};
}
}
switch (state_) {
case State::Idle:
if (act) {
// 动作触发,记录触发时间
act_trigger_time_ = now;
// 根据是否保持进入不同状态
state_ = hold_mode_ ? State::HoldActive : State::WaitForFeedback;
// 注意:同一周期内如果立即满足反馈和监控,继续处理(不会递归,只是走下面的分支)
// 由于状态已改变,下面会根据新状态再次判断 fb / mon
}
break;
case State::WaitForFeedback:
// 非保持模式:不再关心 act只等待反馈或超时
if (fb) {
// 反馈到达,重置触发状态
reset();
// 反馈后检查监控表达式
if (mon) {
return AlarmInfo{AlarmInfo::Alarm, "监控条件满足(反馈后)"};
}
}
break;
case State::HoldActive:
// 保持模式:必须检查 act 是否仍为真
if (!act) {
// 动作条件不再满足,清除触发状态
reset();
} else {
// act 保持为真,检查反馈
if (fb) {
// 反馈到达,重置触发状态
reset();
if (mon) {
return AlarmInfo{AlarmInfo::Alarm,
"监控条件满足(保持模式下反馈后)"};
}
}
}
break;
}
return std::nullopt; // 无报警
}
private:
enum class State { Idle, WaitForFeedback, HoldActive };
bool hold_mode_; // 是否保持模式
std::chrono::milliseconds timeout_; // 超时时间
State state_; // 当前状态
std::chrono::steady_clock::time_point act_trigger_time_; // 动作触发的时间点
};
// ------------------------- 简单测试 -------------------------
#include <cassert>
#include <thread>
void test_non_hold_normal() {
std::cout
<< "\n=== 测试:非保持模式,正常流程(动作触发 → 反馈 → 监控真)===\n";
ExprMonitorSM sm(false, std::chrono::milliseconds(5000));
// 第1周期动作触发
auto alarm = sm.update(true, false, false);
assert(!alarm.has_value());
// 第2周期反馈到达监控为真
alarm = sm.update(false, true, true);
assert(alarm.has_value() && alarm->type == AlarmInfo::Alarm);
std::cout << "报警信息: " << alarm->message << std::endl;
// 状态应已重置,再次触发
alarm = sm.update(true, false, false);
assert(!alarm.has_value());
}
void test_non_hold_timeout() {
std::cout << "\n=== 测试:非保持模式,超时未反馈 ===\n";
ExprMonitorSM sm(false, std::chrono::milliseconds(200));
auto now = std::chrono::steady_clock::now();
// 动作触发
auto alarm = sm.update(true, false, false, now);
assert(!alarm.has_value());
// 模拟超时(过去 300ms
auto later = now + std::chrono::milliseconds(300);
alarm = sm.update(false, false, false, later);
assert(alarm.has_value() && alarm->type == AlarmInfo::Timeout);
std::cout << "报警信息: " << alarm->message << std::endl;
}
void test_hold_normal() {
std::cout << "\n=== 测试:保持模式,动作持续为真 → 反馈 → 监控真 ===\n";
ExprMonitorSM sm(true, std::chrono::milliseconds(5000));
// 第1周期动作触发
auto alarm = sm.update(true, false, false);
assert(!alarm.has_value());
// 第2周期动作仍为真反馈为真监控为真
alarm = sm.update(true, true, true);
assert(alarm.has_value() && alarm->type == AlarmInfo::Alarm);
std::cout << "报警信息: " << alarm->message << std::endl;
}
void test_hold_act_false() {
std::cout << "\n=== 测试:保持模式,动作中途变假,无反馈 ===\n";
ExprMonitorSM sm(true, std::chrono::milliseconds(5000));
// 动作触发
auto alarm = sm.update(true, false, false);
assert(!alarm.has_value());
// 动作变假,状态应退回空闲,不会报警
alarm = sm.update(false, false, false);
assert(!alarm.has_value());
// 重新触发
alarm = sm.update(true, false, false);
assert(!alarm.has_value());
}
void test_hold_timeout() {
std::cout << "\n=== 测试:保持模式,动作持续为真但超时未反馈 ===\n";
ExprMonitorSM sm(true, std::chrono::milliseconds(200));
auto now = std::chrono::steady_clock::now();
// 动作触发
auto alarm = sm.update(true, false, false, now);
assert(!alarm.has_value());
// 动作保持为真,但超过超时时间
auto later = now + std::chrono::milliseconds(300);
alarm = sm.update(true, false, false, later);
assert(alarm.has_value() && alarm->type == AlarmInfo::Timeout);
std::cout << "报警信息: " << alarm->message << std::endl;
}
void test_feedback_without_mon() {
std::cout << "\n=== 测试:反馈为真但监控为假,不报警 ===\n";
ExprMonitorSM sm(false, std::chrono::milliseconds(5000));
// 动作触发
auto alarm = sm.update(true, false, false);
assert(!alarm.has_value());
// 反馈为真,监控为假 → 不报警,但状态重置
alarm = sm.update(false, true, false);
assert(!alarm.has_value());
// 可以再次触发动作
alarm = sm.update(true, false, false);
assert(!alarm.has_value());
}
int main() {
test_non_hold_normal();
test_non_hold_timeout();
test_hold_normal();
test_hold_act_false();
test_hold_timeout();
test_feedback_without_mon();
std::cout << "\n所有测试通过!\n";
return 0;
}