SerialChannelImpl.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. using System;
  2. using IvfTl.Control.Entity;
  3. using IvfTl.Control.Entity.GlobalEnums;
  4. using ivf_tl_SerialHelper.Util;
  5. namespace IvfTl.Hardware.Impl
  6. {
  7. /// <summary>
  8. /// ISerialChannel 实现,内部包装 control 的 ivf_tl_SerialHelper.Util.ComBin(不改其内部逻辑)。
  9. /// ComBin 自带发送队列线程 + RingBuffer + taskAutoResetEvent 同步等待,本层只转发 + 统一返回值/延时语义。
  10. /// 每个 ISerialChannel 实例唯一对应一个 COM 口(由 HAL 字典缓存保证唯一持有,杜绝同口重复 Open)。
  11. /// 一个 COM 口同一时刻一条在途指令:用 _ioLock 实例锁串行化本通道所有 Wait 调用。
  12. /// 返回值约定(13 §3.2):位置/计数失败 -1,温压失败 -1m,布尔操作失败 false。
  13. /// </summary>
  14. public sealed class SerialChannelImpl : ISerialChannel
  15. {
  16. private readonly ComBin _com; // 包装的旧具体串口栈
  17. private readonly object _ioLock = new object();
  18. private readonly string _portName;
  19. public SerialChannelImpl(int houseId, string portName)
  20. {
  21. _portName = portName;
  22. _com = new ComBin(houseId, portName);
  23. }
  24. public string PortName => _portName;
  25. public bool IsOpen { get; private set; }
  26. public Action<string> Log { get; set; }
  27. public object RawComBin => _com;
  28. // 13 §3.5/3 读超时与到位延时(属性化,禁止写死)。M1 暂不下推到旧 ComBin 的固定 milliseconds(旧栈固定超时),
  29. // 仅作为电机延时缺省值来源;下推到旧栈属 M2 真机标定(V-010 系列)。
  30. public int MoveReadTimeoutMs { get; set; } = 12000;
  31. public int QueryReadTimeoutMs { get; set; } = 3000;
  32. public int MotorSettleMs { get; set; } = 1500;
  33. private int Delay(int delayMs) => delayMs < 0 ? MotorSettleMs : delayMs;
  34. // ── 生命周期 ──
  35. public bool Open()
  36. {
  37. lock (_ioLock)
  38. {
  39. IsOpen = _com.OpenPort();
  40. return IsOpen;
  41. }
  42. }
  43. public void Close()
  44. {
  45. lock (_ioLock)
  46. {
  47. _com.IsStop = true;
  48. _com.ClosePort();
  49. IsOpen = false;
  50. }
  51. }
  52. // ── 通用收发 ──
  53. public byte[] SendWait(byte[] frame, int extraWaitMs = 0)
  54. {
  55. // TODO(M2): 旧 ComBin 不暴露"裸帧发送 + 取回复缓冲"入口(均经 CustomProtocol + Create*Command);
  56. // 裸帧通道供扩展协议/自动对焦自定义命令用,M1 不需要,留 TODO + 待验证。
  57. return null;
  58. }
  59. // ── 握手 ──
  60. public int ShakeHandsWait()
  61. {
  62. lock (_ioLock)
  63. {
  64. var c = new CustomProtocol();
  65. return _com.ShakeHandsWait(c);
  66. }
  67. }
  68. // ── EEPROM ──
  69. public int ReadCcdSnWait()
  70. {
  71. lock (_ioLock) { return _com.GetCCDSNWait(new CustomProtocol()); }
  72. }
  73. public int ReadLightBrightnessWait()
  74. {
  75. lock (_ioLock) { return _com.ReadEEPROMLightNumWait(new CustomProtocol()); }
  76. }
  77. public int ReadWellHorizontalPosWait(int well)
  78. {
  79. lock (_ioLock) { return _com.ReadEEPROMhoriMtWellHorHorWait(new CustomProtocol(), well); }
  80. }
  81. public int ReadWellFocusZeroWait(int well)
  82. {
  83. // M-06:按 well 读该 well 的 Z 对焦零点(EEPROM 地址 0x08+4*(well-1),与 autofocustool 权威表一致)。
  84. // 真机实证各 well 焦点零点 EEPROM 真分槽且不同(舱8/舱9 raw 抓包);此前底层硬编码 well-1 致忽略入参。
  85. // 纯只读;消费方 CalibrationEngine 对所有 Z 移动恒 ClampZ[0,125000],且粗对焦用固定中心 90000,无电机风险。
  86. lock (_ioLock) { return _com.ReadEEPROMvertMtStartPulseWait(new CustomProtocol(), well); }
  87. }
  88. public int ReadScanStepWait()
  89. {
  90. lock (_ioLock) { return _com.ReadEEPROMvertMtScanPluseWait(new CustomProtocol()); }
  91. }
  92. public bool WriteWellHorizontalPosWait(int well, int pulseValue)
  93. {
  94. // M1-B2:control ComBin 已补 WriteEEPROMhoriMtWellHorHorWait(调既有 CreateWriteEEPROMhoriMtWellHoriPos,
  95. // T1.1 子代理逐字节核实与 operate 完全一致:0x12 + 同 well 地址表 + 小端 pulse + 同 CreateORC)。
  96. // 写命令无显式成功出口(旧栈 void),阻塞收到回复即视为已下发,返回 true。
  97. // ⚠ 待真机 V-010:写E方破坏性,0x12 回包长度 control/operate 有差异,"写成功"判定真机核对。
  98. lock (_ioLock) { _com.WriteEEPROMhoriMtWellHorHorWait(new CustomProtocol(), well, pulseValue); }
  99. try { Aivfo.OperationLog.OperationLogger.Log("写EEPROM", "写水平电机well位置", input: new { port = _portName, well, pulseValue }, result: "成功"); } catch { }
  100. return true;
  101. }
  102. public bool WriteScanStepWait(int pulseValue)
  103. {
  104. lock (_ioLock) { _com.WriteEEPROMvertMtScanPluseWait(new CustomProtocol(), pulseValue); }
  105. try { Aivfo.OperationLog.OperationLogger.Log("写EEPROM", "写垂直扫描间隔", input: new { port = _portName, pulseValue }, result: "成功"); } catch { }
  106. return true;
  107. }
  108. public bool WriteOpenIntakeTimeWait(int newValue, bool isBuffer = false)
  109. {
  110. lock (_ioLock)
  111. {
  112. if (isBuffer) _com.WriteEEPROOpenIntakeTimeBufferWait(new CustomProtocol(), newValue);
  113. else _com.WriteEEPROOpenIntakeTimeWait(new CustomProtocol(), newValue);
  114. }
  115. try { Aivfo.OperationLog.OperationLogger.Log("写EEPROM", isBuffer ? "写缓冲瓶进气阀时间" : "写舱室进气阀时间", input: new { port = _portName, newValue, isBuffer }, result: "成功"); } catch { }
  116. return true;
  117. }
  118. public bool WriteOpenVentTimeWait(int newValue)
  119. {
  120. // M-01 已补:control Commander/ComBin 补齐 CreateWriteEEPROOpenVentTimeCommand + WriteEEPROOpenVentTimeWait
  121. // (builder 地址 00 03 08,与合并前 operate 逐字节一致)。写命令旧栈无显式成功出口(void),
  122. // 阻塞收到回复即视为已下发,返回 true。
  123. lock (_ioLock) { _com.WriteEEPROOpenVentTimeWait(new CustomProtocol(), newValue); }
  124. try { Aivfo.OperationLog.OperationLogger.Log("写EEPROM", "写舱室排气阀时间", input: new { port = _portName, newValue }, result: "成功"); } catch { }
  125. return true;
  126. }
  127. public int ReadOpenVentTimeWait()
  128. {
  129. // M-02 已补:control 补齐 CreateReadEEPROMVentNum + ReadEEPROMVentWait(地址 00 03 08)。失败返回 -1。
  130. lock (_ioLock) { return _com.ReadEEPROMVentWait(new CustomProtocol()); }
  131. }
  132. public bool WriteLightBrightnessWait(int newValue)
  133. {
  134. // M-03 已补:control 补齐 CreateWriteEEPROMLightNum + WriteEEPROMLightNumWait(地址 00 05 34)。
  135. lock (_ioLock) { _com.WriteEEPROMLightNumWait(new CustomProtocol(), newValue); }
  136. try { Aivfo.OperationLog.OperationLogger.Log("写EEPROM", "写灯光亮度", input: new { port = _portName, newValue }, result: "成功"); } catch { }
  137. return true;
  138. }
  139. // ── 电机:垂直 ──
  140. public bool VerticalMoveToWait(int pulse, int delayMs = -1)
  141. {
  142. lock (_ioLock)
  143. {
  144. // control VerticalMotorAbsoluteWait 需 (custom, waitTime, currentVer, currentHor, pictureId, well, focal);
  145. // HAL 简化签名只给目标脉冲,附带参数用 0/-1 占位(调试/对焦走采集流程时按需另传,见 M2)。
  146. return _com.VerticalMotorAbsoluteWait(new CustomProtocol(), Delay(delayMs), pulse, 0, 0, 0, 0);
  147. }
  148. }
  149. public bool VerticalForwardWait(int pulse, int delayMs = -1)
  150. {
  151. // M2: control SerialHelper ComBin 已补 VerticalMotorForwardWait(忠实搬运 operate 实现)。
  152. lock (_ioLock) { return _com.VerticalMotorForwardWait(new CustomProtocol(), Delay(delayMs), pulse); }
  153. }
  154. public bool VerticalBackwardWait(int pulse, int delayMs = -1)
  155. {
  156. lock (_ioLock) { return _com.VerticalMotorBackwardWait(new CustomProtocol(), Delay(delayMs), pulse); }
  157. }
  158. public bool VerticalResetWait(int delayMs = -1)
  159. {
  160. lock (_ioLock) { return _com.VerticalMotorResetWait(new CustomProtocol(), Delay(delayMs)); }
  161. }
  162. public int ReadVerticalPositionWait()
  163. {
  164. lock (_ioLock) { return _com.ReadVerticalMotorWait(new CustomProtocol()); }
  165. }
  166. // ── 电机:水平 ──
  167. public bool HorizontalMoveToWait(int pulse, int delayMs = -1)
  168. {
  169. lock (_ioLock) { return _com.HorizontalMotorAbsoluteWait(new CustomProtocol(), Delay(delayMs), pulse); }
  170. }
  171. public bool HorizontalForwardWait(int pulse, int delayMs = -1)
  172. {
  173. // M2: control SerialHelper ComBin 已补 HorizontalMotorForwardWait(忠实搬运 operate 实现)。
  174. lock (_ioLock) { return _com.HorizontalMotorForwardWait(new CustomProtocol(), Delay(delayMs), pulse); }
  175. }
  176. public bool HorizontalBackwardWait(int pulse, int delayMs = -1)
  177. {
  178. lock (_ioLock) { return _com.HorizontalMotorBackwardWait(new CustomProtocol(), Delay(delayMs), pulse); }
  179. }
  180. public bool HorizontalResetWait(int delayMs = -1)
  181. {
  182. lock (_ioLock) { return _com.HorizontalMotorResetWait(new CustomProtocol(), Delay(delayMs)); }
  183. }
  184. public int ReadHorizontalPositionWait()
  185. {
  186. lock (_ioLock) { return _com.ReadHorizontalMotorWait(new CustomProtocol()); }
  187. }
  188. // ── 环境量 ──
  189. public decimal TemperatureWait()
  190. {
  191. lock (_ioLock) { return _com.TemperatureWait(new CustomProtocol()); }
  192. }
  193. public decimal ShangTemperatureWait()
  194. {
  195. lock (_ioLock) { return _com.ShangTemperatureWait(new CustomProtocol()); }
  196. }
  197. public decimal BoLiTemperatureWait()
  198. {
  199. lock (_ioLock) { return _com.BoLiTemperatureWait(new CustomProtocol()); }
  200. }
  201. public decimal PressureWait()
  202. {
  203. lock (_ioLock) { return _com.PressureWait(new CustomProtocol()); }
  204. }
  205. public (decimal pressure, decimal t1, decimal t2) BufferBottleStateWait()
  206. {
  207. lock (_ioLock)
  208. {
  209. var (p, a, b) = _com.BufferBottleState(new CustomProtocol());
  210. return (p, a, b);
  211. }
  212. }
  213. public DoorState DoorStatusWait()
  214. {
  215. lock (_ioLock)
  216. {
  217. State s = _com.DoorStatusWait(new CustomProtocol());
  218. switch (s)
  219. {
  220. case State.打开: return DoorState.打开;
  221. case State.关闭: return DoorState.关闭;
  222. default: return DoorState.未知;
  223. }
  224. }
  225. }
  226. // ── IO / LED / 气阀 ──
  227. public bool OpenLedWait()
  228. {
  229. // 旧 OpenLEDWait 返回 void:阻塞等待回复后即视为成功(无 IsSuccess 出口可读)。
  230. lock (_ioLock) { _com.OpenLEDWait(new CustomProtocol()); return true; }
  231. }
  232. public bool CloseLedWait()
  233. {
  234. lock (_ioLock) { _com.CloseLEDWait(new CustomProtocol()); return true; }
  235. }
  236. public bool OpenIntakeValveWait()
  237. {
  238. lock (_ioLock) { return _com.OpenIntakeValveWait(new CustomProtocol(), 0); }
  239. }
  240. public bool CloseIntakeValveWait()
  241. {
  242. lock (_ioLock) { return _com.CloseIntakeValveWait(new CustomProtocol(), 0); }
  243. }
  244. public bool OpenExhaustValveWait()
  245. {
  246. lock (_ioLock) { return _com.OpenExhaustValveWait(new CustomProtocol(), 0); }
  247. }
  248. public bool CloseExhaustValveWait()
  249. {
  250. // 旧 CloseExhaustValveWait 返回 void。
  251. lock (_ioLock) { _com.CloseExhaustValveWait(new CustomProtocol(), 0); return true; }
  252. }
  253. public bool HouseAerationWait()
  254. {
  255. lock (_ioLock) { return _com.HouseAerationWait(new CustomProtocol()); }
  256. }
  257. public bool HouseVentWait()
  258. {
  259. lock (_ioLock) { return _com.HouseVentWait(new CustomProtocol()); }
  260. }
  261. public bool BufferBottleAerationWait()
  262. {
  263. lock (_ioLock) { return _com.BufferBottleAerationWait(new CustomProtocol()); }
  264. }
  265. public bool AutoAirSwapWait(bool on)
  266. {
  267. // M2: control SerialHelper ComBin 已补 AutoWait(忠实搬运 operate 实现,命令 0x16)。
  268. lock (_ioLock) { return _com.AutoWait(new CustomProtocol(), on); }
  269. }
  270. public void Dispose()
  271. {
  272. try { Close(); } catch { }
  273. }
  274. }
  275. }