EepromWriteHilTests.cs 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using System;
  2. using System.Threading;
  3. using IvfTl.Hardware.HilTests.Infrastructure;
  4. using IvfTl.Hardware.Impl;
  5. using Xunit;
  6. using Xunit.Abstractions;
  7. namespace IvfTl.Hardware.HilTests
  8. {
  9. /// <summary>
  10. /// M-01/02/03 防回归:写命令(排气阀时间/灯光亮度)真下发到下位机,读回随写变化,写后立即恢复原值(非破坏)。
  11. /// 安全口径:默认 Skip(零写入);仅环境变量 HIL_ALLOW_WRITE=1 才执行。全程仅 EEPROM,无电机。
  12. /// </summary>
  13. [Collection("HIL")]
  14. public class EepromWriteHilTests
  15. {
  16. private readonly HardwareRigFixture _rig;
  17. private readonly ITestOutputHelper _out;
  18. public EepromWriteHilTests(HardwareRigFixture rig, ITestOutputHelper o) { _rig = rig; _out = o; }
  19. private static bool WriteAllowed =>
  20. Environment.GetEnvironmentVariable("HIL_ALLOW_WRITE") == "1";
  21. [SkippableFact]
  22. public void WriteVentTime_RoundTrips_AndRestoresOriginal()
  23. {
  24. Skip.IfNot(WriteAllowed, "写路径默认关闭;设 HIL_ALLOW_WRITE=1 才跑(写后立即恢复原值)");
  25. RoundTrip("排气阀时间(M-01写/M-02读)",
  26. ch => ch.ReadOpenVentTimeWait(), (ch, v) => ch.WriteOpenVentTimeWait(v));
  27. }
  28. [SkippableFact]
  29. public void WriteLightBrightness_RoundTrips_AndRestoresOriginal()
  30. {
  31. Skip.IfNot(WriteAllowed, "写路径默认关闭;设 HIL_ALLOW_WRITE=1 才跑(写后立即恢复原值)");
  32. RoundTrip("灯光亮度(M-03写)",
  33. ch => ch.ReadLightBrightnessWait(), (ch, v) => ch.WriteLightBrightnessWait(v));
  34. }
  35. private void RoundTrip(string label, Func<SerialChannelImpl, int> read, Action<SerialChannelImpl, int> write)
  36. {
  37. Skip.If(_rig.FirstChamberWithWells() == null, "无响应真舱:无硬件 / control 正占用串口 / 未连接");
  38. // 逐舱(排除舱11)找到第一个能读到该项的真舱再验:不同舱配置不同 E方,
  39. // 单一固定舱可能无此项(如灯光),逐舱试避免漏验该命令(对齐原 harness 取证逻辑)。
  40. foreach (var chamber in _rig.Chambers)
  41. {
  42. if (chamber.HouseSn == 11) continue; // 缓冲瓶/总控,无舱室排气阀/灯光
  43. SerialChannelImpl ch = null;
  44. try
  45. {
  46. ch = new SerialChannelImpl(0, chamber.Port);
  47. if (!ch.Open()) continue;
  48. // 读前丢弃一帧 + 间隔排空(隔离任何尾噪声),拿稳定原值。
  49. int ReadStable()
  50. {
  51. try { read(ch); } catch { }
  52. Thread.Sleep(700);
  53. int a = read(ch);
  54. Thread.Sleep(700);
  55. return a;
  56. }
  57. int v0 = ReadStable();
  58. if (v0 < 0) { _out.WriteLine($"[{label}] 舱{chamber.HouseSn} 无此项(读={v0}),试下一舱"); continue; }
  59. _out.WriteLine($"[{label}] 舱{chamber.HouseSn} 原值 V0={v0}");
  60. int target = v0 + 1;
  61. write(ch, target); Thread.Sleep(700);
  62. int v1 = ReadStable();
  63. _out.WriteLine($"[{label}] 写 {target} 后读回={v1}");
  64. write(ch, v0); Thread.Sleep(700); // 恢复原值
  65. int v2 = ReadStable();
  66. _out.WriteLine($"[{label}] 写回 {v0} 后读回={v2}");
  67. Assert.Equal(target, v1); // 写真下发:读回随写变化
  68. Assert.Equal(v0, v2); // 已恢复原值:非破坏
  69. return; // 已在该舱取得证据
  70. }
  71. finally { try { ch?.Close(); } catch { } }
  72. }
  73. Skip.If(true, $"[{label}] 所有真舱均无此项,无法取证(非失败)");
  74. }
  75. }
  76. }