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);
}
}
}