879 lines
27 KiB
C++
879 lines
27 KiB
C++
// #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 ¤t) {
|
||
// 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 ¤t = ::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;
|
||
} |