Преглед на файлове

docs: 明确离线指令与PLC边界

main
suyu преди 1 месец
родител
ревизия
ded0288b1b
променени са 5 файла, в които са добавени 31 реда и са изтрити 11 реда
  1. +1
    -0
      AGENTS.md
  2. +10
    -2
      docs/ai/handoff.md
  3. +7
    -3
      docs/architecture.md
  4. +8
    -2
      docs/工程格式说明.md
  5. +5
    -4
      docs/开发顺序.md

+ 1
- 0
AGENTS.md Целия файл

@@ -55,3 +55,4 @@ mingw32-make -j2
## 注意
- 生成注释的文本结尾别加逗号 `。`。
- 你写完代码需要测试真机PLC可以直接连 COM3,9600 8e1配置。
- 离线仿真不会把PLC程序下载到真机PLC的,不做这个。

+ 10
- 2
docs/ai/handoff.md Целия файл

@@ -30,8 +30,9 @@
- HMI 已开放不绑定寄存器的 `Label` 和独立 `PageJump` 创建入口,属性区按控件类型显示绑定、按钮操作或目标页面
- HMI 已增加 AlarmList 和报警配置入口,支持 M ON、D 高限、D 低限,统一显示当前报警和确认状态;运行态无报警时隐藏,报警恢复后立即移除
- 离线执行器按工程顺序扫描所有启用逻辑,禁用草稿不阻止运行;轨迹按逻辑 ID 隔离,运行工作台可切换当前投影
- 梯形图已支持上升沿、下降沿、T 常开/常闭触点和非保持 TON;边沿只输出一个扫描周期,TON 按 `steady_clock` 计算实际 ET
- T 是 `T0~T4000` 的离线仿真内部资源,不读写 M/D,也不进入 Modbus 轮询;同一 T 只允许一个已启用 TON 驱动
- 梯形图已支持上升沿、下降沿、T/C 常开/常闭触点、非保持 TON、CTU/CTD、MOVE 和 ADD/SUB;边沿与计数都按上升沿扫描语义执行,TON 按 `steady_clock` 计算实际 ET
- T/C 是 `T0~T4000`、`C0~C4000` 的离线仿真内部资源;C 计数器的 CV 保存到 D 地址,PV 支持常量或 D 地址,复位使用 M 地址;T/C 资源本身不读写 M/D,也不进入 Modbus 轮询,同一资源只允许一个已启用驱动
- ADD/SUB 使用 `int32_t` 中间值并将结果饱和到 `-32768~32767`;越界只在运行轨迹的 `WordTraceValue::overflow` 标记,不停止扫描
- 工程已支持 M/D 地址注释和 `LadderRung` 网络注释;地址注释只保存地址与文本,不混入当前值和引用状态
- HMI 运行按钮已区分悬停、按下、释放和禁止写入外观,运行态不再显示编辑选中框,可写按钮使用手型光标
- PLC 轮询集合已扩展为 HMI、报警定义、梯形图和自由监控地址的并集,连接后可动态增删监控地址
@@ -58,6 +59,7 @@
- 自由监控表属于当前调试会话,不进入工程 `1.0` JSON,不重新引入数据点表
- 工程 `1.0` 直接要求顶层 `registerComments` 和每个网络的 `comment` 字段,不增加旧工程迁移或缺省兼容
- 50 ms Qt 定时器只调度离线扫描;每个 TON 不创建独立 Qt 定时器,真机模式继续停止整个软件逻辑执行器
- 项目梯形图不下载到 PLC;真机模式停止本地软件逻辑执行器,只轮询新指令实际引用的 M/D 地址

## 自动化验证

@@ -160,6 +162,12 @@ HMI 图元现已分离编辑选择与运行输入状态。运行按钮悬停时
2026-08-17 使用 `COM3 / 9600 / 8E1 / 站号 1` 完成报警功能后的真机只读冒烟,成功读取
`M0~M2 = OFF`、`D0 = 0`,测试结束后正常关闭串口。本次没有执行任何 PLC 写操作。

本轮新增 CTU/CTD、MOVE、ADD/SUB 离线逻辑和编辑配置。领域校验限制 C/T 资源及 M/D 地址
范围,C 计数器要求唯一驱动和已绑定 C 触点;计数按上升沿执行,CV 通过 D 地址读写,CTU
复位为 0、CTD 复位装载 PV,ADD/SUB 越界采用有符号 16 位饱和并记录溢出轨迹。JSON 保存
加载、离线执行、主窗口入口和真机轮询地址覆盖已通过,项目 Release 构建通过。真机仍只验证
M/D 通信,不执行或下载这些本地梯形图指令。

## 待完成事项

1. 在 PLC STOP 状态确认 COM2 参数和 RS-485 A/B 接线


+ 7
- 3
docs/architecture.md Целия файл

@@ -93,13 +93,15 @@ Parallel

工具栏中的常开、常闭、上升沿、下降沿、T 触点和比较条件在没有选择时追加到当前网络末尾,选中一个条件节点时插入到该节点后。并联支路按钮默认建立常开触点,下拉菜单可选择常闭、边沿、T 触点或比较条件。新增节点保持待配置状态,并自动选中供属性区继续编辑。

条件节点使用 `std::variant` 保存独立配置类型,当前包含 M 常开/常闭触点、M 上升沿/下降沿触点、T 常开/常闭触点和 D 值与常量比较。输出支持普通、置位、复位 M 线圈和非保持 TON。边沿节点在每个扫描周期比较当前 M 值与该逻辑节点自己的上一扫描值,只产生一个扫描周期的脉冲。T 地址是 `T0~T4000` 的离线资源,不是 M/D 地址。新增节点类型时应增加独立配置类型及校验、存储和执行分支,不能向通用节点堆叠无关字段。
条件节点使用 `std::variant` 保存独立配置类型,当前包含 M 常开/常闭触点、M 上升沿/下降沿触点、T 常开/常闭触点、C 常开/常闭触点和 D 值与常量比较。输出支持普通、置位、复位 M 线圈、非保持 TON、CTU/CTD、MOVE 以及 ADD/SUB。边沿节点在每个扫描周期比较当前 M 值与该逻辑节点自己的上一扫描值,只产生一个扫描周期的脉冲。T 地址是 `T0~T4000` 的离线资源,C 地址是 `C0~C4000` 的离线计数器资源,两者都不是 M/D 地址。新增节点类型时应增加独立配置类型及校验、存储和执行分支,不能向通用节点堆叠无关字段。

CTU/CTD 的 C 编号只标识软件执行器中的计数器实例;计数当前值 CV 显式保存到 D 地址,PV 支持常量或 D 地址,复位输入使用 M 地址。CTU 和 CTD 都只在网络条件的上升沿执行一次计数,C 触点读取对应计数器的完成状态。C 资源在已启用逻辑中必须只有一个计数指令驱动,C 触点必须能够找到该驱动,因此不会把 C 误当作需要 Modbus 读取的外部寄存器。

## 执行与运行反馈

`SoftwareLogicExecutor` 按 `controlLogics` 数组顺序扫描所有已启用逻辑,再按网络顺序递归求值 `Node / Series / Parallel`。禁用逻辑仅保留结构校验,未完成的禁用草稿不会阻止离线运行。普通线圈每周期写入网络结果,置位和复位线圈只在网络成立时写入;前面逻辑或网络的写入对后面逻辑和网络在同一扫描周期立即可见。

上升沿和下降沿是标准的一次扫描脉冲,运行状态按逻辑 ID 和节点 ID 隔离。TON 是正常非保持接通延时:输入接通后记录 `steady_clock` 起点,`ET` 使用实际经过的毫秒数,达到 `PT` 后 `Q` 为真;输入断开立即清零 `ET/Q`。TON 的输出状态保存在离线执行器的 T 资源表中,T 触点只读取对应 TON 的 `Q`。软件不为每个 TON 创建 Qt `QTimer`,现有 50 ms `QTimer` 只负责扫描调度,因此不会与 Qt 事件循环或 PLC 轮询形成额外定时器线程。
上升沿和下降沿是标准的一次扫描脉冲,运行状态按逻辑 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 轮询形成额外定时器线程。

每次扫描生成按逻辑 ID 分区的 `LogicTraceSnapshot`,记录节点、表达式、网络和线圈的导通状态,避免不同逻辑中重复的 `rung-1`、`contact-1` 相互覆盖。运行工作台的逻辑下拉框只切换当前轨迹投影,所有已启用逻辑仍持续执行。逻辑画布以绿色显示导通节点和路径;执行错误携带逻辑、网络和节点上下文,画布选择并以红色突出故障位置。

@@ -109,6 +111,8 @@ Parallel

HMI 控件和梯形图节点直接绑定 `M0~M4000`、`D0~D4000` 地址,不要求预先创建数据点。地址是程序和通信的真实标识,属性面板只编辑区域与地址。

M/D 是外部地址类型:M 保存位输入、复位信号和线圈结果,D 保存字操作数、MOVE/ADD/SUB 目标以及计数器 CV。T/C 是软件逻辑资源类型,只在离线模式维护运行状态,不在工程中映射为 PLC 的 T/C 区寄存器;项目不把梯形图下载到 PLC,因此真机模式只通信访问新指令引用的 M/D 地址。

工程级 `registerComments` 只保存 M/D 地址和注释文本,作为地址元数据供编辑器和注释对话框使用,不保存当前值、引用位置或缓存状态,也不会因为存在注释而加入 PLC 轮询。`LadderRung.comment` 保存单个网络的说明文本。两者在 JSON 中分开建模,不能重新引入混合“名称、注释、当前值、引用位置”的数据点表。

## 自由监控与运行工作台
@@ -140,7 +144,7 @@ HMI 控件和梯形图节点直接绑定 `M0~M4000`、`D0~D4000` 地址,不要

`PlcCommunicationService` 使用 `QModbusRtuSerialMaster` 异步连接、读取和写入。轮询集合由
HMI 引用、报警定义、梯形图中的 M/D 引用和自由监控地址合并而成,去重后按区域合并相邻地址。
T 触点、TON 和工程级注释不会进入该集合。M 使用线圈,D 使用保持寄存器;所有 Modbus 地址均为从 `0` 开始的原始地址。
T/C 触点、TON、CTU/CTD 的 C 资源和工程级注释不会进入该集合;只有计数器 CV、PV 的 D 引用、复位 M 以及 MOVE/ADD/SUB 的 M/D 条件和操作数会进入集合。M 使用线圈,D 使用保持寄存器;所有 Modbus 地址均为从 `0` 开始的原始地址。

PLC 连接后可以动态增删自由监控地址。存在读取请求时,新的轮询集合在当前响应处理完成后
应用,旧响应仍按发出时的读取块解析。连接级首次读取完成后,动态增加地址不会撤销真机


+ 8
- 2
docs/工程格式说明.md Целия файл

@@ -125,16 +125,22 @@ AlarmList 只负责显示项目级当前报警,不保存独立触发逻辑,

`enabled` 决定离线执行器是否扫描该逻辑。所有启用逻辑按 `controlLogics` 数组顺序执行;禁用逻辑仍要求 ID、名称、网络和表达式结构合法,但允许保留未完成节点作为草稿。

网络、`Node / Series / Parallel` 条件表达式、触点、边沿、T 触点、比较、线圈和 TON 字段沿用当前结构化梯形图模型。网格坐标、画布连线和运行轨迹是 UI 或运行会话投影,不进入 JSON。节点配置的类型和值域如下:
网络、`Node / Series / Parallel` 条件表达式、触点、边沿、T/C 触点、比较、线圈和输出指令字段沿用当前结构化梯形图模型。网格坐标、画布连线和运行轨迹是 UI 或运行会话投影,不进入 JSON。节点配置的类型和值域如下:

```json
{"type": "edgeContact", "address": {"area": "M", "index": 0}, "mode": "rising"}
{"type": "edgeContact", "address": {"area": "M", "index": 0}, "mode": "falling"}
{"type": "timerContact", "timer": {"index": 0}, "mode": "normallyOpen"}
{"type": "ton", "timer": {"index": 0}, "presetMs": 1000}
{"type": "counterContact", "counter": {"index": 0}, "mode": "normallyOpen"}
{"type": "counter", "counter": {"index": 0}, "mode": "up", "currentValueAddress": {"area": "D", "index": 10}, "preset": {"kind": "constant", "value": 10}, "resetAddress": {"area": "M", "index": 0}}
{"type": "move", "source": {"kind": "register", "address": {"area": "D", "index": 1}}, "destination": {"area": "D", "index": 2}}
{"type": "arithmetic", "operation": "add", "left": {"kind": "register", "address": {"area": "D", "index": 2}}, "right": {"kind": "constant", "value": 1}, "destination": {"area": "D", "index": 2}}
```

T 地址范围为 `0~4000`,TON `presetMs` 范围为 `1~86400000`。上升沿和下降沿是一次扫描脉冲;TON 是非保持接通延时,输入断开时 `ET/Q` 立即清零。T 不参与 Modbus,也不写入 M/D 仓库。
T/C 资源地址范围均为 `0~4000`,TON `presetMs` 范围为 `1~86400000`。C 仅标识离线计数器实例,计数当前值必须绑定 D 地址,复位必须绑定 M 地址,PV 可为有符号 16 位常量或 D 地址。CTU/CTD 按条件上升沿分别递增/递减;CTU 复位将 CV 置 0,CTD 复位将 CV 装载 PV,CV 始终限制在 `0~32767`,C 触点读取完成状态。上升沿和下降沿是一次扫描脉冲;TON 是非保持接通延时,输入断开时 `ET/Q` 立即清零。T/C 不参与 Modbus,也不写入 M/D 仓库。

MOVE、ADD 和 SUB 只能把结果写入 D 地址,源操作数和算术左右操作数可以是有符号 16 位常量或 D 地址。指令仅在所在网络条件成立时执行;ADD/SUB 使用更宽中间类型计算,结果超出 `-32768~32767` 时饱和到对应边界,并在离线运行轨迹中记录 `overflow: true`,不会中止扫描。

## 校验与读写



+ 5
- 4
docs/开发顺序.md Целия файл

@@ -59,8 +59,9 @@

- 使用 `Node / Series / Parallel` 表达式树建立梯形图逻辑模型,支持嵌套串并联关系。
- 支持节点前后串联插入、与节点并联、与整个支路并联、删除和输出线圈配置。
- 实现常开、常闭、上升沿、下降沿、T 触点、普通线圈、置位/复位、TON 以及 D 值与常量比较。
- 上升沿和下降沿按一次扫描脉冲执行;TON 使用离线执行器的 `steady_clock` 和 T 资源表,不为每个 TON 创建独立 Qt 定时器。
- 实现常开、常闭、上升沿、下降沿、T/C 触点、普通线圈、置位/复位、TON、CTU/CTD、MOVE、ADD/SUB 以及 D 值与常量比较。
- 上升沿和下降沿按一次扫描脉冲执行;TON 使用离线执行器的 `steady_clock` 和 T 资源表,不为每个 TON 创建独立 Qt 定时器;CTU/CTD 使用 C 资源和 D 区 CV,按上升沿计数。
- 明确 M/D 为外部地址、T/C 为离线资源;ADD/SUB 以有符号 16 位结果饱和处理溢出,不能让一次越界中止扫描。
- M/D 注释作为工程级地址元数据保存,网络注释作为 `LadderRung` 字段保存,两者都不改变寄存器轮询行为。
- 新增节点类型时使用独立配置类型,不向通用节点结构持续堆叠无关字段。
- 编辑器只生成逻辑模型,不直接修改 HMI 或 PLC。
@@ -71,9 +72,9 @@

## 8. 实现离线仿真运行

- 实现虚拟 M/D 寄存器和固定周期的软件逻辑执行器,T 仅作为离线仿真内部资源。
- 实现虚拟 M/D 寄存器和固定周期的软件逻辑执行器,T/C 仅作为离线仿真内部资源,计数器 CV 通过 D 地址可观测
- 将 HMI、虚拟寄存器和控制逻辑形成完整闭环。
- 验证 TON 的接通延时、断开复位、多个 T 独立计时和网络顺序语义。
- 验证 TON 的接通延时、断开复位、多个 T 独立计时、CTU/CTD 上升沿计数、复位/完成状态、MOVE ADD/SUB 的网络顺序语义。
- 实现启动、停止、异常和当前运行状态反馈。
- 记录节点、支路和网络导通轨迹,在画布突出导通路径和故障节点。



Зареждане…
Отказ
Запис