@@ -88,6 +88,7 @@ HMI 按钮操作作为工程 `1.0` 的强类型字段保存,支持 `置 ON`、
```text
ConditionExpression
├── Node 单个触点或比较条件
├── Wire 恒真的横线叶子,保存网格列跨度
├── Series 子表达式依次串联,执行 AND
└── Parallel 子表达式并联,执行 OR
```
@@ -102,11 +103,11 @@ Parallel
└── Node(C)
```
`LogicEditorService` 支持在当前节点后串联插入,并为单个节点 或同一网络中的连续逻辑范围建立并联支路。例如选择 `B、C` 后建立并联会得到 `A AND ((B AND C) OR D)`。服务层负责校验范围连续性和子表达式完整性,拒绝跨网络、非连续或截断内部子表达式的选择。删除后会归一化空容器和只有一个子项的容器,防止无效嵌套进入执行器。
`LogicEditorService` 支持在当前节点或横线后串联插入,并为单个叶子 或同一网络中的连续逻辑范围建立并联支路。例如选择 `B、C` 后建立并联会得到 `A AND ((B AND C) OR D)`。横线使用 `Wire` 叶子保存 `1~256` 列跨度;围绕连续范围建立竖线时,服务层原子创建一个同跨度的横线旁路和 `Parallel` 容器 。服务层负责校验范围连续性和子表达式完整性,拒绝跨网络、非连续或截断内部子表达式的选择。删除后会归一化空容器和只有一个子项的容器,防止无效嵌套进入执行器。
`LogicEditorWidget` 将表达式树投影到固定行列网格,串联节点横向占列,并联分支纵向占行,所有连接只使用水平线和竖线。用户只选择画布中可见的节点:单击定位当前节点,橡皮框或多选连续节点后可直接建立并联支路。内部 `Series / Parallel` 容器不作为可选 UI 对象暴露。网格 是编辑投影,不持久化自由线段,因此不会产生悬空线、环路和多输出路径。
`LogicEditorWidget` 将表达式树投影到固定行列网格,串联节点横向占列,并联分支纵向占行,所有连接只使用水平线和竖线。触点、横线和竖线连接段都可以在画布选择;竖线连接段映射到对应的并联子表达式,删除竖线会删除该支路并归一化结构。内部 `Series / Parallel` 容器仍不作为通用 UI 对象暴露。竖线来自 `Parallel` 边界,不保存为独立领域对象;网格和像素坐标只 是编辑投影,不持久化自由线段,因此不会产生悬空线、环路和多输出路径。
工具栏中的常开、常闭、上升沿、下降沿、T 触点和比较条件在没有选择时追加到当前网络末尾,选中一个条件节点时插入到该节点后。并联支路按钮默认建立常开触点,下拉菜单可选择常闭、边沿、T 触点或比较条件 。新增节点保持待配置状态,并自动选中供属性区继续编辑。
工具栏中的常开、常闭、上升沿、下降沿、T 触点和比较条件在没有选择时追加到当前网络末尾,选中一个条件节点时插入到该节点后;选中横线后使用条件动作会原位替换横线。`F11` 在所选条件或横线后插入横线,没有选择时追加;`F12` 为所选连续范围建立横线旁路和竖线连接;`Shift+F11` 和 `Shift+F12` 分别删除所选横线和竖线支路。并联支路按钮继续用于新增可配置条件分支 。新增节点保持待配置状态,并自动选中供属性区继续编辑。
条件节点使用 `std::variant` 保存独立配置类型,当前包含 M 常开/常闭触点、M 上升沿/下降沿触点、T 常开/常闭触点、C 常开/常闭触点和 D 值与常量比较。输出支持普通、置位、复位 M 线圈、非保持 TON、CTU/CTD、MOVE 以及 ADD/SUB。边沿节点在每个扫描周期比较当前 M 值与该逻辑节点自己的上一扫描值,只产生一个扫描周期的脉冲。T 地址是 `T0~T4000` 的离线资源,C 地址是 `C0~C4000` 的离线计数器资源,两者都不是 M/D 地址。新增节点类型时应增加独立配置类型及校验、存储和执行分支,不能向通用节点堆叠无关字段。
@@ -114,7 +115,7 @@ CTU/CTD 的 C 编号只标识软件执行器中的计数器实例;计数当前
## 执行与运行反馈
`SoftwareLogicExecutor` 按 `controlLogics` 数组顺序扫描所有已启用逻辑,再按网络顺序递归求值 `Node / Series / Parallel`。禁用逻辑仅保留结构校验,未完成的禁用草稿不会阻止离线运行。普通线圈每周期写入网络结果,置位和复位线圈只在网络成立时写入;前面逻辑或网络的写入对后面逻辑和网络在同一扫描周期立即可见。
`SoftwareLogicExecutor` 按 `controlLogics` 数组顺序扫描所有已启用逻辑,再按网络顺序递归求值 `Node / Wire / Series / Parallel`。`Wire` 的逻辑值恒真,但导通轨迹等于其输入电流,因此上游断开时横线不会错误显示为导通 。禁用逻辑仅保留结构校验,未完成的禁用草稿不会阻止离线运行。普通线圈每周期写入网络结果,置位和复位线圈只在网络成立时写入;前面逻辑或网络的写入对后面逻辑和网络在同一扫描周期立即可见。
上升沿和下降沿是标准的一次扫描脉冲,运行状态按逻辑 ID 和节点 ID 隔离。TON 是正常非保持接通延时:输入接通后记录 `steady_clock` 起点,`ET` 使用实际经过的毫秒数,达到 `PT` 后 `Q` 为真;输入断开立即清零 `ET/Q`。TON 的输出状态保存在离线执行器的 T 资源表中,T 触点只读取对应 TON 的 `Q`。CTU 计数值在 `0~32767` 范围内递增,达到 PV 后保持完成;CTD 复位时装载 PV,在 `0~32767` 范围内递减,达到 0 后保持完成。ADD/SUB 使用有符号 16 位 D 值,先以更宽的中间类型计算,超出 `-32768~32767` 时饱和到边界并在运行轨迹标记 `overflow`,不会因单次算术溢出停止整个扫描。MOVE、ADD/SUB 只有网络条件成立时才写入目标 D,并在同一扫描周期对后续网络可见。软件不为每个 TON 创建 Qt `QTimer`,现有 50 ms `QTimer` 只负责扫描调度,因此不会与 Qt 事件循环或 PLC 轮询形成额外定时器线程。
@@ -126,7 +127,7 @@ CTU/CTD 的 C 编号只标识软件执行器中的计数器实例;计数当前
HMI 控件和梯形图节点直接绑定 `M0~M4000`、`D0~D4000` 地址,不要求预先创建数据点。地址是程序和通信的真实标识,属性面板只编辑区域与地址。
M/D 是外部地址类型:M 保存位输入、复位信号和线圈结果,D 保存字操作数、MOVE/ADD/SUB 目标以及计数器 CV。T/C 是软件逻辑资源类型,只在离线模式维护运行状态,不在工程中映射为 PLC 的 T/C 区寄存器;项目不把梯形图下载到 PLC,因此真机模式只通信访问新指令 引用的 M/D 地址。
M/D 是外部地址类型:M 保存位输入、复位信号和线圈结果,D 保存字操作数、MOVE/ADD/SUB 目标以及计数器 CV。T/C 是软件逻辑资源类型,只在离线模式维护运行状态,不在工程中映射为 PLC 的 T/C 区寄存器;`Wire` 只是无地址的逻辑结构,不进入 M/D 引用收集和 PLC 轮询。 项目不把梯形图下载到 PLC,因此真机模式只通信访问节点实际 引用的 M/D 地址。
工程级 `registerComments` 只保存 M/D 地址和注释文本,作为地址元数据供编辑器和注释对话框使用,不保存当前值、引用位置或缓存状态,也不会因为存在注释而加入 PLC 轮询。`LadderRung.comment` 保存单个网络的说明文本。两者在 JSON 中分开建模,不能重新引入混合“名称、注释、当前值、引用位置”的数据点表。
@@ -159,7 +160,7 @@ M/D 是外部地址类型:M 保存位输入、复位信号和线圈结果,D
`PlcCommunicationService` 使用 `QModbusRtuSerialMaster` 异步连接、读取和写入。轮询集合由
HMI 引用、报警定义、梯形图中的 M/D 引用和自由监控地址合并而成,去重后按区域合并相邻地址。
T/C 触点、TON、CTU/CTD 的 C 资源和工程级注释不会进入该集合;只有计数器 CV、PV 的 D 引用、复位 M 以及 MOVE/ADD/SUB 的 M/D 条件和操作数会进入集合。M 使用线圈,D 使用保持寄存器;所有 Modbus 地址均为从 `0` 开始的原始地址。
T/C 触点、TON、CTU/CTD 的 C 资源、横线 和工程级注释不会进入该集合;只有计数器 CV、PV 的 D 引用、复位 M 以及 MOVE/ADD/SUB 的 M/D 条件和操作数会进入集合。M 使用线圈,D 使用保持寄存器;所有 Modbus 地址均为从 `0` 开始的原始地址。
PLC 连接后可以动态增删自由监控地址。存在读取请求时,新的轮询集合在当前响应处理完成后
应用,旧响应仍按发出时的读取块解析。连接级首次读取完成后,动态增加地址不会撤销真机