using Microsoft.Extensions.Options; using SSPCTester.Devices.Config; using SSPCTester.Devices.Drivers.Mock; using SSPCTester.Devices.Drivers.Real; using SSPCTester.Devices.Interfaces; namespace SSPCTester.Devices.Drivers; /// 根据可变设置在 Mock 与真实 SSPC 间切换。 public sealed class ConfigurableSspc : ISspc { private readonly DeviceOptions _options; private readonly MockSspc _mock; private readonly SspcModbus _real; public ConfigurableSspc(IOptions options, MockSspc mock, SspcModbus real) { _options = options.Value; _mock = mock; _real = real; _mock.ConnectionChanged += Forward; _real.ConnectionChanged += Forward; } private ISspc Current => _options.Sspc.UseMock ? _mock : _real; public int ChannelCount => 24; public bool IsConnected => Current.IsConnected; public string DisplayName => Current.DisplayName; public event EventHandler? ConnectionChanged; public Task ConnectAsync(CancellationToken ct = default) => Current.ConnectAsync(ct); public async Task DisconnectAsync() { await _mock.DisconnectAsync().ConfigureAwait(false); await _real.DisconnectAsync().ConfigureAwait(false); } public Task TurnOnAsync(int physicalSlot, CancellationToken ct = default) => Current.TurnOnAsync(physicalSlot, ct); public Task TurnOffAsync(int physicalSlot, CancellationToken ct = default) => Current.TurnOffAsync(physicalSlot, ct); public Task FlashAsync(int physicalSlot, int milliseconds, CancellationToken ct = default) => Current.FlashAsync(physicalSlot, milliseconds, ct); public Task GetChannelStateAsync(int physicalSlot, CancellationToken ct = default) => Current.GetChannelStateAsync(physicalSlot, ct); public Task ReadMeasurementAsync(int physicalSlot, CancellationToken ct = default) => Current.ReadMeasurementAsync(physicalSlot, ct); public Task> ReadMeasurementsAsync(CancellationToken ct = default) => Current.ReadMeasurementsAsync(ct); private void Forward(object? sender, bool connected) => ConnectionChanged?.Invoke(this, connected); } public sealed class ConfigurablePowerSupply : IPowerSupply { private readonly DeviceOptions _options; private readonly MockPowerSupply _mock; private readonly Udp5080 _real; public ConfigurablePowerSupply(IOptions options, MockPowerSupply mock, Udp5080 real) { _options = options.Value; _mock = mock; _real = real; _mock.ConnectionChanged += Forward; _real.ConnectionChanged += Forward; } private IPowerSupply Current => _options.PowerSupply.UseMock ? _mock : _real; public bool IsConnected => Current.IsConnected; public string DisplayName => Current.DisplayName; public event EventHandler? ConnectionChanged; public Task ConnectAsync(CancellationToken ct = default) => Current.ConnectAsync(ct); public async Task DisconnectAsync() { await _mock.DisconnectAsync(); await SafeDisconnect(_real); } public Task SetVoltageAsync(double volts, CancellationToken ct = default) => Current.SetVoltageAsync(volts, ct); public Task SetCurrentLimitAsync(double amps, CancellationToken ct = default) => Current.SetCurrentLimitAsync(amps, ct); public Task OutputAsync(bool on, CancellationToken ct = default) => Current.OutputAsync(on, ct); public Task GetOutputStateAsync(CancellationToken ct = default) => Current.GetOutputStateAsync(ct); public Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default) => Current.ReadAsync(ct); public Task QueryIdentityAsync(CancellationToken ct = default) => Current.QueryIdentityAsync(ct); public Task QueryErrorAsync(CancellationToken ct = default) => Current.QueryErrorAsync(ct); private void Forward(object? sender, bool connected) => ConnectionChanged?.Invoke(this, connected); private static async Task SafeDisconnect(IDeviceConnection device) { try { await device.DisconnectAsync(); } catch (NotImplementedException) { } } } public sealed class ConfigurableLoad : ILoad { private readonly DeviceOptions _options; private readonly MockLoad _mock; private readonly It87xxLoad _real; public ConfigurableLoad(IOptions options, MockLoad mock, It87xxLoad real) { _options = options.Value; _mock = mock; _real = real; _mock.ConnectionChanged += Forward; _real.ConnectionChanged += Forward; } private ILoad Current => _options.Load.UseMock ? _mock : _real; public bool IsConnected => Current.IsConnected; public string DisplayName => Current.DisplayName; public event EventHandler? ConnectionChanged; public Task ConnectAsync(CancellationToken ct = default) => Current.ConnectAsync(ct); public async Task DisconnectAsync() { await _mock.DisconnectAsync(); await SafeDisconnect(_real); } public Task SetModeAsync(LoadMode mode, CancellationToken ct = default) => Current.SetModeAsync(mode, ct); public Task SetValueAsync(double value, CancellationToken ct = default) => Current.SetValueAsync(value, ct); public Task InputAsync(bool on, CancellationToken ct = default) => Current.InputAsync(on, ct); public Task GetInputStateAsync(CancellationToken ct = default) => Current.GetInputStateAsync(ct); public Task ResetAsync(CancellationToken ct = default) => Current.ResetAsync(ct); public Task<(double volts, double amps)> ReadAsync(CancellationToken ct = default) => Current.ReadAsync(ct); public Task ReadPowerAsync(CancellationToken ct = default) => Current.ReadPowerAsync(ct); public Task QueryIdentityAsync(CancellationToken ct = default) => Current.QueryIdentityAsync(ct); public Task QueryErrorAsync(CancellationToken ct = default) => Current.QueryErrorAsync(ct); private void Forward(object? sender, bool connected) => ConnectionChanged?.Invoke(this, connected); private static async Task SafeDisconnect(IDeviceConnection device) { try { await device.DisconnectAsync(); } catch (NotImplementedException) { } } } public sealed class ConfigurableDaq : IDaq { private readonly DeviceOptions _options; private readonly MockDaq _mock; private readonly Pcie8586Daq _real; public ConfigurableDaq(IOptions options, MockDaq mock, Pcie8586Daq real) { _options = options.Value; _mock = mock; _real = real; _mock.ConnectionChanged += Forward; _real.ConnectionChanged += Forward; _mock.SampleReceived += ForwardSample; _real.SampleReceived += ForwardSample; } private IDaq Current => _options.Daq.UseMock ? _mock : _real; public bool IsConnected => Current.IsConnected; public string DisplayName => Current.DisplayName; public event EventHandler? ConnectionChanged; public event EventHandler? SampleReceived; public Task> EnumerateDevicesAsync(CancellationToken ct = default) => Current.EnumerateDevicesAsync(ct); public Task ConnectAsync(CancellationToken ct = default) => Current.ConnectAsync(ct); public async Task DisconnectAsync() { await _mock.DisconnectAsync(); await SafeDisconnect(_real); } public Task CaptureAsync(int[] channels, int sampleRateHz, double durationSec, CancellationToken ct = default) => Current.CaptureAsync(channels, sampleRateHz, durationSec, ct); public Task ReadInstantAsync(int[] channels, CancellationToken ct = default) => Current.ReadInstantAsync(channels, ct); public Task CaptureAroundActionAsync( DaqActionCaptureRequest request, Func action, CancellationToken ct = default) => Current.CaptureAroundActionAsync(request, action, ct); private void Forward(object? sender, bool connected) => ConnectionChanged?.Invoke(this, connected); private void ForwardSample(object? sender, CurveSample sample) => SampleReceived?.Invoke(this, sample); private static async Task SafeDisconnect(IDeviceConnection device) { try { await device.DisconnectAsync(); } catch (NotImplementedException) { } } } public sealed class ConfigurableSafetyDio : ISafetyDio { private readonly DeviceOptions _options; private readonly MockSafetyDio _mock; private readonly Pci2312SafetyDio _real; public ConfigurableSafetyDio(IOptions options, MockSafetyDio mock, Pci2312SafetyDio real) { _options = options.Value; _mock = mock; _real = real; _mock.ConnectionChanged += Forward; _real.ConnectionChanged += Forward; } private ISafetyDio Current => _options.Pci2312.UseMock ? _mock : _real; public bool IsConnected => Current.IsConnected; public string DisplayName => Current.DisplayName; public event EventHandler? ConnectionChanged; public Task ConnectAsync(CancellationToken ct = default) => Current.ConnectAsync(ct); public async Task DisconnectAsync() { await _mock.DisconnectAsync(); await SafeDisconnect(_real); } public Task ReadInputAsync(int channel, CancellationToken ct = default) => Current.ReadInputAsync(channel, ct); public Task WriteOutputAsync(int channel, bool on, CancellationToken ct = default) => Current.WriteOutputAsync(channel, on, ct); private void Forward(object? sender, bool connected) => ConnectionChanged?.Invoke(this, connected); private static async Task SafeDisconnect(IDeviceConnection device) { try { await device.DisconnectAsync(); } catch (NotImplementedException) { } } }