Explorar el Código

docs: 更新多字数值类型与项目说明

main
suyu hace 3 semanas
padre
commit
61e3022da3
Se han modificado 8 ficheros con 106 adiciones y 106 borrados
  1. +6
    -5
      docs/XDH-60T4-E指令与Modbus要点.md
  2. +50
    -79
      docs/ai/handoff.md
  3. +3
    -3
      docs/architecture.md
  4. +11
    -8
      docs/二次开发/信捷D寄存器与浮点扩展说明.md
  5. +14
    -4
      docs/工程格式说明.md
  6. +5
    -5
      docs/测试约定.md
  7. +16
    -1
      docs/用户使用/数据监控与离线初始值说明.md
  8. +1
    -1
      docs/用户使用/数量边界确认方案.md

+ 6
- 5
docs/XDH-60T4-E指令与Modbus要点.md Ver fichero

@@ -16,7 +16,7 @@ XDH 的实际软元件范围远大于项目范围:普通 M 区为 `M0~M199999`

M 是普通辅助继电器,不可直接驱动外部负载;真机设备是否动作由 PLC 内部程序决定。D 是数据寄存器,单个 D 默认按带符号 16 位数处理,范围为 `-32768~32767`。

32 位数据由两个相邻 D 寄存器组成:起始 D 为低字,后一个 D 为高字,例如 `D10~D11` 组成一个 Float32。HMI 数值控件和自由监控可选择 `Int16` 或 `Float32`,梯形图普通比较、MOVE、ADD、SUB 仍只按 16 位整数执行。
32 位数据由两个相邻 D 寄存器组成,64 位数据由四个相邻 D 寄存器组成。起始 D 保存最低 16 位,后续地址依次保存更高的 16 位。例如 Int32/Float32 的 `D10~D11` 顺序是“低字、高字”,Double 的 `D10~D13` 组合顺序是 `(D13,D12,D11,D10)`。HMI 数值控件和自由监控可选择 `Int16`、`Int32`、`Float32` 或 `Double (Float64)`;Double 使用偶数首地址且最大为 `D3996`。梯形图普通比较、MOVE、ADD、SUB 仍只按 16 位整数执行。

来源:基本指令篇印刷页 35、44。

@@ -65,7 +65,7 @@ XDH 的 Modbus 可访问范围为 `M0~M20479` 和 `D0~D20479`,所以项目约
| `0x0F` | 写多个线圈 | M 区 | 后续批量写入使用,初版可不做 UI 入口。 |
| `0x03` | 读保持寄存器 | D 区 | 读取数值、参数和状态。 |
| `0x06` | 写单个保持寄存器 | D 区 | Int16 数值输入写一个 D。 |
| `0x10` | 写多个保持寄存器 | D 区 | Float32 一次写入连续两个 D。 |
| `0x10` | 写多个保持寄存器 | D 区 | Int32/Float32 一次写入连续两个 D,Double 一次写入连续四个 D。 |

本期联机不使用 X、Y、S、SM、HD 等其他软元件,也不需要实现 PLC 作为 Modbus 主站的编程指令。

@@ -108,8 +108,8 @@ HMI 控件不直接收发串口数据。通信服务更新联机寄存器缓存
### 5.2 读写策略

1. 合并 HMI、报警、梯形图和自由监控实际引用的 M/D 地址。
2. 合并相邻地址,分别使用 `0x01` 批量读 M 区、`0x03` 批量读 D 区。
3. 用户点击按钮时使用 `0x05` 写 M 区;提交 Int16 数值时使用 `0x06` 写一个 D,提交 Float32 时使用 `0x10` 一次写两个连续 D。
2. 合并相邻地址,分别使用 `0x01` 批量读 M 区、`0x03` 批量读 D 区。单个 D 读块最多 120 字,拆块时不得切开 Int32、Float32 或 Double 的连续占用范围。
3. 用户点击按钮时使用 `0x05` 写 M 区;提交 Int16 数值时使用 `0x06` 写一个 D,提交 Int32/Float32 时使用一次 `0x10` 写两个连续 D,提交 Double 时使用一次 `0x10` 写四个连续 D。
4. 写入成功后等待下一次轮询确认实际值,不以本地点击状态代替 PLC 响应。
5. 超时、CRC 错误或 Modbus 异常响应时保留最后一次有效值,并在状态栏和日志中报告错误。

@@ -131,7 +131,8 @@ HMI 控件不直接收发串口数据。通信服务更新联机寄存器缓存
3. PC 发送 `0x01` 读取 `M0`,确认能得到合法 RTU 响应。
4. PC 发送 `0x03` 读取 `D0`,确认寄存器解析正确。
5. 在安全的测试程序中使用 `0x05` 写 `M0` 和 `0x06` 写 `D0`,通过 PLC 监控或 HMI 页面确认写入结果。
6. 完成单点验证后,再开启页面轮询和完整 HMI 联动。
6. PLC 保持 STOP,先读取一组连续 D 原值,再分别验证 Int32、Float32 和 Double 的单次 `0x10` 写入与读回;测试结束后恢复所有原值并再次读回确认。
7. 完成单点和多字验证后,再开启页面轮询和完整 HMI 联动。

## 7. 资料出处



+ 50
- 79
docs/ai/handoff.md Ver fichero

@@ -4,86 +4,57 @@

## 当前状态

- 梯形图使用连续网格模型:每行固定 10 个 `LadderCell`,输出槽独立保存,竖线使用相邻行之间的 `VerticalConnection`
- 工程 JSON 固定为严格 `2.0`;旧 `1.0` 工程直接拒绝,不实现兼容迁移
- 软件逻辑执行器按列传播电源并处理竖线连通分量;离线仿真和真机本地推算的边界保持不变
- `当前窗口需求.md` 的第 1~6 项均已完成:连续网格渲染、统一布局、批量选择删除、编辑后光标前进、内嵌连续输入和逐段运行轨迹均已落地
- 本轮已修复运行轨迹快照重复投影、空行直接输出不补横线、断路输出仍可进入运行三项回归问题
- 梯形图复制粘贴已改为统一片段模型:单横线不再丢失或误复制整行,普通对象片段和明确整行片段使用不同选择语义
- 信捷式语法检查已经落地:`Ctrl+G` 会自动规整当前梯形图的无效横竖线,断路输出保留现场并定位到第 11 列;离线、真机和导出前检查全部已启用逻辑

## 画布渲染与布局

- `LogicEditorWidget` 已将网格、梯形图内容和选择覆盖层拆开,选择框统一位于 `z=100`,不再被相邻网格覆盖右边或下边
- 网格层按整行一次填充统一画布底色,触点、横线、`Gap` 和输出槽不再使用不同语义底色
- 条件区按常开、常闭、上升沿、下降沿和比较块绘制;输出区按普通/SET/RST 线圈及 MOV/ADD/SUB 指令块绘制,数据块显示完整操作数
- 输出区位于条件网格和右母线之间;左右母线使用同一画笔,并严格止于第一行顶部和最后一行底部
- 画布先生成统一 `RowLayout`;网络分组由相邻行之间是否存在竖线动态推导,绘制和命中测试共同使用布局表
- 左侧只显示三位视觉行号;每个网络首行上方预留独立注释带并使用绿色文字,支路行注释不重复显示

## 选择与删除

- 选择模式支持左键橡皮筋框选,触点、横线、输出块和竖线可跨行混选
- 普通拖动替换选择,`Ctrl+拖动`追加选择,`Ctrl+单击`切换单个对象;空格只作为编辑光标,不进入删除请求
- `LogicSelectionDeleteRequest` 将条件/横线网格、输出行和竖线 ID 一次提交给 `LogicEditorService::deleteSelection`
- 服务会先校验完整请求,再一次清空网格、输出和竖线;结构校验失败会恢复模型及工程修改状态
- 一次批量删除只生成一条撤销记录,单次撤销/重做恢复或重删全部对象
- 普通 `Delete` 删除选择集,整行删除快捷键为 `Shift+Delete`

## 复制和粘贴

- `LogicClipboardFragment` 统一保存网格对象片段或整行片段,主窗口不再分别维护条件、输出和行三套剪贴板
- 单击或框选横线、条件、输出和竖线时保存相对行列;未选位置透明,普通复制不把 `Gap` 作为覆盖内容
- 当前光标行和明确整行选择已经拆开;只有点击左侧行号才复制整行,多行整行选择要求视觉连续
- 整行片段保存完整 10 格、输出、网络注释和选中行内部的竖线,粘贴到当前行之后
- 单输出可明确替换输出槽;混合输出冲突、节点冲突、越过第 10 列、跨行不足、末行竖线和行数上限都会在修改前整次拒绝
- 所有新节点、行和竖线重新分配 ID;一次粘贴只生成一条撤销记录,失败不改变模型、修改状态或历史,成功后新对象保持选中

## 连续输入与光标前进

- `LogicEditorService` 统一提供“应用指令并返回下一光标”的编辑结果,工具栏、快捷键和命令语输入共享同一套业务规则
- 空逻辑上插入横线或触点时,服务在一个事务内创建首行并写入第 1 格;成功后逐格右移,第 10 格完成后进入输出槽
- 输出成功后跳到当前网络分组后面的第一个网格;当前分组已经位于末尾时,输出和追加完整空行在一个事务内完成,只生成一条撤销记录
- 完全空行直接写输出时自动生成 10 格 `Wire`;已有内容时只补最右有效内容后的尾部 `Gap`,中间的明确断点保持不变
- 输出事务会在修改前检查行数等边界;追加失败时不会留下已写输出、半行数据或额外撤销记录
- 画布内嵌 `QLineEdit` 和指令补全已恢复;双击网格或输出槽可连续输入,`Enter` 提交、`Escape` 取消,输入错误时保留编辑框并显示错误状态
- 连续输入提交条件后右移,走完第 10 列进入输出槽,输出确认后继续停在下一网络首格;滚动和窗口尺寸变化时输入框跟随目标位置

## 运行轨迹

- 运行态不再使用整格绿色背景;横线、触点左端、触点符号及右端、比较块输入输出线、输出连接线、输出符号和竖线分别读取对应轨迹值着色
- 未导通线路统一使用普通深色,导通线路统一使用监控绿色,故障红色优先;选择覆盖层继续位于最上层
- 竖线只在 `verticalConnectionValues` 明确导通时变绿,缺少轨迹值时保持深色;左右母线使用同一普通颜色
- 控制器和运行监控传递完整 `LogicTraceSnapshot`,只有最终画布按当前逻辑 ID 投影一次;不再因连续调用 `forLogic()` 清空轨迹
- 离线执行器回归覆盖正反转启动、自锁、互锁和停止状态,并校验触点左右端及右侧竖线的真实电源传播

## 语法检查与运行前校验

- `LogicEditorService::checkSyntax()` 同时执行线路规整和语法检查;只删除 `Wire` 和 `VerticalConnection`,不会删除触点、指令或输出
- 已有完整输出路径的网络只保留参与左母线到输出完整路径的线路;没有输出的悬空线路全部删除,一次规整只生成一条撤销记录
- 输出网络已经断路时保留整个网络现场,返回控制逻辑、网络、视觉行、第 11 列输出槽以及实际断开列;未配置指令返回自身行列
- 主窗口输出栏保存结构化错误位置,双击错误可切换控制逻辑、选中对应网格或输出槽并滚动到可见区域
- `ControlLogic::validateForRunning()` 按列传播结构可达性,并在每个边界合并 `VerticalConnection` 支路
- 带输出的行必须存在一条从左母线到输出槽的完整路径;不可达时错误包含控制逻辑、视觉行和断开列
- 没有输出的自动追加空行允许保留;并联网络中的单条 `Gap` 断路支路也允许保留,只要输出仍能从其他支路到达
- 离线入口、完成 PLC 首读后的真机入口和用户运行程序导出先共用服务层规整和语法检查,再执行领域运行校验;真机未首读时仍优先返回首读未完成
- “双线圈检查”是单独菜单动作,定位第二个重复 M 线圈输出;不混入普通语法检查,也不会在运行前自动阻断
- `当前窗口需求.md` 的多字数值扩展已完成:现有 `Int16/Float32` 链路已扩展为 `Int16/Int32/Float32/Float64`
- HMI 数值显示/输入、编辑态数据监控、运行态自由监控、离线初始值、工程 JSON、地址冲突检查、PLC 轮询和 Modbus 写入均使用同一套类型与连续字规则
- 项目仍只生成和运行本地 HMI/梯形图仿真,不生成、编译或下载 PLC 程序;真机本地梯形图轨迹仍只读 PLC 缓存并在临时仓库推算
- 本轮没有实现 Int64、无符号数、二/八/十六进制、ASCII、POU 变量监控、信捷原版寄存器网格或自定义监控偏移
- TouchWin 没有原生 Double64 数值控件;本项目的 `Double (Float64)` HMI 是基于 PLC 连续四个 D 的增强能力

## 类型与地址规则

| 类型 | 占用字数 | 起始地址 | 输入规则 |
| --- | ---: | --- | --- |
| `Int16` | 1 | `D0~D4000` | `-32768~32767` 的整数 |
| `Int32` | 2 | `D0~D3999` | `-2147483648~2147483647` 的整数 |
| `Float32` | 2 | `D0~D3999` | 有限 IEEE-754 单精度值 |
| `Float64` | 4 | 偶数 `D0~D3996` | 有限 IEEE-754 双精度值 |

- 多字值固定按信捷顺序保存:低地址是低 16 位,地址递增时依次保存更高的 16 位
- `Int32Codec`、`Float32Codec`、`Float64Codec` 和统一数值 variant 负责类型化读写;底层仓库仍只保存原始 16 位字
- Float32 显示 9 位有效数字,Double 显示 17 位有效数字;浮点输入使用 C locale 并支持科学计数法,NaN、Inf 和溢出值拒绝
- Double 奇数首地址、Int32/Float32 的 `D4000`、Double 的 `D3997` 及其他越界范围在领域层拒绝

## HMI、监控与工程

- HMI 属性面板和运行输入支持四种 D 类型;Int16/Int32 使用整数输入,Float32/Double 使用科学计数法文本输入
- HMI 多字绑定按完整字范围检查:相同地址和相同类型允许重复绑定,部分重叠或同起始地址不同类型拒绝
- MOVE、ADD、SUB 仍是 16 位整数指令,禁止写入任何 Int32、Float32 或 Float64 HMI 值占用的 D
- 编辑态数据监控和运行态自由监控继续共用 `RegisterMonitorService`;Int32/Float32 批量步长为 2,Double 步长为 4,类型列显示完整占用范围
- 多字离线初始值按连续字块完整捕获;停止仿真后恢复 Int32/Float32/Double 的全部占用字
- 监控表最多 64 行,PLC 上限按去重后的实际 16 位 M/D 地址计数,最多 256 个;候选监控集合会在提交前验证,失败不留下部分监控点
- 工程 JSON 仍是严格 `formatVersion: "2.0"`,`dataType` 新增 `int32` 和 `float64`;未知的 `int64` 等枚举直接拒绝

## PLC 通信

- 仓库增加通用 `readWords/writeWords` 连续字接口;虚拟仓库完整校验后一次复制,PLC 仓库保留 Int16 单字通道并为 2~4 字值使用多字通道
- Int16 继续写一个 Holding Register;Int32、Float32 和 Double 分别把 2 个或 4 个连续字放在一次多寄存器请求中发送
- 轮询元数据从 Float32 起始地址泛化为连续 `RegisterWordRange`;每个读块最多 120 字,拆块边界不会切开 2 字或 4 字值
- 地址和多字范围在当前异步回复结束后一起切换;候选配置失败时运行模式和监控模型都恢复旧状态
- PLC 缓存仍只在真实轮询读回后更新,不以写请求受理代替设备确认

## 最近验证

- `domain_tests` Release 通过,覆盖断路输出拒绝和竖线并联支路绕过断点
- `logic_editor_service_tests` Release 通过,除既有编辑、复制和输出事务外,覆盖无效横竖线规整、有效并联旁路保留、断路网络保留、一次撤销及独立双线圈检查
- `runtime_mode_service_tests` Release 通过,覆盖运行前先规整独立残线、同一断路详情阻止离线和完成首读后的真机运行
- `runtime_panel_controller_tests` Release 通过,覆盖完整执行器轨迹、画布布局、框选、连续输入、复制粘贴,以及语法错误的条件格和第 11 列输出槽定位
- 网格背景像素回归通过,触点、横线、`Gap` 和输出槽的非线路区域采样颜色完全一致
- `offline_simulation_service_tests` Release 通过,覆盖正反转启动、自锁、互锁、停止及分段电源轨迹
- 13 个 Release Functional 测试目标全量通过
- 主程序已重新构建到 `build/release/release/integrated_platform.exe`,离屏启动 3 秒正常保持 Qt 事件循环
- `git diff --check` 通过;只有工作区既有 `runtime_mode_service_tests.cpp` 的 CRLF/LF 转换提示,没有空白错误
- 尚未连接真实 PLC;本轮修改的是编辑事务、运行前静态校验和离线/本地轨迹投影,不涉及设备写入,因此未做 COM3 真机验证
- 真机模式仍只读取 PLC 缓存并在本地推算梯形图轨迹,不生成、下载或写入 PLC 程序

## 下一步

- 人工桌面检查常开/常闭/沿触点、SET/RST、比较、MOV/ADD/SUB 的视觉比例,以及不同系统缩放下的框选边框和内嵌输入框位置
- 有真实接线和已确认寄存器地址后,再单独验证真机读回轨迹;验证过程仍不得向 PLC 下载本地梯形图
- 新增回归覆盖 Int32 最小/最大值和负数、Float32 `20.0` 字序、Double `1.0` 字序、Double 偶数地址、NaN/Inf、JSON 往返、HMI 复制粘贴、多字冲突和 16 位梯形图写入保护
- 监控回归覆盖四类型批量步长、完整轮询地址、离线初始值捕获、停止仿真恢复、64 行与 256 实际地址上限的候选拒绝
- PLC 回归覆盖 Int16 单字路径、Int32/Double 一次多字回调、Double `D118~D121` 不跨 120 字边界、无法合法拆分的重叠范围拒绝和地址集合原子切换
- Qt Release 主程序已重新构建到 `build/release/release/integrated_platform.exe`,离屏启动 3 秒正常保持事件循环
- `git diff --check` 通过;工作区只有 `runtime_mode_service_tests.cpp` 的 CRLF/LF 转换提示,没有空白错误
- 当前 Windows 没有枚举到串口设备,无法使用 `COM3 / 9600 / 8E1 / 站号 1` 做真实 PLC 多寄存器写入,因此本轮没有伪造真机结果

## 工作区与下一步

- 当前改动尚未提交 Git
- 开始本轮前已有的 `docs/工程格式说明.md`、`docs/用户使用/数量边界确认方案.md` 和旧交接修改均已保留并增量合并,没有回退来源不明的改动
- 设备可用后在 PLC STOP 状态先读取一组连续 D 原值,分别验证 Int32、Float32、Double 的一次多寄存器写入与读回,再恢复全部原值并读回确认
- 人工打开 HMI 页面和数据监控,检查四类型下拉框、Double 偶数地址提示、长数值显示和不同系统缩放下的输入框布局

+ 3
- 3
docs/architecture.md Ver fichero

@@ -69,7 +69,7 @@ Project
- 梯形图是连续网格:`Gap/Wire/Node` 是独立格子对象,竖线连接相邻行列边界,插入/删除行会维护连接关系,删线即可拆分网络
- 当前编辑页面和当前逻辑是 UI 会话状态,不写入工程
- HMI 控件类型、默认值、绑定规则和运行值类型由无 Qt 依赖的 `hmi_control_registry` 统一描述
- HMI 数值控件通过 `RegisterDataType` 选择 `Int16` 或 `Float32`;底层仓库始终保存原始 16 位 D 字,`Float32Codec` 负责低字/高字组合
- HMI 数值控件通过 `RegisterDataType` 选择 `Int16`、`Int32`、`Float32` 或 `Float64`;底层仓库始终保存原始 16 位 D 字,统一编解码层按低地址低字顺序组合 1、2 或 4 个连续 D
- 需要寄存器的 HMI 控件、报警条件和梯形图节点直接保存 M/D 地址;项目不再维护统一 `dataPoints` 表
- `registerComments` 只是 M/D 地址元数据,不保存当前值或引用位置,也不会让地址自动进入 PLC 轮询

@@ -178,7 +178,7 @@ PLC <-> PlcCommunicationService <--------------------┘

离线和真机不能直接互切。进入真机不复制或下发离线值;本地轨迹从最新 PLC 缓存开始推算,只表示 PC 根据缓存计算出的结果,不是 PLC 内部真实轨迹。

自由监控是会话级诊断工具,不属于 `Project`,不写入 JSON。每个监控点可选 `Int16` 或 `Float32`,Float32 批量添加按 2 个 D 偏移并显示实际占用范围;完全重复点拒绝,部分重叠点允许添加但提示。它通过活动仓库读取 M/D 或成对读取 Float32,并通过单字或双字请求写入;真机写入仍必须经过连接与首读门槛
自由监控是会话级诊断工具,不属于 `Project`,不写入 JSON。M 监控点固定为位值,D 监控点可选 `Int16`、`Int32`、`Float32` 或 `Float64`。批量添加的步长等于类型占用字数:Int16 为 1,Int32/Float32 为 2,Float64 为 4;类型列显示完整占用范围。完全重复点拒绝,部分重叠点允许添加但提示。读写统一使用连续字块接口;真机 Int16 使用单字写入,Int32、Float32 和 Float64 使用一次多保持寄存器写入,并继续受连接与首读门槛约束

编辑态数据监控写入虚拟 M/D 时,同时更新当前进程内的离线初始值仓库。启动离线仿真时,运行仓库先清空,再复制这份初始值;仿真扫描产生的线圈、MOVE、ADD 和 SUB 结果只写入本轮运行仓库。仿真停止或返回编辑态时丢弃本轮输出并恢复初始值。离线初始值和监控地址均不写入工程 JSON。运行态监控继续复用同一 `RegisterMonitorService`,离线写入虚拟仓库,真机写入 PLC 缓存并等待轮询确认。

@@ -188,7 +188,7 @@ PLC <-> PlcCommunicationService <--------------------┘

PLC 配置窗口的自动搜索使用独立 `PlcDiscoveryService`,不复用正式轮询主站,避免搜索失败污染连接状态、缓存和首读资格。搜索固定使用界面当前站号,优先当前串口参数,再异步遍历全部可用 PC 串口和项目允许的 60 组波特率、数据位、校验位及停止位组合;每组参数只读 `D0`,正常响应或合法 Modbus 异常响应都能证明端口、站号和串口帧匹配。找到后必须先释放搜索串口,再把参数交给原有正式连接流程;取消或全部失败时不保留搜索连接。

轮询集合由 HMI、报警、梯形图中的显式 M/D 引用和自由监控地址合并,按区域去重并合并相邻地址。Float32 的起始地址同时作为成对读取元数据传入通信层;拆分 120 字上限时会调整边界,保证两个连续保持寄存器不会分到不同请求。横线、断路和注释不进入轮询。动态修改监控地址时,当前请求按旧快照解析,空闲后再应用新集合。真机本地轨迹只在全部读块成功完成一轮后推算一次,不在单个读块更新时重复扫描。
轮询集合由 HMI、报警、梯形图中的显式 M/D 引用和自由监控地址合并,按区域去重并合并相邻地址。Int32、Float32 和 Float64 的起始地址及占用字数作为连续范围元数据传入通信层;拆分单次最多 120 字的读块时会向前调整边界,保证一个 2 字或 4 字值不会被切到两个请求。监控表最多 64 行,但 PLC 的 256 上限按去重后的实际 16 位 M/D 地址计数,因此 64 个 Double 已占满 256 个 D 地址,若还有 HMI、报警或梯形图地址会在添加监控点前原子拒绝。横线、断路和注释不进入轮询。动态修改监控地址时,当前请求按旧快照解析,空闲后再同时应用新地址和多字范围。真机本地轨迹只在全部读块成功完成一轮后推算一次,不在单个读块更新时重复扫描。

PLC 缓存只保存最后一次成功读回值。写请求受理后不乐观修改缓存,界面等待后续轮询确认真实值。真机运行资格属于当前连接代次:必须完成完整首读,旧连接的异步回复不能污染重连后的状态。



+ 11
- 8
docs/二次开发/信捷D寄存器与浮点扩展说明.md Ver fichero

@@ -1,6 +1,6 @@
# 信捷 D 寄存器与浮点扩展说明

> 这份文档给后续二次开发使用,说明 D 区的基本规则和当前 Float32/REAL 实现边界。
> 这份文档给后续二次开发使用,说明 D 区的基本规则和当前多字数值实现边界。

## 1. D 寄存器到底是什么

@@ -41,19 +41,22 @@ Modbus 把每个 D 当作一个 16 位保持寄存器:

当前版本支持:

- HMI 数值控件选择 `Int16` 或 `Float32`
- 自由监控选择 `Int16` 或 `Float32`;Float32 批量地址步长为 2,重叠点允许但会提示
- `Float32` 输入支持普通小数和科学计数法,拒绝 NaN、无穷值和 Float32 溢出
- HMI 数值控件和自由监控选择 `Int16`、`Int32`、`Float32` 或 `Double (Float64)`
- Int32/Float32 批量地址步长为 2,Double 步长为 4;完全重复点拒绝,部分重叠点允许但会提示
- Float32/Double 输入支持普通小数和科学计数法,拒绝 NaN、无穷值和类型溢出;Int32 只接受有符号 32 位整数
- Double 只允许偶数首地址,最大起始地址为 `D3996`
- 梯形图的比较、MOVE、ADD/SUB 按 16 位 D 值运行
- PLC 轮询按单个 D 地址收集和合并,并保证 Float32 的两个字不会跨读请求拆开
- Float32 写入使用一次写两个连续保持寄存器;PLC 缓存等待轮询读回,不做乐观修改
- PLC 轮询按单个 D 地址收集和合并,并保证 2 字或 4 字值不会跨 120 字读请求拆开
- Int32/Float32 使用一次多寄存器请求写两个连续 D,Double 使用一次请求写四个连续 D;PLC 缓存等待轮询读回,不做乐观修改

不要为了接入浮点,直接把底层寄存器仓库改成 `float`。底层继续保存原始 16 位字,类型转换集中在 `Float32Codec` 和上层服务。
不要为了接入多字类型,直接把底层寄存器仓库改成 `float` 或 `double`。底层继续保存原始 16 位字,类型转换集中在寄存器数值编解码层和上层服务。

## 5. 后续接入建议

后续增加双字、四字或 `Float64/LREAL` 时,复用“类型决定占用字数、连续读写、统一编解码、重叠刷新”的流程。新类型必须增加独立编解码、地址边界、轮询分块和写入请求测试。只有需求明确时才扩展浮点梯形图指令或浮点报警,不能修改现有普通整数指令语义。
后续增加其他类型时,继续复用“类型决定占用字数、连续读写、统一编解码、重叠刷新”的流程。新类型必须增加独立编解码、地址边界、轮询分块和写入请求测试。当前明确不实现 Int64、无符号数、二/八/十六进制、ASCII、POU 变量监控和自定义监控偏移;只有需求明确时才扩展浮点梯形图指令或浮点报警,不能修改现有普通整数指令语义。

只有当浮点数据真的需要参与梯形图比较、报警或运算时,才继续扩展浮点逻辑指令。不要只做一个浮点显示控件,却让其他模块仍按 16 位整数处理同一组 D。

TouchWin 手册中的数值显示和输入只提供 Word/DWord,没有原生 Double64 控件。本项目的 Double HMI 是基于 PLC 四个连续 D 的增强能力,不描述为 TouchWin 控件复刻。

参考手册:《XD、XL系列可编程控制器用户手册(基本指令篇)》印刷页 44、122、157~158、483。

+ 14
- 4
docs/工程格式说明.md Ver fichero

@@ -64,7 +64,7 @@

`type` 只接受表中列出的控件类型。其他类型按严格 `2.0` 规则直接拒绝加载,不做兼容迁移。

数值显示和数值输入控件必须额外保存 `dataType`,值只能是 `int16` 或 `float32`:
数值显示和数值输入控件必须额外保存 `dataType`,值只能是 `int16`、`int32`、`float32` 或 `float64`:

```json
{
@@ -78,7 +78,16 @@
}
```

`int16` 只占起始 D 一个字,沿用现有有符号 16 位逻辑。`float32` 使用 IEEE-754 单精度,占用起始 D 和下一个 D,低地址保存低字、高地址保存高字;起始地址只能是 `D0~D3999`。数值控件之间允许相同起始地址和相同类型重复绑定,部分重叠或类型冲突会被拒绝。工程格式固定为严格 `2.0`,数值控件缺少 `dataType` 时加载失败。
四种数值类型的 JSON 与地址规则如下:

| `dataType` | 含义 | 占用字数 | 有效起始地址 |
| --- | --- | ---: | --- |
| `int16` | 有符号 16 位整数 | 1 | `D0~D4000` |
| `int32` | 有符号 32 位整数 | 2 | `D0~D3999` |
| `float32` | IEEE-754 单精度浮点 | 2 | `D0~D3999` |
| `float64` | IEEE-754 双精度浮点,界面显示为 `Double (Float64)` | 4 | 偶数首地址 `D0~D3996` |

多字值统一按信捷字序保存:低地址放低 16 位,地址递增时依次保存更高的 16 位。数值控件之间允许相同起始地址和相同类型重复绑定,部分重叠或同起始地址不同类型会被拒绝。工程格式仍固定为严格 `2.0`,字段结构没有升级;数值控件缺少 `dataType` 或使用 `int64` 等未知枚举时加载失败。旧程序无法打开包含新增枚举值的工程。

按钮操作字符串为 `setOn`、`setOff`、`toggle` 或 `momentaryOn`。PageJump 使用目标页面稳定 ID,不使用名称或数组位置:

@@ -96,7 +105,7 @@

编辑草稿允许 `targetPageId` 为空字符串,但进入运行态前必须配置为现存页面 ID。任何页面被 PageJump 引用时不得删除。

AlarmList 只负责显示项目级当前报警,不保存独立触发逻辑,也不直接绑定单个寄存器。编辑界面的标题输入上限为 12 个字符。多个页面放置 AlarmList 时共享同一组当前报警和确认状态。运行态没有报警时控件隐藏;有报警时按当前页的实际记录数收缩高度,每页最多显示 5 条。超过 5 条时通过表头翻页按钮查看,记录不会被丢弃。标题和报警文本按单行绘制,空间不足时显示省略号。报警恢复后对应记录立即移除,最后一条报警恢复后控件再次隐藏
AlarmList 只负责显示项目级当前报警,不保存独立触发逻辑,也不直接绑定单个寄存器。编辑界面的标题输入上限为 12 个字符。多个页面放置 AlarmList 时共享同一组当前报警和确认状态。运行态始终按编辑时设置的位置和尺寸显示控件;有报警时逐行显示,没有报警时显示空状态。每页最多显示 5 条,超出时通过表头翻页按钮查看,记录不会被丢弃。标题和报警文本按单行绘制,空间不足时显示省略号。报警恢复后对应记录立即移除,不改变控件的可见性和尺寸

## 报警定义

@@ -110,11 +119,12 @@ AlarmList 只负责显示项目级当前报警,不保存独立触发逻辑,
}
```

`alarmDefinitions` 是项目级有序数组,报警 ID 必须唯一。触发条件只包含当前业务需要的种:
`alarmDefinitions` 是项目级有序数组,报警 ID 必须唯一。触发条件只包含当前业务需要的种:

| `condition` | 地址区域 | 触发规则 |
| --- | --- | --- |
| `mOn` | M | 位值为 ON |
| `mOff` | M | 位值为 OFF |
| `dHigh` | D | 字值大于等于 `threshold` |
| `dLow` | D | 字值小于等于 `threshold` |



+ 5
- 5
docs/测试约定.md Ver fichero

@@ -16,19 +16,19 @@

| 测试目标 | 主要契约 |
| --- | --- |
| `domain_tests` | 地址、模型、数量边界、Float32 编解码和带竖线并联的输出路径可达性校验 |
| `domain_tests` | 地址、模型、数量边界、Int16/Int32/Float32/Float64 编解码和带竖线并联的输出路径可达性校验 |
| `application_settings_tests` | 默认配置创建、严格 INI 校验、缺失与未知字段、版本和整份回退 |
| `alarm_service_tests` | 报警定义和运行记录生命周期 |
| `hmi_editor_service_tests` | HMI 编辑、原子删除、历史、导航和 Float32 数值控件读写 |
| `hmi_editor_service_tests` | HMI 编辑、原子删除、历史、导航和四种 D 数值控件读写 |
| `logic_editor_service_tests` | 连续网格编辑、输出自动补尾线、网格与整行片段复制粘贴、冲突回滚和历史 |
| `offline_simulation_service_tests` | 梯形图扫描语义、离线初始 M/D 快照、真机缓存副本推算、只读隔离、跨扫描状态和故障处理 |
| `project_management_tests` | JSON 往返、非法文件和工程保存状态 |
| `register_monitor_service_tests` | 监视地址、Int16/Float32 读写、离线初始值捕获、批量步长、重叠提示和活动仓库 |
| `register_monitor_service_tests` | 监视地址、四种 D 类型读写、离线初始值捕获、批量步长、重叠提示和活动仓库 |
| `runtime_project_bundle_tests` | 用户运行程序封装的写入、读取、校验和损坏拒绝 |
| `runtime_mode_service_tests` | 编辑、离线、真机只读轨迹、仓库切换和断路工程启动拦截 |
| `runtime_panel_controller_tests` | 完整执行器快照经过控制器和运行窗口后的轨迹投影、排队回调、画布框选、对象/行号剪贴板和连续输入 |
| `plc_connection_dialog_tests` | PLC 端口刷新及自动搜索开始、取消、进度和参数回填 |
| `plc_runtime_tests` | PLC 缓存、完整轮询通知、成对轮询边界、错误恢复和 Fake gateway |
| `plc_runtime_tests` | PLC 缓存、完整轮询通知、多字范围拆块、一次多寄存器写入、错误恢复和 Fake gateway |

同一规则只在成本最低、失败定位最清楚的层验证:

@@ -95,4 +95,4 @@ pwsh -NoLogo -NoProfile -File .\scripts\run_qt_tests.ps1 -Configuration Release
4. 按风险决定是否重新执行真实 PLC 实测;未重测时引用已有验收记录并说明原因
5. 运行 `git diff --check`

Float32 真机验收还要确认:写入一次发送两个连续保持寄存器,轮询读回后界面才刷新;测试结束恢复 D 起始字和下一个 D 的原值并再次读回确认。
多字类型真机验收还要确认:Int32/Float32 一次发送两个连续保持寄存器,Double 一次发送四个连续保持寄存器,轮询读回后界面才刷新;测试结束恢复全部占用 D 的原值并再次读回确认。

+ 16
- 1
docs/用户使用/数据监控与离线初始值说明.md Ver fichero

@@ -4,14 +4,29 @@

打开主窗口与“HMI 页面”“控制逻辑”并列的“数据监控”编辑页,添加需要观察的 `M` 或 `D` 地址。编辑态写入的 M/D 不会写入 PLC;它们会同时保存为当前进程内的离线仿真初始值。

M 地址只按 ON/OFF 位值监控。D 地址可选择四种类型:

| 类型 | 占用 D 字数 | 批量添加步长 | 起始地址规则 |
| --- | ---: | ---: | --- |
| `Int16` | 1 | 1 | `D0~D4000` |
| `Int32` | 2 | 2 | `D0~D3999` |
| `Float32` | 2 | 2 | `D0~D3999` |
| `Double (Float64)` | 4 | 4 | 偶数 `D0~D3996` |

多字值的类型列会显示完整占用范围,例如 `Int32 (D10~D11)` 和 `Double (Float64) (D20~D23)`。Int32 只接受范围内整数;Float32 和 Double 接受普通小数或科学计数法,但不接受 NaN、无穷值和类型溢出。所有多字值都按低地址低字的信捷顺序解释。

监控表最多 64 行;PLC 轮询上限则按去重后的实际 16 位 M/D 地址计算,最多 256 个。一个 Int32/Float32 占 2 个轮询地址,一个 Double 占 4 个,因此 64 个 Double 已占满 PLC 地址配额,不能再叠加新的 HMI、报警或梯形图地址。添加操作会先验证候选集合,超限时整次拒绝,不会留下半套监控点。

## 离线仿真

点击“离线运行”时,软件先清空上一轮运行值,再装载编辑态确认的初始 M/D。梯形图扫描产生的线圈、MOVE、ADD 和 SUB 结果只属于本轮仿真。

停止离线仿真或返回编辑态后,本轮运行输出会丢弃,监控面板恢复显示下一轮将使用的初始值。初始值只保存在当前进程,不写入工程 JSON。
Int32、Float32 和 Double 写入时会把占用的 2 个或 4 个 D 一起保存到初始值仓库。停止离线仿真或返回编辑态后,本轮运行输出会丢弃,监控面板完整恢复下一轮将使用的初始值。初始值只保存在当前进程,不写入工程 JSON。

## 真机运行

进入真机运行后使用同一个监控地址列表,但数据源切换为 PLC 读回缓存。写入请求必须在 PLC 已连接并完成有效首读后才能提交,写入结果等待后续轮询确认。

Int16 写一个保持寄存器;Int32、Float32 和 Double 分别把连续 2 个或 4 个保持寄存器放在同一次多寄存器请求中写入,避免通信中途失败留下半个新值。单次轮询最多读取 120 个字,拆块边界不会切开一个多字值。

真机监控写入的是 PLC 的 M/D 数据,不会修改 PLC 程序,也不会把本地梯形图推算结果写回 PLC。

+ 1
- 1
docs/用户使用/数量边界确认方案.md Ver fichero

@@ -37,7 +37,7 @@ HMI 页面宽度 `320~1600`、高度 `200~800` 仍是结构安全硬范围;`De
| 报警 | 报警定义数量 | 0 | 256 | 超过配置上限或第 257 条报警时不能创建或加载 | 报警每个刷新周期都要判断 |
| 报警 | 报警列表标题输入长度 | 0 字符 | 12 个字符 | 编辑界面限制继续输入 | 标题需要在表头为翻页控件保留空间,显示不下时使用省略号 |
| 报警 | 单条报警文本输入长度 | 1 字符 | 20 个字符 | 编辑界面限制继续输入 | 报警信息按单行显示并在宽度不足时使用省略号 |
| 报警 | 单页同时可见行数 | 1 行 | 5 行 | 超出后通过表头按钮翻页,活动记录不丢失 | 控制默认控件高度并避免少量报警产生大块留白 |
| 报警 | 单页同时可见行数 | 1 行 | 5 行 | 超出后通过表头按钮翻页,活动记录不丢失 | 控件始终保持编辑时设置的尺寸,当前页不足时保留空白行区域 |
| 注释 | M/D 软元件注释数量 | 0 | 8002 | 超出后拒绝保存或加载 | M0~M4000 和 D0~D4000 每个地址最多一条,共 8002 条 |
| 控制逻辑 | 控制逻辑数量 | 0 | 32 | 超过配置上限或第 33 组时不能创建或加载 | 控制工程树和扫描工作量 |
| 控制逻辑 | 每组逻辑的网络数量 | 0 | 256 | 超过配置上限或第 257 个网络时不能创建或加载 | 每次软件扫描都要执行这些网络 |


Cargando…
Cancelar
Guardar