using CommunityToolkit.Mvvm.ComponentModel; using ivf_tl_Entity.ComEntitys; using ivf_tl_Entity.DebugEntitys; using ivf_tl_Entity.DTO; using ivf_tl_Entity.GlobalEnums; using IvfTl.Hardware; using IvfTl.Hardware.Impl; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Configuration; using System.DirectoryServices.ActiveDirectory; using System.Linq; using System.Security.Principal; using System.Text; using System.Threading.Tasks; using System.Windows; namespace ivf_tl_Operate.ViewModel { public partial class BufferDebugViewModel : ObservableObject { public event Action MessageEvent; // M1-B2:缓冲瓶调试页不再 new ComBin 开第二个物理串口——走借用到的 HAL 句柄(同采集端实例)。 /// M1-B2 HAL 前台借用凭证(缓冲瓶舱 houseSn=11)。 private IvfTl.Hardware.IHardwareLease _halLease = null; /// 借用到的串口句柄;未持借用时为 null。 private IvfTl.Hardware.ISerialChannel Serial => _halLease?.Serial; /// /// 仪器设置 /// public TLSetting tLSetting = new TLSetting(); [ObservableProperty] private HouseInfo currentHouse = null; /// /// 仪器温度1 /// [ObservableProperty] private decimal temperature1 = 0m; /// /// 仪器温度2 /// [ObservableProperty] private decimal temperature2 = 0m; /// /// 压力 /// [ObservableProperty] private decimal bufferBottlePressure = 0m; [ObservableProperty] private int ledLight = 0; [ObservableProperty] private ObservableCollection messageInfoList = new ObservableCollection(); private void ExLog(Exception ex, string name) { AppData.Instance.LogHelper.ExceptionLog(ex, $"HouseDebugPageViewModel.{name}", LogEnum.RunException); } private void ErrorLog(string message, LogEnum logType) { AppData.Instance.LogHelper.TLLog($"HouseDebugPageViewModel.{message}", logType); } public void Start(ref string errora) { try { SerialBin serialBin = new SerialBin(); serialBin.TLLogEvent += AppData.Instance.LogHelper.TLLog; serialBin.ExceptionLogEvent += AppData.Instance.LogHelper.ExceptionLog; serialBin.HouseLogEvent += AppData.Instance.LogHelper.HouseLog; var errorList = serialBin.UpdataCamera(); AppData.Instance.LogHelper.TLLog($"ccdidsn:{JsonConvert.SerializeObject(serialBin.CCDidSn)}", LogEnum.RunRecord); if (errorList.Any()) { errora = $"获取相机Id和CCDSN错误{JsonConvert.SerializeObject(errorList)}"; AppData.Instance.LogHelper.TLLog(errora, LogEnum.RunRecord); return; } errorList = serialBin.Start(ConfigurationManager.AppSettings["autoFocus"].ToString()); AppData.Instance.LogHelper.TLLog($"舱室信息:{JsonConvert.SerializeObject(serialBin.SerialModels)}", LogEnum.RunRecord); AppData.Instance.LogHelper.TLLog($"E方数据:{JsonConvert.SerializeObject(serialBin.HouseEEPROInfos)}", LogEnum.RunRecord); if (errorList.Any()) { errora = $"获取串口信息错误{JsonConvert.SerializeObject(errorList)}"; AppData.Instance.LogHelper.TLLog(errora, LogEnum.RunRecord); return; } var modelCount = serialBin.SerialModels.Count; if (modelCount != 11) { string messageinfo = $"检测到{modelCount}个模块,是否继续运行?"; MessageBoxResult aaa = MessageBox.Show(messageinfo, "提示", MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No, MessageBoxOptions.DefaultDesktopOnly); if (aaa != MessageBoxResult.Yes) { errora = "结束"; return; } } List listIntRunHoues = serialBin.SerialModels.Select(x => x.houseSn).ToList(); TLInitData tLInitData = new TLInitData(); tLInitData.tlSn = $"NEO-1-{serialBin.TLNum}"; tLInitData.dayLighting = serialBin.dayLighting; tLInitData.softwareVersion = "V2.0.0"; tLInitData.verticalMotorPulseMax = 125000; tLInitData.houseLinkDataList = serialBin.SerialModels.OrderBy(x => x.houseSn).ToList(); foreach (var item in serialBin.HouseEEPROInfos) { item.tlSn = tLInitData.tlSn; } tLInitData.houseEEPROInitDTOList = serialBin.HouseEEPROInfos.OrderBy(x => x.houseSn).ToList(); AppData.Instance.LogHelper.TLLog($"舱室信息:{JsonConvert.SerializeObject(tLInitData)}", LogEnum.RunRecord); SettingDataApiData settingDataApiData = AppData.Instance.HttpHelper.GetSettingDataApi(tLInitData); if (settingDataApiData == null) { errora = $"{tLInitData.tlSn}获取仪器设置失败"; return; } AppData.Instance.LogHelper.TLLog(JsonConvert.SerializeObject(settingDataApiData), LogEnum.RunRecord); tLSetting = AppData.Instance.ConvertHelper.ConvertToTLSetting(settingDataApiData.tlInfo, settingDataApiData.tlSetting); CurrentHouse = settingDataApiData.houseList.FirstOrDefault(x => x.houseSn == 11); if (CurrentHouse == null) { errora = $"{tLInitData.tlSn}获取缓冲瓶信息失败"; return; } } catch (Exception ex) { AppData.Instance.LogHelper.ExceptionLog(ex, $"缓冲瓶调试模式初始化", LogEnum.RunException); errora = $"缓冲瓶调试模式初始化异常:{ex.Message}"; } } public async Task ComHouseInit() { await Task.Run(async () => { try { // M1-B2:向 HAL 申请缓冲瓶舱(11)前台借用,复用采集端同一物理串口句柄,不再 new ComBin 开第二个口。 try { var gate = HardwareAccessLayer.Instance.GetHouseGate(CurrentHouse.houseSn); _halLease = gate.Acquire(HardwareUser.OperateDebug); if (_halLease == null) { AddMessageInfo($"[{CurrentHouse.houseSn}]缓冲瓶舱正被占用,借用超时,稍后重试"); return; } } catch (Exception le) { AddMessageInfo($"[{CurrentHouse.houseSn}]HAL 借用异常:{le.Message}"); return; } if (Serial == null) { AddMessageInfo($"[{CurrentHouse.houseSn}]借用到的串口句柄为空(HAL 未扫描到缓冲瓶舱?)"); return; } if (!Serial.IsOpen && !Serial.Open()) { AddMessageInfo($"[{currentHouse.houseSn}][{currentHouse.housePort}]借用串口未打开且兜底打开失败"); return; } AddMessageInfo($"[{currentHouse.houseSn}][{currentHouse.housePort}]缓冲瓶调试已复用采集端串口句柄"); Serial.ShakeHandsWait(); RedL(); var a = Serial.BufferBottleStateWait(); BufferBottlePressure = a.pressure; Temperature1 = a.t1; Temperature2 = a.t2; return; } catch (Exception ex) { AppData.Instance.LogHelper.ExceptionLog(ex, "缓冲瓶调试模式初始化", LogEnum.RunException); AddMessageInfo($"初始化异常:{ex.Message}"); return; } }); } public bool ComHouseUnit() { try { // M1-B2:物理口归采集端持有;调试只归还借用,不 ClosePort。 if (_halLease != null) { try { _halLease.Dispose(); } catch { } _halLease = null; AddMessageInfo($"[{currentHouse.houseSn}]缓冲瓶已归还借用,恢复后台采集"); } return true; } catch (Exception ex) { AppData.Instance.LogHelper.ExceptionLog(ex, "缓冲瓶卸载", LogEnum.RunException); AddMessageInfo($"缓冲瓶卸载异常:{ex.Message}"); return false; } } public void BufferState() { if (Serial == null) return; var a = Serial.BufferBottleStateWait(); BufferBottlePressure = a.pressure; Temperature1 = a.t1; Temperature2 = a.t2; } public void Are() { if (Serial == null) return; // M8-G3-1:缓冲瓶补气为串口设备命令入口,补操作日志埋点(module=缓冲瓶调试)。 Aivfo.OperationLog.OperationLogger.Run("缓冲瓶调试", "缓冲瓶补气", () => Serial.BufferBottleAerationWait(), input: new { houseSn = CurrentHouse?.houseSn }); } /// /// 进气阀打开时间 /// /// public void writeE(int newValue) { if (Serial == null) return; // M1-B2:走 lease.Serial→control ComBin 缓冲瓶进气阀时间写(builder 与 operate 逐字节一致)。⚠ 待真机 V-010。 // M8-G3-1:写进气阀时间为"写 EEPROM 串口命令 + HTTP 持久化"打包操作,用 Begin scope 给父操作名串联子埋点(module=缓冲瓶调试)。 using var _op = Aivfo.OperationLog.OperationLogger.Begin("缓冲瓶调试", "保存缓冲瓶进气阀时间", houseSn: CurrentHouse?.houseSn); try { _op.Input(new { houseSn = CurrentHouse?.houseSn, newValue }); } catch { } Serial.WriteOpenIntakeTimeWait(newValue, isBuffer: true); CurrentHouse.inletValveOpeningTime = newValue; AddMessageInfo($"进气阀打开时间保存服务器结果:{AppData.Instance.HttpHelper.LightsUpdateApi(tLSetting.tlSn, LedLight, CurrentHouse.inletValveOpeningTime)}"); } /// /// 设置灯光亮度 /// /// public void writeL(int newValue) { if (Serial == null) return; // M-03 已补:control 端补齐写灯光亮度 E方命令(builder 地址 00 05 34,与合并前 operate 逐字节一致), // 经 lease.Serial→control ComBin 真正写灯光 EEPROM;同时仍记录服务器。 // M8-G3-1:设置灯光亮度为"写 EEPROM 串口命令 + HTTP 持久化"打包操作,用 Begin scope 给父操作名串联子埋点(module=缓冲瓶调试)。 using var _op = Aivfo.OperationLog.OperationLogger.Begin("缓冲瓶调试", "保存缓冲瓶灯光亮度", houseSn: CurrentHouse?.houseSn); try { _op.Input(new { houseSn = CurrentHouse?.houseSn, newValue }); } catch { } if (!Serial.WriteLightBrightnessWait(newValue)) { AddMessageInfo($"[灯光亮度]下发失败,仅本地暂存{newValue}"); } LedLight = newValue; AddMessageInfo($"灯光亮度保存服务器结果:{AppData.Instance.HttpHelper.LightsUpdateApi(tLSetting.tlSn, LedLight, CurrentHouse.inletValveOpeningTime)}"); } public void RedL() { if (Serial == null) return; LedLight = Serial.ReadLightBrightnessWait(); } private void ComBin_ExceptionLogEvent(Exception exception, string arg2, string arg3, LogEnum @enum) { AppData.Instance.LogHelper.ExceptionLog(exception, $"{arg2}{arg3}", @enum); } private void ComBin_ErrorLogEvent(string arg1, LogEnum @enum) { AppData.Instance.LogHelper.TLLog(arg1, @enum); } private void ComBin_CommandLogEvent(int arg1, DateTime time, string arg3, LogEnum @enum) { AppData.Instance.LogHelper.HouseLog(arg1, time, arg3, @enum); } public void AddMessageInfo(string mess) { MessageEvent?.Invoke(mess); } } }