using System; using System.Windows.Forms; using System.Drawing; using CCDCount.DLL.CanBus; using CanTest; namespace CanOpenSlaveTest { /// /// CANopen从站设备测试界面 /// public class SlaveTestForm : Form { private CanOpenSlaveDevice m_slaveDevice; // UI控件 private GroupBox grpDeviceInfo; private Label lblNodeId; private Label lblState; private Label lblStatus; private GroupBox grpControl; private Button btnStart; private Button btnStop; private Button btnSendTpdo1; private Button btnSendTpdo2; private Button btnSendAllTpdos; private GroupBox grpHeartbeat; private NumericUpDown nudHeartbeatTime; private Button btnConfigureHeartbeat; private TextBox txtLog; private Label lblHeartbeat; private System.ComponentModel.IContainer components; private System.Windows.Forms.Timer m_updateTimer; public SlaveTestForm() { InitializeComponent(); // 在构造函数中创建从站设备(避免设计器错误) if (!DesignMode) { m_slaveDevice = new CanOpenSlaveDevice(nodeId: 1); // 注册事件 m_slaveDevice.OnRpdoReceived += SlaveDevice_OnRpdoReceived; m_slaveDevice.OnNmtStateChanged += SlaveDevice_OnNmtStateChanged; m_slaveDevice.OnSdoReadRequest += SlaveDevice_OnSdoReadRequest; m_slaveDevice.OnSdoWriteRequest += SlaveDevice_OnSdoWriteRequest; // 初始化日志 AppendLog("CANopen从站测试程序已启动"); AppendLog("节点ID: " + m_slaveDevice.NodeId.ToString()); AppendLog("点击'启动从站'按钮开始测试\n"); } } private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.grpDeviceInfo = new System.Windows.Forms.GroupBox(); this.lblNodeId = new System.Windows.Forms.Label(); this.lblState = new System.Windows.Forms.Label(); this.lblStatus = new System.Windows.Forms.Label(); this.grpControl = new System.Windows.Forms.GroupBox(); this.btnStart = new System.Windows.Forms.Button(); this.btnStop = new System.Windows.Forms.Button(); this.btnSendTpdo1 = new System.Windows.Forms.Button(); this.btnSendTpdo2 = new System.Windows.Forms.Button(); this.btnSendAllTpdos = new System.Windows.Forms.Button(); this.grpHeartbeat = new System.Windows.Forms.GroupBox(); this.lblHeartbeat = new System.Windows.Forms.Label(); this.nudHeartbeatTime = new System.Windows.Forms.NumericUpDown(); this.btnConfigureHeartbeat = new System.Windows.Forms.Button(); this.txtLog = new System.Windows.Forms.TextBox(); this.m_updateTimer = new System.Windows.Forms.Timer(this.components); this.grpDeviceInfo.SuspendLayout(); this.grpControl.SuspendLayout(); this.grpHeartbeat.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.nudHeartbeatTime)).BeginInit(); this.SuspendLayout(); // // grpDeviceInfo // this.grpDeviceInfo.Controls.Add(this.lblNodeId); this.grpDeviceInfo.Controls.Add(this.lblState); this.grpDeviceInfo.Controls.Add(this.lblStatus); this.grpDeviceInfo.Location = new System.Drawing.Point(10, 10); this.grpDeviceInfo.Name = "grpDeviceInfo"; this.grpDeviceInfo.Size = new System.Drawing.Size(380, 100); this.grpDeviceInfo.TabIndex = 0; this.grpDeviceInfo.TabStop = false; this.grpDeviceInfo.Text = "设备信息"; // // lblNodeId // this.lblNodeId.AutoSize = true; this.lblNodeId.Location = new System.Drawing.Point(10, 25); this.lblNodeId.Name = "lblNodeId"; this.lblNodeId.Size = new System.Drawing.Size(77, 15); this.lblNodeId.TabIndex = 0; this.lblNodeId.Text = "节点ID: -"; // // lblState // this.lblState.AutoSize = true; this.lblState.Location = new System.Drawing.Point(10, 50); this.lblState.Name = "lblState"; this.lblState.Size = new System.Drawing.Size(61, 15); this.lblState.TabIndex = 1; this.lblState.Text = "状态: -"; // // lblStatus // this.lblStatus.AutoSize = true; this.lblStatus.Location = new System.Drawing.Point(10, 75); this.lblStatus.Name = "lblStatus"; this.lblStatus.Size = new System.Drawing.Size(128, 15); this.lblStatus.TabIndex = 2; this.lblStatus.Text = "运行状态: 未启动"; // // grpControl // this.grpControl.Controls.Add(this.btnStart); this.grpControl.Controls.Add(this.btnStop); this.grpControl.Controls.Add(this.btnSendTpdo1); this.grpControl.Controls.Add(this.btnSendTpdo2); this.grpControl.Controls.Add(this.btnSendAllTpdos); this.grpControl.Location = new System.Drawing.Point(400, 10); this.grpControl.Name = "grpControl"; this.grpControl.Size = new System.Drawing.Size(380, 100); this.grpControl.TabIndex = 1; this.grpControl.TabStop = false; this.grpControl.Text = "控制"; // // btnStart // this.btnStart.Location = new System.Drawing.Point(10, 25); this.btnStart.Name = "btnStart"; this.btnStart.Size = new System.Drawing.Size(100, 30); this.btnStart.TabIndex = 0; this.btnStart.Text = "启动从站"; this.btnStart.Click += new System.EventHandler(this.BtnStart_Click); // // btnStop // this.btnStop.Enabled = false; this.btnStop.Location = new System.Drawing.Point(120, 25); this.btnStop.Name = "btnStop"; this.btnStop.Size = new System.Drawing.Size(100, 30); this.btnStop.TabIndex = 1; this.btnStop.Text = "停止从站"; this.btnStop.Click += new System.EventHandler(this.BtnStop_Click); // // btnSendTpdo1 // this.btnSendTpdo1.Enabled = false; this.btnSendTpdo1.Location = new System.Drawing.Point(10, 60); this.btnSendTpdo1.Name = "btnSendTpdo1"; this.btnSendTpdo1.Size = new System.Drawing.Size(100, 30); this.btnSendTpdo1.TabIndex = 2; this.btnSendTpdo1.Text = "发送TPDO1"; this.btnSendTpdo1.Click += new System.EventHandler(this.BtnSendTpdo1_Click); // // btnSendTpdo2 // this.btnSendTpdo2.Enabled = false; this.btnSendTpdo2.Location = new System.Drawing.Point(120, 60); this.btnSendTpdo2.Name = "btnSendTpdo2"; this.btnSendTpdo2.Size = new System.Drawing.Size(100, 30); this.btnSendTpdo2.TabIndex = 3; this.btnSendTpdo2.Text = "发送TPDO2"; this.btnSendTpdo2.Click += new System.EventHandler(this.BtnSendTpdo2_Click); // // btnSendAllTpdos // this.btnSendAllTpdos.Enabled = false; this.btnSendAllTpdos.Location = new System.Drawing.Point(230, 60); this.btnSendAllTpdos.Name = "btnSendAllTpdos"; this.btnSendAllTpdos.Size = new System.Drawing.Size(120, 30); this.btnSendAllTpdos.TabIndex = 4; this.btnSendAllTpdos.Text = "发送所有TPDO"; this.btnSendAllTpdos.Click += new System.EventHandler(this.BtnSendAllTpdos_Click); // // grpHeartbeat // this.grpHeartbeat.Controls.Add(this.lblHeartbeat); this.grpHeartbeat.Controls.Add(this.nudHeartbeatTime); this.grpHeartbeat.Controls.Add(this.btnConfigureHeartbeat); this.grpHeartbeat.Location = new System.Drawing.Point(10, 120); this.grpHeartbeat.Name = "grpHeartbeat"; this.grpHeartbeat.Size = new System.Drawing.Size(770, 60); this.grpHeartbeat.TabIndex = 2; this.grpHeartbeat.TabStop = false; this.grpHeartbeat.Text = "心跳配置"; // // lblHeartbeat // this.lblHeartbeat.AutoSize = true; this.lblHeartbeat.Location = new System.Drawing.Point(10, 25); this.lblHeartbeat.Name = "lblHeartbeat"; this.lblHeartbeat.Size = new System.Drawing.Size(107, 15); this.lblHeartbeat.TabIndex = 0; this.lblHeartbeat.Text = "心跳时间(ms):"; // // nudHeartbeatTime // this.nudHeartbeatTime.Location = new System.Drawing.Point(110, 22); this.nudHeartbeatTime.Maximum = new decimal(new int[] { 10000, 0, 0, 0}); this.nudHeartbeatTime.Name = "nudHeartbeatTime"; this.nudHeartbeatTime.Size = new System.Drawing.Size(100, 25); this.nudHeartbeatTime.TabIndex = 1; this.nudHeartbeatTime.Value = new decimal(new int[] { 100, 0, 0, 0}); // // btnConfigureHeartbeat // this.btnConfigureHeartbeat.Enabled = false; this.btnConfigureHeartbeat.Location = new System.Drawing.Point(220, 20); this.btnConfigureHeartbeat.Name = "btnConfigureHeartbeat"; this.btnConfigureHeartbeat.Size = new System.Drawing.Size(100, 30); this.btnConfigureHeartbeat.TabIndex = 2; this.btnConfigureHeartbeat.Text = "配置心跳"; this.btnConfigureHeartbeat.Click += new System.EventHandler(this.BtnConfigureHeartbeat_Click); // // txtLog // this.txtLog.BackColor = System.Drawing.Color.White; this.txtLog.Font = new System.Drawing.Font("微软雅黑", 9F); this.txtLog.ForeColor = System.Drawing.Color.Black; this.txtLog.Location = new System.Drawing.Point(10, 190); this.txtLog.Multiline = true; this.txtLog.Name = "txtLog"; this.txtLog.ReadOnly = true; this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; this.txtLog.Size = new System.Drawing.Size(770, 360); this.txtLog.TabIndex = 3; // // m_updateTimer // this.m_updateTimer.Enabled = true; this.m_updateTimer.Interval = 500; // // SlaveTestForm // this.ClientSize = new System.Drawing.Size(782, 553); this.Controls.Add(this.grpDeviceInfo); this.Controls.Add(this.grpControl); this.Controls.Add(this.grpHeartbeat); this.Controls.Add(this.txtLog); this.Name = "SlaveTestForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "CANopen从站设备测试"; this.grpDeviceInfo.ResumeLayout(false); this.grpDeviceInfo.PerformLayout(); this.grpControl.ResumeLayout(false); this.grpHeartbeat.ResumeLayout(false); this.grpHeartbeat.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.nudHeartbeatTime)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); } private void BtnStart_Click(object sender, EventArgs e) { try { AppendLog("正在启动从站..."); if (m_slaveDevice.Start(CanBaudRate.BaudRate_1M)) { AppendLog("✓ 从站启动成功"); btnStart.Enabled = false; btnStop.Enabled = true; btnSendTpdo1.Enabled = true; btnSendTpdo2.Enabled = true; btnSendAllTpdos.Enabled = true; btnConfigureHeartbeat.Enabled = true; UpdateDeviceInfo(); } else { AppendLog("✗ 从站启动失败"); MessageBox.Show("启动失败!请检查CAN设备连接。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } catch (Exception ex) { AppendLog($"✗ 启动错误: {ex.Message}"); MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void BtnStop_Click(object sender, EventArgs e) { try { AppendLog("正在停止从站..."); m_slaveDevice.Stop(); AppendLog("✓ 从站已停止"); btnStart.Enabled = true; btnStop.Enabled = false; btnSendTpdo1.Enabled = false; btnSendTpdo2.Enabled = false; btnSendAllTpdos.Enabled = false; btnConfigureHeartbeat.Enabled = false; UpdateDeviceInfo(); } catch (Exception ex) { AppendLog($"✗ 停止错误: {ex.Message}"); } } private void BtnSendTpdo1_Click(object sender, EventArgs e) { try { m_slaveDevice.SendTpdo(1); AppendLog("→ 已发送TPDO1"); } catch (Exception ex) { AppendLog($"✗ 发送TPDO1失败: {ex.Message}"); } } private void BtnSendTpdo2_Click(object sender, EventArgs e) { try { m_slaveDevice.SendTpdo(2); AppendLog("→ 已发送TPDO2"); } catch (Exception ex) { AppendLog($"✗ 发送TPDO2失败: {ex.Message}"); } } private void BtnSendAllTpdos_Click(object sender, EventArgs e) { try { m_slaveDevice.SendAllTpdos(); AppendLog("→ 已发送所有TPDO"); } catch (Exception ex) { AppendLog($"✗ 发送TPDO失败: {ex.Message}"); } } private void BtnConfigureHeartbeat_Click(object sender, EventArgs e) { try { ushort heartbeatTime = (ushort)nudHeartbeatTime.Value; m_slaveDevice.ConfigureHeartbeat(heartbeatTime); AppendLog($"✓ 心跳已配置: {heartbeatTime}ms"); } catch (Exception ex) { AppendLog($"✗ 配置心跳失败: {ex.Message}"); } } private void SlaveDevice_OnRpdoReceived(byte nodeId, byte pdoNumber, byte[] data) { if (this.InvokeRequired) { this.Invoke(new Action(() => SlaveDevice_OnRpdoReceived(nodeId, pdoNumber, data))); return; } string dataStr = BitConverter.ToString(data).Replace("-", " "); AppendLog($"← 收到RPDO{pdoNumber} [节点{nodeId}]: {dataStr}"); } private void SlaveDevice_OnNmtStateChanged(NmtState oldState, NmtState newState) { if (this.InvokeRequired) { this.Invoke(new Action(() => SlaveDevice_OnNmtStateChanged(oldState, newState))); return; } AppendLog($"⟳ NMT状态改变: {oldState} → {newState}"); UpdateDeviceInfo(); } private void SlaveDevice_OnSdoReadRequest(byte nodeId, ushort index, byte subIndex) { if (this.InvokeRequired) { this.Invoke(new Action(() => SlaveDevice_OnSdoReadRequest(nodeId, index, subIndex))); return; } AppendLog($"? SDO读取请求: 索引0x{index:X4}, 子索引{subIndex}"); } private void SlaveDevice_OnSdoWriteRequest(byte nodeId, ushort index, byte subIndex, uint value) { if (this.InvokeRequired) { this.Invoke(new Action(() => SlaveDevice_OnSdoWriteRequest(nodeId, index, subIndex, value))); return; } AppendLog($"↓ SDO写入请求: 索引0x{index:X4}, 子索引{subIndex}, 值0x{value:X8}"); } private void UpdateTimer_Tick(object sender, EventArgs e) { UpdateDeviceInfo(); } private void UpdateDeviceInfo() { if (this.InvokeRequired) { this.Invoke(new Action(UpdateDeviceInfo)); return; } lblNodeId.Text = $"节点ID: {m_slaveDevice.NodeId}"; lblState.Text = $"状态: {m_slaveDevice.CurrentState}"; lblStatus.Text = $"运行状态: {(m_slaveDevice.IsRunning ? "运行中" : "已停止")}"; } private void AppendLog(string message) { if (this.InvokeRequired) { this.Invoke(new Action(AppendLog), message); return; } string timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); // 使用字符串拼接而非插值,确保兼容性 txtLog.AppendText("[" + timestamp + "] " + message + "\r\n"); // 自动滚动到底部 txtLog.SelectionStart = txtLog.Text.Length; txtLog.ScrollToCaret(); } protected override void OnFormClosing(FormClosingEventArgs e) { if (m_slaveDevice != null) { m_slaveDevice.Stop(); m_slaveDevice.Dispose(); } m_updateTimer?.Stop(); m_updateTimer?.Dispose(); base.OnFormClosing(e); } } }