操作端逻辑与配置全景.md 27 KB

operate 操作端 · 逻辑与配置全景(接手指南)

2026-06-22 全量源码梳理(3 路并行核实),一切以源码为准,关键处标 file:line。 用途:接手 operate(操作端 WPF)这套合并后代码的全图;与 control-逻辑与配置全景.md 互为两半(control=机器驱动大脑,operate=人机交互+承载 control)。 行号若无另注,均指 ivf_tl_operate_2.0/ivf_tl_Operate/(现有合并版)下对应文件;差异对照基准版 临时文件/ivf_tl_operate_2.0/ivf_tl_Operate/。 ⚠ 第八节是本文核心:合并后相对基准的改动/降级/待验证项登记(operate 侧)——control 全景管不到这半边,坑都在这里。


〇、一句话定位

operate = 培养箱的"人机交互端 + control 宿主":登录→显示舱室/胚胎/曲线/报警→工程师调试(借 control 串口动硬件)→改配置/加皿/管胚胎,全走 HTTP 与服务器交互;合并后还在自己进程里把 control 当类库托起来跑(Task.Run StartRun),所以现在"一个软件"= operate UI 进程内含 control 驱动线程。

关键现状(合并引入):

  • operate 进程内托管 control:登录成功后后台线程 ivf_tl_Control.AppData.Login → HAL.ScanDevices → StartMain.StartRun()(MainWindow.xaml.cs:67-132)。这是"operate 关了 control 也跟着死"的根源,也是双进程拆分要拆的点。
  • 调试页改 HAL 借用:所有"进调试动硬件"的页面,从基准的"自己 new ComBin/new Camera 直开物理口",改为向 HAL 借用采集端同一物理句柄(gate.Acquire(OperateDebug)),用完只归还不关口。
  • 新增三页:服务监控(只读跨读 control 快照)、统一配置(写本地 App.config)、软键盘(替代 osk.exe)。
  • 降级集中地:4 处硬件下发被降级,根因统一在 control/IvfTl.Hardware/Impl/SerialChannelImpl.cs(control 端缺 Commander builder)。

一、进程 / 启动时序

单实例(Mutex ivf_tl_Operate)。启动顺序:

触发点 file:line 做了什么
App() 构造 App.xaml.cs:25-31 记日志;注册 App_Startup/App_Exit(App_Exit 体为空——退出语义缺失)
OnStartup App.xaml.cs:33-46 单实例互斥,已运行则提示并 Shutdown;开 Stylus 触控
App_Startup App.xaml.cs:52-68 注册 UI/Task/非UI 三类全局异常;MigratePlaintextCredentials()(明文口令一次性加密回写,须先于读凭据);InitOperationLog();ClickTrailLogger.Install()(全局点击层);ChangeLanguage()
InitOperationLog App.xaml.cs:74-96 起操作日志:project=operate、Kafka=kfkaIP:kfkaPort(缺则 127.0.0.1:9092)、topic=tl-oplog、配置 exe 同目录 oplog-config.json;全 try 兜底
MainWindow() 构造 MainWindow.xaml.cs:27-45 把 MainGrid 包进 Viewbox(Uniform)做竖屏自适应(合并去掉了 #if DEBUG,Release 也生效)
MainWindow_Loaded MainWindow.xaml.cs:47-61 LoginWindow.ShowDialog(),失败则关窗退出;成功后建 MainPageViewModel(TlSn)+首页
登录提交 LoginWindow.xaml.cs:42-95 校验账号/密码/设备号;AppData.AppDataInit() 成功后 setAppConfig() 写回
AppDataInit AppData.cs:114-147 建 HttpHelper→云端校验账号→置 TlNum/TlSn(NEO-1-{TlNum})→建 MqttHelper(连 broker 订阅)→拉 TLSettingCommon+受精类型字典→设操作日志上下文
登录后后台线程 MainWindow.xaml.cs:67-132 Task.Run 托管 control:ivf_tl_Control.AppData.Login(同账号透传)→ LogService.Pan=cacheDiskHAL.ScanDevices()(设备发现一次)→ StartMain.StartRun()(阻塞常驻)。全程异常只记日志、不退进程(已去掉 control 原 Environment.Exit)

control 登录窗(Window1)已从启动路径剔除,改由 operate 单登录账号透传。ScanDevices 仅在 ⑨ 调一次,保证前后台拿同一组句柄。


二、窗口 / 页面骨架

Windows/(独立窗口):LoginWindow(登录,内置软键盘)、MessageWindow/MessagePrompt(提示/确认)、GetDateWindow(选日期)、PhotoWindowNew(看图)。

View/(MainWindow 容器内切换的 UserControl):MainPageView(首页舱室总览)、DetailPageView(胚胎详情,含 10s 报警轮询)、PhotoPageView/ChartPageView/AlarmPageView/DishRecordViewHouseSettingPageView/HouseDebugPageView/AutoFocusSettingView/CCDSettingView/BufferDebugViewSettingPageView/AboutView/AddDishWindowViewServiceMonitorView(新增)UnifiedConfigView(新增)

CustomUserControls/:CustomHouseInfo/CustomDishInfo/PhotoBox/AlarmControl 等;SoftKeyboard+SoftKeyboardHost(新增,替代 osk.exe)

导航:单容器 MainWindow._container.Content,LoadPage(UserControl)(MainWindow.xaml.cs:135)切页,AppData.BackMainPage()(AppData.cs:177)回首页。无导航框架。


三、业务模块(职责 + 操作 + 背后动作)

凡"动硬件"均走 Serial.*/Cam.*(= HAL 借用句柄 → control 串口/相机);凡"查/改数据"均走 AppData.Instance.HttpHelper.*(HTTP)。

3.1 首页/舱室总览 — MainPageViewModel(1023 行)

  • 职责:10 舱卡片状态、培养记录、报警计数/语音、MQTT 实时消息。
  • 操作:看舱室 Init():142→GetHouseCultureListApi;报警轮询 StartThread():745→SearchAlarmHistoryNumApi/TlInfoTimeApi/SearchAlarmHistoryApi;报警静音 SetAlarmMute:957;MQTT 实时 RecMqttMessage():516。
  • 结束培养 EndDish(houseSn):347 —— 仅本地清空 ExDish/发育时间,无 HTTP 下发(注意:与"皿管理结束培养走 HTTP"是两条路)。
  • 隐性写 control::768 ivf_tl_Control.AppData.Instance.LastHttpOkAt = DateTime.Now(HTTP 成功时反写 control 单例,供监控透出)。
  • 差异:与基准方法一一对应、无功能降级,改动仅加操作日志埋点(行号下移)。

3.2 舱室设置 / 对焦调试 — HouseDebugPageViewModel(1592 行,基准 954)

  • 进/出调试:ComHouseInit():244 —— HAL.GetHouseGate(houseSn).Acquire(OperateDebug):256-257 借用;返回 null=该舱正被采集占用→提示重试(:258-262),异常→提示并退出(:264-268)。Serial/Cam = _halLease.Serial/.Camera(:44/46)。ComHouseUnit():355 —— Dispose() 归还,绝不 ClosePort/UnInit(:359-360,否则关掉采集端口)。
  • 读环境:温 RedTem:383、压 RedPre:392、门 RedDoor:401。
  • LED/气阀:开关 LED(422/436)、开关进气阀(450/462)、开关排气阀(474/487)、舱室排气 HouseVent:510。
  • 电机点动:水平/垂直 复位/前进/后退/绝对移动(:589 起)。
  • 写 EEPROM:进气阀时间 WriteOpenIntakeTime:520(真下发)、垂直间隔脉冲 WriteOVerSpace:565、保存水平位 SaveWellHor:579。
  • 存图:SavePic:748、水平抓图 ShuiPingZhuaPai:775、清晰图层抓图 AutoFocusPic:834。
  • 一键标定(新增):把借用的 Serial/Camnew CalibrationEngine(...)(见 DebugCalibrationAdapter.cs)。
  • 降级 3 处见 §八:排气阀时间写/读、存图实现。

3.3 对焦设置 — AutoFocusSettingViewModel(33 行,两版相同)

  • 展示/编辑各舱 autoFocus 开关、well 级对焦设置。构造 HTTP FocusSettingApi(TlSn):19。无串口/降级。
  • 对焦"层数/层间距/层下移"几何预览在 DebugCalibrationAdapter.LayerPreviewItem(PhotoLayerCalculator.ComputeLayerPositions)。

3.4 缓冲瓶调试 — BufferDebugViewModel(311 行,基准 273)

  • 进/出:ComHouseInit():154 借用缓冲瓶舱(houseSn=11),ComHouseUnit():208 归还。
  • 操作:读状态 BufferState():229;补气 Are():238;进气阀时间 writeE:251→WriteOpenIntakeTimeWait(...,isBuffer:true):259(真下发)+HTTP LightsUpdateApi:261;读灯光 RedL():285(真读)。
  • 降级 1 处见 §八:灯光亮度写 EEPROM。

3.5 皿管理 / 胚胎操作

  • 加皿/编辑/平衡(逻辑在 View/AddDishWindowView.xaml.cs):AddCultureRecordApi:614、UpdateDishInfoApi:426、StartBalanceApi:669/StopBalanceApi:655。纯 HTTP,无降级。
  • 胚胎详情 DetailPageViewModel(101 行,两版相同):Init():42→GetQuickButtonsApi:47、GetRecordDetailApi:53;详情页起 10s 报警轮询(DetailPageView.xaml.cs:91-120GetHouseCropAlarmApi)。
  • 胚胎照片 PhotoPageViewModel(146 行,两版相同):GetPictureViewApi:88/GetSourcePictureViewApi:80,纯 HTTP。

3.6 其它 ViewModel(逐一扫过)

  • DishRecordViewModel(34)/AlarmPageViewModel(42):纯分页/日期状态容器,无业务调用。
  • ChartPageViewModel(252,两版相同):环境曲线 RefHistroy():206→GetHouseEnvironmentListApi
  • HouseSettingPageViewModel(26):SettingSystemApi:17+GetSettingHouseApi:18,纯 HTTP。
  • ServiceMonitorViewModel(192,新增,只读):每 2s 跨读 ivf_tl_Control.AppData.Instance.GetMonitorSnapshot():77,无下发控件;⚠ StaleSeconds=30(:28)、堆积阈值(:112-116)标 [D10] 占位、[M7] 运行时未验证。
  • UnifiedConfigViewModel(85,新增):只写本地层 App.config(IP/端口/盘符/tlNum/语言/凭据),SaveAll():61 凭据 SaveEncrypted 加密;⚠ :60 返回值恒 true 占位(异常被 Helper 吞,不反映真实成败);数据库层项本页只读。
  • DebugCalibrationAdapter.cs(55,新增):无运行逻辑,仅数据类型;注释说明旧 DebugSerial/CameraAdapter 已退役删除。

四、operate ↔ control 交接面(= 双进程拆分改造清单)

合并后 control 跑在 operate 同进程,operate 三种方式直连 control。拆双进程时全部要改成 IPC/HTTP:

# file:line 直连方式 拆进程后改成
1 MainWindow.xaml.cs:89 ControlAppData.Login() 同账号透传 启动独立进程 + 透传凭证
2 MainWindow.xaml.cs:100 直写 ControlAppData.LogService.Pan 启动参数/进程内配置
3 MainWindow.xaml.cs:103,121 new StartMain()+StartRun() 进程内跑 control 拉起 control.exe 并等就绪
4 MainWindow.xaml.cs:110,112 HAL.Instance.Log/.ScanDevices() 移入 control 进程自做
5 HouseDebugPageViewModel.cs:256,257 HAL.GetHouseGate().Acquire 借串口 跨进程借用协议(让出/恢复采集)
6 BufferDebugViewModel.cs:163,164 HAL.GetHouseGate().Acquire 借串口 同上
7 ServiceMonitorViewModel.cs:77 ControlAppData.GetMonitorSnapshot() 直读 HTTP/IPC 拉快照
8 MainPageViewModel.cs:768 直写 ControlAppData.LastHttpOkAt 心跳 跨进程上报通讯心跳

全目录已确认:其余 ViewModel 无 HAL/ControlAppData 直连,只走 HTTP。 借用语义:前台 Acquire(OperateDebug) 触发 control 采集让路(协作式),复用同一物理句柄,Dispose 即归还恢复采集——详见 control-逻辑与配置全景.md §6.2。


五、operate ↔ 服务器 HTTP

5.1 HttpHelper 机制(ivf_tl_Services/HttpHelper.cs,1580 行,单例)

  • BaseUrl:AppData.cs:80 {urlIp}:{urlPort}/(经 AppConfigHelper 容错读,缺键回默认);InitHttpClient(强制 Tls12,ExpectContinue=false)后立即 Login()
  • 超时(两层,无重试):ServiceTimeout=12s(:42,HttpClient 整体)、AsyncTimeout=10s(:39,每次 SendAsync 的 CTS)。任何失败/超时直接返回 null,各 Api 吞异常返默认。
  • 认证:GetToken():1348 缓存 token,每请求加头 token
  • 统一收发:三个 callWebService 重载(无 body / JSON / Dictionary→Form)+ callWebServiceNoToken → 全汇聚 HttpClientSendAsync:1449。
  • trace_id + 计时 + 操作日志(M8-P3b,合并新增):HttpClientSendAsync:1449-1497 取 OperationLogContext.TraceId ?? NewTraceId() 写请求头 traceId(:1460,与 Java 网关对齐,实现 C#→Java 链路串联)+ Stopwatch 计时 + 四类分支统一 SafeOpLog(module=HTTP,operation=接口路径,output>2000 截断,全 try 兜底)。

5.2 接口清单(全部经 HttpHelper,POST 居多)

登录 /api/gateway/auth/login(:1322/1354);天平 起/停 …/balance/startBalance(:191)/stopBalance(:215);在培列表 …/getHouseCultureList(:246);皿 增 addCultureRecord(:279)/结束 endCultureRecord(:308)/更新 updateCultureRecord(:332);图片视频 getPicturesByRecordId(:364);记录详情 getRecordDetail(:400);切层 switchVideoPictureLayers(:440)/switchVideoLayerByPicture(:985);快捷/时间按钮 …/getButtons(:468/497);仪器设置 …/setting/data(:529);系统设置 …/setting/system(:563)/更新(:595);版本 getVersionBySn(:619);舱室设置 …/setting/house(:651)/更新(:681)/调试回写 …/house/debugging(:780)/well 更新 …/house/well/update(:808)/对焦 …/house/focus/setting(:835)/立即拍照 …/house/immediately(:866);通用设置 …/setting/common(:719)/更新(:751);光照更新 …/lights/update(:894);仪器时间 …/tlInfo/time(:927);字典 queryDictionaryByType(:960);视频时间轴 getVideoTimeLine(:1008);环境列表 …/getHouseEnvironmentList(:1033);标记去向 markEmbryoDestination(:1058);皿记录 查/数 getEmbryoCultureRecord(Num)(:1081/1107);告警 数/历史 getAlarmNum(:1135)/getAlarm(:1161);图片视图 getPictures(:1189)/原始图 getSourcePictures(:1215);按 id 取皿 getCultureRecordById(:1241);静音 muteAlarm(:1267);裁剪告警 getHouseCropAlarm(:1290);文件下载(GET) DownLoadFileAsync(:97/138)。

接口清单与基准无增删,仅行号因埋点偏移。


六、凭据与加密

  • :userName/tlNum 明文读;passWordCryptoHelper.Decrypt 回填(LoginWindow.xaml.cs:36-39)。
  • :AppData.SetApp/setAppConfig(AppData.cs:187-228,XmlDocument 直改 ivf_tl_Operate.dll.config)写 userName/tlNum 明文、passWord 加密。
  • 加密:Helpers/CryptoHelper.cs —— DPAPI ProtectedData,LocalMachine 作用域,附加熵 "ivf_tl_operate_M5_02",密文前缀 enc:+Base64;Encrypt/Decrypt/IsEncrypted 幂等、失败回退原值不抛。
  • 迁移:AppConfigHelper.MigratePlaintextCredentials()(:88-126)启动时一次性把明文 passWord/engineerPwd 加密回写(幂等)。
  • 工程师口令:engineerPwd 默认 tl13579(AppConfigHelper.cs:20-23),GetEngineerPwd():129 解密取用。
  • 配置封装:Helpers/AppConfigHelper.cs 容错读写(缺键返默认,不裸 NPE)。

七、配置参数全表(operate 侧 App.config)

文件 ivf_tl_Operate/App.config。「基准」= 是否在基准版 临时文件/.../App.config(基准仅 11 键、无加密、无 oplog、无 control 业务键)。

🟢 2026-06-23 配置收敛(本表为收敛前历史快照,差异见下):① 共享连接键 outInter/urlIp/urlPort/mqttIp/mqttPort/kfkaIP/kfkaPort 已从 ivf_tl_Operate/App.config 迁出到 operate 输出根的唯一数据源 tl-shared.config(operate/control 经 <appSettings file=> 合并读);② 表中那批 CCDError/csTime/gbTime/VentNum/VentPre/VentWaitTimeB/VentWaitTimeD/AutoWaitTime/CCDAutoWaitTime/CCDFailedWaitTime/CCDFailedNumber/QueuAir 是 operate 死副本(operate 不读、只 control 读),已从 operate App.config 删除(control 自己那份保留)。收敛后 operate App.config 只留:autoFocus/userName/passWord/engineerPwd/tlNum/houseEnabled/Language/StopPro/cacheDisk/controlPort/controlExePath。详见 specs/2026-06-23-配置收敛-operate-control连接组单一数据源-design.md

key 现值 类别 基准 / 合并新增
autoFocus 0 业务(下位机换气开关) 基准有
outInter 0 连接(0内网/1外网) 基准有
userName admin 凭据 基准有
passWord 启动迁移为 enc: 凭据 基准有(原明文,合并加密)
engineerPwd enc:(默认 tl13579) 凭据 合并新增
tlNum 20230411 业务(设备号) 基准有
urlIp http://127.0.0.1 连接 基准有(原 192.168.1.92,合并改值,需现场核对)
urlPort 10010 连接 基准有
mqttIp 192.168.0.108 连接 基准有(原 192.168.1.92,合并改值)
mqttPort 1883 连接 基准有
kfkaIP / kfkaPort 192.168.0.108 / 9092 连接(oplog) 合并新增
houseEnabled 业务(禁用舱) 基准有
Language Chinese.xaml 业务 基准有
CCDError/csTime/gbTime/VentNum/VentPre/VentWaitTimeB/VentWaitTimeD/AutoWaitTime/CCDAutoWaitTime/CCDFailedWaitTime/CCDFailedNumber/QueuAir 见值 业务(control 换气/CCD) 合并新增(并入的 control 键)
StopPro 15 业务(关机倒计时) 合并新增(control)
cacheDisk C 业务(缓存盘,MainWindow:96 透传 control) 合并新增(control)

含义见 control-逻辑与配置全景.md §8.1(这些 control 业务键由 control 端消费)。operate 端实际只读 outInter/urlIp/urlPort/mqtt/kfka/userName/passWord/engineerPwd/tlNum/Language/houseEnabled/autoFocus/cacheDisk。


八、★ 合并改动 / 降级 / 待验证登记(operate 侧核心)

control 全景管不到 operate 调试页,这一节是另一半文档的存在理由。降级根因统一:control/IvfTl.Hardware/Impl/SerialChannelImpl.cs——control 端 Commander 缺对应 builder,HAL 实现"不臆造字节"返回桩值,VM 层据返回值给提示。

8.1 功能降级登记表(相对基准,真实功能缺失)

2026-06-23 更新:M-01/M-02/M-03 已修复并真机验证(TDD red→green + 非破坏性回环)——control 端补齐 3 个 E方 builder + ComBin Wait + SerialChannelImpl 去桩,见 进度/待验证清单.md 同日段。下表前三行标 ✅已修复。M-04 存图经代码核查等价(24bpp/原生尺寸/canonical Y翻转,同权威 af ImageConverter)、M-05(0x12 帧长合并回归)、M-06(按 well 焦点零点)均已修复/定论(详见 §8.2 + 待验证清单)。

模块 操作 基准行为 现状(file:line) UI 提示 风险
对焦调试 写舱室排气阀时间 ✅已修复 WriteEEPROOpenVentTimeWait 真下发 Serial.WriteOpenVentTimeWait_com.WriteEEPROOpenVentTimeWait(SerialChannelImpl.cs:130 已去桩;control 补 CreateWriteEEPROOpenVentTimeCommand 地址 00 03 08) 已解除:真机回环验证 舱9 200→201→200 / 舱8 90→91→90 PASS
对焦调试 读舱室排气阀时间 ✅已修复 ReadEEPROMVentWait 真读 Serial.ReadOpenVentTimeWait_com.ReadEEPROMVentWait(SerialChannelImpl.cs:137 已去桩;control 补 CreateReadEEPROMVentNum) 已解除:真机读回真实值(200/90),非旧 -1 桩
缓冲瓶调试 写灯光亮度 EEPROM ✅已修复 WriteEEPROMLightNumWait 真写 Serial.WriteLightBrightnessWait_com.WriteEEPROMLightNumWait(SerialChannelImpl.cs:143 已去桩;control 补 CreateWriteEEPROMLightNum 地址 00 05 34) 已解除:真机回环 舱8 灯光 500→501→500 PASS
对焦调试 调试页存图 ✅代码核查等价 camera.SavePic(name,w,h)→厂商 MVCAPI.SavePic(buf,w,h,name) Cam.SavePicCameraImpl.SavePic 丢弃 w/h→Camera.SaveBmpPic(name)=24bpp+原生尺寸+RotateNoneFlipY+按扩展名存(CameraImpl.cs:148-153) ❌ 无提示(实现透明替换) 已解除:朝向逻辑与权威 af ImageConverter 逐字一致(Y翻转=全系统正确朝向);忽略入参 w/h 正确(缓冲=相机原生尺寸);width=1600→1600*3=4800 四字节对齐,整块拷贝无错行。与不透明 native 厂商编码器逐字节一致既不可能也无必要(=M-04)

8.2 待验证 / 桩(非降级,但成功语义不可靠或未实现)

  • 写 EEPROM 类"成功=true"普遍不可靠:WriteWellHorizontalPosWait/WriteScanStepWait/WriteOpenIntakeTimeWait 因旧栈写命令无显式成功出口,"阻塞收到回复即 return true",未把回包状态字传播给调用方(SerialChannelImpl.cs:106-118,接口注释 ISerialChannel.cs:54-65)。有下发,但成功与否未传回。属 M-05 残留(非回归,基线 operate 同样无条件 true)。
  • ✅ 2026-06-23 M-05 帧错位根因已修复并真机实证:control/ivf_tl_SerialHelper/Util/Commander.cs CustomProtocolLength0x12 写E方回包帧长设成 6(合并回归;合并前 operate 基线=12),只读前 6 字节 → 把数据字节 [4] 误当状态字(非0→误判失败)、ORC 错位、且残留 6 字节污染紧接的下一次读(=M-01/02/03 验证时"写后读垃圾值"现象的根因)。真机 raw 抓包实证 0x12 回包确为 12 字节(舱8/舱9 一致,回包 [3]=0x0C 自证),改 control 帧长表 0x12→12。TDD:ivf_tl_SerialHelper.Tests/CustomProtocolLengthTests.cs red→green(0x12=12 + 整表对齐基线,22 单测过);真机回环"紧凑写→立即读、无丢帧 workaround"舱8/舱9 各 12 轮 24/24 全干净(旧码此处必出 -1/垃圾)。修复后 Channel 既有 receivedBuffer[lenght-2] 状态字检查也落到正确位置 [10]。详见 进度/待验证清单.md M-05。
  • SerialChannelImpl.SendWait 返回 null(:61-66):裸帧通道未实现(TODO M2),当前调试页未用,仅影响未来扩展。
  • ✅ 2026-06-23 ReadWellFocusZeroWait 已修复(M-06):此前 control 端忽略 well 入参恒读 well-1(ComBin.ReadEEPROMvertMtStartPulseWait 硬编码 CreateReadEEPROMvertMtStartPulse(1));builder 早支持 case 1-16(地址 0x08+4*(well-1),同 autofocustool 权威表)。改 ComBinwell 参(默认1,SerialBin 舱级读不变)+ SerialChannelImpl 传真 well。真机集成 red→green:各 well 修前全返回 well-1(舱9恒80200/舱8恒74600)→ 修后 per-well 各异(与 raw 抓包诊断逐 well 吻合)。对 autofocus Z 电机零影响:消费方 CalibrationEngine 粗对焦用固定中心 90000、eepromZ 未参与 Z 定位、所有 Z 移动恒 ClampZ[0,125000]。详见 进度/待验证清单.md M-06。
  • ServiceMonitorViewModel 阈值占位:StaleSeconds=30、上传堆积阈值标 [D10] 占位、[M7] 运行时未验证。
  • UnifiedConfigViewModel.SaveAll 恒返回 true(:60-82):异常被 Helper 吞,返回值不代表真实保存结果。
  • CameraImpl.SetGain 返回 -1(control/IvfTl.Hardware/Impl/CameraImpl.cs:69-75,TODO M2):旧 Camera 未暴露独立增益设置(增益随 Init 固定),与 SendWait/ReadWellFocusZeroWait 同性质的待验证桩。当前调试/采集链路不调它,自动对焦标定若需调增益再补 native 包装。

8.3 合并新增能力(非降级,记录在案)

  • Helpers/ 整目录新增:AppConfigHelper(配置容错)、CryptoHelper(DPAPI 加密)、ClickTrailLogger(全局点击层日志)。
  • App.xaml.cs 新增:凭据迁移、操作日志初始化、点击层安装、UI 异常按签名 10s 节流(:184-220,防 8GB 日志复发)。
  • 新增页:ServiceMonitorView(只读监控)、UnifiedConfigView(本地配置)、内置软键盘。
  • HttpHelper 新增 trace_id 承接 + 计时 + 操作日志埋点(见 §5.1)。

8.4 bug 修复(合并相对基准修正,正向)

  • 语言字典移除:基准 RemoveAt(Count-1) 盲删(误删 AdaptiveStyles 致 8GB 日志);合并改按引用/按 /Language/ 精确移除(App.xaml.cs:265-281)。
  • BaseUrl 取值健壮化:基准裸 ConfigurationManager.AppSettings[...](缺键 NPE/FormatException);合并改 AppConfigHelper.GetString/GetInt(缺键回默认不崩)。
  • passWord 加密治理:基准明文读写 → 合并 DPAPI 加密。

九、operate 自身后台线程(非 control)

线程/任务 file:line 形态 职责
control 后台托管 MainWindow.xaml.cs:67-132 Task.Run 一次 登录后起 control(内部阻塞常驻)
胚胎详情报警轮询 DetailPageView.xaml.cs:91-120 Task.Run+while+Sleep(10s) operate 唯一常驻轮询:每 10s GetHouseCropAlarmApi 刷报警;vm==null 退出
MQTT 订阅回调 AppData.cs:138-143 事件回调 broker 推送舱室实时数据(登录建立)
日志洪流节流 App.xaml.cs:184-205 静态字典 同签名异常 10s 内只放行一条(合并新增)
按钮短任务 多页 Task.Run 短任务 调试/查询点击不卡 UI,用完即结束

operate 内无 DispatcherTimer/Timers.Timer/显式 new Thread;常驻后台只有"详情页 10s 轮询"+"control 托管线程"。


十、可疑残留 / 上线前清理项(均经核实,多为基准同源残留、合并未清)

  1. AppData.cs:91-111 #if DEBUG 外网覆盖:Debug 编译下连续 4 次覆盖 BaseUrl,最终写死 http://test-gateway.aivfo.com:36000/(测试外网),无视 App.config。真机验证/抓真实问题必须用 Release,否则连到测试环境。(与基准一致,非合并引入)
  2. AppData.cs:84-90 outInter==1 外网分支:Release 下也会把 BaseUrl 切 test-gateway.aivfo.com:36000、MqttIp 211.149.139.131。当前 outInter=0 走内网,但这是个地址打外网的开关。
  3. HttpHelper.GetMp4():75-94 死代码:硬编码外网 FastDFS 地址 + 桌面绝对路径,无调用方(测试残留),建议删。
  4. 多处 #if DEBUG 本地绝对路径(AppData.cs:243-247、App.xaml.cs:243-246):Logo/语言文件指向 C:\PersonalSpace\work\...,仅开发机有效。
  5. urlIp=127.0.0.1/mqttIp=192.168.0.108(App.config,合并改值):需现场确认实际网关 IP(注释已标 [M7] 现场核对)。
  6. control 托管线程静默失败:登录/StartRun/HAL 失败全部只记日志不退进程(MainWindow.xaml.cs:84/91/118/123/130)——control 后台没起来时 operate 前台仍可用,易被忽略(无显式告警)。
  7. OperateHwTest = 测试代码,非交付件(ivf_tl_operate_2.0/OperateHwTest/Program.cs,与 ivf_tl_Operate 平级的控制台项目):internal class Program,真机硬件闭环测试 CLI,子命令 scan/motor/http/camera,复用 operate 真实 ivf_tl_Entity.ComEntitys.ComBinHttpHelper 驱动真机;硬编码 admin/123456 与 7 舱→COM 口映射、电机脉冲安全钳位。属测试/诊断工具(性质同 control 侧 ivf_tl_ControlTest 老壳),交付打包不含、上线前确认随测试资料归档或排除,勿当产品功能。

十一、给"双进程拆分"的关键结论(operate 侧)

  1. operate 进程内托管 control 是拆分的拆除对象:§四 8 个直连点要全改成跨进程(启动 control.exe + 等就绪 + IPC 借串口 + HTTP 读状态 + 心跳上报)。
  2. 退出语义缺失同样在 operate 侧:App_Exit 空体、去掉了 control 的 Environment.Exit——拆分后 operate 关闭只关 UI,control 进程续命;需补对称停机入口(参 control 全景 §九.5)。
  3. 降级要补的是 control 端 builder:§8.1 三处 EEPROM 桩,补 control Commander 三个 builder(CreateWriteEEPROOpenVentTimeCommand / 读排气阀 / CreateWriteEEPROMLightNum)+ 真机核对字节即可接通;存图需真机核对 SaveBmpPic 与 MVCAPI.SavePic 落盘一致性。
  4. 最易被误判"正常"的两处:排气阀时间(静默保留旧值,无提示)、调试页存图(透明换实现,无提示)——上线前必须真机确认。
  5. 写 EEPROM "成功=true" 全部待真机(§8.2):成功语义不可靠,补字节核对前不能据 UI 成功提示判定真已写入。
  6. 纯 HTTP/展示模块(首页/详情/照片/曲线/皿管理/对焦设置)合并无功能差异,可信。