diff --git a/docs/ai/handoff.md b/docs/ai/handoff.md index 80d0ca6..6421f3e 100644 --- a/docs/ai/handoff.md +++ b/docs/ai/handoff.md @@ -1,13 +1,13 @@ # 当前开发交接 -> 更新日期:2026-08-27。本文件只保留当前工作区、本轮改动、验证结果和后续人工检查项。 +> 更新日期:2026-08-29。本文件只保留当前工作区、本轮改动、验证结果和后续人工检查项。 ## 当前状态 - 测试程序已优化:功能测试入口按用例独立报告 `[PASS]/[FAIL]`,单个用例失败不会跳过同一目标的其他用例;HMI 数值运行测试拆出独立用例并去除重复原始字序断言 - 性能测试已调整为合法上限扫描、超限压力扫描、4001 个 M 位边界访问和 256 个 D 字连续块访问四项基准 - HMI 编辑态支持基础控件布局对齐:左、水平居中、右、顶部、垂直居中、底部;至少选中两个控件后从 HMI 工具栏“布局”菜单执行,对齐只修改控件位置并支持单步撤销/重做 -- `当前窗口需求.md` 的状态文本控件已完成,新增独立 `HmiControlType::StatusText`,普通 `Label` 保持固定文本职责 +- `docs/用户使用/状态文本控件说明.md` 的状态文本控件已完成,新增独立 `HmiControlType::StatusText`,普通 `Label` 保持固定文本职责 - M 状态支持一个 M 地址和 OFF/ON 两个显示文本,D 状态支持 `Int16/Int32/Float32/Float64` 以及最多 16 个连续区间 - D 区间统一为 `[下限, 上限)`,首个下限和末个上限必须为“不限”,相邻区间必须首尾相接,覆盖整个数值域 - 状态文本只读;离线从虚拟寄存器读取,真机从 PLC 轮询缓存读取;绑定缺失、仓库不可用、读取失败和 NaN/Inf 统一显示 `--` @@ -18,6 +18,11 @@ - 按钮启用条件配置使用独立 Qt Designer 对话框;支持 M 地址 + OFF/ON、D 地址 + 四种数据类型 + 六种比较方式 + 比较值 - 编辑态数据监控与运行态自由监控使用同一套读写行为:未连接 PLC 时读写虚拟 M/D,连接并完成首读后自动读写 PLC 缓存;PLC 首读期间禁止写入,编辑态 PLC 写入不更新离线初始值 - 普通编程器的运行监控窗口也提供离线/真机模式下拉切换;跨运行模式时自动经过编辑态,真机首读和工程校验失败会保持原运行态 +- 用户运行程序已经收敛为 HMI 专用运行版:导出时只保留 HMI 页面、报警和导航数据,移除控制逻辑与地址备注;运行版隐藏编辑器、梯形图、自由监控、离线模式和串口配置控件 +- 用户运行版启动后自动读取同目录 `config/runtime.ini` 的六个串口字段并连接真实 PLC;运行版不启动本地梯形图扫描,HMI 读写只在 PLC 首读完成后放行 +- 用户运行版串口被拔出或 PLC 端口超时后自动按配置重连,重连和重新首读期间保持 HMI 页面、禁止写入且绝不切换到虚拟数据;普通编程器仍使用原来的手动连接和故障回编辑态流程 +- `json/` 下的两个本地示例工程已同步到严格 `formatVersion: "4.0"`,按钮补齐 `buttonEnableCondition: null` 字段,页面、报警、导航和梯形图数据保持原样 +- 关键 Markdown 文档已按当前代码和文档职责复核,修正 JSON `4.0` 版本约定、状态文本文档引用和验收测试目标数量 ## 领域与运行链路 @@ -33,6 +38,8 @@ - 领域模型和规则:`app/src/domain/hmi_model.h/.cpp`、`hmi_control_registry.*`、`project_model.cpp`、`project_limits.h` - 运行读取:`app/src/services/hmi_runtime_service.*`、`runtime_mode_service.cpp` - 工程持久化:`app/src/infrastructure/json_project_storage.*` +- 运行版配置:`app/src/infrastructure/runtime_settings_loader.*` +- 运行版导出:`app/src/services/project_service.*`、`app/src/ui/main_window.cpp` - 编辑服务和属性面板:`app/src/services/hmi_editor_service.cpp`、`app/src/ui/property_panel_controller.*` - 状态文本对话框:`app/src/ui/status_text_dialog.*` - 按钮启用条件对话框:`app/src/ui/button_extension_dialog.*` @@ -44,20 +51,20 @@ ## 验证结果 -- 13 个 Release Functional 测试目标全部通过,功能用例逐项输出结果:领域 18、设置 6、报警 2、HMI 编辑 12、逻辑编辑 27、离线仿真 19、工程管理 10、监控 7、运行包 1、运行模式 3、运行面板 13、PLC 对话框 3、PLC 运行时 7,共 128 个用例 -- Release Performance 四项基准全部通过:合法上限规模扫描约 22.75 ms/次,超限压力扫描约 1.36 ms/次,4001 个 M 位逐地址读写约 0.0483 ms/次,256 个 D 字连续块读写约 0.000061 ms/次;结果仅作为本机执行器和虚拟仓库基线 +- 14 个 Release Functional 测试目标全部通过,功能用例逐项输出结果:领域 18、设置 6、运行版设置 4、报警 2、HMI 编辑 12、逻辑编辑 27、离线仿真 19、工程管理 11、监控 7、运行包 1、运行模式 4、运行面板 13、PLC 对话框 3、PLC 运行时 7,共 134 个用例 +- Release Performance 四项基准全部通过:合法上限规模扫描约 21.75 ms/次,超限压力扫描约 1.09 ms/次,4001 个 M 位逐地址读写约 0.0479 ms/次,256 个 D 字连续块读写约 0.000062 ms/次;结果仅作为本机执行器和虚拟仓库基线 - HMI 编辑专项覆盖六种对齐方向、批量对齐单步撤销/重做、非法选择原子性和无变化不产生历史记录 - 状态文本专项覆盖 M OFF/ON 映射、D 四类型区间边界、区间间隙/重叠、整数边界、NaN/Inf、只读约束、16 区间上限、JSON 往返和旧 `2.0` 拒绝 - 按钮专项覆盖 M/D 条件满足与不满足、服务层二次拒绝、点动条件变化后的释放复位、条件 JSON 往返和条件引用地址轮询 - 属性面板专项覆盖按钮/数值控件自动分配连续默认地址,以及手动修改地址编号后保持固定区域 - 运行模式专项覆盖 Double 状态文本的 `D70~D73` 轮询地址及四字 `RegisterWordRange` - `git diff --check` 已通过;当前尚未连接真实 PLC,本轮新增编辑态 PLC 监控读写使用 Fake/缓存仓库验证,真实设备读写仍需按 STOP 安全流程现场确认 -- Release 主程序已在本轮最终代码上重新构建;设置 Qt offscreen 环境后启动 3 秒仍保持事件循环,验证结束已关闭进程;本轮未改生产代码,因此未重复构建主程序 +- Release 主程序已在本轮最终代码上重新构建;新增运行版启动链路、最小配置加载和自动重连逻辑通过编译,设置 Qt offscreen 环境后启动验证仍保持事件循环;导出运行版的真实串口连接尚未接入设备验证 ## 工作区说明 - 保留用户已有的 `AGENTS.md` 修改和未跟踪 Word 临时文件,不覆盖、不回退 -- 本轮不提交 Git,等待用户确认后再决定提交边界 +- 本轮代码按用户确认提交;Markdown 文档和来源不明的非代码文件继续保留在工作区,不纳入本次提交 ## 后续人工检查 @@ -67,3 +74,6 @@ - 打开 HMI 页面添加按钮,分别配置 M 位和 D 数值启用条件,确认条件不满足时按钮置灰且无法点击,满足后恢复可操作 - 离线运行写入虚拟 M/D,确认 M OFF/ON 和 D 在 30、80 边界的显示结果;停止运行后恢复编辑占位词 - 设备可用时在 STOP 状态读取原值,确认状态文本使用的 M/D 被轮询读回;测试只读,不向设备写入状态文本数据 +- 用真实工程执行一次“导出用户运行程序”,确认导出目录只出现 HMI 运行 exe、Qt 依赖、平台插件、样式目录和 `config/runtime.ini`,并确认 exe 启动后不出现编辑器或串口配置界面 +- 设备可用时使用导出运行版按 `runtime.ini` 自动连接,在 STOP 状态确认首读和 HMI 读回;测试结束恢复全部临时写入值并再次读回 +- 真机运行中分别拔出 USB 串口适配器、断开 PLC 侧 RS-485 端口并重新接回,确认运行版自动重连、重新首读、恢复 HMI 读写权限,且重连期间不显示虚拟数据 diff --git a/docs/architecture.md b/docs/architecture.md index ce7108e..2049418 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -42,12 +42,12 @@ main.cpp -> UI + Services + Infrastructure | `RuntimeMonitorWidget` | 全应用唯一运行投影,组合可交互 HMI、梯形图轨迹和自由监控 | | `MainWindow` | 窗口级动作、工程文件操作、控制器组合和模式切换 | -运行界面统一投影到独立顶层 `RuntimeMonitorWindow` 中的唯一 `RuntimeMonitorWidget`。该窗口是编程器的工程师运行监控大屏,不是旧的纯 HMI 操作员窗口: +运行界面统一投影到独立顶层 `RuntimeMonitorWindow` 中的唯一 `RuntimeMonitorWidget`。普通编程器中的该窗口是工程师运行监控大屏;带 HMI 工程封装的用户运行版则复用同一投影,只保留 HMI 页面: -- 进入离线或真机运行后,弹出并最大化运行监控窗口;主编程器窗口保留在后面且不改变布局,运行期间由同一份 `ModePolicy` 禁用编辑入口 -- 运行监控窗口顶部始终提供“离线仿真/真机运行”模式选择;从一种运行模式切换到另一种时由 UI 自动经过编辑态,再执行目标模式的完整校验 +- 进入离线或真机运行后,普通编程器弹出并最大化运行监控窗口;主编程器窗口保留在后面且不改变布局,运行期间由同一份 `ModePolicy` 禁用编辑入口 +- 普通编程器运行监控窗口顶部提供“离线仿真/真机运行”模式选择;用户运行版隐藏模式、配置和诊断控件,启动后自动连接真实 PLC - 主窗口不保留运行监控页签;编辑态主窗口提供与“HMI 页面”“控制逻辑”并列的“数据监控”编辑页签,运行态显示弹窗中的运行监控投影 -- 离线时显示可交互 HMI、软件梯形图轨迹和自由监控;真机时同时显示可交互 HMI、自由监控和根据 PLC 缓存计算的“本地推算轨迹” +- 普通编程器离线时显示可交互 HMI、软件梯形图轨迹和自由监控;真机时同时显示可交互 HMI、自由监控和根据 PLC 缓存计算的“本地推算轨迹”;用户运行版只显示可交互 HMI - HMI 页面跳转、按钮和数值输入都通过同一份 `HmiNavigationService` 和活动寄存器仓库完成;离线写虚拟 M/D,真机写 PLC,仿真停止或通信不可用时禁止写入 - 运行监控只能通过界面内的返回编辑按钮请求 `MainWindow -> RuntimeModeService` 返回编辑态;运行期间系统窗口关闭路径被忽略,离线时先停止软件扫描,真机时保留 PLC 连接但撤销运行会话;应用退出时允许顶层窗口真正关闭 @@ -89,7 +89,7 @@ Project ## 应用启动配置 -`ApplicationSettingsLoader` 在 Qt 应用创建后、其他业务对象创建前读取可执行文件目录下的 `config/application.ini`。配置只读取一次,不热更新,也不写入工程 JSON。 +普通编程器由 `ApplicationSettingsLoader` 在 Qt 应用创建后、其他业务对象创建前读取可执行文件目录下的 `config/application.ini`。配置只读取一次,不热更新,也不写入工程 JSON。带工程封装的用户运行版不读取这份完整配置,而是使用下方独立的最小串口配置。 ```text config/application.ini @@ -107,13 +107,15 @@ ApplicationSettings(启动后只读) - 重复字段、版本不兼容、非法 UTF-8、类型错误或越界值会使整份文件失效,所有配置回退为代码默认值 - 配置创建或加载严重失败时主窗口继续创建,启动诊断先进入底部输出面板,再异步弹出一次警告框 - HMI 宽高只决定新建页面的初始尺寸;已有页面继续使用工程 JSON 中保存的尺寸 -- PLC 默认参数只用于本次进程第一次打开配置窗口时的初值;用户在窗口中的修改只保留在当前进程,不自动回写 INI +- PLC 默认参数只用于本次进程第一次打开配置窗口时的初值;用户在普通编程器窗口中的修改只保留在当前进程,不自动回写 INI 字段、范围和用户操作方式见 `docs/用户使用/应用配置说明.md`。 ## 用户运行程序导出 -编程器通过“导出用户运行程序”把当前工程先原子写入临时 JSON,再将当前已编译的编程器 exe 复制为模板,把 JSON 追加到 exe 尾部的固定封装格式中,并复制 Qt 运行库和平台插件。封装格式包含魔数、版本、数据长度和 SHA-256,写入使用临时文件后原子改名。带有有效工程封装的 exe 启动时读取自身尾部工程数据,读取工程成功后直接隐藏编辑器并进入离线运行;运行监控顶部提供离线/真机切换、PLC 配置、断开和退出程序入口。普通 `integrated_platform.exe` 没有工程封装时按编程器入口启动。 +编程器通过“导出用户运行程序”先复制当前工程的 HMI 页面、报警和页面导航所需数据,明确移除控制逻辑和地址备注,再原子写入临时 JSON。随后将当前已编译的编程器 exe 复制为模板,把裁剪后的 JSON 追加到 exe 尾部的固定封装格式中,并复制 Qt 运行库、平台插件和 `config/runtime.ini`。封装格式包含魔数、版本、数据长度和 SHA-256,写入使用临时文件后原子改名。带有有效工程封装的 exe 启动时读取自身尾部工程数据,隐藏编辑器,只显示 HMI 页面,并从 `config/runtime.ini` 自动连接真实 PLC;运行版不提供离线仿真、梯形图、本地逻辑推算、自由监控、串口配置或模式切换控件。普通 `integrated_platform.exe` 没有工程封装时按编程器入口启动。 + +`config/runtime.ini` 只允许 `[PlcDefaults]` 下的六个串口字段:`PortName`、`ServerAddress`、`BaudRate`、`DataBits`、`Parity` 和 `StopBits`。文件不存在时自动创建代码默认值;字段错误时整份回退到默认串口参数。运行版的 HMI 读写直接使用 PLC 轮询缓存,运行版不启动离线执行器,也不执行本地梯形图扫描。串口被拔出后运行版按固定间隔重新打开串口;PLC 端口无响应触发通信超时恢复,恢复失败时同样重新建立连接并重新完成首读。 `scripts/package_qt_app.ps1` 只用于维护者构建编程器发布包和复制 Qt 运行库,不参与工程导出。编程器发布包包含自身 exe 及 Qt 运行库后可以移动到任意目录,导出时不再依赖 PowerShell、qmake、MinGW 或项目源码目录。 @@ -141,7 +143,7 @@ ApplicationSettings(启动后只读) `LogicEditorService::checkSyntax()` 在当前控制逻辑上执行信捷式“规整 LD + 语法检查”。服务按列计算从左母线向右的结构可达性和从所有输出向左的反向可达性;对于已经存在完整输出路径的网络,只保留能够参与完整路径的 `Wire` 和 `VerticalConnection`,没有输出的残线全部清除。规整不删除条件节点、输出或数据指令;若某个输出网络本身断路,则该网络不参与自动清理,保留用户现场并返回控制逻辑、网络、视觉行和第 11 列输出槽位置。一次检查对多条横竖线的修改只提交一条梯形图撤销记录。 -`RuntimeModeService` 在离线启动和完成 PLC 首读后的真机启动前调用 `LogicEditorService::checkEnabledSyntax()`;用户运行程序导出执行同一检查。规整完成后,`ControlLogic::validateForRunning()` 继续使用和执行器相同的逐列边界与竖线连通关系做最终静态可达性检查。没有输出的自动追加空行可以继续保留;任何带输出的行都必须存在从左母线到第 10 列边界的结构路径。中间 `Gap` 只有在其他并联支路能够绕过时才允许运行,否则运行和导出都会停止。`LogicEditorService::checkDoubleCoils()` 作为单独动作检查重复 M 线圈并定位第二个输出,不混入普通语法检查或运行前阻断。 +`RuntimeModeService` 在普通编程器的离线启动和完成 PLC 首读后的真机启动前调用 `LogicEditorService::checkEnabledSyntax()`;HMI 专用运行版没有控制逻辑,不执行本地逻辑语法检查和扫描。普通编程器用户运行程序导出只校验裁剪后的 HMI 工程,规整完成后,`ControlLogic::validateForRunning()` 继续使用和执行器相同的逐列边界与竖线连通关系做最终静态可达性检查。没有输出的自动追加空行可以继续保留;任何带输出的行都必须存在从左母线到第 10 列边界的结构路径。中间 `Gap` 只有在其他并联支路能够绕过时才允许运行,否则普通编程器运行会停止。`LogicEditorService::checkDoubleCoils()` 作为单独动作检查重复 M 线圈并定位第二个输出,不混入普通语法检查或运行前阻断。 节点配置使用 `std::variant` 的独立类型。当前条件包括 M 常开/常闭触点、M 上升沿/下降沿触点和 D 与常量比较;输出包括普通/置位/复位 M 线圈、MOVE、ADD 和 SUB。新增或恢复指令必须增加独立配置、校验、JSON、执行、编辑和测试分支,不能向通用节点堆叠无关字段。 diff --git a/docs/测试约定.md b/docs/测试约定.md index c8a4f2a..0bea7c6 100644 --- a/docs/测试约定.md +++ b/docs/测试约定.md @@ -18,6 +18,7 @@ | --- | --- | | `domain_tests` | 地址、模型、数量边界、Int16/Int32/Float32/Float64 编解码和带竖线并联的输出路径可达性校验 | | `application_settings_tests` | 默认配置创建、严格 INI 校验、缺失与未知字段、版本和整份回退 | +| `runtime_settings_tests` | HMI 运行版最小串口配置创建、六个串口字段读取、整份回退和原子写回 | | `alarm_service_tests` | 报警定义和运行记录生命周期 | | `hmi_editor_service_tests` | HMI 编辑、原子删除、历史、导航和四种 D 数值控件读写 | | `logic_editor_service_tests` | 连续网格编辑、网络注释首行归属与合并冲突、输出自动补尾线、网格与整行片段复制粘贴、冲突回滚和历史 | @@ -45,7 +46,7 @@ pwsh -NoLogo -NoProfile -File .\scripts\run_qt_tests.ps1 -Configuration Release ``` -`app/tests/tests.pro` 只聚合上述 13 个功能测试目标。测试构建输出放在 `build/`,不写入 `app/`。 +`app/tests/tests.pro` 只聚合上述 14 个功能测试目标。测试构建输出放在 `build/`,不写入 `app/`。 ## 性能测试 @@ -91,7 +92,7 @@ pwsh -NoLogo -NoProfile -File .\scripts\run_qt_tests.ps1 -Configuration Release ## 提交前检查 -1. 运行 13 个 Release 功能测试目标 +1. 运行 14 个 Release 功能测试目标 2. 单独运行 `performance_tests` 并保留基准输出 3. 构建 Qt Release 主程序 4. 按风险决定是否重新执行真实 PLC 实测;未重测时引用已有验收记录并说明原因 diff --git a/docs/用户使用/应用配置说明.md b/docs/用户使用/应用配置说明.md index 71dba6f..1acacda 100644 --- a/docs/用户使用/应用配置说明.md +++ b/docs/用户使用/应用配置说明.md @@ -1,6 +1,6 @@ # 应用配置说明 -应用配置文件用于调整少量用户体验型数量、新建 HMI 页面的默认尺寸,以及 PLC 配置窗口的串口初值。工程内容仍保存在 JSON 工程文件中,两类文件互不替代。 +普通编程器的应用配置文件用于调整少量用户体验型数量、新建 HMI 页面的默认尺寸,以及 PLC 配置窗口的串口初值。工程内容仍保存在 JSON 工程文件中,两类文件互不替代。导出的 HMI 专用运行版不读取这份完整配置,而是使用运行版目录下只包含串口参数的 `config/runtime.ini`。 ## 文件位置与生效方式 @@ -54,7 +54,7 @@ StopBits=1 | `ProjectLimits.MaxHmiControlsPerPage` | 128 | `1~128` | 单页 HMI 控件上限 | | `ProjectLimits.MaxAlarmDefinitions` | 256 | `0~256` | 单工程报警定义上限,`0` 表示禁止添加报警 | | `ProjectLimits.MaxControlLogics` | 32 | `1~32` | 单工程控制逻辑组上限 | -| `ProjectLimits.MaxRungsPerLogic` | 256 | `0~256` | 单组逻辑网络上限,`0` 表示逻辑组只能保持空网络 | +| `ProjectLimits.MaxRungsPerLogic` | 256 | `0~256` | 每组逻辑的梯形图行数上限,`0` 表示逻辑组只能保持空逻辑 | | `ProjectLimits.MaxOutputMessages` | 1000 | `1~1000` | 主界面底部输出保留条数 | | `HmiDefaults.DefaultPageWidth` | 800 | `320~1600` | 新建 HMI 页面的默认宽度,像素 | | `HmiDefaults.DefaultPageHeight` | 400 | `200~800` | 新建 HMI 页面的默认高度,像素 | @@ -69,6 +69,28 @@ StopBits=1 PLC 默认配置只负责填充 PLC 配置窗口。若 `PortName` 对应串口当前不存在,端口列表仍只显示 Windows 实际检测到的可用串口,不会人为加入一个无效端口。用户在窗口里搜索或修改参数后,结果只在本次程序运行期间保留。 +## HMI 专用运行版配置 + +导出的运行版只读取同目录下的: + +```text +config/runtime.ini +``` + +该文件只保留 `[PlcDefaults]` 下的六个字段:`PortName`、`ServerAddress`、`BaudRate`、`DataBits`、`Parity` 和 `StopBits`。运行版启动后自动使用这些参数连接真实 PLC,不显示串口配置窗口,也不读取 `ProjectLimits`、`HmiDefaults` 或 `Config` 分区。文件不存在时自动创建如下最小配置: + +```ini +[PlcDefaults] +PortName=COM3 +ServerAddress=1 +BaudRate=9600 +DataBits=8 +Parity=2 +StopBits=1 +``` + +运行版配置的错误处理是整份回退到代码默认串口参数,不会影响编程器目录中的 `application.ini`。串口设备拔出或 PLC 通信超时后,运行版会自动按当前配置重连,不需要额外的配置窗口。 + ## 校验与回退 普通字段缺失时,该字段使用代码默认值,其他合法字段继续生效;未知字段会被忽略。这两种情况都会在主界面底部输出提示,但不会弹警告。 @@ -87,4 +109,4 @@ PLC 默认配置只负责填充 PLC 配置窗口。若 `PortName` 对应串口 程序加载工程时使用与编辑入口相同的启动配置。已有工程超过新上限时会整体拒绝加载,错误信息会给出超限数组、实际数量和当前上限;当前工程不会被部分替换,原 JSON 文件也不会被修改。 -全工程 HMI 控件上限 2048、全工程网络上限 2048、M/D 地址范围、16 位数值范围、梯形图结构、表达式安全限制、Modbus 通信限制和工程文件容量仍是代码硬限制,不允许通过 INI 修改。 +全工程 HMI 控件上限 2048、全工程梯形图行数上限 2048、M/D 地址范围、16 位数值范围、连续网格结构安全限制、Modbus 通信限制和工程文件容量仍是代码硬限制,不允许通过 INI 修改。 diff --git a/docs/用户使用/数量边界确认方案.md b/docs/用户使用/数量边界确认方案.md index f689b8e..f253b38 100644 --- a/docs/用户使用/数量边界确认方案.md +++ b/docs/用户使用/数量边界确认方案.md @@ -13,7 +13,7 @@ | `MaxRungsPerLogic` | 256 | 0 | 256 | | `MaxOutputMessages` | 1000 | 1 | 1000 | -全工程 HMI 控件数量固定为 2048,全工程网络数量固定为 2048,均不对用户开放。因为可配置的单页控件上限不可能超过 128、单组网络上限不可能超过 256,所以它们与全工程硬上限的关联关系始终成立,不需要再增加可配置字段。 +全工程 HMI 控件数量固定为 2048,全工程梯形图行数固定为 2048,均不对用户开放。因为可配置的单页控件上限不可能超过 128、每组逻辑行数上限不可能超过 256,所以它们与全工程硬上限的关联关系始终成立,不需要再增加可配置字段。 HMI 页面宽度 `320~1600`、高度 `200~800` 仍是结构安全硬范围;`DefaultPageWidth` 和 `DefaultPageHeight` 只允许在该范围内设置新建页面默认尺寸,不改变已有页面,也不改变宽高硬边界。 @@ -41,14 +41,10 @@ HMI 页面宽度 `320~1600`、高度 `200~800` 仍是结构安全硬范围;`De | 报警 | 单页同时可见行数 | 1 行 | 5 行 | 超出后通过表头按钮翻页,活动记录不丢失 | 控件始终保持编辑时设置的尺寸,当前页不足时保留空白行区域 | | 注释 | M/D 软元件注释数量 | 0 | 8002 | 超出后拒绝保存或加载 | M0~M4000 和 D0~D4000 每个地址最多一条,共 8002 条 | | 控制逻辑 | 控制逻辑数量 | 0 | 32 | 超过配置上限或第 33 组时不能创建或加载 | 控制工程树和扫描工作量 | -| 控制逻辑 | 每组逻辑的网络数量 | 0 | 256 | 超过配置上限或第 257 个网络时不能创建或加载 | 每次软件扫描都要执行这些网络 | -| 控制逻辑 | 全工程网络数量 | 0 | 2048 | 第 2049 个网络不能创建或加载 | 限制离线扫描、编辑快照和工程文件总工作量 | -| 单个网络 | 条件表达式节点和叶子总数 | 0 | 1024 | 超出后编辑操作回退,JSON 加载失败 | 防止单个网络过度复杂 | -| 单个网络 | 表达式嵌套深度 | 1 层 | 12 层 | 第 13 层在解析时直接拒绝 | 控制递归求值和画布布局深度 | -| 单个容器 | 串联或并联子项数量 | 2 | 64 | 第 65 项不能加入或加载 | 控制单层表达式规模 | -| 单个网络 | 条件区列数 | 0(空网络草稿) | 10 | 第 11 个条件不能加入,加载失败;存在输出时不足 10 列也失败 | 输出网络前 10 列必须由条件、横线或断路显式占满 | -| 单个网络 | 总列数 | 0(空网络草稿) | 11 | 第 11 列固定放输出指令 | 运行网络固定为前 10 列条件区加第 11 列输出 | -| 单个网络 | 逻辑网格行数 | 1 | 64 | 超出后编辑操作回退,加载失败 | 防止并联支路纵向无限扩展 | +| 控制逻辑 | 每组逻辑的梯形图行数 | 0 | 256 | 超过配置上限或第 257 行时不能创建或加载 | 每次软件扫描都要按顺序处理这些行 | +| 控制逻辑 | 全工程梯形图行数 | 0 | 2048 | 第 2049 行不能创建或加载 | 限制离线扫描、编辑快照和工程文件总工作量 | +| 单行梯形图 | 条件区列数 | 0(空行草稿) | 10 | 第 11 个条件不能加入,加载失败;存在输出时不足 10 列也失败 | 输出行前 10 列必须由条件、横线或断路显式占满 | +| 单行梯形图 | 总列数 | 0(空行草稿) | 11 | 第 11 列固定放输出指令 | 运行行固定为前 10 列条件区加第 11 列输出 | | 横线 | 单段横线跨度 | 1 列 | 10 列 | 拒绝编辑或加载 | 横线只能占用条件区,不能占用输出列 | | 断路 | 单段空白跨度 | 1 列 | 10 列 | 拒绝编辑或加载 | `Gap` 明确占用条件区空白网格;带输出的路径不可达时拒绝运行 | | 字符串 | ID、格式版本、页面跳转目标 ID | 0 字节 | 128 个 UTF-8 字节 | 拒绝保存或加载;业务要求非空的 ID 仍必须非空 | ID 只用于稳定识别,不需要长文本 | @@ -89,7 +85,7 @@ HMI 页面宽度 `320~1600`、高度 `200~800` 仍是结构安全硬范围;`De | 工程文件路径长度 | 不在业务层另设上限 | 交给 Windows 和 Qt 的文件接口处理,工程内容仍受 16 MiB 限制 | | 可用 COM 端口列表数量 | 不另设上限 | 列表来自操作系统,项目不持久化累积这些端口 | | 报警阈值和普通 HMI 数值的额外业务范围 | 不再加第二套范围 | 统一使用 D 的 `-32768~32767` | -| 加减法参与次数 | 不单独限制 | 执行量已经受 32 组逻辑、每组 256 个网络和单网络复杂度限制 | +| 加减法参与次数 | 不单独限制 | 执行量已经受 32 组逻辑、每组 256 行和每行固定 10 个条件列限制 | ## 3. 这些数字从哪里来 @@ -102,8 +98,8 @@ HMI 页面宽度 `320~1600`、高度 `200~800` 仍是结构安全硬范围;`De ## 4. 用户实际会看到什么 -- 正常编辑时,达到页面、控件、报警、逻辑或网络的当前配置上限后,软件会直接提示具体上限,不会先添加再留下坏工程 -- 手工改 JSON 绕过界面也没用,加载时会按同一份启动配置重新检查数组数量,并检查文件大小、字符串长度、页面尺寸和表达式深度 +- 正常编辑时,达到页面、控件、报警、逻辑或梯形图行数的当前配置上限后,软件会直接提示具体上限,不会先添加再留下坏工程 +- 手工改 JSON 绕过界面也没用,加载时会按同一份启动配置重新检查数组数量,并检查文件大小、字符串长度、页面尺寸和连续网格结构 - 用户调低上限后,已有工程一旦超限会整体拒绝加载,错误会给出超限项目、实际数量和当前配置上限,不会加载一半或修改原文件 - PLC 参数不只在对话框里限制,真正连接前还会再检查一次 - 超过当前 `MaxOutputMessages` 时,只删除最旧日志,不影响工程和 PLC 数据 @@ -111,8 +107,8 @@ HMI 页面宽度 `320~1600`、高度 `200~800` 仍是结构安全硬范围;`De ## 5. 本次验收结果 -- 2026-08-25 外部应用配置接入后,12 个 Release 功能测试目标全部通过;覆盖动态领域上限、编辑入口、严格配置加载和调低上限后的 JSON 原子拒绝 +- 截至 2026-08-28,外部应用配置接入后的 13 个 Release 功能测试目标全部通过;覆盖动态领域上限、编辑入口、严格配置加载和调低上限后的 JSON 原子拒绝 - 2026-08-19 使用真实 PLC 在 `COM3、9600、8E1、站号 1` 下完成读写验证:先读取 `D4000=0`,写入 `1` 后读回 `1`,再恢复并读回 `0` - 真机验证没有下载 PLC 程序,测试结束后 `D4000` 已恢复原值 - 2026-08-21 用户使用 `json/motor_forward_reverse.json` 完成真实 PLC RUN 联动手动验收,确认 HMI 正转启动、反转启动、停止和运行状态反馈正常 -- 2026-08-21 重新执行 10 个 Release 自动化测试目标,全部通过;自动化测试覆盖软件逻辑、运行模式、PLC 缓存和 UI 工作流,现场 RUN 联动另由真实设备手动验收 +- 2026-08-27 重新执行 13 个 Release 功能测试目标,全部通过;自动化测试覆盖软件逻辑、运行模式、PLC 缓存和 UI 工作流,现场 RUN 联动另由真实设备手动验收 diff --git a/docs/用户使用/用户运行程序导出说明.md b/docs/用户使用/用户运行程序导出说明.md index 31bb2a8..0df94b6 100644 --- a/docs/用户使用/用户运行程序导出说明.md +++ b/docs/用户使用/用户运行程序导出说明.md @@ -1,11 +1,11 @@ # 用户运行程序导出说明 -编程器中的“文件 -> 导出用户运行程序”会把当前工程封装成一个专用的 Windows 运行程序。导出的程序不包含可见的工程编辑流程,用户双击 exe 后直接进入该工程的运行监控界面。 +编程器中的“文件 -> 导出用户运行程序”会把当前工程的 HMI 页面封装成一个专用的 Windows 运行程序。导出的程序不包含工程编辑流程、离线仿真、梯形图、自由监控或串口配置界面,用户双击 exe 后直接看到 HMI 页面并连接真实 PLC。 ## 导出流程 -1. 先在编程器中完成 HMI 页面、控制逻辑、报警和 M/D 地址绑定 -2. 确认工程可以进入运行态,不能保留未配置的运行节点 +1. 先在编程器中完成 HMI 页面、报警和 M/D 地址绑定 +2. 确认 HMI 页面和报警引用的地址完整,不能保留未配置的运行控件 3. 选择“文件 -> 导出用户运行程序” 4. 先选择目标父目录,再输入导出文件夹名称,例如 `电机正反转` 5. 等待导出进度完成,程序会在父目录下生成同名文件夹,里面包含 exe、Qt 运行库和平台插件 @@ -19,20 +19,36 @@ ├── Qt5Core.dll ├── Qt5Gui.dll ├── ... + ├── config/ + │ └── runtime.ini ├── platforms/ └── styles/ ``` -导出使用随编程器发布的已编译运行程序模板,不会重新执行 qmake 或 MinGW 编译;同一时间只能执行一个导出任务。 +导出使用当前编程器 exe 作为已编译运行程序模板,不会重新执行 qmake 或 MinGW 编译。若从 `build/debug` 或 `build/release` 等开发目录运行编程器,而 exe 同目录没有 Qt DLL,导出器会自动从 Qt 安装目录和当前 PATH 查找并复制 Qt、MinGW 运行库及平台插件;正式发布目录仍优先使用自身携带的运行库。同一时间只能执行一个导出任务。 -工程 JSON 会在导出时封装到 exe 尾部,并使用长度、版本和 SHA-256 校验保护数据;用户不需要接触 JSON,也不需要安装编程器。 +导出的工程数据只保留 HMI 页面、报警和页面导航需要的内容,控制逻辑和地址备注不会进入运行包。工程 JSON 会在导出时封装到 exe 尾部,并使用长度、版本和 SHA-256 校验保护数据;用户不需要接触 JSON,也不需要安装编程器。 ## 用户操作 -打开导出的 exe 后直接进入离线仿真。运行界面顶部可以切换“离线仿真”和“真机运行”。真机运行前点击“PLC 配置”,设置串口、站号、波特率、数据位、校验位和停止位,连接成功并完成首次读取后再切换到真机运行。 +打开导出的 exe 后直接显示 HMI 页面,程序自动读取同目录 `config/runtime.ini` 并连接真实 PLC。运行版不显示模式切换、PLC 配置、自由监控和梯形图控件;HMI 按钮和输入控件只有在 PLC 连接成功并完成首次读取后才允许写入。串口设备被拔出、PLC 端口无响应或通信超时后,运行版会自动重新连接并重新完成首读,恢复期间 HMI 保持只读。 + +运行版配置文件只保留串口字段: + +```ini +[PlcDefaults] +PortName=COM3 +ServerAddress=1 +BaudRate=9600 +DataBits=8 +Parity=2 +StopBits=1 +``` + +文件不存在时程序会自动创建默认文件。串口配置有错误时整份回退到代码默认值,并提示检查 `config/runtime.ini`、设备和接线。修改后重启运行版才会重新读取。 “退出程序”只退出用户运行程序,不会进入工程编辑器。 ## 编程器发布 -维护者在构建编程器发布包时仍可使用 `scripts/package_qt_app.ps1` 完成 Qt Release 构建和运行库复制。发布给工程师的编程器目录只需要包含编程器 exe、Qt 运行库、平台插件和配置目录;工程师把整个目录移动到其他位置后,仍可直接导出用户运行程序,不需要安装 PowerShell 7、Qt SDK 或 MinGW。 +维护者在构建编程器发布包时仍可使用 `scripts/package_qt_app.ps1` 完成 Qt Release 构建和运行库复制。发布给工程师的编程器目录继续使用完整的 `config/application.ini`;导出的每个运行版目录使用自己的 `config/runtime.ini`,两者互不覆盖。工程师把整个目录移动到其他位置后,仍可直接导出用户运行程序,不需要安装 PowerShell 7、Qt SDK 或 MinGW。 diff --git a/docs/用户使用/连续梯形图网格说明.md b/docs/用户使用/连续梯形图网格说明.md index 7471a02..a733e2d 100644 --- a/docs/用户使用/连续梯形图网格说明.md +++ b/docs/用户使用/连续梯形图网格说明.md @@ -58,7 +58,7 @@ 运行态保持网格背景不变,只给实际电流路径着色。横线按左右半段显示,触点左端取网格输入电源、触点符号和右端取网格输出电源,竖线取对应连接段电源,输出连接线取行末电源,输出符号取输出节点状态。未导通使用统一深色,导通使用监控绿,故障红色优先;选择框仍位于所有轨迹图层之上。左右母线始终使用相同的普通深色,不参与运行绿色投影。 -进入离线运行、完成 PLC 首读后进入真机运行、导出用户运行程序之前,软件都会检查每个输出是否能沿触点、横线和竖线连接回左母线。没有输出的自动追加空行允许保留;并联网络中的单条断路支路也可以保留,只要输出仍有其他完整路径。若输出不可达,界面会提示具体控制逻辑、视觉行和断开列,并保持在编辑态。 +进入离线运行和普通编程器完成 PLC 首读后进入真机运行之前,软件都会检查每个输出是否能沿触点、横线和竖线连接回左母线。HMI 专用运行版导出不包含控制逻辑,只校验 HMI 页面和报警引用。没有输出的自动追加空行允许保留;并联网络中的单条断路支路也可以保留,只要输出仍有其他完整路径。若输出不可达,界面会提示具体控制逻辑、视觉行和断开列,并保持在编辑态。 运行控制器始终传递完整轨迹快照,画布只按当前控制逻辑投影一次。这样离线扫描和基于 PLC 缓存的真机本地推算都会显示逐段轨迹,不会因为重复筛选而变成全深色。 diff --git a/docs/用户使用/鼠标画线与删线说明.md b/docs/用户使用/鼠标画线与删线说明.md index b27d2c7..bc9585c 100644 --- a/docs/用户使用/鼠标画线与删线说明.md +++ b/docs/用户使用/鼠标画线与删线说明.md @@ -46,7 +46,7 @@ - 规整不会删除触点、比较指令、输出线圈或数据指令,也不会自动补线 - 如果某个输出网络已经断路,该网络保持原样并报告控制逻辑、网络、行和列;断路输出定位在第 11 列 - 双击输出栏中的语法错误可以切换到对应控制逻辑并选中错误位置 -- 进入离线运行、完成 PLC 首读后的真机运行以及导出用户运行程序前,都会用同一规则检查全部已启用控制逻辑;存在语法错误时停止后续操作 +- 进入离线运行和普通编程器完成 PLC 首读后的真机运行前,会用同一规则检查全部已启用控制逻辑;HMI 专用运行版导出只校验裁剪后的 HMI 工程,不执行控制逻辑语法检查 - 双线圈不属于普通语法检查范围,继续作为独立检查项处理 ## 数据与限制