将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。

This commit is contained in:
QI Mingxuan
2026-04-16 17:31:13 +08:00
parent 6ec4c3ddaa
commit 2bd6e566c3
581 changed files with 74600 additions and 222 deletions
@@ -0,0 +1,69 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace XP.Hardware.RaySource.Comet.Host
{
/// <summary>
/// 强制退出密码输入对话框
/// Force exit password input dialog
/// </summary>
internal sealed class ForceExitPasswordDialog : Form
{
private readonly TextBox _txtPassword;
/// <summary>
/// 用户输入的密码 | The password entered by user
/// </summary>
public string EnteredPassword => _txtPassword.Text;
public ForceExitPasswordDialog()
{
// 窗体属性 | Form properties
Text = "强制退出验证 | Force Exit Verification";
FormBorderStyle = FormBorderStyle.FixedDialog;
StartPosition = FormStartPosition.CenterParent;
MaximizeBox = false;
MinimizeBox = false;
ClientSize = new Size(320, 130);
// 提示标签 | Prompt label
var lbl = new Label
{
Text = "请输入管理员密码以强制退出:\r\nPlease enter admin password to force exit:",
Location = new Point(12, 12),
AutoSize = true
};
// 密码输入框 | Password text box
_txtPassword = new TextBox
{
Location = new Point(12, 52),
Size = new Size(290, 23),
UseSystemPasswordChar = true
};
// 确定按钮 | OK button
var btnOk = new Button
{
Text = "确定",
DialogResult = DialogResult.OK,
Location = new Point(146, 90),
Size = new Size(75, 28)
};
// 取消按钮 | Cancel button
var btnCancel = new Button
{
Text = "取消",
DialogResult = DialogResult.Cancel,
Location = new Point(227, 90),
Size = new Size(75, 28)
};
AcceptButton = btnOk;
CancelButton = btnCancel;
Controls.AddRange(new Control[] { lbl, _txtPassword, btnOk, btnCancel });
}
}
}
@@ -0,0 +1,691 @@
namespace XP.Hardware.RaySource.Comet.Host
{
partial class XplorePlaneCometHost
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_notifyIcon != null)
{
_notifyIcon.Visible = false;
_notifyIcon.Dispose();
_notifyIcon = null;
}
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
#region Windows
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(XplorePlaneCometHost));
this._mainLayout = new System.Windows.Forms.TableLayoutPanel();
this._operationPanel = new System.Windows.Forms.Panel();
this._connGroup = new System.Windows.Forms.GroupBox();
this._lblIpAddress = new System.Windows.Forms.Label();
this._txtIpAddress = new System.Windows.Forms.TextBox();
this._lblPort = new System.Windows.Forms.Label();
this._nudPort = new System.Windows.Forms.NumericUpDown();
this._lblCpuName = new System.Windows.Forms.Label();
this._txtCpuName = new System.Windows.Forms.TextBox();
this._lblSourcePort = new System.Windows.Forms.Label();
this._nudSourcePort = new System.Windows.Forms.NumericUpDown();
this._lblStationNumber = new System.Windows.Forms.Label();
this._nudStationNumber = new System.Windows.Forms.NumericUpDown();
this._btnInitialize = new System.Windows.Forms.Button();
this._btnConnectVariables = new System.Windows.Forms.Button();
this._btnDisconnect = new System.Windows.Forms.Button();
this._lblConnectionState = new System.Windows.Forms.Label();
this._lblPviState = new System.Windows.Forms.Label();
this._lblHeartbeat = new System.Windows.Forms.Label();
this._xrayGroup = new System.Windows.Forms.GroupBox();
this._btnTurnOn = new System.Windows.Forms.Button();
this._btnTurnOff = new System.Windows.Forms.Button();
this._paramGroup = new System.Windows.Forms.GroupBox();
this._lblVoltage = new System.Windows.Forms.Label();
this._nudVoltage = new System.Windows.Forms.NumericUpDown();
this._btnSetVoltage = new System.Windows.Forms.Button();
this._lblCurrent = new System.Windows.Forms.Label();
this._nudCurrent = new System.Windows.Forms.NumericUpDown();
this._btnSetCurrent = new System.Windows.Forms.Button();
this._statusGroup = new System.Windows.Forms.GroupBox();
this._btnReadVoltage = new System.Windows.Forms.Button();
this._btnReadCurrent = new System.Windows.Forms.Button();
this._btnReadSystemStatus = new System.Windows.Forms.Button();
this._btnReadErrors = new System.Windows.Forms.Button();
this._maintGroup = new System.Windows.Forms.GroupBox();
this._btnWarmUp = new System.Windows.Forms.Button();
this._btnTraining = new System.Windows.Forms.Button();
this._btnFilamentCalibration = new System.Windows.Forms.Button();
this._btnAutoCenter = new System.Windows.Forms.Button();
this._btnTxiOn = new System.Windows.Forms.Button();
this._btnTxiOff = new System.Windows.Forms.Button();
this._btnForceExit = new System.Windows.Forms.Button();
this._logGroup = new System.Windows.Forms.GroupBox();
this._rtbLog = new System.Windows.Forms.RichTextBox();
this._mainLayout.SuspendLayout();
this._operationPanel.SuspendLayout();
this._connGroup.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this._nudPort)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this._nudSourcePort)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this._nudStationNumber)).BeginInit();
this._xrayGroup.SuspendLayout();
this._paramGroup.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this._nudVoltage)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this._nudCurrent)).BeginInit();
this._statusGroup.SuspendLayout();
this._maintGroup.SuspendLayout();
this._logGroup.SuspendLayout();
this.SuspendLayout();
//
// _mainLayout
//
this._mainLayout.ColumnCount = 1;
this._mainLayout.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this._mainLayout.Controls.Add(this._operationPanel, 0, 0);
this._mainLayout.Controls.Add(this._logGroup, 0, 1);
this._mainLayout.Dock = System.Windows.Forms.DockStyle.Fill;
this._mainLayout.Location = new System.Drawing.Point(0, 0);
this._mainLayout.Name = "_mainLayout";
this._mainLayout.Padding = new System.Windows.Forms.Padding(8);
this._mainLayout.RowCount = 2;
this._mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 450F));
this._mainLayout.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this._mainLayout.Size = new System.Drawing.Size(780, 700);
this._mainLayout.TabIndex = 0;
//
// _operationPanel
//
this._operationPanel.Controls.Add(this._connGroup);
this._operationPanel.Controls.Add(this._xrayGroup);
this._operationPanel.Controls.Add(this._paramGroup);
this._operationPanel.Controls.Add(this._statusGroup);
this._operationPanel.Controls.Add(this._maintGroup);
this._operationPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this._operationPanel.Location = new System.Drawing.Point(11, 11);
this._operationPanel.Name = "_operationPanel";
this._operationPanel.Size = new System.Drawing.Size(758, 444);
this._operationPanel.TabIndex = 0;
//
// _connGroup
//
this._connGroup.Controls.Add(this._lblIpAddress);
this._connGroup.Controls.Add(this._txtIpAddress);
this._connGroup.Controls.Add(this._lblPort);
this._connGroup.Controls.Add(this._nudPort);
this._connGroup.Controls.Add(this._lblCpuName);
this._connGroup.Controls.Add(this._txtCpuName);
this._connGroup.Controls.Add(this._lblSourcePort);
this._connGroup.Controls.Add(this._nudSourcePort);
this._connGroup.Controls.Add(this._lblStationNumber);
this._connGroup.Controls.Add(this._nudStationNumber);
this._connGroup.Controls.Add(this._btnInitialize);
this._connGroup.Controls.Add(this._btnConnectVariables);
this._connGroup.Controls.Add(this._btnDisconnect);
this._connGroup.Controls.Add(this._lblConnectionState);
this._connGroup.Controls.Add(this._lblPviState);
this._connGroup.Controls.Add(this._lblHeartbeat);
this._connGroup.Location = new System.Drawing.Point(0, 0);
this._connGroup.Name = "_connGroup";
this._connGroup.Size = new System.Drawing.Size(750, 100);
this._connGroup.TabIndex = 0;
this._connGroup.TabStop = false;
this._connGroup.Text = "连接参数";
//
// _lblIpAddress
//
this._lblIpAddress.AutoSize = true;
this._lblIpAddress.Location = new System.Drawing.Point(10, 25);
this._lblIpAddress.Name = "_lblIpAddress";
this._lblIpAddress.Size = new System.Drawing.Size(85, 21);
this._lblIpAddress.TabIndex = 0;
this._lblIpAddress.Text = "IP地址:";
//
// _txtIpAddress
//
this._txtIpAddress.Location = new System.Drawing.Point(70, 22);
this._txtIpAddress.Name = "_txtIpAddress";
this._txtIpAddress.Size = new System.Drawing.Size(120, 31);
this._txtIpAddress.TabIndex = 1;
this._txtIpAddress.Text = "192.168.12.10";
//
// _lblPort
//
this._lblPort.AutoSize = true;
this._lblPort.Location = new System.Drawing.Point(200, 25);
this._lblPort.Name = "_lblPort";
this._lblPort.Size = new System.Drawing.Size(63, 21);
this._lblPort.TabIndex = 2;
this._lblPort.Text = "端口:";
//
// _nudPort
//
this._nudPort.Location = new System.Drawing.Point(240, 22);
this._nudPort.Maximum = new decimal(new int[] {
65535,
0,
0,
0});
this._nudPort.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this._nudPort.Name = "_nudPort";
this._nudPort.Size = new System.Drawing.Size(70, 31);
this._nudPort.TabIndex = 3;
this._nudPort.Value = new decimal(new int[] {
11159,
0,
0,
0});
//
// _lblCpuName
//
this._lblCpuName.AutoSize = true;
this._lblCpuName.Location = new System.Drawing.Point(320, 25);
this._lblCpuName.Name = "_lblCpuName";
this._lblCpuName.Size = new System.Drawing.Size(96, 21);
this._lblCpuName.TabIndex = 4;
this._lblCpuName.Text = "CPU名称:";
//
// _txtCpuName
//
this._txtCpuName.Location = new System.Drawing.Point(390, 22);
this._txtCpuName.Name = "_txtCpuName";
this._txtCpuName.Size = new System.Drawing.Size(80, 31);
this._txtCpuName.TabIndex = 5;
this._txtCpuName.Text = "cpu";
//
// _lblSourcePort
//
this._lblSourcePort.AutoSize = true;
this._lblSourcePort.Location = new System.Drawing.Point(480, 25);
this._lblSourcePort.Name = "_lblSourcePort";
this._lblSourcePort.Size = new System.Drawing.Size(84, 21);
this._lblSourcePort.TabIndex = 6;
this._lblSourcePort.Text = "源端口:";
//
// _nudSourcePort
//
this._nudSourcePort.Location = new System.Drawing.Point(540, 22);
this._nudSourcePort.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this._nudSourcePort.Name = "_nudSourcePort";
this._nudSourcePort.Size = new System.Drawing.Size(70, 31);
this._nudSourcePort.TabIndex = 7;
this._nudSourcePort.Value = new decimal(new int[] {
11,
0,
0,
0});
//
// _lblStationNumber
//
this._lblStationNumber.AutoSize = true;
this._lblStationNumber.Location = new System.Drawing.Point(620, 25);
this._lblStationNumber.Name = "_lblStationNumber";
this._lblStationNumber.Size = new System.Drawing.Size(63, 21);
this._lblStationNumber.TabIndex = 8;
this._lblStationNumber.Text = "站号:";
//
// _nudStationNumber
//
this._nudStationNumber.Location = new System.Drawing.Point(660, 22);
this._nudStationNumber.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this._nudStationNumber.Name = "_nudStationNumber";
this._nudStationNumber.Size = new System.Drawing.Size(60, 31);
this._nudStationNumber.TabIndex = 9;
this._nudStationNumber.Value = new decimal(new int[] {
1,
0,
0,
0});
//
// _btnInitialize
//
this._btnInitialize.Location = new System.Drawing.Point(10, 58);
this._btnInitialize.Name = "_btnInitialize";
this._btnInitialize.Size = new System.Drawing.Size(120, 28);
this._btnInitialize.TabIndex = 10;
this._btnInitialize.Text = "初始化连接";
this._btnInitialize.Click += new System.EventHandler(this.OnInitialize);
//
// _btnConnectVariables
//
this._btnConnectVariables.Enabled = false;
this._btnConnectVariables.Location = new System.Drawing.Point(140, 58);
this._btnConnectVariables.Name = "_btnConnectVariables";
this._btnConnectVariables.Size = new System.Drawing.Size(100, 28);
this._btnConnectVariables.TabIndex = 11;
this._btnConnectVariables.Text = "连接变量";
this._btnConnectVariables.Click += new System.EventHandler(this.OnConnectVariables);
//
// _btnDisconnect
//
this._btnDisconnect.Enabled = false;
this._btnDisconnect.Location = new System.Drawing.Point(250, 58);
this._btnDisconnect.Name = "_btnDisconnect";
this._btnDisconnect.Size = new System.Drawing.Size(100, 28);
this._btnDisconnect.TabIndex = 12;
this._btnDisconnect.Text = "断开连接";
this._btnDisconnect.Click += new System.EventHandler(this.OnDisconnect);
//
// _lblConnectionState
//
this._lblConnectionState.ForeColor = System.Drawing.Color.Red;
this._lblConnectionState.Location = new System.Drawing.Point(370, 63);
this._lblConnectionState.Name = "_lblConnectionState";
this._lblConnectionState.Size = new System.Drawing.Size(174, 23);
this._lblConnectionState.TabIndex = 13;
this._lblConnectionState.Text = "状态: 未连接";
//
// _lblPviState
//
this._lblPviState.AutoSize = true;
this._lblPviState.ForeColor = System.Drawing.Color.Gray;
this._lblPviState.Location = new System.Drawing.Point(575, 63);
this._lblPviState.Name = "_lblPviState";
this._lblPviState.Size = new System.Drawing.Size(73, 21);
this._lblPviState.TabIndex = 13;
this._lblPviState.Text = "未连接";
//
// _lblHeartbeat
//
this._lblHeartbeat.Font = new System.Drawing.Font("Segoe UI", 12F);
this._lblHeartbeat.ForeColor = System.Drawing.Color.Gray;
this._lblHeartbeat.Location = new System.Drawing.Point(720, 58);
this._lblHeartbeat.Name = "_lblHeartbeat";
this._lblHeartbeat.Size = new System.Drawing.Size(24, 24);
this._lblHeartbeat.TabIndex = 15;
this._lblHeartbeat.Text = "●";
//
// _xrayGroup
//
this._xrayGroup.Controls.Add(this._btnTurnOn);
this._xrayGroup.Controls.Add(this._btnTurnOff);
this._xrayGroup.Location = new System.Drawing.Point(0, 105);
this._xrayGroup.Name = "_xrayGroup";
this._xrayGroup.Size = new System.Drawing.Size(750, 65);
this._xrayGroup.TabIndex = 1;
this._xrayGroup.TabStop = false;
this._xrayGroup.Text = "射线控制";
//
// _btnTurnOn
//
this._btnTurnOn.Enabled = false;
this._btnTurnOn.Location = new System.Drawing.Point(10, 25);
this._btnTurnOn.Name = "_btnTurnOn";
this._btnTurnOn.Size = new System.Drawing.Size(150, 28);
this._btnTurnOn.TabIndex = 0;
this._btnTurnOn.Text = "开启高压 (TurnOn)";
this._btnTurnOn.Click += new System.EventHandler(this.OnTurnOn);
//
// _btnTurnOff
//
this._btnTurnOff.Enabled = false;
this._btnTurnOff.Location = new System.Drawing.Point(170, 25);
this._btnTurnOff.Name = "_btnTurnOff";
this._btnTurnOff.Size = new System.Drawing.Size(150, 28);
this._btnTurnOff.TabIndex = 1;
this._btnTurnOff.Text = "关闭高压 (TurnOff)";
this._btnTurnOff.Click += new System.EventHandler(this.OnTurnOff);
//
// _paramGroup
//
this._paramGroup.Controls.Add(this._lblVoltage);
this._paramGroup.Controls.Add(this._nudVoltage);
this._paramGroup.Controls.Add(this._btnSetVoltage);
this._paramGroup.Controls.Add(this._lblCurrent);
this._paramGroup.Controls.Add(this._nudCurrent);
this._paramGroup.Controls.Add(this._btnSetCurrent);
this._paramGroup.Location = new System.Drawing.Point(0, 175);
this._paramGroup.Name = "_paramGroup";
this._paramGroup.Size = new System.Drawing.Size(750, 65);
this._paramGroup.TabIndex = 2;
this._paramGroup.TabStop = false;
this._paramGroup.Text = "参数设置";
//
// _lblVoltage
//
this._lblVoltage.AutoSize = true;
this._lblVoltage.Location = new System.Drawing.Point(10, 28);
this._lblVoltage.Name = "_lblVoltage";
this._lblVoltage.Size = new System.Drawing.Size(107, 21);
this._lblVoltage.TabIndex = 0;
this._lblVoltage.Text = "电压(kV):";
//
// _nudVoltage
//
this._nudVoltage.DecimalPlaces = 1;
this._nudVoltage.Location = new System.Drawing.Point(80, 25);
this._nudVoltage.Maximum = new decimal(new int[] {
300,
0,
0,
0});
this._nudVoltage.Name = "_nudVoltage";
this._nudVoltage.Size = new System.Drawing.Size(80, 31);
this._nudVoltage.TabIndex = 1;
//
// _btnSetVoltage
//
this._btnSetVoltage.Enabled = false;
this._btnSetVoltage.Location = new System.Drawing.Point(170, 23);
this._btnSetVoltage.Name = "_btnSetVoltage";
this._btnSetVoltage.Size = new System.Drawing.Size(90, 28);
this._btnSetVoltage.TabIndex = 2;
this._btnSetVoltage.Text = "设置电压";
this._btnSetVoltage.Click += new System.EventHandler(this.OnSetVoltage);
//
// _lblCurrent
//
this._lblCurrent.AutoSize = true;
this._lblCurrent.Location = new System.Drawing.Point(280, 28);
this._lblCurrent.Name = "_lblCurrent";
this._lblCurrent.Size = new System.Drawing.Size(117, 21);
this._lblCurrent.TabIndex = 3;
this._lblCurrent.Text = "电流(μA):";
//
// _nudCurrent
//
this._nudCurrent.DecimalPlaces = 1;
this._nudCurrent.Location = new System.Drawing.Point(350, 25);
this._nudCurrent.Maximum = new decimal(new int[] {
5000,
0,
0,
0});
this._nudCurrent.Name = "_nudCurrent";
this._nudCurrent.Size = new System.Drawing.Size(80, 31);
this._nudCurrent.TabIndex = 4;
//
// _btnSetCurrent
//
this._btnSetCurrent.Enabled = false;
this._btnSetCurrent.Location = new System.Drawing.Point(440, 23);
this._btnSetCurrent.Name = "_btnSetCurrent";
this._btnSetCurrent.Size = new System.Drawing.Size(90, 28);
this._btnSetCurrent.TabIndex = 5;
this._btnSetCurrent.Text = "设置电流";
this._btnSetCurrent.Click += new System.EventHandler(this.OnSetCurrent);
//
// _statusGroup
//
this._statusGroup.Controls.Add(this._btnReadVoltage);
this._statusGroup.Controls.Add(this._btnReadCurrent);
this._statusGroup.Controls.Add(this._btnReadSystemStatus);
this._statusGroup.Controls.Add(this._btnReadErrors);
this._statusGroup.Location = new System.Drawing.Point(0, 245);
this._statusGroup.Name = "_statusGroup";
this._statusGroup.Size = new System.Drawing.Size(750, 64);
this._statusGroup.TabIndex = 3;
this._statusGroup.TabStop = false;
this._statusGroup.Text = "状态读取";
//
// _btnReadVoltage
//
this._btnReadVoltage.Enabled = false;
this._btnReadVoltage.Location = new System.Drawing.Point(10, 25);
this._btnReadVoltage.Name = "_btnReadVoltage";
this._btnReadVoltage.Size = new System.Drawing.Size(100, 28);
this._btnReadVoltage.TabIndex = 0;
this._btnReadVoltage.Text = "读取电压";
this._btnReadVoltage.Click += new System.EventHandler(this.OnReadVoltage);
//
// _btnReadCurrent
//
this._btnReadCurrent.Enabled = false;
this._btnReadCurrent.Location = new System.Drawing.Point(120, 25);
this._btnReadCurrent.Name = "_btnReadCurrent";
this._btnReadCurrent.Size = new System.Drawing.Size(100, 28);
this._btnReadCurrent.TabIndex = 1;
this._btnReadCurrent.Text = "读取电流";
this._btnReadCurrent.Click += new System.EventHandler(this.OnReadCurrent);
//
// _btnReadSystemStatus
//
this._btnReadSystemStatus.Enabled = false;
this._btnReadSystemStatus.Location = new System.Drawing.Point(230, 25);
this._btnReadSystemStatus.Name = "_btnReadSystemStatus";
this._btnReadSystemStatus.Size = new System.Drawing.Size(120, 28);
this._btnReadSystemStatus.TabIndex = 2;
this._btnReadSystemStatus.Text = "读取系统状态";
this._btnReadSystemStatus.Click += new System.EventHandler(this.OnReadSystemStatus);
//
// _btnReadErrors
//
this._btnReadErrors.Enabled = false;
this._btnReadErrors.Location = new System.Drawing.Point(360, 25);
this._btnReadErrors.Name = "_btnReadErrors";
this._btnReadErrors.Size = new System.Drawing.Size(120, 28);
this._btnReadErrors.TabIndex = 3;
this._btnReadErrors.Text = "读取错误信息";
this._btnReadErrors.Click += new System.EventHandler(this.OnReadErrors);
//
// _maintGroup
//
this._maintGroup.Controls.Add(this._btnWarmUp);
this._maintGroup.Controls.Add(this._btnTraining);
this._maintGroup.Controls.Add(this._btnFilamentCalibration);
this._maintGroup.Controls.Add(this._btnAutoCenter);
this._maintGroup.Controls.Add(this._btnTxiOn);
this._maintGroup.Controls.Add(this._btnTxiOff);
this._maintGroup.Controls.Add(this._btnForceExit);
this._maintGroup.Location = new System.Drawing.Point(0, 317);
this._maintGroup.Name = "_maintGroup";
this._maintGroup.Size = new System.Drawing.Size(750, 76);
this._maintGroup.TabIndex = 4;
this._maintGroup.TabStop = false;
this._maintGroup.Text = "维护操作";
//
// _btnWarmUp
//
this._btnWarmUp.Enabled = false;
this._btnWarmUp.Location = new System.Drawing.Point(10, 25);
this._btnWarmUp.Name = "_btnWarmUp";
this._btnWarmUp.Size = new System.Drawing.Size(100, 28);
this._btnWarmUp.TabIndex = 0;
this._btnWarmUp.Text = "暖机设置";
this._btnWarmUp.Click += new System.EventHandler(this.OnWarmUp);
//
// _btnTraining
//
this._btnTraining.Enabled = false;
this._btnTraining.Location = new System.Drawing.Point(120, 25);
this._btnTraining.Name = "_btnTraining";
this._btnTraining.Size = new System.Drawing.Size(100, 28);
this._btnTraining.TabIndex = 1;
this._btnTraining.Text = "训机设置";
this._btnTraining.Click += new System.EventHandler(this.OnTraining);
//
// _btnFilamentCalibration
//
this._btnFilamentCalibration.Enabled = false;
this._btnFilamentCalibration.Location = new System.Drawing.Point(230, 25);
this._btnFilamentCalibration.Name = "_btnFilamentCalibration";
this._btnFilamentCalibration.Size = new System.Drawing.Size(100, 28);
this._btnFilamentCalibration.TabIndex = 2;
this._btnFilamentCalibration.Text = "灯丝校准";
this._btnFilamentCalibration.Click += new System.EventHandler(this.OnFilamentCalibration);
//
// _btnAutoCenter
//
this._btnAutoCenter.Enabled = false;
this._btnAutoCenter.Location = new System.Drawing.Point(340, 25);
this._btnAutoCenter.Name = "_btnAutoCenter";
this._btnAutoCenter.Size = new System.Drawing.Size(100, 28);
this._btnAutoCenter.TabIndex = 3;
this._btnAutoCenter.Text = "自动定心";
this._btnAutoCenter.Click += new System.EventHandler(this.OnAutoCenter);
//
// _btnTxiOn
//
this._btnTxiOn.Enabled = false;
this._btnTxiOn.Location = new System.Drawing.Point(450, 25);
this._btnTxiOn.Name = "_btnTxiOn";
this._btnTxiOn.Size = new System.Drawing.Size(100, 28);
this._btnTxiOn.TabIndex = 4;
this._btnTxiOn.Text = "TXI ON";
this._btnTxiOn.Click += new System.EventHandler(this.OnTxiOn);
//
// _btnTxiOff
//
this._btnTxiOff.Enabled = false;
this._btnTxiOff.Location = new System.Drawing.Point(560, 25);
this._btnTxiOff.Name = "_btnTxiOff";
this._btnTxiOff.Size = new System.Drawing.Size(100, 28);
this._btnTxiOff.TabIndex = 5;
this._btnTxiOff.Text = "TXI OFF";
this._btnTxiOff.Click += new System.EventHandler(this.OnTxiOff);
//
// _btnForceExit
//
this._btnForceExit.BackColor = System.Drawing.Color.DarkRed;
this._btnForceExit.ForeColor = System.Drawing.Color.White;
this._btnForceExit.Location = new System.Drawing.Point(670, 25);
this._btnForceExit.Name = "_btnForceExit";
this._btnForceExit.Size = new System.Drawing.Size(75, 28);
this._btnForceExit.TabIndex = 6;
this._btnForceExit.Text = "强制退出";
this._btnForceExit.UseVisualStyleBackColor = false;
this._btnForceExit.Click += new System.EventHandler(this.OnForceExitClick);
//
// _logGroup
//
this._logGroup.Controls.Add(this._rtbLog);
this._logGroup.Dock = System.Windows.Forms.DockStyle.Fill;
this._logGroup.Location = new System.Drawing.Point(11, 461);
this._logGroup.Name = "_logGroup";
this._logGroup.Size = new System.Drawing.Size(758, 228);
this._logGroup.TabIndex = 1;
this._logGroup.TabStop = false;
this._logGroup.Text = "日志输出";
//
// _rtbLog
//
this._rtbLog.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(30)))), ((int)(((byte)(30)))));
this._rtbLog.Dock = System.Windows.Forms.DockStyle.Fill;
this._rtbLog.Font = new System.Drawing.Font("Consolas", 9F);
this._rtbLog.ForeColor = System.Drawing.Color.LightGreen;
this._rtbLog.Location = new System.Drawing.Point(3, 27);
this._rtbLog.Name = "_rtbLog";
this._rtbLog.ReadOnly = true;
this._rtbLog.Size = new System.Drawing.Size(752, 198);
this._rtbLog.TabIndex = 0;
this._rtbLog.Text = "";
//
// XplorePlaneCometHost
//
this.ClientSize = new System.Drawing.Size(780, 700);
this.Controls.Add(this._mainLayout);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MinimumSize = new System.Drawing.Size(780, 600);
this.Name = "XplorePlaneCometHost";
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "XplorePlane Comet Host";
this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
this._mainLayout.ResumeLayout(false);
this._operationPanel.ResumeLayout(false);
this._connGroup.ResumeLayout(false);
this._connGroup.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this._nudPort)).EndInit();
((System.ComponentModel.ISupportInitialize)(this._nudSourcePort)).EndInit();
((System.ComponentModel.ISupportInitialize)(this._nudStationNumber)).EndInit();
this._xrayGroup.ResumeLayout(false);
this._paramGroup.ResumeLayout(false);
this._paramGroup.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this._nudVoltage)).EndInit();
((System.ComponentModel.ISupportInitialize)(this._nudCurrent)).EndInit();
this._statusGroup.ResumeLayout(false);
this._maintGroup.ResumeLayout(false);
this._logGroup.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
// 布局控件
private System.Windows.Forms.TableLayoutPanel _mainLayout;
private System.Windows.Forms.Panel _operationPanel;
private System.Windows.Forms.GroupBox _connGroup;
private System.Windows.Forms.GroupBox _xrayGroup;
private System.Windows.Forms.GroupBox _paramGroup;
private System.Windows.Forms.GroupBox _statusGroup;
private System.Windows.Forms.GroupBox _logGroup;
// 连接参数标签
private System.Windows.Forms.Label _lblIpAddress;
private System.Windows.Forms.Label _lblPort;
private System.Windows.Forms.Label _lblCpuName;
private System.Windows.Forms.Label _lblSourcePort;
private System.Windows.Forms.Label _lblStationNumber;
// 连接参数输入
private System.Windows.Forms.TextBox _txtIpAddress;
private System.Windows.Forms.NumericUpDown _nudPort;
private System.Windows.Forms.TextBox _txtCpuName;
private System.Windows.Forms.NumericUpDown _nudSourcePort;
private System.Windows.Forms.NumericUpDown _nudStationNumber;
// 连接操作按钮
private System.Windows.Forms.Button _btnInitialize;
private System.Windows.Forms.Button _btnConnectVariables;
private System.Windows.Forms.Button _btnDisconnect;
private System.Windows.Forms.Label _lblConnectionState;
private System.Windows.Forms.Label _lblPviState;
private System.Windows.Forms.Label _lblHeartbeat;
// 射线控制按钮
private System.Windows.Forms.Button _btnTurnOn;
private System.Windows.Forms.Button _btnTurnOff;
// 参数设置
private System.Windows.Forms.Label _lblVoltage;
private System.Windows.Forms.NumericUpDown _nudVoltage;
private System.Windows.Forms.Button _btnSetVoltage;
private System.Windows.Forms.Label _lblCurrent;
private System.Windows.Forms.NumericUpDown _nudCurrent;
private System.Windows.Forms.Button _btnSetCurrent;
// 状态读取按钮
private System.Windows.Forms.Button _btnReadVoltage;
private System.Windows.Forms.Button _btnReadCurrent;
private System.Windows.Forms.Button _btnReadSystemStatus;
private System.Windows.Forms.Button _btnReadErrors;
// 维护操作
private System.Windows.Forms.GroupBox _maintGroup;
private System.Windows.Forms.Button _btnWarmUp;
private System.Windows.Forms.Button _btnTraining;
private System.Windows.Forms.Button _btnFilamentCalibration;
private System.Windows.Forms.Button _btnAutoCenter;
private System.Windows.Forms.Button _btnTxiOn;
private System.Windows.Forms.Button _btnTxiOff;
private System.Windows.Forms.Button _btnForceExit;
// 日志输出
private System.Windows.Forms.RichTextBox _rtbLog;
// 托盘图标
private System.Windows.Forms.NotifyIcon _notifyIcon;
}
}
@@ -0,0 +1,995 @@
using System;
using System.Drawing;
using System.IO;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32.SafeHandles;
using XP.Hardware.RaySource.Comet;
using XP.Hardware.RaySource.Comet.Host.Pipe;
using XP.Hardware.RaySource.Comet.Host.Properties;
using XP.Hardware.RaySource.Comet.Messages;
using XP.Hardware.RaySource.Comet.Messages.Responses;
namespace XP.Hardware.RaySource.Comet.Host
{
/// <summary>
/// XplorePlane Comet Host 主窗体
/// 集成托盘图标、管道通信、PVI 客户端生命周期和功能测试按钮
/// </summary>
public partial class XplorePlaneCometHost : Form
{
#region
/// <summary>
/// 命令管道名称(客户端写 → Host 读)
/// </summary>
private const string CmdPipeName = "XP.Hardware.RaySource.Comet.Cmd";
/// <summary>
/// 响应管道名称(Host 写 → 客户端读)
/// </summary>
private const string RspPipeName = "XP.Hardware.RaySource.Comet.Rsp";
/// <summary>
/// 写入锁,防止命令响应和推送消息交错
/// </summary>
private static readonly object WriteLock = new object();
/// <summary>
/// 管道是否已连接,用于控制日志是否推送到管道
/// </summary>
private volatile bool _isPipeConnected;
/// <summary>
/// 管道轮询定时器
/// </summary>
private System.Windows.Forms.Timer _pipeTimer;
/// <summary>
/// 命令管道服务端
/// </summary>
private NamedPipeServerStream _cmdPipe;
/// <summary>
/// 响应管道服务端
/// </summary>
private NamedPipeServerStream _rspPipe;
/// <summary>
/// 管道读取器
/// </summary>
private StreamReader _pipeReader;
/// <summary>
/// 管道写入器
/// </summary>
private StreamWriter _pipeWriter;
/// <summary>
/// 是否正在等待客户端连接
/// </summary>
private bool _isWaitingConnection;
/// <summary>
/// 异步连接结果(命令管道)
/// </summary>
private IAsyncResult _cmdConnectResult;
/// <summary>
/// 异步连接结果(响应管道)
/// </summary>
private IAsyncResult _rspConnectResult;
/// <summary>
/// Win32 PeekNamedPipe API,用于非阻塞检测管道中是否有可读数据
/// StreamReader.Peek() 在异步模式 NamedPipe 上不可靠:
/// 当内部缓冲区为空时,Peek 调用底层同步 Read,异步管道会返回 0 字节,
/// 导致 StreamReader 误判为 EOF,后续所有读取永远返回 -1/null
/// </summary>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool PeekNamedPipe(
SafePipeHandle hNamedPipe,
IntPtr lpBuffer,
uint nBufferSize,
IntPtr lpBytesRead,
out uint lpTotalBytesAvail,
IntPtr lpBytesLeftThisMessage);
/// <summary>
/// 检查命令管道中是否有可读数据(非阻塞)
/// </summary>
private bool HasPipeData()
{
if (_cmdPipe == null || !_cmdPipe.IsConnected)
return false;
bool result = PeekNamedPipe(
_cmdPipe.SafePipeHandle,
IntPtr.Zero, 0, IntPtr.Zero,
out uint bytesAvailable,
IntPtr.Zero);
return result && bytesAvailable > 0;
}
#endregion
#region Comet Timer常量
/// <summary>
/// 连接状态定时器
/// </summary>
private System.Windows.Forms.Timer _pviConnectTimer;
/// <summary>
/// 看门狗定时器
/// </summary>
private System.Windows.Forms.Timer _watchDogTimer;
/// <summary>
/// 心跳闪烁状态(true=绿色,false=灰色)
/// </summary>
private bool _heartbeatToggle;
#endregion
public XplorePlaneCometHost()
{
InitializeComponent();
InitializeTrayIcon();
SetupLogger();
SubscribeLocalEvents();
StartPipeLoop();
StartCometPviTimer();
}
#region
/// <summary>
/// 初始化系统托盘图标和右键菜单
/// </summary>
private void InitializeTrayIcon()
{
var contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("XplorePlane Comet Host", null, null).Enabled = false;
contextMenu.Items.Add(new ToolStripSeparator());
contextMenu.Items.Add("测试窗口|Test(&S)", null, (s, e) =>
{
this.ShowInTaskbar = true;
this.Show();
this.WindowState = FormWindowState.Normal;
this.Activate();
});
contextMenu.Items.Add("退出|Exit(&X)", null, OnExitClick);
_notifyIcon = new NotifyIcon
{
Icon = Resource.Comet_Host_Icon,
Text = "XP.Hardware.RaySource.Comet.Host",
Visible = true,
ContextMenuStrip = contextMenu
};
_notifyIcon.DoubleClick += (s, e) =>
{
this.ShowInTaskbar = true;
this.Show();
this.WindowState = FormWindowState.Normal;
this.Activate();
};
}
#endregion
#region
/// <summary>
/// 设置统一日志回调
/// 界面日志始终输出,管道推送仅在管道连接后生效
/// </summary>
private void SetupLogger()
{
CometPviClient.SetLogger((level, message, logArgs) =>
{
// 始终输出到界面
string formatted = logArgs != null && logArgs.Length > 0
? FormatLogMessage(message, logArgs)
: message;
AppendLog($"[{level}] {formatted}");
// 管道已连接时,同步推送到主进程
if (_isPipeConnected)
{
var logResponse = new LogResponse
{
Success = true,
PushType = "Log",
Level = level.ToString(),
Message = message,
Args = logArgs != null ? Array.ConvertAll(logArgs, a => a?.ToString() ?? "") : null
};
PushNotifier.SendPush(logResponse);
}
});
}
#endregion
#region
/// <summary>
/// 启动管道通信:创建管道并开始异步等待连接,启动轮询定时器
/// </summary>
private void StartPipeLoop()
{
// 创建管道
_cmdPipe = new NamedPipeServerStream(CmdPipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
_rspPipe = new NamedPipeServerStream(RspPipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
// 异步等待客户端连接
_cmdConnectResult = _cmdPipe.BeginWaitForConnection(null, null);
_rspConnectResult = _rspPipe.BeginWaitForConnection(null, null);
_isWaitingConnection = true;
AppendLog("[管道] 等待客户端连接...");
// 启动定时器轮询(50ms 间隔)
_pipeTimer = new System.Windows.Forms.Timer();
_pipeTimer.Interval = 50;
_pipeTimer.Tick += PipeTimer_Tick;
_pipeTimer.Start();
}
/// <summary>
/// 是否正在处理管道命令,防止 DoEvents 期间 Timer 重入
/// </summary>
private bool _isProcessingCommand;
/// <summary>
/// 定时器回调:检查管道连接状态和读取命令
/// </summary>
private void PipeTimer_Tick(object sender, EventArgs e)
{
// 防止 HandleInitialize 中 DoEvents 导致的 Timer 重入
if (_isProcessingCommand)
return;
try
{
// 阶段1:等待客户端连接
if (_isWaitingConnection)
{
if (_cmdConnectResult.IsCompleted && _rspConnectResult.IsCompleted)
{
_cmdPipe.EndWaitForConnection(_cmdConnectResult);
_rspPipe.EndWaitForConnection(_rspConnectResult);
_pipeReader = new StreamReader(_cmdPipe);
_pipeWriter = new StreamWriter(_rspPipe) { AutoFlush = true };
// 初始化推送管理器
PushNotifier.Initialize(_pipeWriter, WriteLock);
// 订阅 PVI 推送事件
SubscribePviPushEvents();
_isPipeConnected = true;
_isWaitingConnection = false;
AppendLog("[管道] 客户端已连接");
}
return;
}
// 阶段2:轮询读取命令
if (!_cmdPipe.IsConnected)
{
AppendLog("[管道] 客户端已断开");
CleanupPipe();
return;
}
// 检查管道中是否有可读数据(非阻塞)
// 使用 Win32 PeekNamedPipe 替代 StreamReader.Peek()
// StreamReader.Peek() 在异步模式 NamedPipe 上会误判 EOF,导致后续命令永远无法读取
if (!HasPipeData())
return;
_isProcessingCommand = true;
try
{
string line = _pipeReader.ReadLine();
if (line == null)
{
AppendLog("[管道] 客户端已关闭连接");
CleanupPipe();
return;
}
AppendLog($"[管道] 收到命令:{line}", Color.Cyan);
var command = MessageSerializer.DeserializeCommand(line);
if (command == null)
{
var errorResponse = new OperationResponse
{
Success = false,
ErrorMessage = "命令反序列化失败"
};
WriteResponse(_pipeWriter, errorResponse);
return;
}
var response = CommandDispatcher.Dispatch(command);
WriteResponse(_pipeWriter, response);
if (CommandDispatcher.ShouldExit)
{
AppendLog("[管道] 收到断开命令,管道循环退出");
CleanupPipe();
}
}
finally
{
_isProcessingCommand = false;
}
}
catch (Exception ex)
{
AppendLog($"[管道] 通信异常:{ex.Message}", Color.Red);
CleanupPipe();
}
}
/// <summary>
/// 清理管道资源
/// </summary>
private void CleanupPipe()
{
_pipeTimer?.Stop();
_isPipeConnected = false;
try { _pipeReader?.Dispose(); } catch { }
try { _pipeWriter?.Dispose(); } catch { }
try { _cmdPipe?.Dispose(); } catch { }
try { _rspPipe?.Dispose(); } catch { }
_pipeReader = null;
_pipeWriter = null;
_cmdPipe = null;
_rspPipe = null;
}
/// <summary>
/// 线程安全地写入响应到管道
/// </summary>
private static void WriteResponse(StreamWriter writer, RaySourceResponse response)
{
var json = MessageSerializer.Serialize(response);
lock (WriteLock)
{
writer.WriteLine(json);
}
}
#endregion
#region PVI
/// <summary>
/// 订阅 CometPviClient 事件,通过 PushNotifier 推送给主进程
/// </summary>
private void SubscribePviPushEvents()
{
CometPviClient.StatusChanged += (sender, status) =>
{
PushNotifier.SendPush(new StatusResponse
{
Success = true,
PushType = "StatusChanged",
SetVoltage = status.SetVoltage,
ActualVoltage = status.ActualVoltage,
SetCurrent = status.SetCurrent,
ActualCurrent = status.ActualCurrent,
IsXRayOn = status.IsXRayOn,
WarmUpStatus = status.WarmUpStatus,
VacuumStatus = status.VacuumStatus,
StartUpStatus = status.StartUpStatus,
AutoCenterStatus = status.AutoCenterStatus,
FilamentAdjustStatus = status.FilamentAdjustStatus,
IsInterlockActive = status.IsInterlockActive,
WatchdogStatus = status.WatchdogStatus,
PowerMode = status.PowerMode,
TxiStatus = status.TxiStatus
});
};
CometPviClient.XRayStateChanged += (sender, isXRayOn) =>
{
PushNotifier.SendPush(new OperationResponse
{
Success = true,
PushType = "XRayStateChanged",
Data = isXRayOn
});
};
CometPviClient.ErrorOccurred += (sender, errorMessage) =>
{
PushNotifier.SendPush(new OperationResponse
{
Success = false,
PushType = "ErrorOccurred",
ErrorMessage = errorMessage
});
};
CometPviClient.ConnectionStateChanged += (sender, state) =>
{
PushNotifier.SendPush(new OperationResponse
{
Success = true,
PushType = "ConnectionStateChanged",
Data = state.ToString()
});
};
}
#endregion
#region Comet Timer事件
private void StartCometPviTimer()
{
// 启动连接状态定时器轮询(100ms 间隔)
_pviConnectTimer = new System.Windows.Forms.Timer();
_pviConnectTimer.Interval = 100;
_pviConnectTimer.Tick += PviConnectTimer_Tick;
_pviConnectTimer.Start();
// 启动看门狗定时器轮询(1000ms 间隔)
_watchDogTimer = new System.Windows.Forms.Timer();
_watchDogTimer.Interval = 1000;
_watchDogTimer.Tick += WatchDogTimer_Tick;
_watchDogTimer.Start();
}
private void PviConnectTimer_Tick(object sender, EventArgs e)
{
try
{
bool bRaySourceConnected = CometPviClient.ReadRaySourceConnectStatus();
// 根据当前连接状态更新标签
var state = CometPviClient.CurrentConnectionState;
switch (state)
{
case PviConnectionState.RaySourceConnected:
_lblPviState.Text = "射线源就绪";
_lblPviState.ForeColor = Color.Green;
break;
case PviConnectionState.VariablesConnected:
_lblPviState.Text = "变量已连接";
_lblPviState.ForeColor = Color.DarkGoldenrod;
break;
case PviConnectionState.ServiceConnected:
_lblPviState.Text = "Service已连接";
_lblPviState.ForeColor = Color.Orange;
break;
default:
_lblPviState.Text = "未连接";
_lblPviState.ForeColor = Color.Red;
break;
}
}
catch (Exception ex)
{
AppendLog($"[错误] 连接状态定时器出错失败:{ex.Message}", Color.Red);
}
}
private void WatchDogTimer_Tick(object sender, EventArgs e)
{
try
{
CometPviClient.SetWatchDog();
// 心跳闪烁:绿色/灰色交替
_heartbeatToggle = !_heartbeatToggle;
_lblHeartbeat.ForeColor = _heartbeatToggle ? Color.LimeGreen : Color.Gray;
}
catch (Exception ex)
{
_lblHeartbeat.ForeColor = Color.Red;
AppendLog($"[错误] 看门狗定时器出错失败:{ex.Message}", Color.Red);
}
}
#endregion
#region
/// <summary>
/// 订阅 CometPviClient 事件,将状态输出到界面
/// </summary>
private void SubscribeLocalEvents()
{
// 订阅连接状态变更
CometPviClient.ConnectionStateChanged += (sender, state) =>
{
AppendLog($"[连接状态] {state}");
SafeInvoke(() =>
{
switch (state)
{
case PviConnectionState.RaySourceConnected:
_lblConnectionState.Text = "状态: 射线源已连接";
_lblConnectionState.ForeColor = Color.Green;
_btnConnectVariables.Enabled = false;
_btnDisconnect.Enabled = true;
_btnInitialize.Enabled = false;
break;
case PviConnectionState.ServiceConnected:
_lblConnectionState.Text = "状态: PVI Service 已连接";
_lblConnectionState.ForeColor = Color.Orange;
_btnConnectVariables.Enabled = true;
_btnDisconnect.Enabled = true;
_btnInitialize.Enabled = false;
break;
case PviConnectionState.VariablesConnected:
_lblConnectionState.Text = "状态: 变量已连接";
_lblConnectionState.ForeColor = Color.DarkGoldenrod;
SetOperationButtonsEnabled(true);
_btnConnectVariables.Enabled = false;
break;
case PviConnectionState.Disconnected:
_lblConnectionState.Text = "状态: 已断开";
_lblConnectionState.ForeColor = Color.Red;
SetOperationButtonsEnabled(false);
_btnConnectVariables.Enabled = false;
_btnDisconnect.Enabled = false;
_btnInitialize.Enabled = true;
break;
}
});
};
// 订阅状态更新
CometPviClient.StatusChanged += (sender, status) =>
{
AppendLog($"[状态更新] 电压={status.ActualVoltage}kV, 电流={status.ActualCurrent}μA, XRay={status.IsXRayOn}");
};
// 订阅射线状态变更
CometPviClient.XRayStateChanged += (sender, isOn) =>
{
AppendLog($"[射线状态] XRay {(isOn ? "" : "")}");
};
// 订阅错误事件
CometPviClient.ErrorOccurred += (sender, errorMsg) =>
{
AppendLog($"[错误] {errorMsg}", Color.Red);
};
}
/// <summary>
/// 格式化日志消息,替换占位符
/// </summary>
private string FormatLogMessage(string message, object[] args)
{
try
{
string result = message;
for (int i = 0; i < args.Length; i++)
{
result = result.Replace("{" + i + "}", args[i]?.ToString() ?? "null");
}
return result;
}
catch
{
return message;
}
}
#endregion
#region
private void OnInitialize(object sender, EventArgs e)
{
try
{
_btnInitialize.Enabled = false;
AppendLog("[操作] 开始初始化 PVI 连接...");
CometPviClient.Initialize(
_txtIpAddress.Text,
(int)_nudPort.Value,
_txtCpuName.Text,
(int)_nudSourcePort.Value,
(int)_nudStationNumber.Value);
}
catch (Exception ex)
{
AppendLog($"[错误] 初始化失败:{ex.Message}", Color.Red);
_btnInitialize.Enabled = true;
}
}
private void OnConnectVariables(object sender, EventArgs e)
{
try
{
AppendLog("[操作] 开始连接 PVI 变量...");
CometPviClient.ConnectVariables();
}
catch (Exception ex)
{
AppendLog($"[错误] 连接变量失败:{ex.Message}", Color.Red);
}
}
private void OnDisconnect(object sender, EventArgs e)
{
try
{
AppendLog("[操作] 断开连接...");
CometPviClient.Disconnect();
}
catch (Exception ex)
{
AppendLog($"[错误] 断开连接失败:{ex.Message}", Color.Red);
}
}
private void OnTurnOn(object sender, EventArgs e)
{
try
{
AppendLog("[操作] 开启高压...");
CometPviClient.TurnOn();
AppendLog("[操作] TurnOn 命令已发送");
}
catch (Exception ex)
{
AppendLog($"[错误] TurnOn 失败:{ex.Message}", Color.Red);
}
}
private void OnTurnOff(object sender, EventArgs e)
{
try
{
AppendLog("[操作] 关闭高压...");
CometPviClient.TurnOff();
AppendLog("[操作] TurnOff 命令已发送");
}
catch (Exception ex)
{
AppendLog($"[错误] TurnOff 失败:{ex.Message}", Color.Red);
}
}
private void OnSetVoltage(object sender, EventArgs e)
{
try
{
float voltage = (float)_nudVoltage.Value;
AppendLog($"[操作] 设置电压:{voltage} kV");
CometPviClient.SetVoltage(voltage);
AppendLog($"[操作] SetVoltage 命令已发送,电压={voltage}kV");
}
catch (Exception ex)
{
AppendLog($"[错误] SetVoltage 失败:{ex.Message}", Color.Red);
}
}
private void OnSetCurrent(object sender, EventArgs e)
{
try
{
float current = (float)_nudCurrent.Value;
AppendLog($"[操作] 设置电流:{current} μA");
CometPviClient.SetCurrent(current);
AppendLog($"[操作] SetCurrent 命令已发送,电流={current}μA");
}
catch (Exception ex)
{
AppendLog($"[错误] SetCurrent 失败:{ex.Message}", Color.Red);
}
}
private void OnReadVoltage(object sender, EventArgs e)
{
try
{
float voltage = CometPviClient.ReadVoltage();
AppendLog($"[读取] 实际电压:{voltage} kV");
}
catch (Exception ex)
{
AppendLog($"[错误] ReadVoltage 失败:{ex.Message}", Color.Red);
}
}
private void OnReadCurrent(object sender, EventArgs e)
{
try
{
float current = CometPviClient.ReadCurrent();
AppendLog($"[读取] 实际电流:{current} μA");
}
catch (Exception ex)
{
AppendLog($"[错误] ReadCurrent 失败:{ex.Message}", Color.Red);
}
}
private void OnReadSystemStatus(object sender, EventArgs e)
{
try
{
var status = CometPviClient.ReadSystemStatus();
AppendLog("========== 系统状态 ==========");
AppendLog($" 设定电压: {status.SetVoltage} kV | 实际电压: {status.ActualVoltage} kV");
AppendLog($" 设定电流: {status.SetCurrent} μA | 实际电流: {status.ActualCurrent} μA");
AppendLog($" 射线状态: {(status.IsXRayOn ? "" : "")}");
AppendLog($" 暖机: {status.WarmUpStatus} | 真空: {status.VacuumStatus}");
AppendLog($" 训机: {status.StartUpStatus} | 自动定心: {status.AutoCenterStatus}");
AppendLog($" 灯丝调整: {status.FilamentAdjustStatus}");
AppendLog($" 连锁: {(status.IsInterlockActive ? "" : "")} | 看门狗: {status.WatchdogStatus}");
AppendLog($" 功率模式: {status.PowerMode} | TXI: {status.TxiStatus}");
AppendLog("==============================");
}
catch (Exception ex)
{
AppendLog($"[错误] ReadSystemStatus 失败:{ex.Message}", Color.Red);
}
}
private void OnReadErrors(object sender, EventArgs e)
{
try
{
var errors = CometPviClient.ReadErrors();
AppendLog("========== 错误信息 ==========");
AppendLog($" 系统错误: {errors.SystemError}");
AppendLog($" HSG错误: {errors.HSGError}");
AppendLog($" 管错误: {errors.TubeError}");
AppendLog($" 管真空错误: {errors.TubeVacError}");
AppendLog("==============================");
}
catch (Exception ex)
{
AppendLog($"[错误] ReadErrors 失败:{ex.Message}", Color.Red);
}
}
private void OnWarmUp(object sender, EventArgs e)
{
try
{
AppendLog("[维护] 执行暖机设置...", Color.Yellow);
CometPviClient.WarmUp();
AppendLog("[维护] 暖机设置指令已发送", Color.Lime);
}
catch (Exception ex)
{
AppendLog($"[错误] 暖机设置失败:{ex.Message}", Color.Red);
}
}
private void OnTraining(object sender, EventArgs e)
{
try
{
AppendLog("[维护] 执行训机设置...", Color.Yellow);
CometPviClient.Training();
AppendLog("[维护] 训机设置指令已发送", Color.Lime);
}
catch (Exception ex)
{
AppendLog($"[错误] 训机设置失败:{ex.Message}", Color.Red);
}
}
private void OnFilamentCalibration(object sender, EventArgs e)
{
try
{
AppendLog("[维护] 执行灯丝校准...", Color.Yellow);
CometPviClient.FilamentCalibration();
AppendLog("[维护] 灯丝校准指令已发送", Color.Lime);
}
catch (Exception ex)
{
AppendLog($"[错误] 灯丝校准失败:{ex.Message}", Color.Red);
}
}
private void OnAutoCenter(object sender, EventArgs e)
{
try
{
AppendLog("[维护] 执行全部电压自动定心...", Color.Yellow);
CometPviClient.AutoCenter();
AppendLog("[维护] 自动定心指令已发送", Color.Lime);
}
catch (Exception ex)
{
AppendLog($"[错误] 自动定心失败:{ex.Message}", Color.Red);
}
}
private void OnTxiOn(object sender, EventArgs e)
{
try
{
AppendLog("[维护] 执行 TXI ON...", Color.Yellow);
CometPviClient.TxiOn();
AppendLog("[维护] TXI ON 指令已发送", Color.Lime);
}
catch (Exception ex)
{
AppendLog($"[错误] TXI ON 失败:{ex.Message}", Color.Red);
}
}
private void OnTxiOff(object sender, EventArgs e)
{
try
{
AppendLog("[维护] 执行 TXI OFF...", Color.Yellow);
CometPviClient.TxiOff();
AppendLog("[维护] TXI OFF 指令已发送", Color.Lime);
}
catch (Exception ex)
{
AppendLog($"[错误] TXI OFF 失败:{ex.Message}", Color.Red);
}
}
#endregion
#region
/// <summary>
/// 设置操作类按钮的启用状态
/// </summary>
private void SetOperationButtonsEnabled(bool enabled)
{
_btnTurnOn.Enabled = enabled;
_btnTurnOff.Enabled = enabled;
_btnSetVoltage.Enabled = enabled;
_btnSetCurrent.Enabled = enabled;
_btnReadVoltage.Enabled = enabled;
_btnReadCurrent.Enabled = enabled;
_btnReadSystemStatus.Enabled = enabled;
_btnReadErrors.Enabled = enabled;
_btnWarmUp.Enabled = enabled;
_btnTraining.Enabled = enabled;
_btnFilamentCalibration.Enabled = enabled;
_btnAutoCenter.Enabled = enabled;
_btnTxiOn.Enabled = enabled;
_btnTxiOff.Enabled = enabled;
}
/// <summary>
/// 线程安全地追加日志到 RichTextBox
/// </summary>
private void AppendLog(string message, Color? color = null)
{
SafeInvoke(() =>
{
var timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
var logLine = $"[{timestamp}] {message}\n";
_rtbLog.SelectionStart = _rtbLog.TextLength;
_rtbLog.SelectionLength = 0;
_rtbLog.SelectionColor = color ?? Color.LightGreen;
_rtbLog.AppendText(logLine);
_rtbLog.ScrollToCaret();
});
}
/// <summary>
/// 线程安全地在 UI 线程执行操作
/// </summary>
private void SafeInvoke(Action action)
{
if (this.IsDisposed) return;
if (this.InvokeRequired)
{
try { this.Invoke(action); }
catch (ObjectDisposedException) { }
}
else
{
action();
}
}
#endregion
#region 退
/// <summary>
/// 窗体加载后立即隐藏,默认只显示托盘图标
/// </summary>
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Visible = false;
this.ShowInTaskbar = false;
this.WindowState = FormWindowState.Minimized;
}
/// <summary>
/// 关闭窗体时最小化到托盘,不退出应用
/// </summary>
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.Hide();
this.ShowInTaskbar = false;
_notifyIcon.ShowBalloonTip(1000, "XplorePlane Comet Host",
"程序已最小化到系统托盘", ToolTipIcon.Info);
}
}
/// <summary>
/// 托盘菜单退出(已禁用,仅提示)
/// </summary>
private void OnExitClick(object sender, EventArgs e)
{
MessageBox.Show("XplorePlane Comet Host does not allow manual exit; it will close along with the shutdown of XplorePlane.\r\nXplorePlane Comet Host不允许手动退出,它会跟随XplorePlane的关闭一并退出。", "XplorePlane Comet Host Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
/// <summary>
/// 强制退出按钮点击 — 需要输入密码 Hexagon 才可退出
/// Force exit button click — requires password "Hexagon" to exit
/// </summary>
private void OnForceExitClick(object sender, EventArgs e)
{
// 使用自定义输入对话框获取密码 | Use custom input dialog to get password
using (var dlg = new ForceExitPasswordDialog())
{
if (dlg.ShowDialog(this) == DialogResult.OK && dlg.EnteredPassword == "Hexagon")
{
AppendLog("[系统] 强制退出已授权,正在退出... | Force exit authorized, exiting...", Color.Orange);
ColseForm(sender, e);
}
else if (dlg.DialogResult == DialogResult.OK)
{
// 密码错误 | Wrong password
MessageBox.Show("密码错误,无法退出。\r\nIncorrect password, cannot exit.",
"XplorePlane Comet Host", MessageBoxButtons.OK, MessageBoxIcon.Error);
AppendLog("[警告] 强制退出尝试失败:密码错误 | Force exit attempt failed: wrong password", Color.Red);
}
}
}
/// <summary>
/// 托盘菜单退出
/// </summary>
private void ColseForm(object sender, EventArgs e)
{
CleanupPipe();
try { CometPviClient.Dispose(); } catch { }
if (_notifyIcon != null)
{
_notifyIcon.Visible = false;
_notifyIcon.Dispose();
_notifyIcon = null;
}
// 移除 FormClosing 拦截,允许窗体真正关闭
this.FormClosing -= OnFormClosing;
Application.Exit();
}
#endregion
}
}
@@ -0,0 +1,326 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
</value>
</data>
</root>