using System.Net; using Common; using DotNext; namespace Peripherals.OscilloscopeClient; static class OscilloscopeAddr { const UInt32 BASE = 0x8000_0000; /// /// 0x0000_0000:R/W[0] wave_run 启动捕获/关闭 /// public const UInt32 START_CAPTURE = BASE + 0x0000_0000; /// /// 0x0000_0001: R/W[7:0] trig_level 触发电平 /// public const UInt32 TRIG_LEVEL = BASE + 0x0000_0001; /// /// 0x0000_0002:R/W[0] trig_edge 触发边沿,0-下降沿,1-上升沿 /// public const UInt32 TRIG_EDGE = BASE + 0x0000_0002; /// /// 0x0000_0003: R/W[9:0] h shift 水平偏移量 /// public const UInt32 H_SHIFT = BASE + 0x0000_0003; /// /// 0x0000_0004: R/W[9:0] deci rate 抽样率,0—1023 /// public const UInt32 DECI_RATE = BASE + 0x0000_0004; /// /// 0x0000_0005:R/W[0] ram refresh RAM刷新 /// public const UInt32 RAM_FRESH = BASE + 0x0000_0005; /// /// 0x0000 0006:R[19: 0] ad_freq AD采样频率 /// public const UInt32 AD_FREQ = BASE + 0x0000_0006; /// /// Ox0000_0007: R[7:0] ad_vpp AD采样幅度 /// public const UInt32 AD_VPP = BASE + 0x0000_0007; /// /// 0x0000_0008: R[7:0] ad max AD采样最大值 /// public const UInt32 AD_MAX = BASE + 0x0000_0008; /// /// 0x0000_0009: R[7:0] ad_min AD采样最小值 /// public const UInt32 AD_MIN = BASE + 0x0000_0009; /// /// 0x0000_1000-0x0000_13FF:R[7:0] wave_rd_data 共1024个字节 /// public const UInt32 RD_DATA_ADDR = BASE + 0x0000_1000; public const UInt32 RD_DATA_LENGTH = 0x0000_0400; } class Oscilloscope { private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); readonly int timeout = 2000; readonly int taskID = 0; readonly int port; readonly string address; private IPEndPoint ep; /// /// 初始化示波器客户端 /// /// 示波器设备IP地址 /// 示波器设备端口 /// 超时时间(毫秒) public Oscilloscope(string address, int port, int timeout = 2000) { if (timeout < 0) throw new ArgumentException("Timeout couldn't be negative", nameof(timeout)); this.address = address; this.port = port; this.ep = new IPEndPoint(IPAddress.Parse(address), port); this.timeout = timeout; } /// /// 控制示波器的捕获开关 /// /// 是否启动捕获 /// 操作结果,成功返回true,否则返回异常信息 public async ValueTask> SetCaptureEnable(bool enable) { UInt32 value = enable ? 1u : 0u; var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.START_CAPTURE, value, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to set capture enable: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to START_CAPTURE returned false"); return new(new Exception("Failed to set capture enable")); } return true; } /// /// 设置触发电平 /// /// 触发电平值(0-255) /// 操作结果,成功返回true,否则返回异常信息 public async ValueTask> SetTriggerLevel(byte level) { var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.TRIG_LEVEL, level, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to set trigger level: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to TRIG_LEVEL returned false"); return new(new Exception("Failed to set trigger level")); } return true; } /// /// 设置触发边沿 /// /// true为上升沿,false为下降沿 /// 操作结果,成功返回true,否则返回异常信息 public async ValueTask> SetTriggerEdge(bool risingEdge) { UInt32 value = risingEdge ? 1u : 0u; var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.TRIG_EDGE, value, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to set trigger edge: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to TRIG_EDGE returned false"); return new(new Exception("Failed to set trigger edge")); } return true; } /// /// 设置水平偏移量 /// /// 水平偏移量值(0-1023) /// 操作结果,成功返回true,否则返回异常信息 public async ValueTask> SetHorizontalShift(UInt16 shift) { if (shift > 1023) return new(new ArgumentException("Horizontal shift must be 0-1023", nameof(shift))); var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.H_SHIFT, shift, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to set horizontal shift: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to H_SHIFT returned false"); return new(new Exception("Failed to set horizontal shift")); } return true; } /// /// 设置抽样率 /// /// 抽样率值(0-1023) /// 操作结果,成功返回true,否则返回异常信息 public async ValueTask> SetDecimationRate(UInt16 rate) { if (rate > 1023) return new(new ArgumentException("Decimation rate must be 0-1023", nameof(rate))); var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.DECI_RATE, rate, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to set decimation rate: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to DECI_RATE returned false"); return new(new Exception("Failed to set decimation rate")); } return true; } /// /// 刷新RAM /// /// 操作结果,成功返回true,否则返回异常信息 public async ValueTask> RefreshRAM() { var ret = await UDPClientPool.WriteAddr(this.ep, this.taskID, OscilloscopeAddr.RAM_FRESH, 1u, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to refresh RAM: {ret.Error}"); return new(ret.Error); } if (!ret.Value) { logger.Error("WriteAddr to RAM_FRESH returned false"); return new(new Exception("Failed to refresh RAM")); } return true; } /// /// 获取AD采样频率 /// /// 操作结果,成功返回采样频率值,否则返回异常信息 public async ValueTask> GetADFrequency() { var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_FREQ, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to read AD frequency: {ret.Error}"); return new(ret.Error); } if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 4) { logger.Error("ReadAddr returned invalid data for AD frequency"); return new(new Exception("Failed to read AD frequency")); } UInt32 freq = Number.BytesToUInt32(ret.Value.Options.Data).Value; // 取低20位 [19:0] freq &= 0xFFFFF; return freq; } /// /// 获取AD采样幅度 /// /// 操作结果,成功返回采样幅度值,否则返回异常信息 public async ValueTask> GetADVpp() { var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_VPP, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to read AD VPP: {ret.Error}"); return new(ret.Error); } if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 1) { logger.Error("ReadAddr returned invalid data for AD VPP"); return new(new Exception("Failed to read AD VPP")); } return ret.Value.Options.Data[3]; } /// /// 获取AD采样最大值 /// /// 操作结果,成功返回采样最大值,否则返回异常信息 public async ValueTask> GetADMax() { var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_MAX, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to read AD max: {ret.Error}"); return new(ret.Error); } if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 1) { logger.Error("ReadAddr returned invalid data for AD max"); return new(new Exception("Failed to read AD max")); } return ret.Value.Options.Data[3]; } /// /// 获取AD采样最小值 /// /// 操作结果,成功返回采样最小值,否则返回异常信息 public async ValueTask> GetADMin() { var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, OscilloscopeAddr.AD_MIN, this.timeout); if (!ret.IsSuccessful) { logger.Error($"Failed to read AD min: {ret.Error}"); return new(ret.Error); } if (ret.Value.Options.Data == null || ret.Value.Options.Data.Length < 1) { logger.Error("ReadAddr returned invalid data for AD min"); return new(new Exception("Failed to read AD min")); } return ret.Value.Options.Data[3]; } /// /// 获取波形采样数据 /// /// 操作结果,成功返回采样数据数组,否则返回异常信息 public async ValueTask> GetWaveformData() { var ret = await UDPClientPool.ReadAddr4BytesAsync( this.ep, this.taskID, OscilloscopeAddr.RD_DATA_ADDR, (int)OscilloscopeAddr.RD_DATA_LENGTH / 32, this.timeout ); if (!ret.IsSuccessful) { logger.Error($"Failed to read waveform data: {ret.Error}"); return new(ret.Error); } var data = ret.Value; if (data == null || data.Length != OscilloscopeAddr.RD_DATA_LENGTH / 8) { logger.Error($"Waveform data length mismatch: {data?.Length}"); return new(new Exception("Waveform data length mismatch")); } // 处理波形数据:从每4个字节中提取第4个字节(索引3)作为有效数据 // 数据格式:低八位有效,即[4*i + 3]才是有效数据 int sampleCount = data.Length / 4; byte[] waveformData = new byte[sampleCount]; for (int i = 0; i < sampleCount; i++) { waveformData[i] = data[4 * i + 3]; } return waveformData; } }