端口数据读取与转发程序
This commit is contained in:
commit
47c339f1b3
62
.gitignore
vendored
Normal file
62
.gitignore
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,dotnetcore
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode,dotnetcore
|
||||
|
||||
### DotnetCore ###
|
||||
# .NET Core build folders
|
||||
bin/
|
||||
obj/
|
||||
|
||||
# Common node modules locations
|
||||
/node_modules
|
||||
/wwwroot/node_modules
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
### Windows ###
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,dotnetcore
|
||||
|
||||
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||
|
354
Form1.Designer.cs
generated
Normal file
354
Form1.Designer.cs
generated
Normal file
@ -0,0 +1,354 @@
|
||||
namespace sscom_sender;
|
||||
|
||||
partial class Form1
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.cmbPort1 = new System.Windows.Forms.ComboBox();
|
||||
this.cmbBaud1 = new System.Windows.Forms.ComboBox();
|
||||
this.btnConnect1 = new System.Windows.Forms.Button();
|
||||
this.lblPort1 = new System.Windows.Forms.Label();
|
||||
this.lblBaud1 = new System.Windows.Forms.Label();
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.cmbPort2 = new System.Windows.Forms.ComboBox();
|
||||
this.cmbBaud2 = new System.Windows.Forms.ComboBox();
|
||||
this.btnConnect2 = new System.Windows.Forms.Button();
|
||||
this.lblPort2 = new System.Windows.Forms.Label();
|
||||
this.lblBaud2 = new System.Windows.Forms.Label();
|
||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||
this.txtUrl = new System.Windows.Forms.TextBox();
|
||||
this.lblUrl = new System.Windows.Forms.Label();
|
||||
this.btnStartUpload = new System.Windows.Forms.Button();
|
||||
this.btnStopUpload = new System.Windows.Forms.Button();
|
||||
this.groupBox4 = new System.Windows.Forms.GroupBox();
|
||||
this.txtLog = new System.Windows.Forms.TextBox();
|
||||
this.btnClearLog = new System.Windows.Forms.Button();
|
||||
this.btnSaveLog = new System.Windows.Forms.Button();
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.groupBox3.SuspendLayout();
|
||||
this.groupBox4.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.lblBaud1);
|
||||
this.groupBox1.Controls.Add(this.lblPort1);
|
||||
this.groupBox1.Controls.Add(this.btnConnect1);
|
||||
this.groupBox1.Controls.Add(this.cmbBaud1);
|
||||
this.groupBox1.Controls.Add(this.cmbPort1);
|
||||
this.groupBox1.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(200, 120);
|
||||
this.groupBox1.TabIndex = 0;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "串口1";
|
||||
//
|
||||
// cmbPort1
|
||||
//
|
||||
this.cmbPort1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbPort1.FormattingEnabled = true;
|
||||
this.cmbPort1.Location = new System.Drawing.Point(60, 25);
|
||||
this.cmbPort1.Name = "cmbPort1";
|
||||
this.cmbPort1.Size = new System.Drawing.Size(121, 23);
|
||||
this.cmbPort1.TabIndex = 0;
|
||||
//
|
||||
// cmbBaud1
|
||||
//
|
||||
this.cmbBaud1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbBaud1.FormattingEnabled = true;
|
||||
this.cmbBaud1.Items.AddRange(new object[] {
|
||||
"9600",
|
||||
"19200",
|
||||
"38400",
|
||||
"57600",
|
||||
"115200"});
|
||||
this.cmbBaud1.Location = new System.Drawing.Point(60, 54);
|
||||
this.cmbBaud1.Name = "cmbBaud1";
|
||||
this.cmbBaud1.Size = new System.Drawing.Size(121, 23);
|
||||
this.cmbBaud1.TabIndex = 1;
|
||||
//
|
||||
// btnConnect1
|
||||
//
|
||||
this.btnConnect1.Location = new System.Drawing.Point(60, 83);
|
||||
this.btnConnect1.Name = "btnConnect1";
|
||||
this.btnConnect1.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnConnect1.TabIndex = 2;
|
||||
this.btnConnect1.Text = "连接";
|
||||
this.btnConnect1.UseVisualStyleBackColor = true;
|
||||
this.btnConnect1.Click += new System.EventHandler(this.btnConnect1_Click);
|
||||
//
|
||||
// lblPort1
|
||||
//
|
||||
this.lblPort1.AutoSize = true;
|
||||
this.lblPort1.Location = new System.Drawing.Point(15, 28);
|
||||
this.lblPort1.Name = "lblPort1";
|
||||
this.lblPort1.Size = new System.Drawing.Size(32, 15);
|
||||
this.lblPort1.TabIndex = 3;
|
||||
this.lblPort1.Text = "端口";
|
||||
//
|
||||
// lblBaud1
|
||||
//
|
||||
this.lblBaud1.AutoSize = true;
|
||||
this.lblBaud1.Location = new System.Drawing.Point(15, 57);
|
||||
this.lblBaud1.Name = "lblBaud1";
|
||||
this.lblBaud1.Size = new System.Drawing.Size(44, 15);
|
||||
this.lblBaud1.TabIndex = 4;
|
||||
this.lblBaud1.Text = "波特率";
|
||||
//
|
||||
// groupBox2
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.lblBaud2);
|
||||
this.groupBox2.Controls.Add(this.lblPort2);
|
||||
this.groupBox2.Controls.Add(this.btnConnect2);
|
||||
this.groupBox2.Controls.Add(this.cmbBaud2);
|
||||
this.groupBox2.Controls.Add(this.cmbPort2);
|
||||
this.groupBox2.Location = new System.Drawing.Point(230, 12);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(200, 120);
|
||||
this.groupBox2.TabIndex = 1;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "串口2";
|
||||
//
|
||||
// cmbPort2
|
||||
//
|
||||
this.cmbPort2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbPort2.FormattingEnabled = true;
|
||||
this.cmbPort2.Location = new System.Drawing.Point(60, 25);
|
||||
this.cmbPort2.Name = "cmbPort2";
|
||||
this.cmbPort2.Size = new System.Drawing.Size(121, 23);
|
||||
this.cmbPort2.TabIndex = 0;
|
||||
//
|
||||
// cmbBaud2
|
||||
//
|
||||
this.cmbBaud2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbBaud2.FormattingEnabled = true;
|
||||
this.cmbBaud2.Items.AddRange(new object[] {
|
||||
"9600",
|
||||
"19200",
|
||||
"38400",
|
||||
"57600",
|
||||
"115200"});
|
||||
this.cmbBaud2.Location = new System.Drawing.Point(60, 54);
|
||||
this.cmbBaud2.Name = "cmbBaud2";
|
||||
this.cmbBaud2.Size = new System.Drawing.Size(121, 23);
|
||||
this.cmbBaud2.TabIndex = 1;
|
||||
//
|
||||
// btnConnect2
|
||||
//
|
||||
this.btnConnect2.Location = new System.Drawing.Point(60, 83);
|
||||
this.btnConnect2.Name = "btnConnect2";
|
||||
this.btnConnect2.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnConnect2.TabIndex = 2;
|
||||
this.btnConnect2.Text = "连接";
|
||||
this.btnConnect2.UseVisualStyleBackColor = true;
|
||||
this.btnConnect2.Click += new System.EventHandler(this.btnConnect2_Click);
|
||||
//
|
||||
// lblPort2
|
||||
//
|
||||
this.lblPort2.AutoSize = true;
|
||||
this.lblPort2.Location = new System.Drawing.Point(15, 28);
|
||||
this.lblPort2.Name = "lblPort2";
|
||||
this.lblPort2.Size = new System.Drawing.Size(32, 15);
|
||||
this.lblPort2.TabIndex = 3;
|
||||
this.lblPort2.Text = "端口";
|
||||
//
|
||||
// lblBaud2
|
||||
//
|
||||
this.lblBaud2.AutoSize = true;
|
||||
this.lblBaud2.Location = new System.Drawing.Point(15, 57);
|
||||
this.lblBaud2.Name = "lblBaud2";
|
||||
this.lblBaud2.Size = new System.Drawing.Size(44, 15);
|
||||
this.lblBaud2.TabIndex = 4;
|
||||
this.lblBaud2.Text = "波特率";
|
||||
//
|
||||
// groupBox3
|
||||
//
|
||||
this.groupBox3.Controls.Add(this.btnStopUpload);
|
||||
this.groupBox3.Controls.Add(this.btnStartUpload);
|
||||
this.groupBox3.Controls.Add(this.lblUrl);
|
||||
this.groupBox3.Controls.Add(this.txtUrl);
|
||||
this.groupBox3.Location = new System.Drawing.Point(450, 12);
|
||||
this.groupBox3.Name = "groupBox3";
|
||||
this.groupBox3.Size = new System.Drawing.Size(320, 120);
|
||||
this.groupBox3.TabIndex = 2;
|
||||
this.groupBox3.TabStop = false;
|
||||
this.groupBox3.Text = "数据上传";
|
||||
//
|
||||
// txtUrl
|
||||
//
|
||||
this.txtUrl.Location = new System.Drawing.Point(15, 40);
|
||||
this.txtUrl.Name = "txtUrl";
|
||||
this.txtUrl.Size = new System.Drawing.Size(290, 23);
|
||||
this.txtUrl.TabIndex = 0;
|
||||
this.txtUrl.Text = "http://localhost:8080/api/data";
|
||||
//
|
||||
// lblUrl
|
||||
//
|
||||
this.lblUrl.AutoSize = true;
|
||||
this.lblUrl.Location = new System.Drawing.Point(15, 22);
|
||||
this.lblUrl.Name = "lblUrl";
|
||||
this.lblUrl.Size = new System.Drawing.Size(56, 15);
|
||||
this.lblUrl.TabIndex = 1;
|
||||
this.lblUrl.Text = "上传地址";
|
||||
//
|
||||
// btnStartUpload
|
||||
//
|
||||
this.btnStartUpload.Location = new System.Drawing.Point(15, 80);
|
||||
this.btnStartUpload.Name = "btnStartUpload";
|
||||
this.btnStartUpload.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnStartUpload.TabIndex = 2;
|
||||
this.btnStartUpload.Text = "开始上传";
|
||||
this.btnStartUpload.UseVisualStyleBackColor = true;
|
||||
this.btnStartUpload.Click += new System.EventHandler(this.btnStartUpload_Click);
|
||||
//
|
||||
// btnStopUpload
|
||||
//
|
||||
this.btnStopUpload.Location = new System.Drawing.Point(110, 80);
|
||||
this.btnStopUpload.Name = "btnStopUpload";
|
||||
this.btnStopUpload.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnStopUpload.TabIndex = 3;
|
||||
this.btnStopUpload.Text = "停止上传";
|
||||
this.btnStopUpload.UseVisualStyleBackColor = true;
|
||||
this.btnStopUpload.Click += new System.EventHandler(this.btnStopUpload_Click);
|
||||
//
|
||||
// groupBox4
|
||||
//
|
||||
this.groupBox4.Controls.Add(this.btnSaveLog);
|
||||
this.groupBox4.Controls.Add(this.btnClearLog);
|
||||
this.groupBox4.Controls.Add(this.txtLog);
|
||||
this.groupBox4.Location = new System.Drawing.Point(12, 150);
|
||||
this.groupBox4.Name = "groupBox4";
|
||||
this.groupBox4.Size = new System.Drawing.Size(758, 270);
|
||||
this.groupBox4.TabIndex = 3;
|
||||
this.groupBox4.TabStop = false;
|
||||
this.groupBox4.Text = "数据日志";
|
||||
//
|
||||
// txtLog
|
||||
//
|
||||
this.txtLog.Location = new System.Drawing.Point(15, 22);
|
||||
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(728, 210);
|
||||
this.txtLog.TabIndex = 0;
|
||||
//
|
||||
// btnClearLog
|
||||
//
|
||||
this.btnClearLog.Location = new System.Drawing.Point(15, 238);
|
||||
this.btnClearLog.Name = "btnClearLog";
|
||||
this.btnClearLog.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnClearLog.TabIndex = 1;
|
||||
this.btnClearLog.Text = "清空日志";
|
||||
this.btnClearLog.UseVisualStyleBackColor = true;
|
||||
this.btnClearLog.Click += new System.EventHandler(this.btnClearLog_Click);
|
||||
//
|
||||
// btnSaveLog
|
||||
//
|
||||
this.btnSaveLog.Location = new System.Drawing.Point(110, 238);
|
||||
this.btnSaveLog.Name = "btnSaveLog";
|
||||
this.btnSaveLog.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnSaveLog.TabIndex = 2;
|
||||
this.btnSaveLog.Text = "保存日志";
|
||||
this.btnSaveLog.UseVisualStyleBackColor = true;
|
||||
this.btnSaveLog.Click += new System.EventHandler(this.btnSaveLog_Click);
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.toolStripStatusLabel1});
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 428);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Size = new System.Drawing.Size(784, 22);
|
||||
this.statusStrip1.TabIndex = 4;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// toolStripStatusLabel1
|
||||
//
|
||||
this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
|
||||
this.toolStripStatusLabel1.Size = new System.Drawing.Size(32, 17);
|
||||
this.toolStripStatusLabel1.Text = "就绪";
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(784, 450);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Controls.Add(this.groupBox4);
|
||||
this.Controls.Add(this.groupBox3);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Name = "Form1";
|
||||
this.Text = "串口数据采集与上传系统";
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
|
||||
this.Load += new System.EventHandler(this.Form1_Load);
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox1.PerformLayout();
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.groupBox3.ResumeLayout(false);
|
||||
this.groupBox3.PerformLayout();
|
||||
this.groupBox4.ResumeLayout(false);
|
||||
this.groupBox4.PerformLayout();
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.ComboBox cmbPort1;
|
||||
private System.Windows.Forms.ComboBox cmbBaud1;
|
||||
private System.Windows.Forms.Button btnConnect1;
|
||||
private System.Windows.Forms.Label lblPort1;
|
||||
private System.Windows.Forms.Label lblBaud1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.ComboBox cmbPort2;
|
||||
private System.Windows.Forms.ComboBox cmbBaud2;
|
||||
private System.Windows.Forms.Button btnConnect2;
|
||||
private System.Windows.Forms.Label lblPort2;
|
||||
private System.Windows.Forms.Label lblBaud2;
|
||||
private System.Windows.Forms.GroupBox groupBox3;
|
||||
private System.Windows.Forms.TextBox txtUrl;
|
||||
private System.Windows.Forms.Label lblUrl;
|
||||
private System.Windows.Forms.Button btnStartUpload;
|
||||
private System.Windows.Forms.Button btnStopUpload;
|
||||
private System.Windows.Forms.GroupBox groupBox4;
|
||||
private System.Windows.Forms.TextBox txtLog;
|
||||
private System.Windows.Forms.Button btnClearLog;
|
||||
private System.Windows.Forms.Button btnSaveLog;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
|
||||
}
|
461
Form1.cs
Normal file
461
Form1.cs
Normal file
@ -0,0 +1,461 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO.Ports;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace sscom_sender
|
||||
{
|
||||
public partial class Form1 : Form
|
||||
{
|
||||
// 串口对象
|
||||
private SerialPort? serialPort1;
|
||||
private SerialPort? serialPort2;
|
||||
|
||||
// 数据缓冲区
|
||||
private StringBuilder buffer1 = new StringBuilder();
|
||||
private StringBuilder buffer2 = new StringBuilder();
|
||||
|
||||
// 数据队列
|
||||
private ConcurrentQueue<DataPacket> dataQueue = new ConcurrentQueue<DataPacket>();
|
||||
|
||||
// 线程控制
|
||||
private CancellationTokenSource? uploadCancellationTokenSource;
|
||||
private CancellationTokenSource? logCancellationTokenSource;
|
||||
private Task? uploadTask;
|
||||
private Task? logTask;
|
||||
|
||||
// HTTP客户端
|
||||
private readonly HttpClient httpClient = new HttpClient();
|
||||
|
||||
// 日志文件路径
|
||||
private readonly string logFilePath = Path.Combine(Application.StartupPath, "data_log.txt");
|
||||
|
||||
// 线程安全的日志队列
|
||||
private ConcurrentQueue<string> logQueue = new ConcurrentQueue<string>();
|
||||
|
||||
public Form1()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Form1_Load(object sender, EventArgs e)
|
||||
{
|
||||
// 初始化串口列表
|
||||
RefreshPortList();
|
||||
|
||||
// 设置默认波特率
|
||||
cmbBaud1.SelectedIndex = 4; // 115200
|
||||
cmbBaud2.SelectedIndex = 4; // 115200
|
||||
|
||||
// 启动日志线程
|
||||
StartLogThread();
|
||||
|
||||
UpdateStatus("系统已启动");
|
||||
}
|
||||
|
||||
private void RefreshPortList()
|
||||
{
|
||||
string[] ports = SerialPort.GetPortNames();
|
||||
|
||||
cmbPort1.Items.Clear();
|
||||
cmbPort2.Items.Clear();
|
||||
|
||||
foreach (string port in ports)
|
||||
{
|
||||
cmbPort1.Items.Add(port);
|
||||
cmbPort2.Items.Add(port);
|
||||
}
|
||||
|
||||
if (ports.Length > 0)
|
||||
{
|
||||
cmbPort1.SelectedIndex = 0;
|
||||
if (ports.Length > 1)
|
||||
cmbPort2.SelectedIndex = 1;
|
||||
else
|
||||
cmbPort2.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnConnect1_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (serialPort1?.IsOpen == true)
|
||||
{
|
||||
// 断开连接
|
||||
serialPort1.Close();
|
||||
btnConnect1.Text = "连接";
|
||||
UpdateStatus("串口1已断开");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 建立连接
|
||||
try
|
||||
{
|
||||
serialPort1 = new SerialPort(
|
||||
cmbPort1.Text,
|
||||
int.Parse(cmbBaud1.Text),
|
||||
Parity.None,
|
||||
8,
|
||||
StopBits.One);
|
||||
|
||||
serialPort1.DataReceived += SerialPort1_DataReceived;
|
||||
serialPort1.Open();
|
||||
|
||||
btnConnect1.Text = "断开";
|
||||
UpdateStatus($"串口1已连接: {cmbPort1.Text}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"串口1连接失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnConnect2_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (serialPort2?.IsOpen == true)
|
||||
{
|
||||
// 断开连接
|
||||
serialPort2.Close();
|
||||
btnConnect2.Text = "连接";
|
||||
UpdateStatus("串口2已断开");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 建立连接
|
||||
try
|
||||
{
|
||||
serialPort2 = new SerialPort(
|
||||
cmbPort2.Text,
|
||||
int.Parse(cmbBaud2.Text),
|
||||
Parity.None,
|
||||
8,
|
||||
StopBits.One);
|
||||
|
||||
serialPort2.DataReceived += SerialPort2_DataReceived;
|
||||
serialPort2.Open();
|
||||
|
||||
btnConnect2.Text = "断开";
|
||||
UpdateStatus($"串口2已连接: {cmbPort2.Text}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"串口2连接失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SerialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
if (serialPort1?.IsOpen == true)
|
||||
{
|
||||
string data = serialPort1.ReadExisting();
|
||||
ProcessSerialData(data, 1, buffer1);
|
||||
}
|
||||
}
|
||||
|
||||
private void SerialPort2_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||
{
|
||||
if (serialPort2?.IsOpen == true)
|
||||
{
|
||||
string data = serialPort2.ReadExisting();
|
||||
ProcessSerialData(data, 2, buffer2);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessSerialData(string data, int portNumber, StringBuilder buffer)
|
||||
{
|
||||
// 将数据添加到缓冲区
|
||||
buffer.Append(data);
|
||||
|
||||
// 查找完整的数据包(以换行符结束)
|
||||
string bufferContent = buffer.ToString();
|
||||
string[] lines = bufferContent.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (lines.Length > 0)
|
||||
{
|
||||
// 处理完整的行
|
||||
for (int i = 0; i < lines.Length - 1; i++)
|
||||
{
|
||||
ProcessCompleteDataLine(lines[i], portNumber);
|
||||
}
|
||||
|
||||
// 检查最后一行是否完整
|
||||
if (bufferContent.EndsWith("\r") || bufferContent.EndsWith("\n"))
|
||||
{
|
||||
ProcessCompleteDataLine(lines[lines.Length - 1], portNumber);
|
||||
buffer.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 保留不完整的最后一行
|
||||
buffer.Clear();
|
||||
buffer.Append(lines[lines.Length - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessCompleteDataLine(string line, int portNumber)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line)) return;
|
||||
|
||||
var dataPacket = new DataPacket
|
||||
{
|
||||
PortNumber = portNumber,
|
||||
RawData = line,
|
||||
Timestamp = DateTime.Now
|
||||
};
|
||||
|
||||
// 如果是串口1且数据格式匹配BESTPOS,提取经纬度
|
||||
if (portNumber == 1 && line.Contains("BESTPOSA"))
|
||||
{
|
||||
var coordinates = ExtractCoordinates(line);
|
||||
if (coordinates != null)
|
||||
{
|
||||
dataPacket.Latitude = coordinates.Value.Latitude;
|
||||
dataPacket.Longitude = coordinates.Value.Longitude;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到队列
|
||||
dataQueue.Enqueue(dataPacket);
|
||||
|
||||
// 添加到日志显示
|
||||
string logMessage = $"[{dataPacket.Timestamp:yyyy-MM-dd HH:mm:ss}] 串口{portNumber}: {line}";
|
||||
if (dataPacket.Latitude.HasValue && dataPacket.Longitude.HasValue)
|
||||
{
|
||||
logMessage += $" [经度: {dataPacket.Longitude:F8}, 纬度: {dataPacket.Latitude:F8}]";
|
||||
}
|
||||
|
||||
AddLogMessage(logMessage);
|
||||
}
|
||||
|
||||
private (double Latitude, double Longitude)? ExtractCoordinates(string data)
|
||||
{
|
||||
try
|
||||
{
|
||||
// BESTPOS数据格式解析
|
||||
// #BESTPOSA,COM1,14394,98.0,UNKNOWN,1,1699.000,1700908,2,18;INSUFFICIENT_OBS,NONE,纬度,经度,高度,undulation,datum,lat_std,lon_std,hgt_std,stn_id,diff_age,sol_age,#obs,#L1,#L2,reserved,ext_sol_stat,galileo_beidou_sig_mask,gps_glonass_sig_mask*checksum
|
||||
string[] parts = data.Split(',');
|
||||
if (parts.Length >= 14)
|
||||
{
|
||||
if (double.TryParse(parts[11], out double latitude) &&
|
||||
double.TryParse(parts[12], out double longitude))
|
||||
{
|
||||
return (latitude, longitude);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
AddLogMessage($"坐标解析错误: {ex.Message}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void btnStartUpload_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(txtUrl.Text))
|
||||
{
|
||||
MessageBox.Show("请输入上传地址", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
uploadCancellationTokenSource = new CancellationTokenSource();
|
||||
uploadTask = Task.Run(() => UploadWorker(uploadCancellationTokenSource.Token));
|
||||
|
||||
btnStartUpload.Enabled = false;
|
||||
btnStopUpload.Enabled = true;
|
||||
UpdateStatus("数据上传已启动");
|
||||
}
|
||||
|
||||
private void btnStopUpload_Click(object sender, EventArgs e)
|
||||
{
|
||||
uploadCancellationTokenSource?.Cancel();
|
||||
btnStartUpload.Enabled = true;
|
||||
btnStopUpload.Enabled = false;
|
||||
UpdateStatus("数据上传已停止");
|
||||
}
|
||||
|
||||
private async Task UploadWorker(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (dataQueue.TryDequeue(out DataPacket? packet))
|
||||
{
|
||||
await UploadData(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(100, cancellationToken); // 等待100ms
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Invoke(() => AddLogMessage($"上传错误: {ex.Message}"));
|
||||
await Task.Delay(5000, cancellationToken); // 错误后等待5秒
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UploadData(DataPacket packet)
|
||||
{
|
||||
try
|
||||
{
|
||||
var jsonData = JsonSerializer.Serialize(packet);
|
||||
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await httpClient.PostAsync(txtUrl.Text, content);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
Invoke(() => AddLogMessage($"数据上传成功: 串口{packet.PortNumber}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Invoke(() => AddLogMessage($"数据上传失败: {response.StatusCode} - 串口{packet.PortNumber}"));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Invoke(() => AddLogMessage($"上传异常: {ex.Message}"));
|
||||
}
|
||||
}
|
||||
|
||||
private void StartLogThread()
|
||||
{
|
||||
logCancellationTokenSource = new CancellationTokenSource();
|
||||
logTask = Task.Run(() => LogWorker(logCancellationTokenSource.Token));
|
||||
}
|
||||
|
||||
private async Task LogWorker(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
var logsToWrite = new List<string>();
|
||||
|
||||
// 批量获取日志
|
||||
while (logQueue.TryDequeue(out string? logMessage))
|
||||
{
|
||||
logsToWrite.Add(logMessage);
|
||||
if (logsToWrite.Count >= 10) break; // 批量写入,最多10条
|
||||
}
|
||||
|
||||
if (logsToWrite.Count > 0)
|
||||
{
|
||||
await File.AppendAllLinesAsync(logFilePath, logsToWrite, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(1000, cancellationToken); // 等待1秒
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 日志写入错误,避免无限循环
|
||||
Console.WriteLine($"日志写入错误: {ex.Message}");
|
||||
await Task.Delay(5000, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddLogMessage(string message)
|
||||
{
|
||||
// 添加到界面显示
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(() => AddLogMessage(message));
|
||||
return;
|
||||
}
|
||||
|
||||
txtLog.AppendText(message + Environment.NewLine);
|
||||
txtLog.SelectionStart = txtLog.Text.Length;
|
||||
txtLog.ScrollToCaret();
|
||||
|
||||
// 添加到日志文件队列
|
||||
logQueue.Enqueue(message);
|
||||
|
||||
// 限制界面显示的行数
|
||||
if (txtLog.Lines.Length > 1000)
|
||||
{
|
||||
var lines = txtLog.Lines.Skip(500).ToArray();
|
||||
txtLog.Text = string.Join(Environment.NewLine, lines);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStatus(string message)
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(() => UpdateStatus(message));
|
||||
return;
|
||||
}
|
||||
|
||||
toolStripStatusLabel1.Text = message;
|
||||
AddLogMessage($"[系统] {message}");
|
||||
}
|
||||
|
||||
private void btnClearLog_Click(object sender, EventArgs e)
|
||||
{
|
||||
txtLog.Clear();
|
||||
}
|
||||
|
||||
private void btnSaveLog_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var saveDialog = new SaveFileDialog())
|
||||
{
|
||||
saveDialog.Filter = "文本文件|*.txt|所有文件|*.*";
|
||||
saveDialog.FileName = $"log_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
|
||||
|
||||
if (saveDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
File.WriteAllText(saveDialog.FileName, txtLog.Text);
|
||||
MessageBox.Show("日志保存成功", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"保存失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
// 停止所有线程
|
||||
uploadCancellationTokenSource?.Cancel();
|
||||
logCancellationTokenSource?.Cancel();
|
||||
|
||||
// 关闭串口
|
||||
serialPort1?.Close();
|
||||
serialPort2?.Close();
|
||||
|
||||
// 释放资源
|
||||
httpClient.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// 数据包类
|
||||
public class DataPacket
|
||||
{
|
||||
public int PortNumber { get; set; }
|
||||
public string RawData { get; set; } = string.Empty;
|
||||
public DateTime Timestamp { get; set; }
|
||||
public double? Latitude { get; set; }
|
||||
public double? Longitude { get; set; }
|
||||
}
|
||||
}
|
16
Program.cs
Normal file
16
Program.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace sscom_sender;
|
||||
|
||||
static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
// To customize application configuration such as set high DPI settings or default font,
|
||||
// see https://aka.ms/applicationconfiguration.
|
||||
ApplicationConfiguration.Initialize();
|
||||
Application.Run(new Form1());
|
||||
}
|
||||
}
|
16
sscom-sender.csproj
Normal file
16
sscom-sender.csproj
Normal file
@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<RootNamespace>sscom_sender</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
8
sscom-sender.csproj.user
Normal file
8
sscom-sender.csproj.user
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Compile Update="Form1.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
24
sscom-sender.sln
Normal file
24
sscom-sender.sln
Normal file
@ -0,0 +1,24 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.2.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sscom-sender", "sscom-sender.csproj", "{F03C6C53-8989-99E6-D747-EC03449AD20F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F03C6C53-8989-99E6-D747-EC03449AD20F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F03C6C53-8989-99E6-D747-EC03449AD20F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F03C6C53-8989-99E6-D747-EC03449AD20F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F03C6C53-8989-99E6-D747-EC03449AD20F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {707867E8-3EF5-4E83-A851-9053BE677857}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Loading…
x
Reference in New Issue
Block a user