using IvfTl.Control.Entity; using IvfTl.Control.Entity.GlobalEnums; using ivf_tl_UtilHelper; using System.Diagnostics; namespace ivf_tl_SerialHelper.Util { /// /// 封装指令发送以及解析线程 /// public class ComBin { /// /// 异常日志 /// 异常、名称、参数 /// public event Action ExceptionLogEvent; /// /// 错误日志 /// public event Action ErrorLogEvent; /// /// 指令记录日志 /// public event Action CommandLogEvent; /// /// 串口状态 /// public event Action ComStateEvent; public ComBin(int houseId, string portName) { this.houseId = houseId; this.portName = portName; _commandQueue = new Queue(); _channel = new Channel(houseId, portName); _channel.DataReceived += _channel_DataReceived; _channel.ExceptionLogEvent += _channel_ExceptionLogEvent; _channel.ErrorLogEvent += _channel_ErrorLogEvent; _channel.CommandLogEvent += _channel_CommandLogEvent; ; StartSendCommandThread(); } private void _channel_CommandLogEvent(int arg1, DateTime arg2, string arg3, LogEnum arg4) { CommandLogEvent?.Invoke(arg1, arg2, arg3, arg4); } private void _channel_ErrorLogEvent(string arg1, LogEnum arg2) { ErrorLogEvent?.Invoke(arg1, arg2); } private void _channel_ExceptionLogEvent(Exception arg1, string arg2, string arg3, LogEnum arg4) { ExceptionLogEvent?.Invoke(arg1, arg2, arg3, arg4); } public Channel _channel { get; set; } = null; /// /// 是否停止发送指令线程循环 /// public bool IsStop = false; /// /// 指令发送失败以后是否无限重发 /// public bool IsStopWhile = true; private int houseId = 0; private string portName = null; /// /// 命令队列 /// private Queue _commandQueue; /// /// 指令超时重发等待毫秒 /// private int milliseconds = 1000 * 30; /// /// 发送指令的线程同步控制器 /// private AutoResetEvent sendAutoResetEvent = new AutoResetEvent(false); /// /// 运行线程等待指令的同步控制器 /// private AutoResetEvent taskAutoResetEvent = new AutoResetEvent(false); /// /// 指令发送锁 /// private object SendCommandLock = new object(); /// /// 指令计数 /// private double commandNumber = 1; /// /// 串口状态 0正常 1异常 /// private int ComState = -1; /// /// 开启发送指令线程 /// public void StartSendCommandThread() { Task.Factory.StartNew(() => { Stopwatch SendStopWatch = new Stopwatch(); CustomProtocol customProtocol = null; while (true) { try { if (IsStop) { return; } lock (_commandQueue) { if (_commandQueue.Any()) { customProtocol = _commandQueue.Dequeue(); } } if (customProtocol != null) { SendStopWatch.Restart(); string Content = $"[{houseId}][{portName}][{customProtocol.commandNumber}][{customProtocol.commandType}][Send:{StringHelper.ByteToHexStr(customProtocol.sendBuffer)}]"; customProtocol.IsSuccess = SendCommand(customProtocol, Content); string Content11 = $"{Content}[Rec:{StringHelper.ByteToHexStr(customProtocol.receivedBuffer)}]"; if (customProtocol.WaitTime != 0) { CommandLogEvent?.Invoke(houseId, DateTime.Now, $"{Content11}[等待{customProtocol.WaitTime}毫秒]", LogEnum.HouseComRecord); Thread.Sleep(customProtocol.WaitTime); } CommandLogEvent?.Invoke(houseId, DateTime.Now, $"{Content11}[本轮指令总耗时:{StringHelper.TimeToString(SendStopWatch.Elapsed)}][End]", LogEnum.HouseComRecord); SendStopWatch.Stop(); if (customProtocol.IsWaitOne) { taskAutoResetEvent.Set(); } customProtocol = null; } else { //CommandLogEvent?.Invoke(houseId, DateTime.Now, $"空指令,等待50毫秒", LogEnum.HouseComRecord); Thread.Sleep(50); } } catch (Exception ex) { ExceptionLogEvent?.Invoke(ex, $"[{houseId}][{portName}]指令发送线程", null, LogEnum.RunException); } } }, TaskCreationOptions.LongRunning); } /// /// 指令发送 /// /// /// private bool SendCommand(CustomProtocol customProtocol, string Content) { try { //超时重发3次后表示通讯中断 var result = false; bool isopen = true; bool sendRs = false; do { for (int i = 0; i < 3; i++) { if (isopen) { sendRs = _channel.Send(customProtocol); CommandLogEvent?.Invoke(houseId, DateTime.Now, $"{Content}[第{i + 1}次发送结果:{sendRs}]", LogEnum.HouseComRecord); } if (sendRs) { result = sendAutoResetEvent.WaitOne(milliseconds);//延时等待下位机回复 if (result) { break; } else { sendRs = false; CommandLogEvent?.Invoke(houseId, DateTime.Now, $"{Content}第{i + 1}次等待超时", LogEnum.HouseComRecord); ErrorLogEvent?.Invoke($"{Content}第{i + 1}次等待超时", LogEnum.RunError); if (i != 2) { isopen = _channel.ReopenPort(); CommandLogEvent?.Invoke(houseId, DateTime.Now, $"{Content}[第{i + 1}次重新打开串口结果:{isopen}]", LogEnum.HouseComRecord); if (!isopen) { ErrorLogEvent?.Invoke($"{Content}第{i + 1}次重新打开串口失败", LogEnum.RunError); } } } } else { ErrorLogEvent?.Invoke($"{Content}第{i + 1}次发送失败", LogEnum.RunError); if (i != 2) { Thread.Sleep(milliseconds); isopen = _channel.ReopenPort(); CommandLogEvent?.Invoke(houseId, DateTime.Now, $"{Content}[第{i + 1}次重新打开串口结果:{isopen}]", LogEnum.HouseComRecord); if (!isopen) { ErrorLogEvent?.Invoke($"{Content}第{i + 1}次重新打开串口失败", LogEnum.RunError); } } } } //ErrorLogEvent?.Invoke($"{result}、{IsStopWhile}", LogEnum.RunError); if (!result && !IsStopWhile) { return false; } ComlossAlarm(result); } while (!result); return true; } catch (Exception ex) { ExceptionLogEvent?.Invoke(ex, $"{Content}指令发送", null, LogEnum.RunException); return false; } } private void _channel_DataReceived(CustomProtocol obj) { sendAutoResetEvent.Set(); } /// /// 发送封装 /// /// private void Enqueue(CustomProtocol custom) { lock (_commandQueue) { _commandQueue.Enqueue(custom); } } public bool OpenPort() { bool ok = _channel.OpenPort(); // 借用复用死锁修复(D1-08):HAL.ScanDevices 扫描每口后经 SerialChannelImpl.Close() 置 IsStop=true, // 令发送线程 while(IsStop)return 永久退出;采集端 serialBin.Start() 随后借用同一缓存 ComBin、 // 直接调本方法重开端口(返回 True)再 ShakeHandsWait 入队握手指令,但发送线程已死、无人出队处理, // ShakeHandsWait 的 taskAutoResetEvent.WaitOne()(无超时)→ 永久死锁(旧合并 operate 僵尸即卡此)。 // 故:重开端口成功且发送线程处于停止态时,复位 IsStop 并重启发送线程(SendCommandLock 防并发双起)。 if (ok) { lock (SendCommandLock) { if (IsStop) { IsStop = false; StartSendCommandThread(); } } } return ok; } public bool ClosePort() { return _channel.ClosePort(); } /// /// 通讯报警 /// /// public void ComlossAlarm(bool result) { if(!result) { if(ComState != 1) { ComState = 1; ComStateEvent?.Invoke(1); } return; } if (ComState == 0) return; ComState = 0; ComStateEvent?.Invoke(0); } #region 仓室状态 /// /// 握手指令 /// public int ShakeHandsWait(CustomProtocol custom) { //握手 custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.commandType = Enums.ShakeHands; custom.CreateHandCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseShakeHandsCommand(custom.receivedBuffer); } /// /// 读仓门状态 /// /// /// public State DoorStatusWait(CustomProtocol custom) { custom.commandType = Enums.DoorStatus; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadDoorCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return State.未知; return Analysiser.ParseDoorStatus(custom.receivedBuffer); } /// /// 仓室温度 /// /// /// public decimal TemperatureWait(CustomProtocol custom) { custom.commandType = Enums.Temperature; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadTemperatureCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1m; return Analysiser.ParseTemperatureCommand(custom.receivedBuffer); } /// /// 上盖板温度 /// /// /// public decimal ShangTemperatureWait(CustomProtocol custom) { custom.commandType = Enums.Temperature; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadShangTemperatureCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1m; return Analysiser.ParseTemperatureCommand(custom.receivedBuffer); } /// /// 玻璃片下方温度 /// /// /// public decimal BoLiTemperatureWait(CustomProtocol custom) { custom.commandType = Enums.BoLiTemperature; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadBoLiTemperatureCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1m; return Analysiser.ParseTemperatureCommand(custom.receivedBuffer); } /// /// 仓室压力 /// /// /// public decimal PressureWait(CustomProtocol custom) { custom.commandType = Enums.Pressure; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadPressureCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1m; return Analysiser.ParsePressureCommand(custom.receivedBuffer); } /// /// 获取缓冲瓶状态 /// /// public (decimal, decimal, decimal) BufferBottleState(CustomProtocol custom) { custom.commandType = Enums.BufferBottlePressure; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateBufferBottlePressureCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return (-1m,-1m,-1m); return (Analysiser.ParsePressureCommand(custom.receivedBuffer), Analysiser.ParseTLTemperature1Command(custom.receivedBuffer), Analysiser.ParseTLTemperature2Command(custom.receivedBuffer)); } #endregion #region 电机 /// /// 水平电机复位 /// /// /// public bool HorizontalMotorResetWait(CustomProtocol custom, int waitTime) { custom.commandType = Enums.HorizontalMotorReset; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateHorizontalMotorResetCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 水平电机绝对运动 /// /// /// /// /// public bool HorizontalMotorAbsoluteWait(CustomProtocol custom, int waitTime, int newValue) { custom.commandType = Enums.HorizontalMotorAbsolute; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.HorizontalMotorPulse = newValue; custom.CreateHorizontalMotorMoveToCommand(newValue); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 水平电机正向运动(相对) /// 忠实搬运 operate 侧 ComBin.HorizontalMotorForwardWait(命令构造器 control 侧已存在)。 /// public bool HorizontalMotorForwardWait(CustomProtocol custom, int waitTime, int newValue) { custom.commandType = Enums.HorizontalMotorForward; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.HorizontalMotorPulse = newValue; custom.CreateHorizontalMotorForwardCommand(newValue); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 水平电机反向运动(相对) /// 忠实搬运 operate 侧 ComBin.HorizontalMotorBackward(命令构造器 control 侧已存在)。 /// public bool HorizontalMotorBackwardWait(CustomProtocol custom, int waitTime, int newValue) { custom.commandType = Enums.HorizontalMotorBackward; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.HorizontalMotorPulse = newValue; custom.CreateHorizontalMotorBackwardCommand(newValue); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 读水平电机位置 /// public int ReadHorizontalMotorWait(CustomProtocol custom) { custom.commandType = Enums.ReadHorizontalMotor; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadHorizontalMotorCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseCurrentMotor(custom.receivedBuffer); } /// /// 读垂直电机位置 /// public int ReadVerticalMotorWait(CustomProtocol custom) { custom.commandType = Enums.ReadVerticalMotor; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadVerticalMotorCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseCurrentMotor(custom.receivedBuffer); } /// /// 垂直电机复位 /// public bool VerticalMotorResetWait(CustomProtocol custom, int waitTime) { custom.commandType = Enums.VerticalMotorReset; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateVerticalMotorResetCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 垂直电机绝对运动 /// /// 指令对象 /// 电机运动等待时间 /// 垂直电机目标位置 /// 当前水平电机位置 /// 图片编号 /// 当前well /// 当前层数 public bool VerticalMotorAbsoluteWait(CustomProtocol custom, int waitTime, int currentVer, int currentHor, int pictureId, int well, int focal) { custom.commandType = Enums.VerticalMotorAbsolute; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.VerticalMotorPulse = currentVer; custom.HorizontalMotorPulse = currentHor; custom.pictureId = pictureId; custom.well = well; custom.focal = focal; custom.CreateVerticalMotorAbsoluteMovementCommand(currentVer); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 垂直电机正向运动(相对) /// 忠实搬运 operate 侧 ComBin.VerticalMotorForwardWait(命令构造器 control 侧已存在)。 /// public bool VerticalMotorForwardWait(CustomProtocol custom, int waitTime, int newValue) { custom.commandType = Enums.VerticalMotorForward; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateVerticalMotorForwardCommand(newValue); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 垂直电机反向运动(相对) /// 忠实搬运 operate 侧 ComBin.VerticalMotorBackwardWait(命令构造器 control 侧已存在)。 /// public bool VerticalMotorBackwardWait(CustomProtocol custom, int waitTime, int newValue) { custom.commandType = Enums.VerticalMotorBackward; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateVerticalMotorBackwardCommand(newValue); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } #endregion #region 控制 /// /// 自动换气开关 /// 忠实搬运 operate 侧 ComBin.AutoWait(命令构造器/枚举 control 侧本任务已补)。 /// public bool AutoWait(CustomProtocol custom, bool auto) { custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.commandType = Enums.AutoAirSwap; custom.CreateAutoCommand(auto); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return false; return custom.receivedBuffer[custom.lenght - 2] == 0; } /// /// 仓室补气 /// /// public bool HouseAerationWait(CustomProtocol custom) { custom.commandType = Enums.HouseAeration; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateHouseAerationCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); return custom.IsSuccess; } /// /// 仓室排气 /// /// public bool HouseVentWait(CustomProtocol custom) { custom.commandType = Enums.HouseVent; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateHouseVentCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); return custom.IsSuccess; } /// /// 缓冲瓶补气 /// /// public bool BufferBottleAerationWait(CustomProtocol custom) { custom.commandType = Enums.BufferBottleAeration; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateBufferBottleAerationCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); return custom.IsSuccess; } /// /// 关闭仓室进气阀 /// /// /// public bool CloseIntakeValveWait(CustomProtocol custom, int waitTime) { custom.commandType = Enums.CloseIntakeValve; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateCloseIntakeValveCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 打开仓室排气阀 /// /// public bool OpenExhaustValveWait(CustomProtocol custom, int waitTime) { custom.commandType = Enums.OpenExhaustValve; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateOpenExhaustValveCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 打开舱室进气阀 /// /// /// /// public bool OpenIntakeValveWait(CustomProtocol custom, int waitTime) { custom.commandType = Enums.OpenIntakeValve; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateOpenIntakeValveCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } return custom.IsSuccess; } /// /// 关闭排气阀 /// /// /// public void CloseExhaustValveWait(CustomProtocol custom, int waitTime) { custom.commandType = Enums.CloseExhaustValve; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateCloseExhaustValveCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (waitTime > 0) { Thread.Sleep(waitTime); } } /// /// 打开LEd灯 /// /// public void OpenLEDWait(CustomProtocol custom) { custom.commandType = Enums.OpenLED; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateOpenLEDCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); } /// /// 关闭Led灯 /// /// public void CloseLEDWait(CustomProtocol custom) { custom.commandType = Enums.CloseLED; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateCloseLEDCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); } #endregion #region 参数 /// /// 读取TL仪器编号 /// public int ReadTLNumWait(CustomProtocol custom) { custom.commandType = Enums.ReadTLNum; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadTLNumCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// /// 获取CCDSN /// public int GetCCDSNWait(CustomProtocol custom) { custom.commandType = Enums.GetCCDSN; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateGetModuleCommand(); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// /// 读E方-->水平电机位置 /// public int ReadEEPROMhoriMtWellHorHorWait(CustomProtocol custom,int horIndex) { custom.commandType = Enums.ReadEEPROMhoriMtWellHor; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadEEPROMhoriMtWellHoriPos(horIndex); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// /// 读E方-->垂直电机清晰位置(Z对焦零点)。well=1..16 选该 well 的 EEPROM 槽(地址 0x08+4*(well-1)); /// 默认 well=1 保持舱级单值老调用(SerialBin eepromClearPosition)行为不变。 /// M-06:builder 早已支持 case 1-16,此前硬编码 (1) 致 ReadWellFocusZeroWait 忽略 well 恒读 well-1; /// 真机实证各 well 焦点零点 EEPROM 真分槽且不同(舱8/舱9 raw 抓包),改为按 well 读。 /// /// public int ReadEEPROMvertMtStartPulseWait(CustomProtocol custom, int well = 1) { custom.commandType = Enums.ReadEEPROMvertMtStartPulse; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadEEPROMvertMtStartPulse(well); custom.IsWaitOne = true; Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// /// 读E方-->垂直电机间隔脉冲 /// /// public int ReadEEPROMvertMtScanPluseWait(CustomProtocol custom) { custom.commandType = Enums.ReadEEPROMvertMtScanPluse; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateReadEEPROMvertMtScanPluse(); Enqueue( custom);//断层扫描间隔数 taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// /// 读E方-->仓室进气阀打开时间 /// /// public int ReadEEPROOpenIntakeTimeWait(CustomProtocol custom) { custom.commandType = Enums.ReadEEPROOpenIntakeTime; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateReadEEPROOpenIntakeTimeCommand(); Enqueue( custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// /// 读E方-->缓冲瓶进气阀打开时间 /// /// public int ReadEEPROOpenIntakeTimeBufferWait(CustomProtocol custom) { custom.commandType = Enums.ReadEEPROOpenIntakeTime; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateReadEEPROOpenIntakeTimeBufferCommand(); Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// /// 读E方-->下加热板目标温度 /// /// public decimal ReadTargetTempWait(CustomProtocol custom) { custom.commandType = Enums.ReadTargetTemp; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.CreateReadTargetTemp(); custom.IsWaitOne = true; Enqueue( custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1m; var num = Analysiser.ParseEEPROMPulse(custom.receivedBuffer); return Math.Round(num / 100.00m, 2, MidpointRounding.AwayFromZero); } /// /// 读E方-->灯光亮度 /// /// public int ReadEEPROMLightNumWait(CustomProtocol custom) { custom.commandType = Enums.ReadLightNum; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateReadEEPROMLightNum(); Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } // ── M1-B2 写E方调试动作包装(operate 调试页接入 lease.Serial 走本类,杜绝调试页 new ComBin/开第二个物理口)── // 字节级一致性:T1.1 子代理已逐字节核实下列 4 个 Create* builder 与 operate 端完全相同 // (命令码 0x12 + 相同 well 地址表/固定地址 + 小端 pulse + 同 CreateORC 校验),故发送字节安全。 // ⚠ 待真机(V-010):写E方为破坏性操作;control 端 CustomProtocolLength 对 0x12 期望回包长度与 operate 不同, // "写成功判定/回包等待"语义需真机核对(不影响发出的命令字节)。WriteEEPROOpenVentTime/WriteLightNum // 因 control Commander 缺对应 builder,未在此补——调试页对应动作保留旧路径并标注待真机,不臆造字节。 /// 写E方→第 wellSn(1-16) 水平电机位置脉冲(命令 0x12,builder 与 operate 逐字节一致)。⚠ 待真机 V-010。 public void WriteEEPROMhoriMtWellHorHorWait(CustomProtocol custom, int wellSn, int newValue) { custom.commandType = Enums.WriteEEPROMhoriMtWell1HoriPos; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateWriteEEPROMhoriMtWellHoriPos(wellSn, newValue); Enqueue(custom); taskAutoResetEvent.WaitOne(); return; } /// 写E方→垂直电机扫描间隔脉冲(builder 与 operate 逐字节一致)。⚠ 待真机 V-010。 public void WriteEEPROMvertMtScanPluseWait(CustomProtocol custom, int newValue) { custom.commandType = Enums.WriteEEPROMvertMtScanPluse; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateWriteEEPROMvertMtScanPluse(newValue); Enqueue(custom); taskAutoResetEvent.WaitOne(); return; } /// 写E方→舱室进气阀打开时间(builder 与 operate 逐字节一致,地址 00 03 0c)。⚠ 待真机 V-010。 public void WriteEEPROOpenIntakeTimeWait(CustomProtocol custom, int newValue) { custom.commandType = Enums.WriteEEPROOpenIntakeTime; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateWriteEEPROOpenIntakeTimeCommand(newValue); Enqueue(custom); taskAutoResetEvent.WaitOne(); return; } /// 写E方→缓冲瓶进气阀打开时间(builder 与 operate 逐字节一致,地址 00 05 0c)。⚠ 待真机 V-010。 public void WriteEEPROOpenIntakeTimeBufferWait(CustomProtocol custom, int newValue) { custom.commandType = Enums.WriteEEPROOpenIntakeTime; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateWriteEEPROOpenIntakeTimeBufferCommand(newValue); Enqueue(custom); taskAutoResetEvent.WaitOne(); return; } // ── M-01/M-02/M-03 补齐:排气阀时间写/读、灯光亮度写(builder 与 operate 逐字节一致)── /// 写E方→舱室排气阀打开时间(M-01,builder 地址 00 03 08,与 operate 一致)。⚠ 待真机 V-010。 public void WriteEEPROOpenVentTimeWait(CustomProtocol custom, int newValue) { custom.commandType = Enums.WriteEEPROOpenVentTime; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateWriteEEPROOpenVentTimeCommand(newValue); Enqueue(custom); taskAutoResetEvent.WaitOne(); return; } /// 读E方→舱室排气阀打开时间(M-02,builder 地址 00 03 08)。失败返回 -1。 public int ReadEEPROMVentWait(CustomProtocol custom) { custom.commandType = Enums.ReadEEPROOpenVentTime; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateReadEEPROMVentNum(); Enqueue(custom); taskAutoResetEvent.WaitOne(); if (!custom.IsSuccess) return -1; return Analysiser.ParseEEPROMPulse(custom.receivedBuffer); } /// 写E方→灯光亮度(M-03,builder 地址 00 05 34,与 operate 一致)。⚠ 待真机 V-010。 public void WriteEEPROMLightNumWait(CustomProtocol custom, int newValue) { custom.commandType = Enums.WriteLightNum; custom.logDateTime = DateTime.Now; custom.commandNumber = commandNumber++; custom.IsWaitOne = true; custom.CreateWriteEEPROMLightNum(newValue); Enqueue(custom); taskAutoResetEvent.WaitOne(); return; } #endregion #region 调试模式 #endregion } }