diff --git a/SerialPort/SerialPort.csproj b/SerialPort/SerialPort.csproj
index 58d1f34..6f37cfc 100644
--- a/SerialPort/SerialPort.csproj
+++ b/SerialPort/SerialPort.csproj
@@ -13,8 +13,4 @@
-
-
-
-
diff --git a/Soul2-Library.sln b/Soul2-Library.sln
index c84dec2..917368b 100644
--- a/Soul2-Library.sln
+++ b/Soul2-Library.sln
@@ -3,9 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33530.505
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "General", "General\General.csproj", "{8B24AB73-0D6F-426D-92D3-25CBE6ED718E}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerialPort", "SerialPort\SerialPort.csproj", "{B2EFA26A-A2CF-4090-85FD-31085D7A1A65}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools", "Tools\Tools.csproj", "{093CFFEE-8B28-40B0-9752-6614616383C4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -13,14 +11,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {8B24AB73-0D6F-426D-92D3-25CBE6ED718E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8B24AB73-0D6F-426D-92D3-25CBE6ED718E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8B24AB73-0D6F-426D-92D3-25CBE6ED718E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8B24AB73-0D6F-426D-92D3-25CBE6ED718E}.Release|Any CPU.Build.0 = Release|Any CPU
- {B2EFA26A-A2CF-4090-85FD-31085D7A1A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B2EFA26A-A2CF-4090-85FD-31085D7A1A65}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B2EFA26A-A2CF-4090-85FD-31085D7A1A65}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B2EFA26A-A2CF-4090-85FD-31085D7A1A65}.Release|Any CPU.Build.0 = Release|Any CPU
+ {093CFFEE-8B28-40B0-9752-6614616383C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {093CFFEE-8B28-40B0-9752-6614616383C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {093CFFEE-8B28-40B0-9752-6614616383C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {093CFFEE-8B28-40B0-9752-6614616383C4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Tools/Tools.csproj b/Tools/Tools.csproj
new file mode 100644
index 0000000..ddf4612
--- /dev/null
+++ b/Tools/Tools.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net7.0
+ enable
+ enable
+ Soul2.$(MSBuildProjectName.Replace(" ", "_"))
+ Soul2.$(MSBuildProjectName)
+
+
+
+
+
+
+
diff --git a/Tools/general/CollectionsUtils.cs b/Tools/general/CollectionsUtils.cs
new file mode 100644
index 0000000..4b76065
--- /dev/null
+++ b/Tools/general/CollectionsUtils.cs
@@ -0,0 +1,48 @@
+using System.Collections;
+
+namespace Soul2.Tools.General {
+ public static class CollectionsUtils {
+ ///
+ /// 判断非空
+ ///
+ /// 集合对象
+ /// 是否非空
+ public static bool isNotEmpty(this IEnumerable collection) {
+ return !isEmpty(collection);
+ }
+
+ ///
+ /// 判断为空
+ ///
+ /// 集合对象
+ /// 是否为空
+ public static bool isEmpty(this IEnumerable collection) {
+ if (collection == null) {
+ return true;
+ }
+ foreach (var item in collection) {
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// 去重
+ ///
+ ///
+ ///
+ ///
+ public static List duplicateRemoval(this List list) {
+ if (list.isNotEmpty()) {
+ var set = new HashSet(list);
+ return new List(set);
+ } else {
+ return list;
+ }
+ }
+
+ public static HashSet toSet(this IEnumerable collection) {
+ return new HashSet(collection);
+ }
+ }
+}
diff --git a/Tools/general/StringUtils.cs b/Tools/general/StringUtils.cs
new file mode 100644
index 0000000..767b220
--- /dev/null
+++ b/Tools/general/StringUtils.cs
@@ -0,0 +1,129 @@
+namespace Soul2.Tools.General {
+ ///
+ /// 字符串工具类
+ /// By Soul2
+ ///
+ public static class StringUtils {
+ ///
+ /// 判断空值(null或"")
+ ///
+ ///
+ ///
+ public static bool isEmpty(this string str) {
+ return string.IsNullOrEmpty(str);
+ }
+ public static bool isNotEmpty(this string str) {
+ return !string.IsNullOrEmpty(str);
+ }
+
+
+ ///
+ /// 判断空值(null、""或只有空格)
+ ///
+ /// 被判断的字符串
+ ///
+ public static bool isNotBlank(this string str) { return !string.IsNullOrWhiteSpace(str); }
+
+ public static bool IsBlank(this string str) { return string.IsNullOrWhiteSpace(str); }
+
+ ///
+ /// 任何一个为空
+ ///
+ ///
+ ///
+ public static bool isAnyBlank(params string[] strs) {
+ foreach (var str in strs) {
+ if (string.IsNullOrWhiteSpace(str)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// 任何一个为空
+ /// 空格属于非空
+ ///
+ ///
+ ///
+ public static bool isAnyEmpty(params string[] strs) {
+ foreach (var str in strs) {
+ if (string.IsNullOrEmpty(str)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// 任何一个不为空
+ ///
+ ///
+ ///
+ public static bool isNoneBlank(params string[] strs) {
+ foreach (var str in strs) {
+ if (string.IsNullOrWhiteSpace(str)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// 任何一个不为空
+ /// 空格属于非空
+ ///
+ ///
+ ///
+ public static bool isNoneEmpty(params string[] strs) {
+ foreach (var str in strs) {
+ if (string.IsNullOrEmpty(str)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ///
+ /// 如果不以val结尾,则添加到结尾
+ ///
+ ///
+ ///
+ public static void appendIfMissing(this string original, string str) {
+ if (!original.EndsWith(str)) {
+ original += str;
+ }
+ }
+
+ ///
+ /// 如果不以val开头,则添加到开头
+ ///
+ ///
+ ///
+ public static void prependIfMissing(this string original, string str) {
+ if (!original.StartsWith(str)) {
+ original = str + original;
+ }
+ }
+
+ ///
+ /// 翻转
+ /// 例:"123"->"321"
+ ///
+ ///
+ ///
+ public static string flip(this string original) {
+ char[] chars = original.ToCharArray();
+ Array.Reverse(chars);
+ return new string(chars);
+ }
+
+ public static string subStrWith(this string original, int begin, int end) {
+ if (begin < 0 || end > original.Length || begin > end) {
+ throw new ArgumentException("Invalid input parameters");
+ }
+ return original.Substring(begin, end - begin);
+ }
+
+ }
+}
diff --git a/Tools/general/TimerUtils.cs b/Tools/general/TimerUtils.cs
new file mode 100644
index 0000000..7e971f2
--- /dev/null
+++ b/Tools/general/TimerUtils.cs
@@ -0,0 +1,152 @@
+using System.Timers;
+using Timer = System.Timers.Timer;
+
+namespace Soul2.Tools.General {
+ ///
+ /// 扩展System.Timers.Timer
+ /// By Soul2
+ ///
+ public static class TimerUtils {
+ private const int default_loop_times = 512;
+
+ ///
+ /// 一次性计时器
+ /// 运行结束后自动销毁
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Timer startOnce(this Timer timer, double time, Action callback) {
+ void onElapsed(object source, ElapsedEventArgs e) {
+ callback(timer);
+ timer.destroy();
+ }
+ return run(timer, (int)(time * 1000), false, onElapsed);
+ }
+ public static Timer startOnce(this Timer timer, double time, Action callback) {
+ return timer.startOnce(time, (t) => callback?.Invoke());
+ }
+
+ ///
+ /// 循环计时器
+ /// 可以指定运行次数
+ /// 运行结束后自动销毁
+ ///
+ /// 计时器
+ /// 时长
+ /// 次数
+ ///
+ ///
+ public static Timer startLoop(this Timer timer, double time, int times, Action callback) {
+ int run_times = 0;
+ void onElapsed(object source, ElapsedEventArgs e) {
+ run_times += 1;
+ if (run_times <= times) {
+ callback(timer, run_times);
+ } else {
+ timer.destroy();
+ }
+ }
+ return run(timer, (int)(time * 1000), true, onElapsed);
+ }
+
+ public static Timer startLoop(this Timer timer, double time, int times, Action callback) {
+ return timer.startLoop(time, times, (t, i) => callback?.Invoke(t));
+ }
+
+ public static Timer startLoop(this Timer timer, double time, int times, Action callback) {
+ return timer.startLoop(time, times, (t, i) => callback?.Invoke(i));
+ }
+
+ public static Timer startLoop(this Timer timer, double time, int times, Action callback) {
+ return timer.startLoop(time, times, (t, i) => callback?.Invoke());
+ }
+
+ ///
+ /// 循环计时器
+ /// 默认运行次数512
+ ///
+ /// 计时器
+ /// 时长
+ /// 次数
+ ///
+ ///
+ public static Timer startKeep(this Timer timer, double time, Action callback, int times = default_loop_times) {
+ int run_times = 0;
+ void onElapsed(object source, ElapsedEventArgs e) {
+ run_times += 1;
+ if (run_times <= times) {
+ callback(timer, run_times);
+ } else {
+ timer.destroy();
+ }
+ }
+ return run(timer, (int)(time * 1000), true, onElapsed);
+ }
+ public static Timer startKeep(this Timer timer, double time, Action callback, int times = default_loop_times) {
+ return timer.startKeep(time, (t, i) => callback?.Invoke(i));
+ }
+ public static Timer startKeep(this Timer timer, double time, Action callback, int times = default_loop_times) {
+ return timer.startKeep(time, (t, i) => callback?.Invoke(t));
+ }
+ public static Timer startKeep(this Timer timer, double time, Action callback, int times = default_loop_times) {
+ return timer.startKeep(time, (t, i) => callback?.Invoke());
+ }
+
+ public static void destroy(this Timer timer) {
+ if (timer.Enabled) {
+ timer.Stop();
+ }
+ timer.Dispose();
+ }
+
+ // -----------------------------------------
+
+ private static Timer run(Timer timer, int interval, bool loop, ElapsedEventHandler elapsed) {
+ timer.Elapsed += elapsed;
+ timer.Interval = interval;
+ timer.AutoReset = loop;
+ timer.Start();
+ return timer;
+ }
+
+ public static Timer startOnce(double time, Action callback) {
+ return new Timer().startOnce(time, callback);
+ }
+ public static Timer startOnce(double time, Action callback) {
+ return new Timer().startOnce(time, callback);
+ }
+
+ // -----------------------------------------
+
+ public static Timer startLoop(double time, int times, Action callback) {
+ return new Timer().startLoop(time, times, callback);
+ }
+ public static Timer startLoop(double time, int times, Action callback) {
+ return new Timer().startLoop(time, times, callback);
+ }
+ public static Timer startLoop(double time, int times, Action callback) {
+ return new Timer().startLoop(time, times, callback);
+ }
+ public static Timer startLoop(double time, int times, Action callback) {
+ return new Timer().startLoop(time, times, callback);
+ }
+
+ // -----------------------------------------
+
+ public static Timer startKeep(double time, Action callback, int times = default_loop_times) {
+ return new Timer().startKeep(time, callback, times);
+ }
+ public static Timer startKeep(double time, Action callback, int times = default_loop_times) {
+ return new Timer().startKeep(time, callback, times);
+ }
+ public static Timer startKeep(double time, Action callback, int times = default_loop_times) {
+ return new Timer().startKeep(time, callback, times);
+ }
+ public static Timer startKeep(double time, Action callback, int times = default_loop_times) {
+ return new Timer().startKeep(time, callback, times);
+ }
+
+ }
+}
diff --git a/Tools/serialport/GodSerialPortUtils.cs b/Tools/serialport/GodSerialPortUtils.cs
new file mode 100644
index 0000000..694088c
--- /dev/null
+++ b/Tools/serialport/GodSerialPortUtils.cs
@@ -0,0 +1,168 @@
+using System.Diagnostics;
+using GodSharp.SerialPort.Extensions;
+using GodSharp.SerialPort;
+using System.IO.Ports;
+using System.Text.RegularExpressions;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Soul2.Tools.SerialPort {
+ ///
+ /// 串口通信工具类
+ ///
+ public static class GodSerialPortUtils {
+
+ private static GodSerialPort? gsp = null;
+ public static bool debug = false;
+ public static bool be_sending = false;
+ private static byte[]? back_data;
+
+ public class Messages {
+ ///
+ /// 645协议读取通信地址报文
+ ///
+ public const string _645CommunicationAddress = "FE FE FE FE 68 AA AA AA AA AA AA 68 13 00 DF 16";
+ }
+
+ ///
+ /// 打印log
+ ///
+ ///
+ private static void log(string log) {
+ if (debug) {
+ Debug.WriteLine("[GodSerialPortUtils] " + log);
+ }
+ }
+
+ ///
+ /// 查询所有可用串口
+ ///
+ /// 串口名称数组
+ public static string[] find() => System.IO.Ports.SerialPort.GetPortNames();
+
+ ///
+ /// 当前连接状态
+ ///
+ ///
+ public static bool status() => (gsp != null && gsp.IsOpen != false);
+
+ ///
+ /// 发送报文信息
+ ///
+ /// 发送的内容
+ /// 回调函数,参数为byte[]类型的回信
+ /// 是否等待回信完成再执行回调函数,默认为否
+ ///
+ public static void send(string data, Action callback = null, bool wait_complete = false) => send(data.HexToByte(), callback, wait_complete);
+
+ ///
+ /// 发送报文信息
+ ///
+ /// 发送的内容
+ /// 回调函数,参数为byte[]类型的回信
+ /// 是否等待回信完成再执行回调函数,默认为否
+ ///
+ public static void send(byte[] data, Action callback = null, bool wait_complete = false) {
+ if (status() && !be_sending && gsp != null) {
+ // 发送报文并启用 DataReceived 事件
+ void onBack(GodSerialPort _gsp, byte[] bytes) {
+ string buffer = string.Join("", bytes.Select(b => b.ToString("X2")));
+ log("收到数据:" + buffer);
+ be_sending = false;
+ if (back_data != null) {
+ back_data = back_data.Concat(bytes).ToArray();
+ } else {
+ back_data = bytes;
+ }
+ if (!wait_complete || (back_data != null && back_data.Length > 0 && back_data[^1] == 0x16)) {
+ callback?.Invoke(back_data);
+ }
+ }
+ be_sending = true;
+ gsp.Write(data);
+ log($"发送数据:{data.ToHexString()}");
+ gsp.UseDataReceived(true, onBack);
+ } else if (!status() || gsp == null) {
+ // 连接未建立或者串口对象不存在,则抛出异常
+ throw new Exception("先连接再发送报文");
+ } else if (be_sending) {
+ // 上一个报文还未收到回信,则抛出异常
+ throw new Exception("上一个报文还未收到回信!");
+ }
+ // 清空 back_data 数组,避免数据混乱
+ back_data = null;
+ }
+
+ ///
+ /// 打开串口通信
+ ///
+ /// 串口名称
+ /// 波特率
+ /// 校验码
+ /// 数据位
+ /// 停止位
+ /// 握手协议
+ ///
+ public static bool open(string name, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.None, Handshake handshake = Handshake.None) {
+ if (gsp == null) {
+ gsp = new GodSerialPort(name, baudRate, parity, dataBits, stopBits, handshake);
+ }
+ return gsp.Open() & status();
+ }
+
+ ///
+ /// 关闭连接
+ ///
+ /// 是否已关闭
+ public static bool close() {
+ be_sending = false;
+ if (gsp == null) {
+ return true;
+ }
+ var r = gsp.Close();
+ gsp = null;
+ return r;
+ }
+
+ ///
+ /// 16进制加法计算
+ /// 2位,按空格分割,加负数来算减法
+ ///
+ /// 16进制文本
+ /// 增加的值
+ /// 计算后的文本
+ public static string AddValueToHexString(string hexStr, int m) {
+ // 检查输入字符串是否符合要求
+ if (!Regex.IsMatch(hexStr, @"^[\da-fA-F]{2}( [\da-fA-F]{2})*$")) {
+ return "==";
+ }
+ var hexBytes = hexStr.HexToByte();
+ for (int i = 0; i < hexBytes.Length; i++) {
+ hexBytes[i] = (byte)((int)hexBytes[i] + m);
+ }
+
+ return hexBytes.ToHexString();
+ }
+
+ ///
+ /// 计算校验码
+ ///
+ /// 当前报文,不应包含校验码的部分
+ ///
+ public static string CalcChecksum(string msg) {
+ if (msg.StartsWith("FE FE FE FE ")) {
+ msg = msg.Replace("FE FE FE FE ", "");
+ }
+
+ // 检查输入字符串是否符合要求
+ if (!Regex.IsMatch(msg, @"^[\da-fA-F]{2}( [\da-fA-F]{2})*$")) {
+ return "==";
+ }
+
+ var bts = msg.Split(' ').Select(b => Convert.ToInt32(b, 16)).ToArray();
+ var r = (bts.Sum() % 256).ToString("X2");
+ return r;
+ }
+ }
+}
diff --git a/Tools/sql/SqlBuilder.cs b/Tools/sql/SqlBuilder.cs
new file mode 100644
index 0000000..8732806
--- /dev/null
+++ b/Tools/sql/SqlBuilder.cs
@@ -0,0 +1,87 @@
+using Soul2.Tools.General;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Soul2.Tools.sql {
+
+ ///
+ /// SQL语句简单生成器
+ ///
+ public class SqlBuilder {
+ private class WhereItem {
+ public string Key { get; set; }
+ public string Value { get; set; }
+
+ public WhereItem(string key, string value) {
+ Key = key;
+ Value = value;
+ }
+ }
+
+ private List _where;
+ private List _select;
+ private string _tbName;
+ private List _isNullList;
+ private string _lastJoin;
+
+ public SqlBuilder(string tbName) {
+ _tbName = tbName;
+ _where = new List();
+ _select = new List();
+ _isNullList = new List();
+ }
+
+ public SqlBuilder Where(string whichCol, string whatValue) {
+ _where.Add(new WhereItem(whichCol, whatValue));
+ return this;
+ }
+
+ public SqlBuilder Select(string select) {
+ _select.Add(select);
+ return this;
+ }
+
+ public SqlBuilder IsNull(string col) {
+ _isNullList.Add($"{col} is null");
+ return this;
+ }
+
+ public SqlBuilder IsNotNull(string col) {
+ _isNullList.Add($"{col} is not null");
+ return this;
+ }
+
+ public SqlBuilder Last(string lastSql) {
+ _lastJoin = lastSql;
+ return this;
+ }
+
+ public string Build() {
+ var select = "*";
+ if (_select.Count > 0) {
+ select = string.Join(", ", _select);
+ }
+ var sql = $"select {select} from {_tbName}";
+ if (_where.Count > 0) {
+ var whereBuilder = new StringBuilder();
+ foreach (var item in _where) {
+ if (_where.IndexOf(item) != 0) {
+ whereBuilder.Append(" and ");
+ }
+ whereBuilder.Append($"{item.Key} = @{item.Key}");
+ }
+ sql += $" where {whereBuilder}";
+ }
+ if (_isNullList.Count > 0) {
+ foreach (var item in _isNullList) {
+ sql += $" {item}";
+ }
+ }
+ sql += _lastJoin;
+ return sql;
+ }
+ }
+}
diff --git a/Tools/sql/SqlUtils.cs b/Tools/sql/SqlUtils.cs
new file mode 100644
index 0000000..487715f
--- /dev/null
+++ b/Tools/sql/SqlUtils.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Data;
+using System.Xml;
+using System.Data.SqlClient;
+using System.Collections;
+
+namespace Soul2.Tools.sql {
+ ///
+ /// SQL常用操作 工具类
+ ///
+ public class SqlUtils {
+
+
+
+ }
+}