立项:2026-06-22(经 brainstorming 逐项澄清,关键决策已与用户确认) 范围:只动 operate 与 control,front(管理端
ivf_tl_Manage)保持现状不动。 现状基线见项目文档/control-逻辑与配置全景.md(control 全部逻辑 + 配置参数,标 file:line)。 实现方式:分阶段落地(见 §8)。
原本 operate(本机操作界面)与 control(机器驱动:串口/拍照/换气/对焦/上传)是两个独立进程、独立软件,各自连服务器,本地互不通信。"合并"只为代码仓库/管理方便,把 control 逻辑塞进了 operate 进程内(operate MainWindow_Loaded → Task.Run → StartMain.StartRun())。
LongRunning 前台线程撑着)→ 残留无窗口进程(如曾出现的 PID 20268)。ServiceMonitorViewModel 直读 ControlAppData.Instance.GetMonitorSnapshot()),内容也不全。control.exe 常驻驱动机器,operate.exe 可随时开关。| # | 决策 | 选定方案 |
|---|---|---|
| 1 | 进程模型 | operate / control 两个独立进程;代码仍在一个解决方案里管理,装机是一个软件;front 不动 |
| 2 | 进程间通信 | control 开本地 HTTP 小服务(127.0.0.1:<端口>),operate 调用 |
| 3 | 谁拉起 control | operate 按需拉起 + operate 开机自启 + control 用 Mutex 保证单实例 |
| 4 | 调试让串口(B) | operate 调 /serial/pause+/serial/resume,复用现有 HouseGate 闸门,跨进程喊;control 不死、其他舱照常、调完自动恢复 |
| 5 | 整体停止 control(A) | 监控页一个受护栏按钮(二次确认 + 工程师口令 tl13579)→ /shutdown 安全停机 |
| 6 | 监控页补全 | 补:各舱实时活动(拍照/对焦/换气)、后台线程健康/心跳、串口借用/占用状态 |
| 7 | 实现节奏 | 分阶段落地 |
培养箱本机
┌──────────────────────────────────────────────────────┐
│ operate.exe(UI,可随时开关,管理员) │
│ - 本机操作界面:舱室/调试/对焦/配置 │
│ - 服务监控页:轮询 control 的 /status │
│ - 启动时:确保 control 在跑(不在则拉起) │
│ │ 本地 HTTP(127.0.0.1) │
│ │ GET /status POST /serial/pause|resume │
│ ▼ POST /shutdown │
│ control.exe(无界面常驻,管理员,Mutex 单实例) │
│ - StartMain.StartRun():串口/相机/采集/对焦/换气 │
│ - 10×HouseBin 采集循环 + BufferBottleBin + 上报线程 │
│ - 内嵌轻量 HttpListener 提供上述接口 │
└──────────────────────────────────────────────────────┘
│ control 各自连服务器 │ operate 各自连服务器
▼ (MQTT 指令 / Kafka 图片 / HTTP) ▼ (gateway HTTP / MQTT)
中央服务器
要点:operate 与 control 业务上仍各自连服务器(维持现状);本地新增的唯一通道是 control 的 HTTP 小服务,只承载"读状态/借串口/停止"三类本地协调。
Window1 退役)。StartMain.StartRun() 跑起采集 + 起 HttpListener。ivf_tl_Control 类库新建启动器,不改造脏壳 ivf_tl_ControlTest(其唯一正式资产 Window1 启动骨架已被 operate 复刻;其余是测试/死代码,见 §7)。control 进程内用 .NET 自带 HttpListener(轻量,无需 ASP.NET),只监听 127.0.0.1:<端口>。端口写进配置(默认如 38080,可改),避免占用冲突。control 是管理员运行,HttpListener 的 URL ACL 注册天然不受限。
| 方法 | 路径 | 入参 | 返回 | 用途 |
|---|---|---|---|---|
| GET | /status |
— | JSON 快照(见 §6) | 监控页轮询(每 2s) |
| GET | /ping |
— | {ok,pid,tlSn} |
operate 启动时探活,判断要不要拉起 |
| POST | /serial/pause |
{houseSn} |
{ok} |
调试借串口:control 让出该舱串口(MarkPause→暂停采集) |
| POST | /serial/resume |
{houseSn} |
{ok} |
调试完归还:恢复该舱采集 |
| POST | /shutdown |
{token} |
{ok} |
受护栏整体停机(token=工程师口令校验) |
约定:
127.0.0.1 only,拒绝非本机请求(防外部调停机/借串口)。HttpService/HttpHelper 基础设施。control 启动时用命名 Mutex(如 Global\ivf_tl_control_singleton)判重:已存在则立即退出。这是"永远只有一个 control 驱动机器"的硬保证,根治多实例抢串口。(原 ivf_tl_ControlTest.OnStartup 已有 Mutex 范例可参考。)
operate 启动流程(替换现有 MainWindow_Loaded 里 Task.Run(StartRun) 那段):
GET /ping。Process.Start 拉起 control.exe,把账号/密码/缓存盘等通过命令行参数传入(替代原 Window1 读配置 + 透传账号);管理员静默(operate 已是管理员,不弹 UAC)。/ping 直到 control 就绪(带超时与重试),再进入"已连接"。operate 关 UI 只退出自己,绝不动 control(去掉任何"退出时停 control / Environment.Exit 带走后台"的逻辑)。control 继续驱动机器。
修正合并期的缺陷:现
App_Exit空、无对称停机——双进程后这反而是对的(operate 关闭不该影响 control)。
只有监控页那个受护栏按钮(二次确认 + 工程师口令)→ POST /shutdown → control 执行安全停机:停采集主循环 → 停各 LongRunning 上报线程 → 关相机/串口句柄(HardwareAccessLayer.ShutdownAll())→ 释放 Mutex → 进程退出。
control 需新增一个统一
Shutdown()入口(现状只有零散CloseCamera/StopBlance/StopDish,无统一停机,见全景文档第九章)。
装机时把 operate 设为开机自启(注册表 Run 或启动文件夹)。开机 → operate 自动起 → 拉起 control → 机器自动被驱动,用户无需点击。
/status 在现有 GetMonitorSnapshot() 基础上补三块(数据 control 内部已有,全景文档标了 file:line):
现有(保留):control 存活、MQTT 连接、HTTP/Kafka 链路最后成功时间、图片上传队列、磁盘、各舱(串口态/温度/压力/舱态/相机态)。
补充:
WorkingType(DoNothing/AirSwapWorking/CCDWorking/AutoFocusWorking)、RunState、ValveState、cultureState(空闲/培养/平衡)、上次拍照时间。→ 一眼看出哪个舱在拍照/对焦/换气。LastRunTime(超 N 分钟未更新=卡死)、图片上传线程/上报线程存活、各舱采集线程状态。CapturePausedByGate 是否让路中。→ 排障"为什么调试进不去"。operate 侧 ServiceMonitorViewModel.Refresh() 从"直读 ControlAppData.Instance"改为"调 GET /status 拿 JSON 映射"。其余展示逻辑基本不变。
逐文件鉴定(全景文档第九章已记):
Window1:正式启动骨架已被 operate 复刻;其余是测试按钮/shutdown /r 重启电脑/XML 改 config/已禁用的 StopProEvent/注释黑客代码。MainWindow(命名空间 TLTest):100% 测试(硬编码登录、发测试 MQTT、造假 ImageDTO)。StopWindow:死窗口(调用点已禁用)。处置:不改造此脏壳。新 control 启动器基于干净的 ivf_tl_Control 类库新建;ivf_tl_ControlTest 整个项目在阶段3退役删除(确认新启动器跑通后)。
每阶段可独立编译/验证;真机已连,真机相关步骤由 Claude 自主跑完(无需用户在场/配合),仅「水平电机」「垂直 Z 电机」运动范围需守安全区间(参考
临时文件/相关参数.html),其余下位机控制无风险。
ivf_tl_Control 类库。StartMain.StartRun()。HttpListener,先实现 /ping + /status(返回现有快照)。/ping→不在则 Process.Start 拉起 control(传参)。/status 看到 control 活着。(真机验证采集/握手)/status 补 §6 三块内容;ServiceMonitorViewModel 改跨进程读。/serial/pause+/serial/resume,接到现有 HouseGate 闸门;operate 调试页 ComHouseInit/ComHouseUnit 改为跨进程借/还(替代现同进程 gate.Acquire)。/shutdown;control 实现统一 Shutdown() 安全停机。ivf_tl_ControlTest;清理 operate 里残留的"内嵌 control"死代码。/login(127.0.0.1)post 账号,或加密传参。待实现阶段定(列为阶段1的细化点,不留 TBD:默认先用命令行加密串,阶段1 评审时确认)。HardwareAccessLayer.ShutdownAll() 的顺序,避免句柄泄漏(参考全景文档 §六)。真机验证。临时文件/相关参数.html(用户自测值,仅供参考,实际安全范围比文档更宽):水平钳位 0,220000、垂直 Z 钳位 0,125000。除这两轴运动范围外,其余下位机控制无任何风险。