#pragma once #include "project_limits.h" #include "register_address.h" #include #include #include #include #include enum class ContactMode { NormallyOpen, // 常开触点,M 为 1 时条件成立 NormallyClosed // 常闭触点,M 为 0 时条件成立 }; enum class CoilMode { Normal, // 普通线圈,直接写入条件结果 Set, // 条件成立时置位 M Reset // 条件成立时复位 M }; enum class EdgeMode { Rising, // 检测 M 从 0 变为 1 Falling // 检测 M 从 1 变为 0 }; enum class ComparisonOperator { Equal, // 等于 NotEqual, // 不等于 LessThan, // 小于 LessThanOrEqual, // 小于或等于 GreaterThan, // 大于 GreaterThanOrEqual // 大于或等于 }; enum class WordOperandKind { Constant, // 使用固定数值 Register // 使用 D 区寄存器的值 }; struct WordOperand { WordOperandKind kind = WordOperandKind::Constant; // 操作数来源类型 RegisterAddress address{RegisterArea::D, 0}; // 寄存器操作数使用的 D 地址 std::int16_t constant = 0; // 常量操作数的数值 // 校验操作数类型和寄存器地址是否有效 bool validate(std::string *error = nullptr) const; }; struct ContactNodeConfig { RegisterAddress address{RegisterArea::M, 0}; // 触点监控的 M 地址 ContactMode mode = ContactMode::NormallyOpen; // 触点的常开或常闭模式 }; struct EdgeContactNodeConfig { RegisterAddress address{RegisterArea::M, 0}; // 边沿触点监控的 M 地址 EdgeMode mode = EdgeMode::Rising; // 上升沿或下降沿模式 }; struct CoilNodeConfig { RegisterAddress address{RegisterArea::M, 0}; // 线圈写入的 M 地址 CoilMode mode = CoilMode::Normal; // 普通、置位或复位模式 }; struct CompareNodeConfig { RegisterAddress address{RegisterArea::D, 0}; // 参与比较的 D 地址 ComparisonOperator comparison = ComparisonOperator::Equal; // 比较方式 std::int16_t value = 0; // 与 D 值比较的常量 }; struct MoveNodeConfig { WordOperand source; // MOVE 的源操作数 RegisterAddress destination{RegisterArea::D, 0}; // MOVE 的目标 D 地址 }; enum class ArithmeticOperation { Add, // 加法 Subtract // 减法 }; struct ArithmeticNodeConfig { ArithmeticOperation operation = ArithmeticOperation::Add; // 算术运算类型 WordOperand left; // 左操作数 WordOperand right; // 右操作数 RegisterAddress destination{RegisterArea::D, 0}; // 运算结果写入的 D 地址 }; using LogicNodeConfig = std::variant< ContactNodeConfig, EdgeContactNodeConfig, CoilNodeConfig, CompareNodeConfig, MoveNodeConfig, ArithmeticNodeConfig>; // 返回逻辑节点主要使用的地址 std::optional registerAddressForLogicNode( const LogicNodeConfig &config); // 收集逻辑节点涉及的全部有效寄存器地址 void collectRegisterAddressesForLogicNode( const LogicNodeConfig &config, std::vector *addresses); struct LogicNode { std::string id; // 逻辑节点的唯一 ID LogicNodeConfig config; // 节点类型和具体参数 bool configured = true; // 是否已完成运行所需的配置 // 校验节点 ID 和节点参数 bool validate(std::string *error = nullptr) const; // 返回节点是否已完成运行配置 bool isConfigured() const; // 返回节点是否属于条件节点 bool isCondition() const; // 返回节点是否属于输出节点 bool isOutput() const; }; enum class LadderCellKind { Gap, // 空白网格 Wire, // 横向导线网格 Node // 条件节点网格 }; // 条件区的一个固定网格,横线和空白与条件节点具有同等持久化地位 struct LadderCell { std::string id; // 网格的唯一 ID LadderCellKind kind = LadderCellKind::Gap; // 网格类型 std::optional node; // 网格中的条件节点 // 校验网格 ID、类型和节点内容是否匹配 bool validate(std::string *error = nullptr) const; }; // 两个相邻视觉行之间、指定列边界上的一段竖线 struct VerticalConnection { std::string id; // 竖线的唯一 ID std::string upperRungId; // 竖线连接的上方行 ID std::string lowerRungId; // 竖线连接的下方行 ID int columnBoundary = 0; // 竖线所在的列边界 // 校验竖线的关联行和列边界 bool validate(std::string *error = nullptr) const; }; // 连续梯形图的一条视觉行,不再是隔离的网络容器 struct LadderRung { std::string id; // 梯形图行的唯一 ID std::string name; // 梯形图行名称 std::string comment; // 网络首行上的注释 std::optional output; // 行末输出节点 std::vector cells; // 固定数量的条件网格 // 校验梯形图行的完整结构 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; // 控制逻辑的唯一 ID std::string name; // 控制逻辑名称 std::vector rungs; // 按视觉顺序保存的梯形图行 bool enabled = true; // 是否参与运行扫描 std::vector verticalConnections; // 行之间的竖向连接 // 返回指定行所在连续网络的首行下标 std::size_t networkHeadIndex(std::size_t rung_index) const; // 使用指定工程限制校验控制逻辑 bool validate( const ProjectLimitSettings &limits, std::string *error = nullptr) const; // 使用默认工程限制校验控制逻辑结构 bool validateStructure(std::string *error = nullptr) const; // 使用指定工程限制校验控制逻辑结构 bool validateStructure( const ProjectLimitSettings &limits, std::string *error = nullptr) const; // 使用默认工程限制校验运行前的控制逻辑 bool validateForRunning(std::string *error = nullptr) const; // 使用指定工程限制校验运行前的控制逻辑 bool validateForRunning( const ProjectLimitSettings &limits, std::string *error = nullptr) const; }; // 在梯形图行中查找指定 ID 的只读网格 const LadderCell *findLadderCell( const LadderRung &rung, const std::string &cell_id); // 在梯形图行中查找指定 ID 的可写网格 LadderCell *findLadderCell( LadderRung &rung, const std::string &cell_id); // 在控制逻辑中查找指定 ID 的只读竖线 const VerticalConnection *findVerticalConnection( const ControlLogic &logic, const std::string &connection_id); // 在控制逻辑中查找指定 ID 的可写竖线 VerticalConnection *findVerticalConnection( ControlLogic &logic, const std::string &connection_id); // 收集一行中的全部条件节点 void collectConditionNodes( const LadderRung &rung, std::vector *nodes); // 收集控制逻辑中的全部条件节点和输出节点 void collectLogicNodes( const ControlLogic &logic, std::vector *nodes);