| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038 |
- using System;
- using System.Windows.Forms;
- using System.Drawing;
- using System.Diagnostics;
- using System.Threading;
- using System.Threading.Tasks;
- using CCDCount.DLL.CanBus;
- using CanTest;
- namespace CanOpenSlaveTest
- {
- /// <summary>
- /// CANopen从站设备测试界面
- /// </summary>
- 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 GroupBox grpPdo1Send;
- private Label lblPdo1Data0;
- private Label lblPdo1Data1;
- private Label lblPdo1Data2;
- private Label lblPdo1Data3;
- private Label lblPdo1Data4;
- private Label lblPdo1Data5;
- private Label lblPdo1Data6;
- private Label lblPdo1Data7;
- private TextBox txtPdo1Data0;
- private TextBox txtPdo1Data1;
- private TextBox txtPdo1Data2;
- private TextBox txtPdo1Data3;
- private TextBox txtPdo1Data4;
- private TextBox txtPdo1Data5;
- private TextBox txtPdo1Data6;
- private TextBox txtPdo1Data7;
- private Button btnSendTpdo1;
- private Button btnRuleSend;
- private Button btnContinuousSend;
-
- // 连续发送相关控件
- private Label lblPeriodTime;
- private TextBox txtPeriodTime;
- private Label lblPeriodUnit;
- // 规则发送运行时长相关控件
- private Label lblRuleDuration;
- private TextBox txtRuleDuration;
- private Label lblRuleDurationUnit;
-
- private TextBox txtLog;
- private System.ComponentModel.IContainer components;
- private System.Windows.Forms.Timer m_updateTimer;
-
- // 连续发送状态
- private bool m_isContinuousSending = false;
- private CancellationTokenSource m_continuousSendCts;
- private long m_continuousSendCounter = 0;
-
- // 规则发送状态
- private bool m_isRuleSending = false;
- private long m_ruleSendCounter = 0;
- // 规则发送运行时长相关
- private DateTime m_ruleSendStartTime;
- private int m_ruleSendDurationMs = 0;
- private CancellationTokenSource m_ruleSendCts;
-
- 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("心跳周期: 1000ms (固定值)");
- 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.grpPdo1Send = new System.Windows.Forms.GroupBox();
- this.lblPdo1Data0 = new System.Windows.Forms.Label();
- this.lblPdo1Data1 = new System.Windows.Forms.Label();
- this.lblPdo1Data2 = new System.Windows.Forms.Label();
- this.lblPdo1Data3 = new System.Windows.Forms.Label();
- this.lblPdo1Data4 = new System.Windows.Forms.Label();
- this.lblPdo1Data5 = new System.Windows.Forms.Label();
- this.lblPdo1Data6 = new System.Windows.Forms.Label();
- this.lblPdo1Data7 = new System.Windows.Forms.Label();
- this.txtPdo1Data0 = new System.Windows.Forms.TextBox();
- this.txtPdo1Data1 = new System.Windows.Forms.TextBox();
- this.txtPdo1Data2 = new System.Windows.Forms.TextBox();
- this.txtPdo1Data3 = new System.Windows.Forms.TextBox();
- this.txtPdo1Data4 = new System.Windows.Forms.TextBox();
- this.txtPdo1Data5 = new System.Windows.Forms.TextBox();
- this.txtPdo1Data6 = new System.Windows.Forms.TextBox();
- this.txtPdo1Data7 = new System.Windows.Forms.TextBox();
- this.btnSendTpdo1 = new System.Windows.Forms.Button();
- this.btnRuleSend = new System.Windows.Forms.Button();
- this.btnContinuousSend = new System.Windows.Forms.Button();
- this.lblPeriodTime = new System.Windows.Forms.Label();
- this.txtPeriodTime = new System.Windows.Forms.TextBox();
- this.lblPeriodUnit = new System.Windows.Forms.Label();
- // 添加规则发送时长相关控件
- this.lblRuleDuration = new System.Windows.Forms.Label();
- this.txtRuleDuration = new System.Windows.Forms.TextBox();
- this.lblRuleDurationUnit = new System.Windows.Forms.Label();
- this.txtLog = new System.Windows.Forms.TextBox();
- this.m_updateTimer = new System.Windows.Forms.Timer(this.components);
- this.grpDeviceInfo.SuspendLayout();
- this.grpControl.SuspendLayout();
- this.grpPdo1Send.SuspendLayout();
- 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.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);
- //
- // grpPdo1Send
- //
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data0);
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data1);
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data2);
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data3);
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data4);
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data5);
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data6);
- this.grpPdo1Send.Controls.Add(this.lblPdo1Data7);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data0);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data1);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data2);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data3);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data4);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data5);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data6);
- this.grpPdo1Send.Controls.Add(this.txtPdo1Data7);
- this.grpPdo1Send.Controls.Add(this.btnSendTpdo1);
- this.grpPdo1Send.Controls.Add(this.btnRuleSend);
- this.grpPdo1Send.Controls.Add(this.btnContinuousSend);
- this.grpPdo1Send.Controls.Add(this.lblPeriodTime);
- this.grpPdo1Send.Controls.Add(this.txtPeriodTime);
- this.grpPdo1Send.Controls.Add(this.lblPeriodUnit);
- // 添加规则发送时长相关控件到界面
- this.grpPdo1Send.Controls.Add(this.lblRuleDuration);
- this.grpPdo1Send.Controls.Add(this.txtRuleDuration);
- this.grpPdo1Send.Controls.Add(this.lblRuleDurationUnit);
- this.grpPdo1Send.Location = new System.Drawing.Point(10, 120);
- this.grpPdo1Send.Name = "grpPdo1Send";
- this.grpPdo1Send.Size = new System.Drawing.Size(770, 160); // 增加高度以容纳新控件
- this.grpPdo1Send.TabIndex = 2;
- this.grpPdo1Send.TabStop = false;
- this.grpPdo1Send.Text = "TPDO1发送配置";
- //
- // lblPdo1Data0
- //
- this.lblPdo1Data0.AutoSize = true;
- this.lblPdo1Data0.Location = new System.Drawing.Point(10, 25);
- this.lblPdo1Data0.Name = "lblPdo1Data0";
- this.lblPdo1Data0.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data0.TabIndex = 0;
- this.lblPdo1Data0.Text = "Byte0:";
- //
- // lblPdo1Data1
- //
- this.lblPdo1Data1.AutoSize = true;
- this.lblPdo1Data1.Location = new System.Drawing.Point(90, 25);
- this.lblPdo1Data1.Name = "lblPdo1Data1";
- this.lblPdo1Data1.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data1.TabIndex = 1;
- this.lblPdo1Data1.Text = "Byte1:";
- //
- // lblPdo1Data2
- //
- this.lblPdo1Data2.AutoSize = true;
- this.lblPdo1Data2.Location = new System.Drawing.Point(170, 25);
- this.lblPdo1Data2.Name = "lblPdo1Data2";
- this.lblPdo1Data2.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data2.TabIndex = 2;
- this.lblPdo1Data2.Text = "Byte2:";
- //
- // lblPdo1Data3
- //
- this.lblPdo1Data3.AutoSize = true;
- this.lblPdo1Data3.Location = new System.Drawing.Point(250, 25);
- this.lblPdo1Data3.Name = "lblPdo1Data3";
- this.lblPdo1Data3.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data3.TabIndex = 3;
- this.lblPdo1Data3.Text = "Byte3:";
- //
- // lblPdo1Data4
- //
- this.lblPdo1Data4.AutoSize = true;
- this.lblPdo1Data4.Location = new System.Drawing.Point(330, 25);
- this.lblPdo1Data4.Name = "lblPdo1Data4";
- this.lblPdo1Data4.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data4.TabIndex = 4;
- this.lblPdo1Data4.Text = "Byte4:";
- //
- // lblPdo1Data5
- //
- this.lblPdo1Data5.AutoSize = true;
- this.lblPdo1Data5.Location = new System.Drawing.Point(410, 25);
- this.lblPdo1Data5.Name = "lblPdo1Data5";
- this.lblPdo1Data5.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data5.TabIndex = 5;
- this.lblPdo1Data5.Text = "Byte5:";
- //
- // lblPdo1Data6
- //
- this.lblPdo1Data6.AutoSize = true;
- this.lblPdo1Data6.Location = new System.Drawing.Point(490, 25);
- this.lblPdo1Data6.Name = "lblPdo1Data6";
- this.lblPdo1Data6.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data6.TabIndex = 6;
- this.lblPdo1Data6.Text = "Byte6:";
- //
- // lblPdo1Data7
- //
- this.lblPdo1Data7.AutoSize = true;
- this.lblPdo1Data7.Location = new System.Drawing.Point(570, 25);
- this.lblPdo1Data7.Name = "lblPdo1Data7";
- this.lblPdo1Data7.Size = new System.Drawing.Size(47, 15);
- this.lblPdo1Data7.TabIndex = 7;
- this.lblPdo1Data7.Text = "Byte7:";
- //
- // txtPdo1Data0
- //
- this.txtPdo1Data0.Location = new System.Drawing.Point(10, 45);
- this.txtPdo1Data0.MaxLength = 3;
- this.txtPdo1Data0.Name = "txtPdo1Data0";
- this.txtPdo1Data0.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data0.TabIndex = 8;
- this.txtPdo1Data0.Text = "0";
- this.txtPdo1Data0.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // txtPdo1Data1
- //
- this.txtPdo1Data1.Location = new System.Drawing.Point(90, 45);
- this.txtPdo1Data1.MaxLength = 3;
- this.txtPdo1Data1.Name = "txtPdo1Data1";
- this.txtPdo1Data1.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data1.TabIndex = 9;
- this.txtPdo1Data1.Text = "255";
- this.txtPdo1Data1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // txtPdo1Data2
- //
- this.txtPdo1Data2.Location = new System.Drawing.Point(170, 45);
- this.txtPdo1Data2.MaxLength = 3;
- this.txtPdo1Data2.Name = "txtPdo1Data2";
- this.txtPdo1Data2.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data2.TabIndex = 10;
- this.txtPdo1Data2.Text = "255";
- this.txtPdo1Data2.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // txtPdo1Data3
- //
- this.txtPdo1Data3.Location = new System.Drawing.Point(250, 45);
- this.txtPdo1Data3.MaxLength = 3;
- this.txtPdo1Data3.Name = "txtPdo1Data3";
- this.txtPdo1Data3.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data3.TabIndex = 11;
- this.txtPdo1Data3.Text = "255";
- this.txtPdo1Data3.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // txtPdo1Data4
- //
- this.txtPdo1Data4.Location = new System.Drawing.Point(330, 45);
- this.txtPdo1Data4.MaxLength = 3;
- this.txtPdo1Data4.Name = "txtPdo1Data4";
- this.txtPdo1Data4.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data4.TabIndex = 12;
- this.txtPdo1Data4.Text = "255";
- this.txtPdo1Data4.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // txtPdo1Data5
- //
- this.txtPdo1Data5.Location = new System.Drawing.Point(410, 45);
- this.txtPdo1Data5.MaxLength = 3;
- this.txtPdo1Data5.Name = "txtPdo1Data5";
- this.txtPdo1Data5.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data5.TabIndex = 13;
- this.txtPdo1Data5.Text = "255";
- this.txtPdo1Data5.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // txtPdo1Data6
- //
- this.txtPdo1Data6.Location = new System.Drawing.Point(490, 45);
- this.txtPdo1Data6.MaxLength = 3;
- this.txtPdo1Data6.Name = "txtPdo1Data6";
- this.txtPdo1Data6.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data6.TabIndex = 14;
- this.txtPdo1Data6.Text = "255";
- this.txtPdo1Data6.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // txtPdo1Data7
- //
- this.txtPdo1Data7.Location = new System.Drawing.Point(570, 45);
- this.txtPdo1Data7.MaxLength = 3;
- this.txtPdo1Data7.Name = "txtPdo1Data7";
- this.txtPdo1Data7.Size = new System.Drawing.Size(60, 25);
- this.txtPdo1Data7.TabIndex = 15;
- this.txtPdo1Data7.Text = "255";
- this.txtPdo1Data7.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // btnSendTpdo1
- //
- this.btnSendTpdo1.Enabled = false;
- this.btnSendTpdo1.Location = new System.Drawing.Point(10, 95);
- this.btnSendTpdo1.Name = "btnSendTpdo1";
- this.btnSendTpdo1.Size = new System.Drawing.Size(100, 25);
- this.btnSendTpdo1.TabIndex = 16;
- this.btnSendTpdo1.Text = "立即发送";
- this.btnSendTpdo1.Click += new System.EventHandler(this.BtnSendTpdo1_Click);
- //
- // btnRuleSend
- //
- this.btnRuleSend.Enabled = false;
- this.btnRuleSend.Location = new System.Drawing.Point(120, 95);
- this.btnRuleSend.Name = "btnRuleSend";
- this.btnRuleSend.Size = new System.Drawing.Size(100, 25);
- this.btnRuleSend.TabIndex = 17;
- this.btnRuleSend.Text = "规则发送";
- this.btnRuleSend.Click += new System.EventHandler(this.BtnRuleSend_Click);
- //
- // btnContinuousSend
- //
- this.btnContinuousSend.Enabled = false;
- this.btnContinuousSend.Location = new System.Drawing.Point(230, 95);
- this.btnContinuousSend.Name = "btnContinuousSend";
- this.btnContinuousSend.Size = new System.Drawing.Size(100, 25);
- this.btnContinuousSend.TabIndex = 18;
- this.btnContinuousSend.Text = "连续发送";
- this.btnContinuousSend.Click += new System.EventHandler(this.BtnContinuousSend_Click);
- //
- // lblPeriodTime
- //
- this.lblPeriodTime.AutoSize = true;
- this.lblPeriodTime.Location = new System.Drawing.Point(350, 98);
- this.lblPeriodTime.Name = "lblPeriodTime";
- this.lblPeriodTime.Size = new System.Drawing.Size(77, 15);
- this.lblPeriodTime.TabIndex = 19;
- this.lblPeriodTime.Text = "周期时间:";
- //
- // txtPeriodTime
- //
- this.txtPeriodTime.Location = new System.Drawing.Point(430, 95);
- this.txtPeriodTime.Name = "txtPeriodTime";
- this.txtPeriodTime.Size = new System.Drawing.Size(80, 25);
- this.txtPeriodTime.TabIndex = 20;
- this.txtPeriodTime.Text = "1000";
- this.txtPeriodTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // lblPeriodUnit
- //
- this.lblPeriodUnit.AutoSize = true;
- this.lblPeriodUnit.Location = new System.Drawing.Point(520, 98);
- this.lblPeriodUnit.Name = "lblPeriodUnit";
- this.lblPeriodUnit.Size = new System.Drawing.Size(23, 15);
- this.lblPeriodUnit.TabIndex = 21;
- this.lblPeriodUnit.Text = "us";
- //
- // lblRuleDuration
- //
- this.lblRuleDuration.AutoSize = true;
- this.lblRuleDuration.Location = new System.Drawing.Point(350, 128);
- this.lblRuleDuration.Name = "lblRuleDuration";
- this.lblRuleDuration.Size = new System.Drawing.Size(77, 15);
- this.lblRuleDuration.TabIndex = 22;
- this.lblRuleDuration.Text = "持续时间:";
- //
- // txtRuleDuration
- //
- this.txtRuleDuration.Location = new System.Drawing.Point(430, 125);
- this.txtRuleDuration.Name = "txtRuleDuration";
- this.txtRuleDuration.Size = new System.Drawing.Size(80, 25);
- this.txtRuleDuration.TabIndex = 23;
- this.txtRuleDuration.Text = "10";
- this.txtRuleDuration.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
- //
- // lblRuleDurationUnit
- //
- this.lblRuleDurationUnit.AutoSize = true;
- this.lblRuleDurationUnit.Location = new System.Drawing.Point(520, 128);
- this.lblRuleDurationUnit.Name = "lblRuleDurationUnit";
- this.lblRuleDurationUnit.Size = new System.Drawing.Size(23, 15);
- this.lblRuleDurationUnit.TabIndex = 24;
- this.lblRuleDurationUnit.Text = "秒";
- //
- // 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, 260);
- 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, 270);
- this.txtLog.TabIndex = 3;
- //
- // m_updateTimer
- //
- this.m_updateTimer.Enabled = true;
- this.m_updateTimer.Interval = 500;
- //
- // SlaveTestForm
- //
- this.ClientSize = new System.Drawing.Size(782, 543);
- this.Controls.Add(this.grpDeviceInfo);
- this.Controls.Add(this.grpControl);
- this.Controls.Add(this.grpPdo1Send);
- 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.grpPdo1Send.ResumeLayout(false);
- this.grpPdo1Send.PerformLayout();
- 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;
- btnRuleSend.Enabled = true;
- btnContinuousSend.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
- {
- // 如果正在连续发送,先停止
- if (m_isContinuousSending)
- {
- StopContinuousSend();
- }
-
- // 如果正在规则发送,先停止
- if (m_isRuleSending)
- {
- StopRuleSend();
- }
-
- AppendLog("正在停止从站...");
- m_slaveDevice.Stop();
- AppendLog("✓ 从站已停止");
-
- btnStart.Enabled = true;
- btnStop.Enabled = false;
- btnSendTpdo1.Enabled = false;
- btnRuleSend.Enabled = false;
- btnContinuousSend.Enabled = false;
- btnContinuousSend.Text = "连续发送";
- btnRuleSend.Text = "规则发送";
-
- UpdateDeviceInfo();
- }
- catch (Exception ex)
- {
- AppendLog("✗ 停止错误: " + ex.Message);
- }
- }
-
- private void BtnSendTpdo1_Click(object sender, EventArgs e)
- {
- try
- {
- // 从界面读取PDO1数据
- byte[] pdoData = new byte[8];
- pdoData[0] = ParseByteValue(txtPdo1Data0.Text, 0);
- pdoData[1] = ParseByteValue(txtPdo1Data1.Text, 1);
- pdoData[2] = ParseByteValue(txtPdo1Data2.Text, 2);
- pdoData[3] = ParseByteValue(txtPdo1Data3.Text, 3);
- pdoData[4] = ParseByteValue(txtPdo1Data4.Text, 4);
- pdoData[5] = ParseByteValue(txtPdo1Data5.Text, 5);
- pdoData[6] = ParseByteValue(txtPdo1Data6.Text, 6);
- pdoData[7] = ParseByteValue(txtPdo1Data7.Text, 7);
-
- // 构建数据字符串用于日志
- string dataStr = BitConverter.ToString(pdoData).Replace("-", " ");
- AppendLog("→ 发送TPDO1: [" + dataStr + "]");
-
- // TODO: 这里需要修改CanOpenSlaveDevice以支持自定义数据发送
- // 暂时使用默认发送方法
- m_slaveDevice.SendTpdo(1, pdoData);
- }
- catch (Exception ex)
- {
- AppendLog("✗ 发送TPDO1失败: " + ex.Message);
- }
- }
-
- private void BtnContinuousSend_Click(object sender, EventArgs e)
- {
- if (m_isContinuousSending)
- {
- // 停止连续发送
- StopContinuousSend();
- }
- else
- {
- // 启动连续发送
- StartContinuousSend();
- }
- }
-
- /// <summary>
- /// 规则发送按钮点击事件
- /// </summary>
- private void BtnRuleSend_Click(object sender, EventArgs e)
- {
- if (m_isRuleSending)
- {
- // 停止规则发送
- StopRuleSend();
- }
- else
- {
- // 启动规则发送
- StartRuleSend();
- }
- }
-
- /// <summary>
- /// 启动连续发送
- /// </summary>
- private void StartContinuousSend()
- {
- try
- {
- // 解析周期时间(微秒)
- if (!double.TryParse(txtPeriodTime.Text.Trim(), out double periodUs) || periodUs <= 0)
- {
- AppendLog("✗ 周期时间无效,请输入大于0的数值(单位:微秒)");
- return;
- }
-
- // 重置计数器
- m_continuousSendCounter = 0;
-
- // 创建取消令牌
- m_continuousSendCts = new CancellationTokenSource();
- m_isContinuousSending = true;
-
- // 更新按钮文本
- btnContinuousSend.Text = "停止发送";
-
- AppendLog("▶ 开始连续发送 - 周期: " + periodUs.ToString("F0") + "us");
-
- // 启动异步发送任务
- Task.Run(() => ContinuousSendLoop(periodUs, m_continuousSendCts.Token));
- }
- catch (Exception ex)
- {
- AppendLog("✗ 启动连续发送失败: " + ex.Message);
- m_isContinuousSending = false;
- btnContinuousSend.Text = "连续发送";
- }
- }
-
- /// <summary>
- /// 停止连续发送
- /// </summary>
- private void StopContinuousSend()
- {
- try
- {
- m_isContinuousSending = false;
- m_continuousSendCts?.Cancel();
-
- // 等待任务结束
- Thread.Sleep(100);
-
- btnContinuousSend.Text = "连续发送";
- AppendLog("⏹ 连续发送已停止 - 共发送 " + m_continuousSendCounter.ToString() + " 次");
- }
- catch (Exception ex)
- {
- AppendLog("✗ 停止连续发送失败: " + ex.Message);
- }
- }
-
- /// <summary>
- /// 连续发送循环(高精度)
- /// </summary>
- private async Task ContinuousSendLoop(double periodUs, CancellationToken cancellationToken)
- {
- Stopwatch stopwatch = new Stopwatch();
- long sendCount = 0;
-
- // 计算每次循环的目标时间间隔(纳秒)
- long periodNs = (long)(periodUs * 1000.0);
-
- AppendLog("[调试] 目标周期: " + periodUs.ToString("F0") + "us = " + periodNs.ToString() + "ns");
-
- while (!cancellationToken.IsCancellationRequested)
- {
- try
- {
- // 记录开始时间
- stopwatch.Restart();
-
- // 构建PDO数据 - 第一个字节自增
- byte[] pdoData = new byte[8];
- pdoData[0] = (byte)(m_continuousSendCounter % 256); // 第一个字节自增
- pdoData[1] = ParseByteValue(txtPdo1Data1.Text, 1);
- pdoData[2] = ParseByteValue(txtPdo1Data2.Text, 2);
- pdoData[3] = ParseByteValue(txtPdo1Data3.Text, 3);
- pdoData[4] = ParseByteValue(txtPdo1Data4.Text, 4);
- pdoData[5] = ParseByteValue(txtPdo1Data5.Text, 5);
- pdoData[6] = ParseByteValue(txtPdo1Data6.Text, 6);
- pdoData[7] = ParseByteValue(txtPdo1Data7.Text, 7);
-
- // 发送PDO(注意:这里需要修改CanOpenSlaveDevice支持自定义数据)
- // 暂时使用默认方法,实际应该传入pdoData
- m_slaveDevice.SendTpdo(1, pdoData);
-
- sendCount++;
- m_continuousSendCounter++; // 计数器自增
-
- // 每100次输出一次日志,避免日志过多
- if (sendCount % 100 == 0)
- {
- AppendLog("→ 连续发送 #" + sendCount.ToString() + ", Byte0=" + m_continuousSendCounter.ToString());
- }
-
- // 计算已经消耗的时间
- long elapsedNs = stopwatch.ElapsedTicks * 1000000000L / Stopwatch.Frequency;
- long remainingNs = periodNs - elapsedNs;
-
- // 如果还有剩余时间,进行精确延迟
- if (remainingNs > 0)
- {
- // 对于较大的延迟,使用Task.Delay
- if (remainingNs > 100000) // 大于100微秒
- {
- int delayMs = (int)(remainingNs / 1000000);
- await Task.Delay(delayMs, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- // 对于较小的延迟,使用SpinWait
- SpinWait.SpinUntil(() => cancellationToken.IsCancellationRequested,
- TimeSpan.FromTicks(remainingNs * Stopwatch.Frequency / 1000000000L));
- }
- }
- }
- catch (OperationCanceledException)
- {
- // 正常取消
- break;
- }
- catch (Exception ex)
- {
- AppendLog("✗ 连续发送错误: " + ex.Message);
- break;
- }
- }
- }
-
- private byte ParseByteValue(string text, int index)
- {
- if (string.IsNullOrWhiteSpace(text))
- return 0;
-
- if (byte.TryParse(text.Trim(), out byte value))
- return value;
-
- AppendLog("⚠ Byte" + index.ToString() + " 值无效: '" + text + "',使用默认值0");
- return 0;
- }
-
- /// <summary>
- /// 根据规则发送TPDO1(第一字节自增)
- /// </summary>
- private void SendRuleBasedTpdo1()
- {
- // 检查是否达到运行时长限制
- if (m_ruleSendDurationMs > 0)
- {
- double elapsedMs = (DateTime.Now - m_ruleSendStartTime).TotalMilliseconds;
- if (elapsedMs >= m_ruleSendDurationMs)
- {
- StopRuleSend();
- return;
- }
- }
- try
- {
- // 构建PDO数据 - 第一个字节自增
- byte[] pdoData = new byte[8];
- pdoData[0] = (byte)(m_ruleSendCounter % 256); // 第一个字节自增
- pdoData[1] = ParseByteValue(txtPdo1Data1.Text, 1);
- pdoData[2] = ParseByteValue(txtPdo1Data2.Text, 2);
- pdoData[3] = ParseByteValue(txtPdo1Data3.Text, 3);
- pdoData[4] = ParseByteValue(txtPdo1Data4.Text, 4);
- pdoData[5] = ParseByteValue(txtPdo1Data5.Text, 5);
- pdoData[6] = ParseByteValue(txtPdo1Data6.Text, 6);
- pdoData[7] = ParseByteValue(txtPdo1Data7.Text, 7);
-
- // 发送PDO
- m_slaveDevice.SendTpdo(1, pdoData);
-
- // 计数器自增
- m_ruleSendCounter++;
-
- // 输出日志
- string dataStr = BitConverter.ToString(pdoData).Replace("-", " ");
- AppendLog("→ 规则发送 #" + m_ruleSendCounter.ToString() + ", Byte0=" + ((m_ruleSendCounter - 1) % 256).ToString() + ", Data: [" + dataStr + "]");
- }
- 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.ToString() + " [节点" + nodeId.ToString() + "]: " + dataStr);
-
- // 如果启用了规则发送,则发送TPDO1
- if (m_isRuleSending)
- {
- SendRuleBasedTpdo1();
- }
- }
-
- private void SlaveDevice_OnNmtStateChanged(NmtState oldState, NmtState newState)
- {
- if (this.InvokeRequired)
- {
- this.Invoke(new Action(() =>
- SlaveDevice_OnNmtStateChanged(oldState, newState)));
- return;
- }
-
- AppendLog("⟳ NMT状态改变: " + oldState.ToString() + " → " + newState.ToString());
- 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.ToString("X4") + ", 子索引" + subIndex.ToString());
- }
-
- 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.ToString("X4") + ", 子索引" + subIndex.ToString() + ", 值0x" + value.ToString("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.ToString();
- lblState.Text = "状态: " + m_slaveDevice.CurrentState.ToString();
- lblStatus.Text = "运行状态: " + (m_slaveDevice.IsRunning ? "运行中" : "已停止");
- }
-
- private void AppendLog(string message)
- {
- if (this.InvokeRequired)
- {
- this.Invoke(new Action<string>(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_isContinuousSending)
- {
- StopContinuousSend();
- }
-
- // 如果正在规则发送,先停止
- if (m_isRuleSending)
- {
- StopRuleSend();
- }
-
- if (m_slaveDevice != null)
- {
- m_slaveDevice.Stop();
- m_slaveDevice.Dispose();
- }
-
- m_continuousSendCts?.Dispose();
- m_updateTimer?.Stop();
- m_updateTimer?.Dispose();
-
- base.OnFormClosing(e);
- }
-
- /// <summary>
- /// 启动规则发送
- /// </summary>
- private void StartRuleSend()
- {
- try
- {
- // 解析运行时长(秒转毫秒),如果输入为空或无效,默认为0(无限制)
- int durationSeconds = 0;
- if (int.TryParse(txtRuleDuration.Text.Trim(), out int parsedSeconds))
- {
- durationSeconds = Math.Max(0, parsedSeconds); // 确保非负数
- }
- m_ruleSendDurationMs = durationSeconds * 1000; // 转换为毫秒
- // 重置计数器
- m_ruleSendCounter = 0;
- m_ruleSendStartTime = DateTime.Now;
- m_isRuleSending = true;
- m_ruleSendCts = new CancellationTokenSource();
- // 更新按钮文本
- btnRuleSend.Text = "停止规则发送";
- string durationText = durationSeconds > 0 ? durationSeconds.ToString() + "秒" : "无限制";
- AppendLog("▶ 开始规则发送 - 时长: " + durationText);
- // 如果设置了运行时长,则启动定时器来检查时间
- if (m_ruleSendDurationMs > 0)
- {
- Task.Delay(m_ruleSendDurationMs, m_ruleSendCts.Token)
- .ContinueWith(t =>
- {
- if (!t.IsCanceled)
- {
- // 时间到了,自动停止规则发送
- if (this.InvokeRequired)
- {
- this.Invoke(new Action(StopRuleSend));
- }
- else
- {
- StopRuleSend();
- }
- }
- });
- }
- }
- catch (Exception ex)
- {
- AppendLog("✗ 启动规则发送失败: " + ex.Message);
- m_isRuleSending = false;
- btnRuleSend.Text = "规则发送";
- }
- }
-
- /// <summary>
- /// 停止规则发送
- /// </summary>
- private void StopRuleSend()
- {
- try
- {
- m_isRuleSending = false;
- m_ruleSendCts?.Cancel();
- btnRuleSend.Text = "规则发送";
- AppendLog("⏹ 规则发送已停止 - 共发送 " + m_ruleSendCounter.ToString() + " 次");
- }
- catch (Exception ex)
- {
- AppendLog("✗ 停止规则发送失败: " + ex.Message);
- }
- }
- }
- }
|