diff --git a/BOB.sln b/BOB.sln
index f5d88c8..0ebc5f9 100644
--- a/BOB.sln
+++ b/BOB.sln
@@ -5,8 +5,6 @@ VisualStudioVersion = 17.14.36221.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BOB", "BOB\BOB.csproj", "{FC10E4D4-0AA3-487B-B023-F8D2949E45ED}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{6D9764D9-B4DA-43E2-A9D7-40A6C871A6B3}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logger", "Logger\Logger.csproj", "{9150C6A9-AE8D-42C9-8B2D-9DD04A3E7E74}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ORM", "ORM\ORM.csproj", "{4DE5DC6C-7121-4EB9-B8A8-90C694F451E2}"
@@ -17,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Command", "Command\Command.csproj", "{49D249DE-CB09-4390-89DC-6165965C3933}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceCommand", "DeviceCommand\DeviceCommand.csproj", "{94177FB3-45E4-466E-BB9F-761295736D35}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,10 +27,6 @@ Global
{FC10E4D4-0AA3-487B-B023-F8D2949E45ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC10E4D4-0AA3-487B-B023-F8D2949E45ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC10E4D4-0AA3-487B-B023-F8D2949E45ED}.Release|Any CPU.Build.0 = Release|Any CPU
- {6D9764D9-B4DA-43E2-A9D7-40A6C871A6B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6D9764D9-B4DA-43E2-A9D7-40A6C871A6B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6D9764D9-B4DA-43E2-A9D7-40A6C871A6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6D9764D9-B4DA-43E2-A9D7-40A6C871A6B3}.Release|Any CPU.Build.0 = Release|Any CPU
{9150C6A9-AE8D-42C9-8B2D-9DD04A3E7E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9150C6A9-AE8D-42C9-8B2D-9DD04A3E7E74}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9150C6A9-AE8D-42C9-8B2D-9DD04A3E7E74}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -51,6 +47,10 @@ Global
{49D249DE-CB09-4390-89DC-6165965C3933}.Debug|Any CPU.Build.0 = Debug|Any CPU
{49D249DE-CB09-4390-89DC-6165965C3933}.Release|Any CPU.ActiveCfg = Release|Any CPU
{49D249DE-CB09-4390-89DC-6165965C3933}.Release|Any CPU.Build.0 = Release|Any CPU
+ {94177FB3-45E4-466E-BB9F-761295736D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {94177FB3-45E4-466E-BB9F-761295736D35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {94177FB3-45E4-466E-BB9F-761295736D35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {94177FB3-45E4-466E-BB9F-761295736D35}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/BOB/BOB.csproj b/BOB/BOB.csproj
index 8b9be29..898faab 100644
--- a/BOB/BOB.csproj
+++ b/BOB/BOB.csproj
@@ -45,8 +45,8 @@
+
-
diff --git a/BOB/Models/DeviceConfigModel.cs b/BOB/Models/DeviceConfigModel.cs
new file mode 100644
index 0000000..7319518
--- /dev/null
+++ b/BOB/Models/DeviceConfigModel.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.IO.Ports;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BOB.Models
+{
+ public class DeviceConfigModel
+ {
+ public Guid Id { get; set; }
+ public string DeviceName { get; set; }
+ public string DeviceType { get; set; }
+ public string Remark { get; set; }
+ public ICommunicationConfig CommunicationConfig { get; set; }
+
+ public bool IsEnabled { get; set; }
+ }
+ public class TcpConfig : ICommunicationConfig
+ {
+ public string IPAddress { get; set; }
+ public int Port { get; set; }
+ public int ReadTimeout { get; set; }
+ public int WriteTimeout { get; set; }
+ }
+ public class SerialPortConfig : ICommunicationConfig
+ {
+ public string COMPort { get; set; }
+ public int BaudRate { get; set; }
+ public int DataBit { get; set; } = 8;
+ public StopBits StopBit { get; set; } = StopBits.One;
+ public Parity ParityBit { get; set; } = Parity.None;
+ public int ReadTimeout { get; set; }
+ public int WriteTimeout { get; set; }
+ }
+ public interface ICommunicationConfig
+ {
+ int ReadTimeout { get; set; }
+ int WriteTimeout { get; set; }
+ }
+
+}
diff --git a/BOB/SystemConfig.cs b/BOB/SystemConfig.cs
index a49f8b2..7e1f5c0 100644
--- a/BOB/SystemConfig.cs
+++ b/BOB/SystemConfig.cs
@@ -1,4 +1,5 @@
-using Logger;
+using BOB.Models;
+using Logger;
using Newtonsoft.Json;
using System;
using System.IO;
@@ -29,7 +30,7 @@ namespace BOB
}
[JsonIgnore]
- public string SystemPath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BOB系统");
+ public string SystemPath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BOB");
public int PerformanceLevel { get; set; } = 50;
@@ -38,38 +39,9 @@ namespace BOB
public string SubProgramFilePath { get; set; } = @"D:\BOB\子程序\";
public string DefaultSubProgramFilePath { get; set; } = "";
+ public List DeviceList { get; set; } = new();
- // 配置加载方法
- public void LoadFromFile()
- {
- string configPath = Path.Combine(SystemPath, "system.config");
-
- if (!File.Exists(configPath))
- {
- string json = JsonConvert.SerializeObject(Instance, Formatting.Indented);
- File.WriteAllText(configPath, json);
- return;
- }
- try
- {
- string json = File.ReadAllText(configPath);
- var loadedConfig = JsonConvert.DeserializeObject(json);
-
- // 复制所有可写属性(排除JsonIgnore属性)
- PropertyInfo[] properties = typeof(SystemConfig).GetProperties();
- foreach (var prop in properties)
- {
- if (prop.CanWrite && !Attribute.IsDefined(prop, typeof(JsonIgnoreAttribute)))
- {
- prop.SetValue(this, prop.GetValue(loadedConfig));
- }
- }
- }
- catch (Exception ex)
- {
- LoggerHelper.ErrorWithNotify($"配置加载失败: {ex.Message}",ex.StackTrace);
- }
- }
+ #region 配置加载方法
public void SaveToFile()
{
lock (_lock)
@@ -79,8 +51,14 @@ namespace BOB
if (!Directory.Exists(SystemPath))
Directory.CreateDirectory(SystemPath);
- string configPath = Path.Combine(SystemPath, "system.config");
- string json = JsonConvert.SerializeObject(this, Formatting.Indented);
+ string configPath = Path.Combine(SystemPath, "system.json");
+
+ // 支持接口多态序列化
+ string json = JsonConvert.SerializeObject(this, Formatting.Indented,
+ new JsonSerializerSettings
+ {
+ TypeNameHandling = TypeNameHandling.All
+ });
File.WriteAllText(configPath, json);
@@ -92,5 +70,45 @@ namespace BOB
}
}
}
+
+ public void LoadFromFile()
+ {
+ string configPath = Path.Combine(SystemPath, "system.json");
+
+ if (!File.Exists(configPath))
+ {
+ // 文件不存在则保存当前配置
+ SaveToFile();
+ return;
+ }
+
+ try
+ {
+ string json = File.ReadAllText(configPath);
+
+ // 支持接口多态反序列化
+ var loadedConfig = JsonConvert.DeserializeObject(json,
+ new JsonSerializerSettings
+ {
+ TypeNameHandling = TypeNameHandling.All
+ });
+
+ // 复制所有可写属性(排除 JsonIgnore 属性)
+ PropertyInfo[] properties = typeof(SystemConfig).GetProperties();
+ foreach (var prop in properties)
+ {
+ if (prop.CanWrite && !Attribute.IsDefined(prop, typeof(JsonIgnoreAttribute)))
+ {
+ prop.SetValue(this, prop.GetValue(loadedConfig));
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LoggerHelper.ErrorWithNotify($"配置加载失败: {ex.Message}", ex.StackTrace);
+ }
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/Command/Command.csproj b/Command/Command.csproj
index a88feaf..18b694a 100644
--- a/Command/Command.csproj
+++ b/Command/Command.csproj
@@ -7,6 +7,10 @@
enable
+
+
+
+
diff --git a/DeviceCommand/Base/ModbusTcp.cs b/DeviceCommand/Base/ModbusTcp.cs
new file mode 100644
index 0000000..852c381
--- /dev/null
+++ b/DeviceCommand/Base/ModbusTcp.cs
@@ -0,0 +1,146 @@
+using NModbus;
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Base
+{
+ public class ModbusTcp
+ {
+ public string IPAddress { get; set; } = "127.0.0.1";
+ public int Port { get; set; } = 502;
+ public int SendTimeout { get; set; } = 3000;
+ public int ReceiveTimeout { get; set; } = 3000;
+ public TcpClient TcpClient { get; set; } = new();
+ public IModbusMaster Modbus { get; set; }
+
+ public ModbusTcp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
+ {
+ IPAddress = ipAddress;
+ Port = port;
+ SendTimeout = sendTimeout;
+ ReceiveTimeout = receiveTimeout;
+ return this;
+ }
+
+ public static void ChangeDeviceConfig(ModbusTcp modbusTcp, string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
+ {
+ modbusTcp.IPAddress = ipAddress;
+ modbusTcp.Port = port;
+ if (sendTimeout > 0) modbusTcp.SendTimeout = sendTimeout;
+ if (receiveTimeout > 0) modbusTcp.ReceiveTimeout = receiveTimeout;
+ }
+
+ public static async Task ConnectAsync(ModbusTcp modbusTcp, CancellationToken ct = default)
+ {
+ if (!modbusTcp.TcpClient.Connected)
+ {
+ modbusTcp.TcpClient.Close();
+ modbusTcp.TcpClient.Dispose();
+ modbusTcp.TcpClient = new TcpClient();
+ await modbusTcp.TcpClient.ConnectAsync(modbusTcp.IPAddress, modbusTcp.Port, ct);
+ modbusTcp.Modbus = new ModbusFactory().CreateMaster(modbusTcp.TcpClient);
+ }
+ else
+ {
+ var remoteEndPoint = (IPEndPoint)modbusTcp.TcpClient.Client.RemoteEndPoint!;
+ var ip = remoteEndPoint.Address.MapToIPv4().ToString();
+ bool isSameAddress = ip.Equals(modbusTcp.IPAddress);
+ bool isSamePort = remoteEndPoint.Port == modbusTcp.Port;
+ if (!isSameAddress || !isSamePort)
+ {
+ modbusTcp.TcpClient.Close();
+ modbusTcp.TcpClient.Dispose();
+ modbusTcp.TcpClient = new TcpClient();
+ await modbusTcp.TcpClient.ConnectAsync(modbusTcp.IPAddress, modbusTcp.Port, ct);
+ modbusTcp.Modbus = new ModbusFactory().CreateMaster(modbusTcp.TcpClient);
+ }
+ }
+ return true;
+ }
+
+ public static void ModbusTcpInitialize(ModbusTcp modbusTcp)
+ {
+ if (!modbusTcp.TcpClient.Connected)
+ {
+ modbusTcp.TcpClient = new TcpClient();
+ modbusTcp.TcpClient.SendTimeout = modbusTcp.SendTimeout;
+ modbusTcp.TcpClient.ReceiveTimeout = modbusTcp.ReceiveTimeout;
+ }
+ }
+
+ public static void Close(ModbusTcp modbusTcp)
+ {
+ if (modbusTcp.TcpClient.Connected)
+ {
+ modbusTcp.TcpClient.Close();
+ }
+ }
+
+ public static async Task ReadHoldingRegistersAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
+ {
+ var readTask = modbusTcp.Modbus.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(ct);
+ var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
+ var completedTask = await Task.WhenAny(readTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP读取保持寄存器超时");
+ return await readTask;
+ }
+
+ public static async Task WriteSingleRegisterAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort registerAddress, ushort value, CancellationToken ct = default)
+ {
+ var sendTask = modbusTcp.Modbus.WriteSingleRegisterAsync(slaveAddress, registerAddress, value).WaitAsync(ct);
+ var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
+ var completedTask = await Task.WhenAny(sendTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写单寄存器超时");
+ }
+
+ public static async Task WriteMultipleRegistersAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort[] values, CancellationToken ct = default)
+ {
+ var sendTask = modbusTcp.Modbus.WriteMultipleRegistersAsync(slaveAddress, startAddress, values).WaitAsync(ct);
+ var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
+ var completedTask = await Task.WhenAny(sendTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写多寄存器超时");
+ }
+
+ public static async Task ReadCoilAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
+ {
+ var readTask = modbusTcp.Modbus.ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(ct);
+ var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
+ var completedTask = await Task.WhenAny(readTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP读取线圈超时");
+ return await readTask;
+ }
+
+ public static async Task WriteSingleCoilAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort coilAddress, bool value, CancellationToken ct = default)
+ {
+ var sendTask = modbusTcp.Modbus.WriteSingleCoilAsync(slaveAddress, coilAddress, value).WaitAsync(ct);
+ var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
+ var completedTask = await Task.WhenAny(sendTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写单线圈超时");
+ }
+
+ public static async Task WriteMultipleCoilsAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, bool[] values, CancellationToken ct = default)
+ {
+ var sendTask = modbusTcp.Modbus.WriteMultipleCoilsAsync(slaveAddress, startAddress, values).WaitAsync(ct);
+ var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
+ var completedTask = await Task.WhenAny(sendTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP写多线圈超时");
+ }
+
+ public static void ModbusTcpStopNow(ModbusTcp modbusTcp)
+ {
+ if (modbusTcp.TcpClient.Connected) modbusTcp.TcpClient.Close();
+ }
+
+ public static async Task ReadInputRegisterAsync(ModbusTcp modbusTcp, byte slaveAddress, ushort startAddress, ushort numberOfPoints, CancellationToken ct = default)
+ {
+ var readTask = modbusTcp.Modbus.ReadInputRegistersAsync(slaveAddress, startAddress, numberOfPoints).WaitAsync(ct);
+ var timeoutTask = Task.Delay(modbusTcp.ReceiveTimeout, ct);
+ var completedTask = await Task.WhenAny(readTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"ModbusTCP读取输入寄存器超时");
+ return await readTask;
+ }
+ }
+}
diff --git a/DeviceCommand/Base/Serial_Port.cs b/DeviceCommand/Base/Serial_Port.cs
new file mode 100644
index 0000000..eb085bd
--- /dev/null
+++ b/DeviceCommand/Base/Serial_Port.cs
@@ -0,0 +1,160 @@
+using System.Text;
+using System.IO.Ports;
+
+namespace DeviceCommand.Base
+{
+ public class Serial_Port
+ {
+ public string PortName { get; set; } = "COM1";
+ public int BaudRate { get; set; } = 9600;
+ public int DataBits { get; set; } = 8;
+ public StopBits StopBits { get; set; } = StopBits.One;
+ public Parity Parity { get; set; } = Parity.None;
+ public int ReadTimeout { get; set; } = 3000;
+ public int WriteTimeout { get; set; } = 3000;
+ public SerialPort _SerialPort { get; set; } = new SerialPort();
+
+ public Serial_Port CreateDevice(string portName, int baudRate, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, int readTimeout = 3000, int writeTimeout = 3000)
+ {
+ PortName = portName;
+ BaudRate = baudRate;
+ DataBits = dataBits;
+ StopBits = stopBits;
+ Parity = parity;
+ ReadTimeout = readTimeout;
+ WriteTimeout = writeTimeout;
+ return this;
+ }
+
+ public static void ChangeDeviceConfig(Serial_Port serialPort, string PortName, int BaudRate, int dataBits = 8, StopBits stopBits = StopBits.One, Parity parity = Parity.None, int ReadTimeout = 3000, int WriteTimeout = 3000)
+ {
+ serialPort.PortName = PortName;
+ serialPort.BaudRate = BaudRate;
+ serialPort.DataBits = dataBits;
+ serialPort.StopBits = stopBits;
+ serialPort.Parity = parity;
+ if (ReadTimeout > 0) serialPort.ReadTimeout = ReadTimeout;
+ if (WriteTimeout > 0) serialPort.WriteTimeout = WriteTimeout;
+ }
+
+ public static async Task ConnectAsync(Serial_Port serialPort, CancellationToken ct = default)
+ {
+ if (serialPort._SerialPort.PortName != serialPort.PortName
+ || serialPort._SerialPort.BaudRate != serialPort.BaudRate
+ || serialPort._SerialPort.Parity != serialPort.Parity
+ || serialPort._SerialPort.DataBits != serialPort.DataBits
+ || serialPort._SerialPort.StopBits != serialPort.StopBits
+ || serialPort._SerialPort.ReadTimeout != serialPort.ReadTimeout
+ || serialPort._SerialPort.WriteTimeout != serialPort.WriteTimeout)
+ {
+ serialPort._SerialPort.Close();
+ serialPort._SerialPort.PortName = serialPort.PortName;
+ serialPort._SerialPort.BaudRate = serialPort.BaudRate;
+ serialPort._SerialPort.Parity = serialPort.Parity;
+ serialPort._SerialPort.DataBits = serialPort.DataBits;
+ serialPort._SerialPort.StopBits = serialPort.StopBits;
+ serialPort._SerialPort.ReadTimeout = serialPort.ReadTimeout;
+ serialPort._SerialPort.WriteTimeout = serialPort.WriteTimeout;
+ serialPort._SerialPort.Open();
+ }
+ else if (!serialPort._SerialPort.IsOpen)
+ {
+ serialPort._SerialPort.Open();
+ }
+ return true;
+ }
+
+ public static void Close(Serial_Port serialPort)
+ {
+ if (serialPort._SerialPort.IsOpen) serialPort._SerialPort.Close();
+ }
+
+ public static async Task SendAsync(Serial_Port serialPort, byte[] bytes, CancellationToken ct = default)
+ {
+ if (!serialPort._SerialPort.IsOpen) return;
+ var timeoutMs = serialPort.WriteTimeout;
+ if (timeoutMs <= 0)
+ {
+ serialPort._SerialPort.Write(bytes, 0, bytes.Length);
+ return;
+ }
+ var sendTask = Task.Run(() => serialPort._SerialPort.Write(bytes, 0, bytes.Length), ct);
+ var timeoutTask = Task.Delay(timeoutMs, ct);
+ var completedTask = await Task.WhenAny(sendTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"串口通讯异常:写入操作在 {timeoutMs} ms内未完成");
+ await sendTask;
+ }
+
+ public static async Task SendAsync(Serial_Port serialPort, string str, CancellationToken ct = default)
+ {
+ if (!serialPort._SerialPort.IsOpen) return;
+ byte[] bytes = Encoding.UTF8.GetBytes(str);
+ await SendAsync(serialPort, bytes, ct);
+ }
+
+ public static async Task ReadAsync(Serial_Port serialPort, byte[] buffer, CancellationToken ct = default)
+ {
+ if (!serialPort._SerialPort.IsOpen) return null;
+ var timeoutMs = serialPort.ReadTimeout;
+ var readTask = ReadByte(serialPort, buffer, ct);
+ if (timeoutMs <= 0) return await readTask;
+ var timeoutTask = Task.Delay(timeoutMs, ct);
+ var completedTask = await Task.WhenAny(readTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"串口通讯异常:读取操作在 {timeoutMs} ms内未完成");
+ return await readTask;
+ }
+
+ public static async Task ReadByte(Serial_Port serialPort, byte[] buffer, CancellationToken ct)
+ {
+ int bytesRead = 0;
+ while (bytesRead < buffer.Length)
+ {
+ if (serialPort._SerialPort.BytesToRead > 0)
+ {
+ bytesRead += serialPort._SerialPort.Read(buffer, bytesRead, buffer.Length - bytesRead);
+ }
+ }
+ return buffer;
+ }
+
+ public static async Task ReadAsync(Serial_Port serialPort, string delimiter = "\n", CancellationToken ct = default)
+ {
+ if (!serialPort._SerialPort.IsOpen) return null;
+ var timeoutMs = serialPort.ReadTimeout;
+ var readTask = ReadDefaultString(serialPort, delimiter, ct);
+ if (timeoutMs <= 0) return await readTask;
+ var timeoutTask = Task.Delay(timeoutMs, ct);
+ var completedTask = await Task.WhenAny(readTask, timeoutTask);
+ if (completedTask == timeoutTask) throw new TimeoutException($"串口通讯异常:读取操作在 {timeoutMs} ms内未完成");
+ return await readTask;
+ }
+
+ private static async Task ReadDefaultString(Serial_Port serialPort, string delimiter, CancellationToken ct)
+ {
+ delimiter ??= "\n";
+ MemoryStream memoryStream = new();
+ byte[] buffer = new byte[2048];
+ string data = string.Empty;
+ await Task.Run(() =>
+ {
+ while (true)
+ {
+ if (ct.IsCancellationRequested) return;
+ if (serialPort._SerialPort.BytesToRead > 0)
+ {
+ int bytesRead = serialPort._SerialPort.Read(buffer, 0, buffer.Length);
+ memoryStream.Write(buffer, 0, bytesRead);
+ data = Encoding.UTF8.GetString(memoryStream.ToArray());
+ int lineEndIndex = data.IndexOf(delimiter);
+ if (lineEndIndex >= 0)
+ {
+ data = data.Substring(0, lineEndIndex).Trim();
+ return;
+ }
+ }
+ }
+ }, ct);
+ return data;
+ }
+ }
+}
diff --git a/DeviceCommand/Base/TCP.cs b/DeviceCommand/Base/TCP.cs
new file mode 100644
index 0000000..3abd9bb
--- /dev/null
+++ b/DeviceCommand/Base/TCP.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Base
+{
+ public class Tcp
+ {
+ public string IPAddress { get; set; } = "127.0.0.1";
+ public int Port { get; set; } = 502;
+ public int SendTimeout { get; set; } = 3000;
+ public int ReceiveTimeout { get; set; } = 3000;
+ public TcpClient TcpClient { get; set; } = new();
+
+ public Tcp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
+ {
+ IPAddress = ipAddress;
+ Port = port;
+ SendTimeout = sendTimeout;
+ ReceiveTimeout = receiveTimeout;
+ return this;
+ }
+
+ public static void ChangeDeviceConfig(Tcp tcp, string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
+ {
+ tcp.IPAddress = ipAddress;
+ tcp.Port = port;
+ if (sendTimeout > 0) tcp.SendTimeout = sendTimeout;
+ if (receiveTimeout > 0) tcp.ReceiveTimeout = receiveTimeout;
+ }
+
+ public static async Task ConnectAsync(Tcp tcp, CancellationToken ct = default)
+ {
+ if (!tcp.TcpClient.Connected)
+ {
+ tcp.TcpClient.Close();
+ tcp.TcpClient.Dispose();
+ tcp.TcpClient = new TcpClient();
+ await tcp.TcpClient.ConnectAsync(tcp.IPAddress, tcp.Port, ct);
+ }
+ else
+ {
+ var remoteEndPoint = (IPEndPoint)tcp.TcpClient.Client.RemoteEndPoint!;
+ var ip = remoteEndPoint.Address.MapToIPv4().ToString();
+ bool isSameAddress = ip.Equals(tcp.IPAddress);
+ bool isSamePort = remoteEndPoint.Port == tcp.Port;
+
+ if (!isSameAddress || !isSamePort)
+ {
+ tcp.TcpClient.Close();
+ tcp.TcpClient.Dispose();
+ tcp.TcpClient = new TcpClient();
+ await tcp.TcpClient.ConnectAsync(tcp.IPAddress, tcp.Port, ct);
+ }
+ }
+ return true;
+ }
+
+ public static void Close(Tcp tcp)
+ {
+ tcp.TcpClient.Close();
+ }
+
+ public static async Task SendAsync(Tcp tcp, byte[] bytes, CancellationToken ct = default)
+ {
+ var timeoutMs = tcp.SendTimeout;
+ if (timeoutMs <= 0)
+ {
+ await tcp.TcpClient.Client.SendAsync(bytes, ct);
+ return;
+ }
+
+ var sendTask = tcp.TcpClient.Client.SendAsync(bytes, ct).AsTask();
+ var timeoutTask = Task.Delay(timeoutMs, ct);
+
+ var completedTask = await Task.WhenAny(sendTask, timeoutTask);
+ if (completedTask == timeoutTask)
+ throw new TimeoutException($"TCP通讯异常:写入操作在 {timeoutMs} ms内未完成");
+
+ await sendTask;
+ }
+
+ public static async Task SendAsync(Tcp tcp, string str, CancellationToken ct = default)
+ {
+ await SendAsync(tcp, Encoding.UTF8.GetBytes(str), ct);
+ }
+
+ public static async Task ReadAsync(Tcp tcp, byte[] buffer, CancellationToken ct = default)
+ {
+ if (!tcp.TcpClient.Connected) return null;
+
+ var timeoutMs = tcp.ReceiveTimeout;
+ if (timeoutMs <= 0)
+ return await ReadBytes(tcp, buffer, ct);
+
+ var readTask = ReadBytes(tcp, buffer, ct);
+ var timeoutTask = Task.Delay(timeoutMs, ct);
+
+ var completedTask = await Task.WhenAny(readTask, timeoutTask);
+ if (completedTask == timeoutTask)
+ throw new TimeoutException($"TCP通讯异常:读取操作在 {timeoutMs} ms内未完成");
+
+ return await readTask;
+ }
+
+ private static async Task ReadBytes(Tcp tcp, byte[] buffer, CancellationToken ct)
+ {
+ NetworkStream stream = tcp.TcpClient.GetStream();
+ int bytesRead = 0;
+ while (bytesRead < buffer.Length)
+ {
+ int read = await stream.ReadAsync(buffer, bytesRead, buffer.Length - bytesRead, ct);
+ if (read == 0) return null;
+ bytesRead += read;
+ }
+ return buffer;
+ }
+
+ public static async Task ReadAsync(Tcp tcp, string delimiter = "\n", CancellationToken ct = default)
+ {
+ delimiter ??= "\n";
+ var timeoutMs = tcp.ReceiveTimeout;
+ if (timeoutMs <= 0)
+ return await ReadString(tcp, delimiter, ct);
+
+ var readTask = ReadString(tcp, delimiter, ct);
+ var timeoutTask = Task.Delay(timeoutMs, ct);
+
+ var completedTask = await Task.WhenAny(readTask, timeoutTask);
+ if (completedTask == timeoutTask)
+ throw new TimeoutException($"TCP通讯异常:读取操作在 {timeoutMs} ms内未完成");
+
+ return await readTask;
+ }
+
+ private static async Task ReadString(Tcp tcp, string delimiter, CancellationToken ct)
+ {
+ NetworkStream stream = tcp.TcpClient.GetStream();
+ MemoryStream memoryStream = new();
+ byte[] buffer = new byte[2048];
+
+ int bytesRead;
+ while ((bytesRead = await stream.ReadAsync(buffer, ct)) > 0)
+ {
+ memoryStream.Write(buffer, 0, bytesRead);
+ string data = Encoding.UTF8.GetString(memoryStream.ToArray());
+ int lineEndIndex = data.IndexOf(delimiter);
+ if (lineEndIndex >= 0)
+ return data[..lineEndIndex].Trim();
+ }
+ return null;
+ }
+
+ public async Task WriteRead(Tcp tcp, string str, string endstr, CancellationToken ct = default)
+ {
+ await SendAsync(tcp, str, ct);
+ return await ReadAsync(tcp, endstr, ct);
+ }
+
+ public async Task ConnectAsync(CancellationToken ct = default)
+ {
+ return await ConnectAsync(this, ct);
+ }
+ }
+}
diff --git a/DeviceCommand/Device/E36233A.cs b/DeviceCommand/Device/E36233A.cs
new file mode 100644
index 0000000..eab3c2d
--- /dev/null
+++ b/DeviceCommand/Device/E36233A.cs
@@ -0,0 +1,13 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class E36233A:Tcp
+ {
+ }
+}
diff --git a/DeviceCommand/Device/EAEL9080.cs b/DeviceCommand/Device/EAEL9080.cs
new file mode 100644
index 0000000..984a0e9
--- /dev/null
+++ b/DeviceCommand/Device/EAEL9080.cs
@@ -0,0 +1,13 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class EAEL9080:ModbusTcp
+ {
+ }
+}
diff --git a/DeviceCommand/Device/IT6724C.cs b/DeviceCommand/Device/IT6724C.cs
new file mode 100644
index 0000000..48e8632
--- /dev/null
+++ b/DeviceCommand/Device/IT6724C.cs
@@ -0,0 +1,14 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.IO.Ports;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class IT6724C: Serial_Port
+ {
+ }
+}
diff --git a/DeviceCommand/Device/LQ7500-D.cs b/DeviceCommand/Device/LQ7500-D.cs
new file mode 100644
index 0000000..415fe31
--- /dev/null
+++ b/DeviceCommand/Device/LQ7500-D.cs
@@ -0,0 +1,13 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class LQ7500_D: Tcp
+ {
+ }
+}
diff --git a/DeviceCommand/Device/PSB11000.cs b/DeviceCommand/Device/PSB11000.cs
new file mode 100644
index 0000000..7b000b6
--- /dev/null
+++ b/DeviceCommand/Device/PSB11000.cs
@@ -0,0 +1,13 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class PSB11000: ModbusTcp
+ {
+ }
+}
diff --git a/DeviceCommand/Device/SQ0030G1D.cs b/DeviceCommand/Device/SQ0030G1D.cs
new file mode 100644
index 0000000..ddbe3bc
--- /dev/null
+++ b/DeviceCommand/Device/SQ0030G1D.cs
@@ -0,0 +1,13 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class SQ0030G1D: Tcp
+ {
+ }
+}
diff --git a/DeviceCommand/Device/WS-68030-380T.cs b/DeviceCommand/Device/WS-68030-380T.cs
new file mode 100644
index 0000000..dc1aecd
--- /dev/null
+++ b/DeviceCommand/Device/WS-68030-380T.cs
@@ -0,0 +1,13 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class WS_68030_380T:ModbusTcp
+ {
+ }
+}
diff --git a/DeviceCommand/Device/ZXKS.cs b/DeviceCommand/Device/ZXKS.cs
new file mode 100644
index 0000000..09e3753
--- /dev/null
+++ b/DeviceCommand/Device/ZXKS.cs
@@ -0,0 +1,13 @@
+using DeviceCommand.Base;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeviceCommand.Device
+{
+ public class ZXKS:ModbusTcp
+ {
+ }
+}
diff --git a/DeviceCommand/DeviceCommand.csproj b/DeviceCommand/DeviceCommand.csproj
new file mode 100644
index 0000000..b9d7cb2
--- /dev/null
+++ b/DeviceCommand/DeviceCommand.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
diff --git a/ORM/ORM.csproj b/ORM/ORM.csproj
index 72f7a86..bb6e9b3 100644
--- a/ORM/ORM.csproj
+++ b/ORM/ORM.csproj
@@ -12,7 +12,6 @@
-
diff --git a/Service/Service.csproj b/Service/Service.csproj
index 7745202..e092d0c 100644
--- a/Service/Service.csproj
+++ b/Service/Service.csproj
@@ -12,7 +12,6 @@
-