#pragma once #include "register_address.h" #include #include #include #include #include enum class ContactMode { NormallyOpen, NormallyClosed }; enum class CoilMode { Normal, Set, Reset }; enum class EdgeMode { Rising, Falling }; enum class ComparisonOperator { Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual }; struct ContactNodeConfig { RegisterAddress address{RegisterArea::M, 0}; ContactMode mode = ContactMode::NormallyOpen; }; struct EdgeContactNodeConfig { RegisterAddress address{RegisterArea::M, 0}; EdgeMode mode = EdgeMode::Rising; }; struct CoilNodeConfig { RegisterAddress address{RegisterArea::M, 0}; CoilMode mode = CoilMode::Normal; }; struct CompareNodeConfig { RegisterAddress address{RegisterArea::D, 0}; ComparisonOperator comparison = ComparisonOperator::Equal; std::int16_t value = 0; }; class TimerAddress { public: static constexpr int kMinimumIndex = 0; static constexpr int kMaximumIndex = 4000; explicit TimerAddress(int index = 0); int index() const; bool isValid() const; std::string toString() const; bool operator==(const TimerAddress &other) const; bool operator!=(const TimerAddress &other) const; private: int index_ = 0; }; struct TimerContactNodeConfig { TimerAddress address; ContactMode mode = ContactMode::NormallyOpen; }; struct TonNodeConfig { static constexpr int kMinimumPresetMs = 1; static constexpr int kMaximumPresetMs = 86400000; TimerAddress address; int presetMs = 1000; }; using LogicNodeConfig = std::variant< ContactNodeConfig, EdgeContactNodeConfig, TimerContactNodeConfig, CoilNodeConfig, CompareNodeConfig, TonNodeConfig>; std::optional registerAddressForLogicNode( const LogicNodeConfig &config); struct LogicNode { std::string id; LogicNodeConfig config; bool configured = true; bool validate(std::string *error = nullptr) const; bool isConfigured() const; bool isCondition() const; bool isOutput() const; }; enum class ConditionExpressionKind { Node, Series, Parallel }; // 结构化表达式只允许合法的串并联拓扑,不保存可产生悬空线或环路的像素连接 struct ConditionExpression { std::string id; ConditionExpressionKind kind = ConditionExpressionKind::Node; std::optional node; std::vector children; static ConditionExpression fromNode(LogicNode node); bool validate(std::string *error = nullptr) const; bool validateForRunning(std::string *error = nullptr) const; }; // 删除后折叠单子项容器并合并相邻同类容器,保持表达式的规范形态 void normalizeConditionExpression(std::optional *expression); const LogicNode *findConditionNode( const ConditionExpression &expression, const std::string &node_id); LogicNode *findConditionNode( ConditionExpression &expression, const std::string &node_id); const ConditionExpression *findConditionExpression( const ConditionExpression &expression, const std::string &expression_id); ConditionExpression *findConditionExpression( ConditionExpression &expression, const std::string &expression_id); void collectConditionNodes( const ConditionExpression &expression, std::vector *nodes); void collectConditionExpressionIds( const ConditionExpression &expression, std::vector *ids); // 一个网络包含一棵结构化条件表达式,输出指令固定在最右侧 struct LadderRung { std::string id; std::string name; std::string comment; std::optional condition; std::optional output; bool validate(std::string *error = nullptr) const; bool validateStructure(std::string *error = nullptr) const; bool validateForRunning(std::string *error = nullptr) const; }; struct ControlLogic { std::string id; std::string name; std::vector rungs; bool enabled = true; bool validate(std::string *error = nullptr) const; bool validateStructure(std::string *error = nullptr) const; bool validateForRunning(std::string *error = nullptr) const; }; bool validateTimerReferencesForRunning( const std::vector &logics, std::string *error = nullptr);