using System; using System.Drawing; using System.Threading.Tasks; using System.Windows.Forms; using APS7100TestTool.Controllers; using APS7100TestTool.Models; using APS7100TestTool.Libraries; namespace APS7100TestTool.Forms { public partial class ManualTestForm : Form { private IPowerSupplyController? _controller; private DeviceType _deviceType; private System.Windows.Forms.Timer _measureTimer; // 防止测量操作重叠 private volatile bool _isMeasuring = false; // 回调:暂停/恢复 Modbus 轮询 // 当发送本地模式命令时,需要同时暂停 Modbus 轮询,否则设备会立即切换回远程模式 public Action? OnSuspendModbusPolling { get; set; } public Action? OnResumeModbusPolling { get; set; } public ManualTestForm(IPowerSupplyController? controller, DeviceType deviceType) { InitializeComponent(); // 启用双缓冲减少闪烁 this.DoubleBuffered = true; this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true); this.UpdateStyles(); _controller = controller; _deviceType = deviceType; _measureTimer = new System.Windows.Forms.Timer(); _measureTimer.Interval = 1000; _measureTimer.Tick += MeasureTimer_Tick; InitializeUI(); } private void InitializeUI() { // 设置窗口标题 string deviceName = _deviceType == DeviceType.APS7100 ? "APS-7100 (AC)" : "PSW-250 (DC)"; this.Text = $"手动测试 - {deviceName}"; // 根据设备类型调整UI UpdateDeviceTypeUI(); // 初始化命令库 InitializeCommandLibrary(); // 更新连接状态 UpdateConnectionState(_controller != null); if (_controller != null) { ReadCurrentSettings(); // ⚠ 不自动启动测量定时器! // APS7100 收到任何 SCPI 命令后会自动进入远程模式 // 用户需要手动点击"恢复测量"按钮来启动定时测量 // _measureTimer.Start(); // 注释掉,不自动启动 UpdateMeasureButtonState(false); // 初始状态:测量已暂停 LogMessage("ℹ 测量已暂停。点击「恢复测量」按钮可开始自动测量。"); if (_deviceType == DeviceType.APS7100) { LogMessage("⚠ 注意:启动测量后 APS7100 将自动切换到远程模式"); } } else { UpdateMeasureButtonState(false); } } private void UpdateDeviceTypeUI() { bool isAC = (_deviceType == DeviceType.APS7100); // AC电源独有控件 lblFrequency.Visible = isAC; numFrequency.Visible = isAC; btnSetFrequency.Visible = isAC; lblWaveform.Visible = isAC; cmbWaveform.Visible = isAC; lblVoltageRange.Visible = isAC; cmbVoltageRange.Visible = isAC; // AC电源独有的测量值 lblFrequencyLabel.Visible = isAC; lblFrequencyValue.Visible = isAC; lblPFLabel.Visible = isAC; lblPFValue.Visible = isAC; // 调整电压/电流的范围 if (isAC) { numVoltage.Maximum = 350; numVoltage.Value = 220; numCurrent.Maximum = 20; numCurrent.Value = 5; lblCurrent.Text = "电流限值(A):"; } else { numVoltage.Maximum = 72; numVoltage.Value = 12; numCurrent.Maximum = 4.5m; numCurrent.Value = 1; lblCurrent.Text = "电流设定(A):"; } } private void InitializeCommandLibrary() { cmbCommandCategory.Items.Clear(); cmbCommandCategory.Items.Add("全部命令"); var categories = _deviceType == DeviceType.APS7100 ? ScpiCommandLibrary.GetCategories() : PSW250CommandLibrary.GetCategories(); foreach (string category in categories) { cmbCommandCategory.Items.Add(category); } if (cmbCommandCategory.Items.Count > 0) cmbCommandCategory.SelectedIndex = 0; } private void UpdateConnectionState(bool connected) { grpControl.Enabled = connected; grpMeasure.Enabled = connected; grpScpi.Enabled = connected; if (!connected) { lblStatus.Text = "未连接"; lblStatus.ForeColor = Color.Red; } else { lblStatus.Text = "已连接"; lblStatus.ForeColor = Color.Green; } } /// /// 更新控制器(当主窗体连接/断开设备时调用) /// public void UpdateController(IPowerSupplyController? controller) { _controller = controller; UpdateConnectionState(_controller != null); if (_controller != null) { ReadCurrentSettings(); // ⚠ 不自动启动测量定时器 // _measureTimer.Start(); UpdateMeasureButtonState(false); } else { _measureTimer.Stop(); UpdateMeasureButtonState(false); } } private async void ReadCurrentSettings() { if (_controller == null) return; try { var controller = _controller; var deviceType = _deviceType; // 在后台线程执行读取操作,避免阻塞UI // 使用 try-catch 保护每个查询,避免不支持的命令导致整体失败 var settings = await Task.Run(() => { double voltage = 0, frequency = 0, current = 0; VoltageRange voltageRange = VoltageRange.Low; Waveform waveform = Waveform.Sine; bool outputOn = false; try { voltage = controller.GetVoltage(); } catch { } try { frequency = deviceType == DeviceType.APS7100 ? controller.GetFrequency() : 0; } catch { } try { current = controller.GetCurrent(); } catch { } try { voltageRange = deviceType == DeviceType.APS7100 ? controller.GetVoltageRange() : VoltageRange.Low; } catch { } try { waveform = deviceType == DeviceType.APS7100 ? controller.GetWaveform() : Waveform.Sine; } catch { } try { outputOn = controller.GetOutputState(); } catch { } return new { Voltage = voltage, Frequency = frequency, Current = current, VoltageRange = voltageRange, Waveform = waveform, OutputOn = outputOn }; }); // 在UI线程更新控件 numVoltage.Value = (decimal)settings.Voltage; if (_deviceType == DeviceType.APS7100) { numFrequency.Value = (decimal)settings.Frequency; cmbVoltageRange.SelectedIndex = settings.VoltageRange == VoltageRange.Low ? 0 : 1; cmbWaveform.SelectedIndex = (int)settings.Waveform; } numCurrent.Value = (decimal)settings.Current; chkOutput.Checked = settings.OutputOn; } catch (Exception ex) { LogMessage($"读取设置失败: {ex.Message}"); } } private async void MeasureTimer_Tick(object? sender, EventArgs e) { if (_controller == null || _isMeasuring) return; _isMeasuring = true; try { var controller = _controller; var deviceType = _deviceType; // 在后台线程执行测量操作,避免阻塞UI var measurements = await Task.Run(() => { var result = new { Voltage = controller.MeasureVoltage(), Current = controller.MeasureCurrent(), Power = controller.MeasurePower(), Frequency = deviceType == DeviceType.APS7100 ? controller.MeasureFrequency() : 0, PowerFactor = deviceType == DeviceType.APS7100 ? controller.MeasurePowerFactor() : 0 }; return result; }); // 在UI线程更新显示 lblVoltageValue.Text = $"{measurements.Voltage:F2} V"; lblCurrentValue.Text = $"{measurements.Current:F3} A"; lblPowerValue.Text = $"{measurements.Power:F2} W"; if (_deviceType == DeviceType.APS7100) { lblFrequencyValue.Text = $"{measurements.Frequency:F2} Hz"; lblPFValue.Text = $"{measurements.PowerFactor:F3}"; } } catch { } finally { _isMeasuring = false; } } #region Control Events private void btnSetVoltage_Click(object sender, EventArgs e) { if (_controller == null) return; try { _controller.SetVoltage((double)numVoltage.Value); LogMessage($"设置电压: {numVoltage.Value} V"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void btnSetFrequency_Click(object sender, EventArgs e) { if (_controller == null) return; try { _controller.SetFrequency((double)numFrequency.Value); LogMessage($"设置频率: {numFrequency.Value} Hz"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void btnSetCurrent_Click(object sender, EventArgs e) { if (_controller == null) return; try { _controller.SetCurrent((double)numCurrent.Value); LogMessage($"设置电流: {numCurrent.Value} A"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void cmbVoltageRange_SelectedIndexChanged(object sender, EventArgs e) { if (_controller == null || cmbVoltageRange.SelectedIndex < 0) return; try { var range = cmbVoltageRange.SelectedIndex == 0 ? VoltageRange.Low : VoltageRange.High; _controller.SetVoltageRange(range); LogMessage($"设置量程: {range}"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void cmbWaveform_SelectedIndexChanged(object sender, EventArgs e) { if (_controller == null || cmbWaveform.SelectedIndex < 0) return; try { var wave = (Waveform)cmbWaveform.SelectedIndex; _controller.SetWaveform(wave); LogMessage($"设置波形: {wave}"); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void chkOutput_CheckedChanged(object sender, EventArgs e) { if (_controller == null) return; try { _controller.SetOutput(chkOutput.Checked); chkOutput.Text = chkOutput.Checked ? "输出 ON" : "输出 OFF"; chkOutput.BackColor = chkOutput.Checked ? Color.LightGreen : SystemColors.Control; LogMessage($"输出: {chkOutput.Text}"); } catch { } } private void btnReset_Click(object sender, EventArgs e) { if (_controller == null) return; if (MessageBox.Show("确定重置?", "确认", MessageBoxButtons.YesNo) == DialogResult.Yes) { try { _controller.Reset(); LogMessage("设备已重置"); ReadCurrentSettings(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } } #endregion #region SCPI Events private void cmbCommandCategory_SelectedIndexChanged(object sender, EventArgs e) { if (cmbCommandCategory.SelectedIndex < 0) return; lstCommands.Items.Clear(); txtCommandDesc.Text = ""; string? cat = cmbCommandCategory.SelectedItem?.ToString(); if (cat == null) return; var cmds = cat == "全部命令" ? (_deviceType == DeviceType.APS7100 ? ScpiCommandLibrary.GetAllCommands() : PSW250CommandLibrary.GetAllCommands()) : (_deviceType == DeviceType.APS7100 ? ScpiCommandLibrary.GetCommandsByCategory(cat) : PSW250CommandLibrary.GetCommandsByCategory(cat)); foreach (var c in cmds) lstCommands.Items.Add(c); lstCommands.DisplayMember = "Command"; } private void lstCommands_SelectedIndexChanged(object sender, EventArgs e) { if (lstCommands.SelectedItem is ScpiCommandInfo cmd) txtCommandDesc.Text = cmd.FullDescription; } private void btnUseCommand_Click(object sender, EventArgs e) { if (lstCommands.SelectedItem is ScpiCommandInfo cmd) txtScpiCommand.Text = cmd.Command; } private async void btnSendCommand_Click(object sender, EventArgs e) { if (_controller == null) return; string cmd = txtScpiCommand.Text.Trim(); if (string.IsNullOrEmpty(cmd)) return; // 暂停定时器,避免与手动命令冲突 _measureTimer.Stop(); // 检测是否是"本地模式"命令 // APS7100 收到任何 SCPI 命令后都会自动进入远程模式 // 如果用户发送本地模式命令,就不应该恢复测量定时器 bool isLocalModeCommand = IsLocalModeCommand(cmd); try { // 等待当前测量完成 while (_isMeasuring) { await Task.Delay(50); } // 在后台线程执行命令,避免阻塞UI var result = await Task.Run(() => { if (cmd.EndsWith("?")) { return new { IsQuery = true, Response = _controller.SendCustomQuery(cmd) }; } else { _controller.SendCustomCommand(cmd); return new { IsQuery = false, Response = "" }; } }); if (result.IsQuery) { LogMessage($"Send: {cmd}, Resp: {result.Response}"); } else { LogMessage($"Sent: {cmd}"); } // 如果是本地模式命令,提示用户并保持定时器暂停 if (isLocalModeCommand) { // 暂停 Modbus 轮询(这是关键!否则 Modbus 服务会继续发送命令) OnSuspendModbusPolling?.Invoke(); LogMessage("⚠ 已发送本地模式命令"); LogMessage(" ✓ 手动测试页测量已暂停"); LogMessage(" ✓ Modbus 服务轮询已暂停"); LogMessage(" 设备将保持本地模式,点击「恢复测量」可恢复"); UpdateMeasureButtonState(false); } } catch (Exception ex) { LogMessage($"Error: {ex.Message}"); } finally { // 只有非本地模式命令才恢复定时器 if (_controller != null && !isLocalModeCommand) { _measureTimer.Start(); } } } /// /// 检测是否是切换到本地模式的命令 /// private bool IsLocalModeCommand(string cmd) { if (string.IsNullOrEmpty(cmd)) return false; string upperCmd = cmd.ToUpper().Trim(); // 常见的本地模式命令 return upperCmd.Contains("SYST:LOC") || upperCmd.Contains("SYST:COMM:RLST") && upperCmd.Contains("LOCAL") || upperCmd.Contains("RLSTATE") && upperCmd.Contains("LOCAL") || upperCmd == "GTL"; // IEEE 488.2 Go To Local } /// /// 更新测量按钮状态 /// private void UpdateMeasureButtonState(bool isMeasuring) { if (btnToggleMeasure != null) { btnToggleMeasure.Text = isMeasuring ? "暂停测量" : "恢复测量"; btnToggleMeasure.BackColor = isMeasuring ? Color.LightCoral : Color.LightGreen; } } #endregion private void btnClearLog_Click(object sender, EventArgs e) => txtLog.Clear(); private void btnToggleMeasure_Click(object sender, EventArgs e) { if (_measureTimer.Enabled) { // 暂停测量 _measureTimer.Stop(); OnSuspendModbusPolling?.Invoke(); UpdateMeasureButtonState(false); LogMessage("✓ 测量已暂停"); LogMessage(" ✓ Modbus 服务轮询已暂停"); LogMessage(" 设备将保持本地模式"); } else { // 恢复测量 // ⚠ 恢复测量会使 APS7100 自动切换到远程模式 if (_deviceType == DeviceType.APS7100) { LogMessage("⚠ 恢复测量后,APS7100 将自动切换到远程模式"); } OnResumeModbusPolling?.Invoke(); _measureTimer.Start(); UpdateMeasureButtonState(true); LogMessage("✓ 测量已恢复"); LogMessage(" ✓ Modbus 服务轮询已恢复"); } } private void LogMessage(string msg) { if (this.InvokeRequired) { this.Invoke(new Action(LogMessage), msg); return; } txtLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {msg}\r\n"); } protected override void OnFormClosing(FormClosingEventArgs e) { _measureTimer?.Stop(); base.OnFormClosing(e); } } }