using System; using System.Threading; using IvfTl.Hardware.HilTests.Infrastructure; using IvfTl.Hardware.Impl; using Xunit; using Xunit.Abstractions; namespace IvfTl.Hardware.HilTests { /// /// M-01/02/03 防回归:写命令(排气阀时间/灯光亮度)真下发到下位机,读回随写变化,写后立即恢复原值(非破坏)。 /// 安全口径:默认 Skip(零写入);仅环境变量 HIL_ALLOW_WRITE=1 才执行。全程仅 EEPROM,无电机。 /// [Collection("HIL")] public class EepromWriteHilTests { private readonly HardwareRigFixture _rig; private readonly ITestOutputHelper _out; public EepromWriteHilTests(HardwareRigFixture rig, ITestOutputHelper o) { _rig = rig; _out = o; } private static bool WriteAllowed => Environment.GetEnvironmentVariable("HIL_ALLOW_WRITE") == "1"; [SkippableFact] public void WriteVentTime_RoundTrips_AndRestoresOriginal() { Skip.IfNot(WriteAllowed, "写路径默认关闭;设 HIL_ALLOW_WRITE=1 才跑(写后立即恢复原值)"); RoundTrip("排气阀时间(M-01写/M-02读)", ch => ch.ReadOpenVentTimeWait(), (ch, v) => ch.WriteOpenVentTimeWait(v)); } [SkippableFact] public void WriteLightBrightness_RoundTrips_AndRestoresOriginal() { Skip.IfNot(WriteAllowed, "写路径默认关闭;设 HIL_ALLOW_WRITE=1 才跑(写后立即恢复原值)"); RoundTrip("灯光亮度(M-03写)", ch => ch.ReadLightBrightnessWait(), (ch, v) => ch.WriteLightBrightnessWait(v)); } private void RoundTrip(string label, Func read, Action write) { Skip.If(_rig.FirstChamberWithWells() == null, "无响应真舱:无硬件 / control 正占用串口 / 未连接"); // 逐舱(排除舱11)找到第一个能读到该项的真舱再验:不同舱配置不同 E方, // 单一固定舱可能无此项(如灯光),逐舱试避免漏验该命令(对齐原 harness 取证逻辑)。 foreach (var chamber in _rig.Chambers) { if (chamber.HouseSn == 11) continue; // 缓冲瓶/总控,无舱室排气阀/灯光 SerialChannelImpl ch = null; try { ch = new SerialChannelImpl(0, chamber.Port); if (!ch.Open()) continue; // 读前丢弃一帧 + 间隔排空(隔离任何尾噪声),拿稳定原值。 int ReadStable() { try { read(ch); } catch { } Thread.Sleep(700); int a = read(ch); Thread.Sleep(700); return a; } int v0 = ReadStable(); if (v0 < 0) { _out.WriteLine($"[{label}] 舱{chamber.HouseSn} 无此项(读={v0}),试下一舱"); continue; } _out.WriteLine($"[{label}] 舱{chamber.HouseSn} 原值 V0={v0}"); int target = v0 + 1; write(ch, target); Thread.Sleep(700); int v1 = ReadStable(); _out.WriteLine($"[{label}] 写 {target} 后读回={v1}"); write(ch, v0); Thread.Sleep(700); // 恢复原值 int v2 = ReadStable(); _out.WriteLine($"[{label}] 写回 {v0} 后读回={v2}"); Assert.Equal(target, v1); // 写真下发:读回随写变化 Assert.Equal(v0, v2); // 已恢复原值:非破坏 return; // 已在该舱取得证据 } finally { try { ch?.Close(); } catch { } } } Skip.If(true, $"[{label}] 所有真舱均无此项,无法取证(非失败)"); } } }