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 { + + + + } +}