using Common.Attributes; using DeviceCommand.Base; using System; using System.Collections.Generic; using System.Diagnostics.Metrics; using System.IO; using System.Linq; using System.Text; using System.Threading.Channels; using System.Threading.Tasks; using System.Windows.Shapes; using static Common.Attributes.ATSCommandAttribute; using static System.Formats.Asn1.AsnWriter; namespace DeviceCommand.Device { /// /// 示波器(型号:RTM3004) /// [ATSCommand] [DeviceCategory("示波器")] public class RTM3004 : Tcp { /// /// 信号量锁 /// public SemaphoreSlim semaphoreSlimLock { get; set; } = new(1, 1); #region 枚举定义(严格遵循手册规范) /// /// 单个通道名称枚举 /// public enum ChannelName_Single_Enum { /// /// 通道1 /// CH1 = 1, /// /// 通道2 /// CH2 = 2, /// /// 通道3 /// CH3 = 3, /// /// 通道4 /// CH4 = 4 } /// /// 测量项枚举,RTM3004支持8个独立的测量项 /// public enum Measurement_Enum { /// 测量项1 MEAS1 = 1, /// 测量项2 MEAS2 = 2, /// 测量项3 MEAS3 = 3, /// 测量项4 MEAS4 = 4, /// 测量项5 MEAS5 = 5, /// 测量项6 MEAS6 = 6, /// 测量项7 MEAS7 = 7, /// 测量项8 MEAS8 = 8 } /// /// 通道耦合模式枚举 /// public enum CouplingMode { /// 直流限制耦合 DCLimit, /// 交流限制耦合 ACLimit, /// 接地耦合,用于参考电平 GND, /// 直流耦合 DC } /// /// 采集状态(手册 ACQuire:STATE 支持值) /// public enum AcquisitionState { /// 运行中,持续采集波形 RUN, /// 采集完成后停止采集 STOPping, /// 采集完成(设置:不可用) COMPlete, /// 立即中断当前采集 BREak } /// /// 带宽限制(手册 CH:BANdwidth 支持值) /// public enum BandwidthLimit { /// 使用全部带宽,无限制 FULL, /// 频率限制为20 MHz,高频信号被移除以降低噪声 B20 } /// /// 触发模式(手册 TRIGger:A:MODe 支持值) /// public enum TriggerMode { /// 自动模式,无触发时自动扫描 AUTO, /// 正常模式,仅在触发时采集 NORMal, } /// /// 触发斜率/边沿枚举 /// public enum Slope_Enum { /// 上升沿触发,检测电压正向变化 POSitive, /// 下降沿触发,检测电压负向变化 NEGative, /// 上升和下降沿都触发 EITHer } /// /// 参考电平百分比模式枚举 /// 用于设置上升/下降时间测量的上下参考电平 /// public enum Relative_Mode { /// 10%、50%和90%参考电平 TEN, /// 20%、50%和80%参考电平 TWENty, /// 5%、50%和95%参考电平 FIVE, /// 用户自定义参考电平,需配合REFLevel参数使用 USER } #endregion #region 核心控制命令 //罗德与施瓦茨RTM3000示波器没有专门的"切换本地/远程"SCPI命令,自动切换 /// /// 指定电源应用程序的电流源 /// /// 设备 /// 通道名称 /// /// public async Task Set_CurrentSource(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"POWer:SOURce:CURRent {channelName}\n", ct); // 手册 POWer 命令规范 } finally { semaphoreSlimLock.Release(); } } /// /// 指定电源应用程序的电压源 /// /// 设备 /// 通道 /// /// public async Task Set_VoltageSource(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"POWer:SOURce:VOLTage {channelName}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 用于设置上升/下降时间测量的上下参考电平 /// /// 设备 /// 参考电平的百分比 /// /// public async Task Stop_QuickMeasurement(Tcp client, Relative_Mode relativemode, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"REFLevel:RELative:MODE{relativemode}:AOFF\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 启动快速测量(AUTO/NORMal) /// /// 设备 /// 测试项 /// /// public async Task Start_QuickMeasurement(Tcp client, Measurement_Enum measurement, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"MEASurement{measurement}:AON\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 停止快速测量 /// /// 设备 /// 测试项 /// /// public async Task Stop_QuickMeasurement(Tcp client, Measurement_Enum measurement, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"MEASurement{measurement}:AOFF\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 启动自动测量(AUTO/NORMal) /// /// 设备 /// 测试项 /// /// public async Task Start_AutoMeasurement(Tcp client, Measurement_Enum measurement, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"MEASurement{measurement}:ON\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 停止自动测量 /// /// 设备 /// 测试项 /// /// public async Task Stop_AutoMeasurement(Tcp client, Measurement_Enum measurement, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"MEASurement{measurement}:OFF\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 指定测量的通道 /// /// 设备 /// 通道 /// 测试项 /// /// public async Task Set_Measurement_Source(Tcp client, ChannelName_Single_Enum channelName, Measurement_Enum measurement, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"MEASurement{measurement}:SOURce CH{channelName}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 指定A触发的通道 (AUTO/NORMal) /// /// 设备 /// 通道 /// /// public async Task Set_ATrigger_SOURce(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"TRIGger:A:SOURce CH{channelName}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 设置A触发的模式 (AUTO/NORMal) /// /// 设备 /// 触发模式 /// /// public async Task Set_ATrigger_Mode(Tcp client, TriggerMode mode, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { string modeStr = mode.ToString().ToUpper(); await SendAsync(client, $"TRIGger:A:MODE {modeStr}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 设置A触发的触发斜率(沿)(AUTO/NORMal) /// /// 设备 /// 触发斜率(沿) /// /// public async Task Set_ATrigger_Slope(Tcp client, Slope_Enum slope, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { string modeStr = slope.ToString().ToUpper(); await SendAsync(client, $"TRIGger:A:EDGE:SLOPe {slope}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 设置A触发的阈值电压(取决于垂直标度) /// /// 设备 /// 通道 /// 阈值电压/param> /// /// public async Task Set_ATrigger_Level(Tcp client, ChannelName_Single_Enum channelName, float level, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { string modeStr = level.ToString().ToUpper(); await SendAsync(client, $"TRIGger:A:LEVel {channelName} {level}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 设置指定通道的输入耦合模式 /// /// 设备 /// 通道名称 /// 耦合模式 /// /// public async Task Set_ChannelCoupling(Tcp client, ChannelName_Single_Enum channelName, CouplingMode couplingMode, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { string modeStr = couplingMode.ToString().ToUpper(); await SendAsync(client, $"CHANnel {channelName}:COUPling{couplingMode}\n", ct); // 直接使用通道枚举值(如 CHANnel 1:COUPLING AC) } finally { semaphoreSlimLock.Release(); } } /// /// 设置指定通道的输入耦合为DCLimit /// /// 设备 /// 通道名称 /// /// public async Task Set_ChannelCoupling_DCLimit(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await Set_ChannelCoupling(client, channelName, CouplingMode.DCLimit, ct); } /// /// 设置指定通道的输入耦合为ACLimit /// /// 设备 /// 通道名称 /// /// public async Task Set_ChannelCoupling_ACLimit(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await Set_ChannelCoupling(client, channelName, CouplingMode.ACLimit, ct); } /// /// 设置指定通道的输入耦合为GND /// /// 设备 /// 通道名称 /// /// public async Task Set_ChannelCoupling_GND(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await Set_ChannelCoupling(client, channelName, CouplingMode.GND, ct); } /// /// 设置指定通道的输入耦合为DC /// /// 设备 /// 通道名称 /// /// public async Task Set_ChannelCoupling_DC(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await Set_ChannelCoupling(client, channelName, CouplingMode.DC, ct); } /// /// 设置指定通道的硬件带宽限制 /// /// 设备 /// 通道名称 /// 带宽限制 /// /// public async Task Set_ChannelBandwidth(Tcp client, ChannelName_Single_Enum channelName, BandwidthLimit bandwidth, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { string bwStr = $"{(int)bandwidth}E6"; await SendAsync(client, $"CHANnel{channelName}:BANDwidth{bwStr}\n", ct); // 如 CHANnel 1:BANDwidth FULL } finally { semaphoreSlimLock.Release(); } } /// /// 启用指定通道 /// /// 设备 /// 通道名称 /// /// public async Task Start_Channel(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"CHANnel:{channelName}:STATe ON\n", ct); // 手册标准通道启用命令 } finally { semaphoreSlimLock.Release(); } } /// /// 关闭指定通道 /// /// 设备 /// 通道名称 /// /// public async Task Stop_Channel(Tcp client, ChannelName_Single_Enum channelName, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"CHANnel:{channelName}:STATe OFF\n", ct); // 手册标准通道启用命令 } finally { semaphoreSlimLock.Release(); } } /// /// 设置指定通道的垂直标度 (Volts/Div) /// /// 设备 /// 通道名称 /// 标度值(单位:V/div) /// /// public async Task Set_ChannelScale(Tcp client, ChannelName_Single_Enum channelName, float scale, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"CHANnel{channelName}:SCALe{scale}\n", ct); // 如 CH1:SCALE 1.0(单位 V/div) } finally { semaphoreSlimLock.Release(); } } /// /// 设置所有通道及数学波形的水平比例尺(每格时间,秒/格) /// /// 设备 /// 时基标度(单位:s/div) /// /// public async Task Set_Timebase_Scale(Tcp client, double scale, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"TIMebase:SCALe {scale}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 设置水平触发位置 (相对于屏幕中心的偏移,百分比) /// /// 设备 /// 位置百分比 /// /// public async Task Set_Timebase_Position(Tcp client, double position, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"TIMebase:POSition {position}\n", ct); // 位置单位为百分比 } finally { semaphoreSlimLock.Release(); } } /// /// 设置示波器的采集状态 (RUN/STOP) /// /// 设备 /// 采集状态 /// /// public async Task Set_Acquisition_State(Tcp client, AcquisitionState state, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { string stateStr = state.ToString().ToUpper(); await SendAsync(client, $"ACQuire:STATe {stateStr}\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// Trigger 启动采集(替代原电源ON,手册无OUTPUT命令) /// /// 设备 /// /// public async Task Start_Acquisition(Tcp client, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"ACQuire:STATe RUN\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 采集完停止采集 /// /// 设备 /// /// public async Task Stopping_Acquisition(Tcp client, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"ACQuire:STATe STOPping\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 设置采集不可用 /// /// 设备 /// /// public async Task Complete_Acquisition(Tcp client, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"ACQuire:STATe COMPlete\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 立即停止采集 /// /// 设备 /// /// public async Task Break_Acquisition(Tcp client, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { await SendAsync(client, $"ACQuire:STATe BREak\n", ct); } finally { semaphoreSlimLock.Release(); } } /// /// 保存波形数据(保存全通道到CSV文件) /// /// 设备_当前时间.CSV /// 指定通道(默认:D:/BDUWAVE) /// 保存路径(默认:D:/BDUWAVE) /// 保存波形文件名(默认:WAVE_当前时间.PNG) /// /// public async Task Save_Waveform(Tcp client, ChannelName_Single_Enum channelName, string filePath, string fileName, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { if (!Directory.Exists(filePath)) { filePath = $"D:/WAVE"; Directory.CreateDirectory(filePath); } if (string.IsNullOrEmpty(fileName)) { fileName = $"WAVE_{DateTime.Now.ToString()}"; } await SendAsync(client, $"EXPort:WAVeform:SOURce{channelName}\n", ct); // 设置待导出的波形源 await SendAsync(client, $"EXPort:WFMSave:DESTination{filePath}\n", ct); // 设置待导出的目录 await SendAsync(client, "FORMAT CSV\n", ct); // 设置文件格式 await SendAsync(client, $"EXPort:WAVeform:NAME\"{fileName}\"\n", ct); //设置文件名字 await SendAsync(client, $"EXPort:WAVeform:SAVE\n", ct);// 执行保存操作 } finally { semaphoreSlimLock.Release(); } } /// /// 保存屏幕截图(指定格式为PNG) /// /// 设备 /// 保存路径(默认:D:/BDUSCREEN) /// 保存波形文件名(默认:SCREEN_当前时间.PNG) /// /// public async Task Save_Screen_Image(Tcp client, string filePath, string fileName, CancellationToken ct = default) { await semaphoreSlimLock.WaitAsync(ct); try { if (!Directory.Exists(filePath)) { filePath = $"D:/WAVE"; Directory.CreateDirectory(filePath); } if (string.IsNullOrEmpty(fileName)) { fileName = $"WAVE_{DateTime.Now.ToString()}"; } await SendAsync(client, $"EXPort:SCRSave:DESTination{filePath}\n", ct); // 设置待导出的目录 await SendAsync(client, "FORMAT PNG\n", ct); // 设置文件格式 await SendAsync(client, $"MMEMory:NAME\"{fileName}\"\n", ct); //设置文件名字 await SendAsync(client, $"HCOPy:IMMediate\n", ct);// 执行保存操作 } finally { semaphoreSlimLock.Release(); } } /// /// 发送自定义SCPI命令 /// /// 设备 /// SCPI命令字符串 /// /// 命令执行结果 public async Task Send_CustomCommand(Tcp client, string command, CancellationToken ct = default) { if (string.IsNullOrEmpty(command)) throw new ArgumentNullException(nameof(command)); await semaphoreSlimLock.WaitAsync(ct); try { return await WriteRead(client, $"{command}\n", "\n", ct: ct); } finally { semaphoreSlimLock.Release(); } } #endregion } }