commit d00c45363a15a4bda23ba296695bb19d31264343
Author: Xq Yang <2290299376@qq.com>
Date: Thu Jun 20 09:23:01 2024 +0800
7号厂房立库基础能用版本
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5f3d037
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+Tools/*/bin
+WcsMain/bin
+Tools/*/obj
+WcsMain/obj
+bin
+obj
+.vs
+.idea
diff --git a/Tools/ApiTool/ApiTool.csproj b/Tools/ApiTool/ApiTool.csproj
new file mode 100644
index 0000000..df21c88
--- /dev/null
+++ b/Tools/ApiTool/ApiTool.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+
+
+
+
+
+
+
diff --git a/Tools/ApiTool/Dto/ApiResponseInfo.cs b/Tools/ApiTool/Dto/ApiResponseInfo.cs
new file mode 100644
index 0000000..674b1d8
--- /dev/null
+++ b/Tools/ApiTool/Dto/ApiResponseInfo.cs
@@ -0,0 +1,84 @@
+using System.Text;
+
+namespace ApiTool.Dto;
+
+public class ApiResponseInfo
+{
+ ///
+ /// 请求 URL
+ ///
+ public string? RequestUrl { get; set; }
+
+ ///
+ /// 请求字符串
+ ///
+ public string? RequestMsg { get; set; }
+
+ ///
+ /// 响应字符串
+ ///
+ public string? ResponseMsg { get; set; }
+
+ ///
+ /// 请求时间
+ ///
+ public DateTime? RequestTime { get; set; }
+
+ ///
+ /// 响应时间
+ ///
+ public DateTime? ResponseTime { get; set; }
+
+ ///
+ /// 是否发送成功
+ ///
+ ///
+ /// 注意:这里仅表示服务端有响应
+ ///
+ public bool IsSend { get; set; }
+
+ ///
+ /// 请求方式
+ ///
+ public string? RequestMethod { get; set; }
+
+ ///
+ /// 请求耗时
+ ///
+ public double UseTime { get; set; }
+
+ ///
+ /// 返回的异常,没有异常返回 null
+ ///
+ public Exception? RequestException { get; set; }
+
+ ///
+ /// 重写toString
+ ///
+ ///
+ public override string ToString()
+ {
+ StringBuilder builder = new();
+ builder.AppendLine($"[请求结果] {IsSend}");
+ builder.AppendLine($"[请求方式] {RequestMethod}");
+ builder.AppendLine($"[请求地址] {RequestUrl}");
+ builder.AppendLine($"[请求信息] {RequestMsg}");
+ builder.AppendLine($"[响应信息] {ResponseMsg}");
+ builder.AppendLine($"[请求时间] {RequestTime}");
+ builder.AppendLine($"[响应时间] {RequestTime}");
+ builder.AppendLine($"[请求耗时] {UseTime} ms");
+ if (RequestException != default)
+ {
+ builder.AppendLine($"[异常信息] {RequestException.Message}");
+ }
+ return builder.ToString();
+ }
+}
+
+public class ApiResponseInfo : ApiResponseInfo where T : class, new()
+{
+ ///
+ /// 响应的实体类
+ ///
+ public T? ResponseEntity { get; set; }
+}
\ No newline at end of file
diff --git a/Tools/ApiTool/WebApiPost.cs b/Tools/ApiTool/WebApiPost.cs
new file mode 100644
index 0000000..17c395a
--- /dev/null
+++ b/Tools/ApiTool/WebApiPost.cs
@@ -0,0 +1,120 @@
+using System.Diagnostics;
+using System.Net.Http.Headers;
+using System.Text;
+using ApiTool.Dto;
+using Newtonsoft.Json;
+
+
+namespace ApiTool;
+
+public class WebApiPost
+{
+ /*
+ * 作者:菻蔃
+ *
+ * 版本时间:2024年5月10日
+ *
+ */
+
+ public WebApiPost() { }
+
+ private string? _baseUrl = string.Empty;
+
+ private Action? _apiAction;
+
+ public WebApiPost(Action apiAction)
+ {
+ _apiAction = apiAction;
+ }
+
+ public WebApiPost(string url, Action action)
+ {
+ _baseUrl = url;
+ _apiAction = action;
+ }
+
+ ///
+ /// 设置响应事件,
+ ///
+ ///
+ public void SetResponseAction(Action action)
+ {
+ _apiAction = action;
+ }
+ public void SetBaseUrl(string url)
+ {
+ _baseUrl = url;
+ }
+
+ ///
+ /// 执行POST请求
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ApiResponseInfo HttpPost(TRequest requestEntity, string method = "", int time = 10000) where TRequest : class where TResponse : class, new()
+ {
+ ApiResponseInfo result = new()
+ {
+ RequestMethod = "POST"
+ };
+ string address = _baseUrl + method;
+ Encoding encoding = Encoding.UTF8;
+ Stopwatch sw = new();
+ string sendMes = JsonConvert.SerializeObject(requestEntity);
+ sw.Start();
+ try
+ {
+ HttpContent content = new StringContent(sendMes, encoding, "application/json");
+ HttpClient client = new();
+ client.DefaultRequestHeaders.Accept.Clear();
+ client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ client.Timeout = new TimeSpan(0, 0, 0, 0, time);
+ result.RequestTime = DateTime.Now;
+ var requestTask = client.PostAsync(address, content);
+ requestTask.Wait();
+ var responseResult = requestTask.Result;
+ if (responseResult.IsSuccessStatusCode)
+ {
+ var responseRead = responseResult.Content.ReadAsStringAsync();
+ responseRead.Wait();
+ string responseString = responseRead.Result;
+ result.IsSend = true;
+ result.RequestMsg = sendMes;
+ result.RequestUrl = address;
+ result.ResponseMsg = responseString;
+ result.ResponseEntity = JsonConvert.DeserializeObject(responseString);
+ }
+ else
+ {
+ var responseCode = responseResult.StatusCode;
+ var responseRead = responseResult.Content.ReadAsStringAsync();
+ responseRead.Wait();
+ string responseString = responseRead.Result;
+ result.IsSend = false;
+ result.RequestMsg = sendMes;
+ result.RequestUrl = address;
+ result.RequestException = new Exception($"[{responseCode}]{responseString}");
+ }
+ }
+ catch (Exception ex)
+ {
+ result.IsSend = false;
+ result.RequestMsg = sendMes;
+ result.RequestUrl = address;
+ result.RequestException = ex;
+ }
+ result.ResponseTime = DateTime.Now;
+ sw.Stop();
+ result.ResponseTime = DateTime.Now;
+ TimeSpan ts = sw.Elapsed;
+ result.UseTime = ts.TotalMilliseconds;
+ _apiAction?.Invoke(result);
+ return result;
+ }
+
+
+}
\ No newline at end of file
diff --git a/Tools/CirculateTool/CirculateTool.csproj b/Tools/CirculateTool/CirculateTool.csproj
new file mode 100644
index 0000000..22e1b2e
--- /dev/null
+++ b/Tools/CirculateTool/CirculateTool.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+
+
+
diff --git a/Tools/CirculateTool/CirculationAttribute.cs b/Tools/CirculateTool/CirculationAttribute.cs
new file mode 100644
index 0000000..a821bc6
--- /dev/null
+++ b/Tools/CirculateTool/CirculationAttribute.cs
@@ -0,0 +1,30 @@
+namespace CirculateTool;
+
+///
+/// 一个类里面的方法加上这个特性就表示需要被循环执行
+///
+///
+/// 一个类里面的方法加上这个特性就表示需要被循环执行
+///
+/// 循环时间,默认500ms
+/// 方法描述
+/// 方法描述
+[AttributeUsage(AttributeTargets.All)]
+public class CirculationAttribute(string? methodDescription = null, int circulationTime = 500, string[]? tags = null) : Attribute
+{
+
+ ///
+ /// 循环时间
+ ///
+ public int CirculationTime { get; } = circulationTime;
+
+ ///
+ /// 方法描述
+ ///
+ public string? MethodDescription { get; } = methodDescription;
+
+ ///
+ /// 方法或者类的标记
+ ///
+ public string[]? Tags { get; } = tags;
+}
\ No newline at end of file
diff --git a/Tools/CirculateTool/StartCirculation.cs b/Tools/CirculateTool/StartCirculation.cs
new file mode 100644
index 0000000..d7babef
--- /dev/null
+++ b/Tools/CirculateTool/StartCirculation.cs
@@ -0,0 +1,110 @@
+using System.Reflection;
+
+namespace CirculateTool;
+/*
+ * 作者:菻蔃
+ * 版本时间:2023年04月15日
+ *
+ * 注意配合特性使用
+ *
+ */
+
+///
+/// 定时任务类
+///
+public class StartCirculation
+{
+
+ ///
+ /// 触发的异常
+ ///
+ public event ExceptionHandlerEvent? ExceptionHandler;
+
+ public delegate void ExceptionHandlerEvent(string methodDescription, Exception ex);
+
+ ///
+ /// 显示相关信息
+ ///
+ public event MessageHandlerEvent? MessageHandler;
+
+ public delegate void MessageHandlerEvent(string message);
+
+ ///
+ /// 默认的循环时间
+ ///
+ private readonly int _defaultCirculationTime = 500;
+
+ ///
+ /// 启动一个程序集里面带有的类里面的定时方法
+ ///
+ ///
+ ///
+ public virtual void StartAssemblyCirculation(Assembly assembly, object[]? instanceParams = null)
+ {
+ Type[] types = assembly.GetTypes();
+ if (types.Length == 0) return;
+ foreach (Type type in types)
+ {
+ var attributes = type.GetCustomAttributes(false);
+ foreach (var attribute in attributes)
+ {
+ if (attribute is not CirculationAttribute) continue;
+ StartTask(type, instanceParams);
+ break;
+ }
+ }
+ }
+
+ ///
+ /// 开启一个实例里面所有已经添加了特性的方法
+ ///
+ ///
+ ///
+ public virtual void StartTask(Type type, object[]? instanceParams = null)
+ {
+ var methods = type.GetMethods();
+ foreach (var method in methods)
+ {
+ var attributes = method.GetCustomAttributes(false);
+ foreach (var attribute in attributes)
+ {
+ if (attribute is not CirculationAttribute needDurable) continue;
+ string methodDescription = needDurable.MethodDescription ?? $"{type.Name}.{method.Name}";
+ bool Action() => (bool)(method.Invoke(Activator.CreateInstance(type, instanceParams), []) ?? false);
+ StartTask(Action, methodDescription, needDurable.CirculationTime);
+ break;
+ }
+ }
+ }
+
+ ///
+ /// 开启一个方法
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual async void StartTask(Func action, string? description = null, int? durableTime = null)
+ {
+ int durableTimeValue = durableTime ?? _defaultCirculationTime;
+ string methodDescription = description ?? action.Method.Name;
+ CancellationTokenSource cts = new();
+ PeriodicTimer timer = new(new TimeSpan(0, 0, 0, 0, durableTimeValue));
+ MessageHandler?.Invoke($"定时器:{methodDescription},已经启动,执行间隔为:{durableTimeValue} 毫秒。");
+ while (await timer.WaitForNextTickAsync(cts.Token))
+ {
+ try
+ {
+ var result = action();
+ if (result) continue;
+ await cts.CancelAsync();
+ MessageHandler?.Invoke($"定时器:{methodDescription},主动结束。");
+ return; // 该return会结束这个线程
+ }
+ catch (Exception ex)
+ {
+ ExceptionHandler?.Invoke(methodDescription, ex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Tools/DataCheck/CheckData.cs b/Tools/DataCheck/CheckData.cs
new file mode 100644
index 0000000..288345a
--- /dev/null
+++ b/Tools/DataCheck/CheckData.cs
@@ -0,0 +1,55 @@
+using System.Text.RegularExpressions;
+
+namespace DataCheck;
+/*
+ * 作者:icewint
+ *
+ */
+
+///
+/// 数据校验类
+///
+public class CheckData
+{
+ ///
+ /// 校验是否满足设定的规则,需要添加 特性
+ ///
+ ///
+ ///
+ ///
+ public static bool CheckDataRules(T data) where T : class
+ {
+ Type type = typeof(T);
+ var properties = type.GetProperties();
+ foreach (var property in properties)
+ {
+ string? proValue = property.GetValue(data)?.ToString();
+ var attributes = property.GetCustomAttributes(false);
+ foreach (var attribute in attributes)
+ {
+ if (attribute is DataRulesAttribute dataRules)
+ {
+ // 判断是否允许为 NULL
+ if (!dataRules.AllowNull && proValue == null)
+ {
+ // 如果不允许为 null 但是为 null 了就返回错误
+ return false;
+ }
+ // 下面是允许为 null 的情况
+ if (proValue == null)
+ {
+ // 允许 null 并且为 null 满足要求
+ continue;
+ }
+ if (!Regex.IsMatch(proValue, dataRules.RegexRule))
+ {
+ // 允许为 null 但不是 null 且不满足数据要求
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/Tools/DataCheck/DataCheck.csproj b/Tools/DataCheck/DataCheck.csproj
new file mode 100644
index 0000000..0191b67
--- /dev/null
+++ b/Tools/DataCheck/DataCheck.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+
+
+
diff --git a/Tools/DataCheck/DataRulesAttribute.cs b/Tools/DataCheck/DataRulesAttribute.cs
new file mode 100644
index 0000000..ee1c8d4
--- /dev/null
+++ b/Tools/DataCheck/DataRulesAttribute.cs
@@ -0,0 +1,18 @@
+namespace DataCheck;
+
+///
+/// 数据校验规则
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class DataRulesAttribute(bool allowNull = false, string regexRule = ".*") : Attribute
+{
+ ///
+ /// 是否允许空值
+ ///
+ public readonly bool AllowNull = allowNull;
+
+ ///
+ /// 正则表达式
+ ///
+ public readonly string RegexRule = regexRule;
+}
\ No newline at end of file
diff --git a/Tools/EncryptTool/EncryptTool.csproj b/Tools/EncryptTool/EncryptTool.csproj
new file mode 100644
index 0000000..fa71b7a
--- /dev/null
+++ b/Tools/EncryptTool/EncryptTool.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/Tools/EncryptTool/Md5Encrypt.cs b/Tools/EncryptTool/Md5Encrypt.cs
new file mode 100644
index 0000000..a30d361
--- /dev/null
+++ b/Tools/EncryptTool/Md5Encrypt.cs
@@ -0,0 +1,52 @@
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace EncryptTool;
+
+
+/*
+ * 作者:菻蔃
+ * 注意:MD5 加密会被机器容易的破解,请勿用于机密数据
+ * 版本时间:2024年1月21日
+ */
+
+
+///
+/// MD5 加密
+///
+public static class Md5Encrypt
+{
+ ///
+ /// 魔改版加密,用于加密密码,无法破解,本人也无法知道原密码
+ ///
+ /// 需要加密的字符串
+ /// 加密后返回的长度
+ ///
+ public static string EncryptPassword(string? password, int length = 255)
+ {
+ if (string.IsNullOrEmpty(password)) { return string.Empty; }
+ var result = string.Empty;
+ var i = 0;
+ while (result.Length < length)
+ {
+ var bytes = MD5.HashData(Encoding.UTF8.GetBytes(password));
+ var tempStr = Convert.ToBase64String(bytes);
+ tempStr = Regex.Replace(tempStr, "\\W", "").ToUpper();
+ if (i % 2 == 0)
+ {
+ result += Regex.Replace(tempStr, "[0-9]", "");
+ }
+ else
+ {
+ result += Regex.Replace(tempStr, "[A-Z]|[a-z]", "");
+ }
+ password = tempStr;
+ i++;
+ }
+ return result[..length];
+ }
+
+
+
+}
diff --git a/Tools/HkCamera/Class1.cs b/Tools/HkCamera/Class1.cs
new file mode 100644
index 0000000..3e64fba
--- /dev/null
+++ b/Tools/HkCamera/Class1.cs
@@ -0,0 +1,6 @@
+namespace HkCamera;
+
+public class Class1
+{
+
+}
\ No newline at end of file
diff --git a/Tools/HkCamera/HkCamera.csproj b/Tools/HkCamera/HkCamera.csproj
new file mode 100644
index 0000000..0191b67
--- /dev/null
+++ b/Tools/HkCamera/HkCamera.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+
+
+
diff --git a/Tools/LedSimple/LEDColor.cs b/Tools/LedSimple/LEDColor.cs
new file mode 100644
index 0000000..1d94a8c
--- /dev/null
+++ b/Tools/LedSimple/LEDColor.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LedSimple;
+
+public enum LEDColor
+{
+ Red = 0xff,
+ Green = 0xff00,
+ Yellow = 0xffff
+}
\ No newline at end of file
diff --git a/Tools/LedSimple/LEDDLL.cs b/Tools/LedSimple/LEDDLL.cs
new file mode 100644
index 0000000..c7c1810
--- /dev/null
+++ b/Tools/LedSimple/LEDDLL.cs
@@ -0,0 +1,844 @@
+using System.Runtime.InteropServices;
+
+namespace LedSimple;
+
+public class Leddll
+{
+ //颜色值 R 0x0000ff G 0x00ff00 B 0xff0000
+ public const int COLOR_RED = 0xff; //红色
+ public const int COLOR_GREEN = 0xff00; //绿色
+ public const int COLOR_YELLOW = 0xffff; //黄色
+
+ public const int ADDTYPE_STRING = 0; //添加类型为字符串
+ public const int ADDTYPE_FILE = 1; //添加类型为文件
+
+ public const int OK = 0;//函数返回成功
+
+ //******节目定时启用日期时间星期的标志宏***************************************************************************
+ public const int ENABLE_DATE = 0x01;
+ public const int ENABLE_TIME = 0x02;
+ public const int ENABLE_WEEK = 0x04;
+ //*****************************************************************************************************************
+
+ //******节目定时星期里某天启用宏***********************************************************
+ public const int WEEK_MON = 0x01;
+ public const int WEEK_TUES = 0x02;
+ public const int WEEK_WEN = 0x04;
+ public const int WEEK_THUR = 0x08;
+ public const int WEEK_FRI = 0x10;
+ public const int WEEK_SAT = 0x20;
+ public const int WEEK_SUN = 0x40;
+ //*****************************************************************************
+
+ //[StructLayout(LayoutKind.Sequential, Size = 8, CharSet = CharSet.Unicode, Pack = 1)]
+
+ //**通讯设置结构体*********************************************************
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct COMMUNICATIONINFO
+ {
+ public int LEDType; ////LED类型 0.6代T系A系XC系 1.6代E系 2.X1X2 3.7代C系
+ public int SendType; //通讯方式 0.为Tcp发送(又称固定IP通讯), 1.广播发送(又称单机直连) 2.串口通讯 3.磁盘保存 4.广域网通讯
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
+ public string IpStr; //LED屏的IP地址,只有通讯方式为0时才需赋值,其它通讯方式无需赋值
+ public int Commport; //串口号,只有通讯方式为2时才需赋值,其它通讯方式无需赋值
+ public int Baud; //波特率,只有通讯方式为2时才需赋值,其它通讯方式无需赋值, 0.9600 1.57600 2.115200 直接赋值 9600,19200,38400,57600,115200亦可
+ public int LedNumber; //LED的屏号,只有通讯方式为2时,且用485通讯时才需赋值,其它通讯方式无需赋值
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string OutputDir; //磁盘保存的目录,只有通讯方式为3时才需赋值,其它通讯方式无需赋值
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
+ public string networkIdStr; //网络ID,只有通讯方式为4时才需赋值,其它通讯方式无需赋值
+ };
+ //***********************************************************************
+
+ //**区域坐标结构体*********************************************************
+ public struct AREARECT
+ {
+ public int left; //区域左上角横坐标
+ public int top; //区域左上角纵坐标
+ public int width; //区域的宽度
+ public int height; //区域的高度
+ };
+ //****************************************************************************
+ //***字体属性结构对**********************************************************
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct FONTPROP
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
+ public string FontName; //字体名
+ public int FontSize; //字号(单位磅)
+ public int FontColor; //字体颜色
+ public int FontBold; //是否加粗
+ public int FontItalic; //是否斜体
+ public int FontUnderLine; //时否下划线
+ };
+ //****************************************************************************
+
+ //**页面显示的属性结构体****************************************************
+ public struct PLAYPROP
+ {
+ public int InStyle; //入场特技值(取值范围 0-38)
+ public int OutStyle; //退场特技值(现无效,预留,置0)
+ public int Speed; //特技显示速度(取值范围1-255) 值越大,速度越慢
+ public int DelayTime; //页面留停时间(1-65535) 注:当入场特技为连续左移、连续右移、连续上移、连续下移时,此参数无效
+ };
+ /* 特技值对应
+ 0=立即显示
+ 1=随机
+ 2=左移
+ 3=右移
+ 4=上移
+ 5=下移
+ 6=连续左移
+ 7=连续右移
+ 8=连续上移
+ 9=连续下移
+ 10=闪烁
+ 11=激光字(向上)
+ 12=激光字(向下)
+ 13=激光字(向左)
+ 14=激光字(向右)
+ 15=水平交叉拉幕
+ 16=上下交叉拉幕
+ 17=左右切入
+ 18=上下切入
+ 19=左覆盖
+ 20=右覆盖
+ 21=上覆盖
+ 22=下覆盖
+ 23=水平百叶(左右)
+ 24=水平百叶(右左)
+ 25=垂直百叶(上下)
+ 26=垂直百叶(下上)
+ 27=左右对开
+ 28=上下对开
+ 29=左右闭合
+ 30=上下闭合
+ 31=向左拉伸
+ 32=向右拉伸
+ 33=向上拉伸
+ 34=向下拉伸
+ 35=分散向左拉伸
+ 36=分散向右拉伸
+ 37=冒泡
+ 38=下雪
+ */
+ //*******************************************************************************
+ //**设置节目定时属性结构体****************************************************
+ public struct PROGRAMTIME
+ {
+ public int EnableFlag; //启用定时的标记,ENABLE_DATE为启用日期,ENABLE_TIME为启用时间,ENABLE_WEEK为启用星期,可用或运算进行组合,如 ENABLE_DATE | ENABLE_TIME | ENABLE_WEEK
+ public int WeekValue; //启用星期后,选择要定时的星期里的某些天,用宏 WEEK_MON,WEEK_TUES,WEEK_WEN,WEEK_THUR,WEEK_FRI,WEEK_SAT,WEEK_SUN 通过或运算进行组合
+ public int StartYear; //起始年
+ public int StartMonth; //起始月
+ public int StartDay; //起始日
+ public int StartHour; //起姐时
+ public int StartMinute; //起始分
+ public int StartSecond; //起始秒
+ public int EndYear; //结束年
+ public int EndMonth; //结束月
+ public int EndDay; //结束日
+ public int EndHour; //结束时
+ public int EndMinute; //结束分
+ public int EndSecond; //结束秒
+ };
+ //**********************************************************************************
+ //数字时钟属性结构体*********************************************************************************
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct DIGITALCLOCKAREAINFO
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+ public string ShowStr; //自定义显示字符串
+ //[MarshalAs(UnmanagedType.Struct)]
+ public FONTPROP ShowStrFont; //自定义显示字符串以及日期星期时间的字体属性,注意此字体属性里的FontColor只对自定义显示字体有效,其它项的颜色有单独的颜色属性,属性的赋值见FONTPROP结构体说明
+ public int TimeLagType; //时差类型 0为超前,1为滞后
+ public int HourNum; //时差小时数
+ public int MiniteNum; //时差分钟数
+ public int DateFormat; //日期格式 0.YYYY年MM月DD日 1.YY年MM月DD日 2.MM/DD/YYYY 3.YYYY/MM/DD 4.YYYY-MM-DD 5.YYYY.MM.DD 6.MM.DD.YYYY 7.DD.MM.YYYY
+ public int DateColor; //日期字体颜色 格式是16进制 BBGGRR(如:红色0xff 绿色0xff00 黄色0xffff)
+ public int WeekFormat; //星期格式 0.星期X 1.Monday 2.Mon.
+ public int WeekColor; //星期字体颜色
+ public int TimeFormat; //时间格式 0.HH时mm分ss秒 1.HH時mm分ss秒 2.HH:mm:ss 3.上午 HH:mm:ss 4.AM HH:mm:ss 5.HH:mm:ss 上午 6.HH:mm:ss AM
+ public int TimeColor; //时间字体颜色
+ public int IsShowYear; //是否显示年 TRUE为显示 FALSE不显示 下同
+ public int IsShowWeek; //是否显示星期
+ public int IsShowMonth; //是否显示月
+ public int IsShowDay; //是否显示日
+ public int IsShowHour; //是否显示时
+ public int IsShowMinute; //是否显示分
+ public int IsShowSecond; //是否显示秒
+ public int IsMutleLineShow; //是否多行显示
+ };
+ //******************************************************************************
+ //**模拟时钟属性结构体*********************************************************
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct CLOCKAREAINFO
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
+ public string ShowStr; //自定义显示字符串
+ public FONTPROP ShowStrFont; //自定义显示字符串字体属性
+ public int TimeLagType; //时差类型 0为超前,1为滞后
+ public int HourNum; //时差小时数
+ public int MiniteNum; //时差分钟数
+ public int ClockType; //表盘类型 0.圆形 1.正方形
+ public int HourMarkColor; //时标颜色 格式是16进制 BBGGRR(如:红色0xff 绿色0xff00 黄色0xffff)
+ public int HourMarkType; //时标类型 0.圆形 1.正方形
+ public int HourMarkWidth; //时标宽度 1~16
+ public int MiniteMarkColor; //分标颜色
+ public int MiniteMarkType; //分标类型 0.圆形 1.正方形
+ public int MiniteMarkWidth; //分标宽度 1~16
+ public int HourPointerColor; //时针颜色
+ public int MinutePointerColor; //分针颜色
+ public int SecondPointerColor; //秒针颜色
+ public int HourPointerWidth; //时针的宽度 1~5
+ public int MinutePointerWidth; //分针的宽度 1~5
+ public int SecondPointerWidth; //秒针的宽度 1~5
+ public int IsShowDate; //是否显示日期
+ public int DateFormat; //日期格式 0.YYYY年MM月DD日 1.YY年MM月DD日 2.MM/DD/YYYY 3.YYYY/MM/DD 4.YYYY-MM-DD 5.YYYY.MM.DD 6.MM.DD.YYYY 7.DD.MM.YYYY
+ public FONTPROP DateFont; //日期字体属性
+ public int IsShowWeek; //是否显示星期
+ public int WeekFormat; //星期格式 0.星期X 1.Monday 2.Mon.
+ public FONTPROP WeekFont; //星期字体属性
+ };
+ //**************************************************************************************
+
+ //**计时属性结构体**********************************************************************
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct TIMEAREAINFO
+ {
+ public int ShowFormat; //显示格式 0.xx天xx时xx分xx秒 1.xx天xx時xx分xx秒 2.xxDayxxHourxxMinxxSec 3.XXdXXhXXmXXs 4.xx:xx:xx:xx
+ public int nYear; //结束年
+ public int nMonth; //结束月
+ public int nDay; //结束日
+ public int nHour; //结束时
+ public int nMinute; //结束分
+ public int nSecond; //结束秒
+ public int IsShowDay; //是否显示天
+ public int IsShowHour; //是否显示时
+ public int IsShowMinute; //是否显示分
+ public int IsShowSecond; //是否显示秒
+ public int IsMutleLineShow; //是否多行显示,指的是自定义文字与计时文字是否分行显示
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+ public string ShowStr; //自定义文字字符串
+ public int TimeStrColor; //计时文字的颜色
+ public FONTPROP ShowFont; //自定义文字及计时文字颜色,其中FontColor只对文定义文字有效,计时文字颜色为TimeStrColor
+ };
+ //****************************************************************************************
+
+
+ //**LED通讯参数修改结构体*****************************************************************
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct LEDCOMMUNICATIONPARAMETER
+ {
+ public int dwMask; //要修改项的标记 0.修改网络通讯参数 1.修改串口通讯参数 2.修改网口和串口通讯参数
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
+ public string IpStr; //新的IP地址,只有dwMask为0或2时才需赋值,其它值无需赋值,格式例如 192.168.1.100
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
+ public string NetMaskStr; //新的子网掩码,只有dwMask为0或2时才需赋值,其它值无需赋值,格式例如 255.255.255.0
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
+ public string GatewayStr; //新的网关,只有dwMask为0或2时才需赋值,其它值无需赋值,格式例如 192.168.1.1
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 18)]
+ public string MacStr; //新的MAC地址,只有dwMask为0或2时才需赋值,其它值无需赋值,格式例如 12-34-56-78-9a-bc,如无需修改请设为 ff-ff-ff-ff-ff-ff
+ public int Baud; //波特率,只有dwMask为1或2时才需赋值,其它值无需赋值,0.9600 1.57600 2.115200
+ public int LedNumber; //LED屏号 1~255,网络通讯和232通讯赋值 1 即可,485必需和控制卡显示的屏号相同才可通讯
+ };
+ //*****************************************************************************************
+
+
+ //**流水边框属性结构体************************************************************************
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct WATERBORDERINFO
+ {
+ public int Flag; //流水边框加载类型标志,0.为动态库预置的边框 1.为从文件加载的边框
+ public int BorderType; //边框的类型,Flag为0是有效,0.单色边框 1.双基色边框 2.全彩边框
+ public int BorderValue; //边框的值,Flag为0是有效,单色边框取值范围是0~39,双基色边框取值范围是0~34,全彩边框取值范围是0~21
+ public int BorderColor; //边框线颜色,Flag为0并且BorderType为0是才有效
+ public int BorderStyle; //边框显示的样式 0.固定 1.顺时针 2.逆时针 3.闪烁
+ public int BorderSpeed;//边框流动的速度
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string WaterBorderBmpPath; //边框图片文件的路径,注意只能是bmp图片,图片大小必需是宽度为32点,取高度小于等于8
+ };
+ //*********************************************************************************************
+
+
+
+ //**定时开关屏设置属性************************************************************************
+ public struct ONOFFTIMEINFO
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] TimeFlag; //支持3个定时,1代表打开 0关闭
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] StartHour; //开始时钟
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] StartMinute; //开始分钟
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] EndHour; //结束时钟
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] EndMinute; //结束分钟
+ };
+ //********************************************************************************************
+
+ //**定时亮度设置属性**************************************************************************
+ public struct BRIGHTNESSTIMEINFO
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] TimeFlag; //支持3个定时,1代表打开 0关闭
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] StartHour; //开始时钟
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] StartMinute; //开始分钟
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] EndHour; //结束时钟
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] EndMinute; //结束分钟
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public int[] BrightnessValue; //亮度值0~15
+ };
+ //*******************************************************************************************
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
+ public delegate int SERVERINFOCALLBACK(int Msg, int wParam, nint ptr);
+
+ public enum LV_MSG
+ {
+ LV_MSG_NONE,
+ LV_MSG_CARD_ONLINE,//上线通知,通过CARD_INFO结构体指针获取详细上线信息
+ LV_MSG_CARD_OFFLINE,//下线通知,通过CARD_INFO结构体指针获取详细下线信息
+ };
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct CARD_INFO
+ {
+ public int port; //控制卡端口
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
+ public string ipStr; //控制卡IP
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)]
+ public string networkIdStr; //控制卡唯一网络ID(每张卡都贴有唯一网络ID)
+ };
+ /********************************************************************************************
+* LV_InitLed 初始化屏的类型和颜色顺序(C卡)
+* 当Led上显示的文字区域的颜色与下发的不一致, 请的确认Led 屏的RGB顺序,并调用此接口
+* 参数说明
+* nLedType 屏类型 0.6代T系A系XC系 1.6代E系 2.X1X2 3.7代C系 4: E5,E6
+* nRgb 模组的RGB顺序,仅C卡有效,其他卡固定为0. C卡时, 0: R->G->B 1: G->R->B 2:R->B->G 3:B->R->G 4:B->G->R 5:G->B->R
+* 返回值 无
+*
+********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_InitLed", CharSet = CharSet.Unicode)]
+ public static extern void LV_InitLed(int nLedType, int nRgb);
+
+
+ /********************************************************************************************
+ * LV_CreateProgramEx 创建节目对象,返回类型为 HPROGRAM
+ *
+ * 参数说明
+ * LedWidth 屏的宽度
+ * LedHeight 屏的高度
+ * ColorType 屏的颜色 1.单色 2.双基色 3.三基色 注:C卡全彩参数为3 X系列卡参数固定为 4
+ * GrayLevel 灰度等级 赋值 1-5对应的灰度等级分别为 无,4,8,16,32 注:目前C系列的卡才支持,其它型号(T,A,U,XC,W,E,X)参数必须为0
+ * SaveType 节目保存位置,默认为0保存存为flash节目,3保存为ram节目
+ * 注:flash节目掉电不清除,ram节目掉电清除。应用场景需要实时刷新的,建议保存为ram节目, 目前仅C卡程序才支持切换,
+ * 其他卡默认出货为flash程序,如果需要RAM程序请联系业务或者在官网下载,然后使用Led Player对卡进行升级
+ * 返回值
+ * 0 创建节目对象失败
+ * 非0 创建节目对象成功
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_CreateProgramEx", CharSet = CharSet.Unicode)]
+ public static extern nint LV_CreateProgramEx(int LedWidth, int LedHeight, int ColorType, int GrayLevel, int SaveType);
+
+ /*********************************************************************************************
+ * LV_AddProgram 添加一个节目
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * ProgramTime 节目播放时长 0.节目播放时长 非0.指定播放时长
+ * LoopCount 循环播放次数 1-255
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddProgram", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddProgram(nint hProgram, int ProgramNo, int ProgramTime, int LoopCount);
+
+ /*********************************************************************************************
+ * LV_SetProgramTime 设置节目定时
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * pProgramTime 节目定时属性,设置方式见PROGRAMTIME结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_SetProgramTime", CharSet = CharSet.Unicode)]
+ public static extern int LV_SetProgramTime(nint hProgram, int ProgramNo, ref PROGRAMTIME pProgramTime);
+
+ /*********************************************************************************************
+ * LV_AddImageTextArea 添加一个图文区域
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * pAreaRect 区域坐标属性,设置方式见AREARECT结构体注示
+ * nLayout 区域层号,1.前景区(默认) 0.背景区 注:除C系列,其它默认为1
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddImageTextArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddImageTextArea(nint hProgram, int ProgramNo, int AreaNo, ref AREARECT pAreaRect, int nLayout);
+
+ /*********************************************************************************************
+ * LV_AddFileToImageTextArea 添加一个文件到图文区
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * FilePath 文件路径,支持的文件类型有 txt rtf bmp gif png jpg jpeg tiff
+ * pPlayProp 显示的属性,设置方式见PLAYPROP结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddFileToImageTextArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddFileToImageTextArea(nint hProgram, int ProgramNo, int AreaNo, string FilePath, ref PLAYPROP pPlayProp);
+
+ /*********************************************************************************************
+ * LV_AddSingleLineTextToImageTextArea 添加一个单行文本到图文区
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * AddType 添加的类型 0.为字符串 1.文件(只支持txt和rtf文件)
+ * AddStr AddType为0则为字符串数据,AddType为1则为文件路径
+ * pFontProp 如果AddType为字符串类型或AddType为文件类型且文件为txt则可传入以赋值的该结构体,其它可赋NULL
+ * pPlayProp 显示的属性,设置方式见PLAYPROP结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddSingleLineTextToImageTextArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddSingleLineTextToImageTextArea(nint hProgram, int ProgramNo, int AreaNo, int AddType, string AddStr, ref FONTPROP pFontProp, ref PLAYPROP pPlayProp);
+
+ /*********************************************************************************************
+ * LV_AddMultiLineTextToImageTextArea 添加一个多行文本到图文区
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * AddType 添加的类型 0.为字符串 1.文件(只支持txt和rtf文件)
+ * AddStr AddType为0则为字符串数据,AddType为1则为文件路径 换行符(\n)
+ * pFontProp 如果AddType为字符串类型或AddType为文件类型且文件为txt则可传入以赋值的该结构体,其它可赋NULL
+ * pPlayProp 显示的属性,设置方式见PLAYPROP结构体注示
+ * nAlignment 水平对齐样式,0.左对齐 1.右对齐 2.水平居中 (注意:只对字符串和txt文件有效)
+ * IsVCenter 是否垂直居中 0.置顶(默认) 1.垂直居中
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddMultiLineTextToImageTextArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddMultiLineTextToImageTextArea(nint hProgram, int ProgramNo, int AreaNo, int AddType, string AddStr, ref FONTPROP pFontProp, ref PLAYPROP pPlayProp, int nAlignment, int IsVCenter);
+
+ /*********************************************************************************************
+ * LV_AddStaticTextToImageTextArea 添加一个静止文本到图文区
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * AddType 添加的类型 0.为字符串 1.文件(只支持txt和rtf文件)
+ * AddStr AddType为0则为字符串数据,AddType为1则为文件路径
+ * pFontProp 如果AddType为字符串类型或AddType为文件类型且文件为txt则可传入以赋值的该结构体,其它可赋NULL
+ * DelayTime 显示的时长 1~65535
+ * nAlignment 水平对齐样式,0.左对齐 1.右对齐 2.水平居中 (注意:只对字符串和txt文件有效)
+ * IsVCenter 是否垂直居中 0.置顶(默认) 1.垂直居中
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddStaticTextToImageTextArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddStaticTextToImageTextArea(nint hProgram, int ProgramNo, int AreaNo, int AddType, string AddStr, ref FONTPROP pFontProp, int DelayTime, int nAlignment, int IsVCenter);
+
+ /*********************************************************************************************
+ * LV_QuickAddSingleLineTextArea 快速添加一个向左移的单行文本区域
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * pAreaRect 区域坐标属性,设置方式见AREARECT结构体注示
+ * AddType 添加的类型 0.为字符串 1.文件(只支持txt和rtf文件)
+ * AddStr AddType为0则为字符串数据,AddType为1则为文件路径
+ * pFontProp 如果AddType为字符串类型或AddType为文件类型且文件为txt则可传入以赋值的该结构体,其它可赋NULL
+ * nSpeed 滚动速度 1~255
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_QuickAddSingleLineTextArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_QuickAddSingleLineTextArea(nint hProgram, int ProgramNo, int AreaNo, ref AREARECT pAreaRect, int AddType, string AddStr, ref FONTPROP pFontProp, int nSpeed);
+
+ /*********************************************************************************************
+ * LV_AddDigitalClockArea 添加一个数字时钟区域
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * pAreaRect 区域坐标属性,设置方式见AREARECT结构体注示
+ * pDigitalClockAreaInfo 数字时钟属性,见DIGITALCLOCKAREAINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddDigitalClockArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddDigitalClockArea(nint hProgram, int ProgramNo, int AreaNo, ref AREARECT pAreaRect, ref DIGITALCLOCKAREAINFO pDigitalClockAreaInfo);
+
+ /*********************************************************************************************
+ * LV_AddTimeArea 添加一个计时区域
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号(取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * pAreaRect 区域坐标属性,设置方式见AREARECT结构体注示
+ * pTimeAreaInfo 计时属性,见TIMEAREAINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddTimeArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddTimeArea(nint hProgram, int ProgramNo, int AreaNo, ref AREARECT pAreaRect, ref TIMEAREAINFO pTimeAreaInfo);
+
+ /*********************************************************************************************
+ * LV_AddClockArea 添加一个模拟时钟区域
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * pAreaRect 区域坐标属性,设置方式见AREARECT结构体注示
+ * pClockAreaInfo 模拟时钟属性,见CLOCKAREAINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddClockArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddClockArea(nint hProgram, int ProgramNo, int AreaNo, ref AREARECT pAreaRect, ref CLOCKAREAINFO pClockAreaInfo);
+
+ /*********************************************************************************************
+ * LV_AddNeiMaArea 添加一个内码区域
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 从0开始(0-255)
+ * AreaNo 区域号 (1-255)
+ * pAreaRect 区域坐标属性,设置方式见AREARECT结构体注示
+ * 除C卡外的其他卡,内码区域的起点X和Y坐标必须为8的整数倍,如0,8,16等, 宽高必须大于所用字体大小
+ * NeiMaStr 文本字符串 注:字符串编码是GB2312
+ * FontSize 字体大小 16 24 32
+ * FontColor 文字颜色 格式BBGGRR 0xff 红色 0xff00 绿色 0xffff黄色
+ * pPlayProp 显示的属性,设置方式见PLAYPROP结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddNeiMaArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddNeiMaArea(nint hProgram, int ProgramNo, int AreaNo, ref AREARECT pAreaRect, string NeiMaStr, int FontSize, int FontColor, ref PLAYPROP pPlayProp);
+
+
+ /*********************************************************************************************
+ * LV_RefreshNeiMaArea 刷新内码区域
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * NeiMaStr 刷新的数据字符串,格式可以查看<<内码区域局部更新协议>>文档
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_RefreshNeiMaArea", CharSet = CharSet.Unicode)]
+ public static extern int LV_RefreshNeiMaArea(ref COMMUNICATIONINFO pCommunicationInfo, string NeiMaStr);
+
+ /*********************************************************************************************
+ * LV_AddWaterBorder 添加一个流水边框区域
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ * ProgramNo 节目号 (取值范围0-255)(从0开始)
+ * AreaNo 区域号 (取值范围1-255)
+ * pAreaRect 区域坐标属性,设置方式见AREARECT结构体注示
+ * pWaterBorderInfo 流水边框属性,见WATERBORDERINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AddWaterBorder", CharSet = CharSet.Unicode)]
+ public static extern int LV_AddWaterBorder(nint hProgram, int ProgramNo, int AreaNo, ref AREARECT pAreaRect, ref WATERBORDERINFO pWaterBorderInfo);
+
+ /*********************************************************************************************
+ * LV_DeleteProgram 销毁节目对象(注意:如果此节目对象不再使用,请调用此函数销毁,否则会造成内存泄露)
+ *
+ * 参数说明
+ * hProgram 节目对象句柄
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_DeleteProgram", CharSet = CharSet.Unicode)]
+ public static extern void LV_DeleteProgram(nint hProgram);
+
+ /*********************************************************************************************
+ * LV_Send 发送节目,此发送为一对一发送
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * hProgram 节目对象句柄
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_Send", CharSet = CharSet.Unicode)]
+ public static extern int LV_Send(ref COMMUNICATIONINFO pCommunicationInfo, nint hProgram);
+
+ /*********************************************************************************************
+ * LV_TestOnline 测试LED屏是否可连接上
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_TestOnline", CharSet = CharSet.Unicode)]
+ public static extern int LV_TestOnline(ref COMMUNICATIONINFO pCommunicationInfo);
+
+ /*********************************************************************************************
+ * LV_SetBasicInfoEx 设置基本屏参
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * ColorType 屏的颜色 1.单色 2.双基色 3.三基色 注:C卡全彩参数为3 X系列卡参数固定为 4
+ * GrayLevel 灰度等级 赋值 1-5对应的灰度等级分别为 无,4,8,16,32 注:目前C系列的卡才支持,其它型号(T,A,U,XC,W,E,X)参数必须为0
+ * LedWidth 屏的宽度点数
+ * LedHeight 屏的高度点数
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_SetBasicInfoEx", CharSet = CharSet.Unicode)]
+ public static extern int LV_SetBasicInfoEx(ref COMMUNICATIONINFO pCommunicationInfo, int ColorType, int GrayLevel, int LedWidth, int LedHeight);
+
+ /*********************************************************************************************
+ * LV_SetOEDA 设置OE DA
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * Oe OE 0.低有效 1.高有效
+ * Da DA 0.负极性 1.正极性
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_SetOEDA", CharSet = CharSet.Unicode)]
+ public static extern int LV_SetOEDA(ref COMMUNICATIONINFO pCommunicationInfo, int Oe, int Da);
+
+ /*********************************************************************************************
+ * LV_AdjustTime 校时
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_AdjustTime", CharSet = CharSet.Unicode)]
+ public static extern int LV_AdjustTime(ref COMMUNICATIONINFO pCommunicationInfo);
+
+ /*********************************************************************************************
+ * LV_PowerOnOff 开关屏
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * OnOff 开关值 0.开屏 1.关屏 2.重启(仅支持C卡)
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_PowerOnOff", CharSet = CharSet.Unicode)]
+ public static extern int LV_PowerOnOff(ref COMMUNICATIONINFO pCommunicationInfo, int OnOff);
+
+ /*********************************************************************************************
+ * LV_TimePowerOnOff 定时开关屏
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * pTimeInfo 定时开关屏属性,详见ONOFFTIMEINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_TimePowerOnOff", CharSet = CharSet.Unicode)]
+ public static extern int LV_TimePowerOnOff(ref COMMUNICATIONINFO pCommunicationInfo, ref ONOFFTIMEINFO pTimeInfo);
+
+ /*********************************************************************************************
+ * LV_SetBrightness 设置亮度
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * BrightnessValue 亮度值 0~15
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_SetBrightness", CharSet = CharSet.Unicode)]
+ public static extern int LV_SetBrightness(ref COMMUNICATIONINFO pCommunicationInfo, int BrightnessValue);
+
+ /*********************************************************************************************
+ * LV_TimeBrightness 定时亮度
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * pBrightnessTimeInfo 定时亮度属性,详见BRIGHTNESSTIMEINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_TimeBrightness", CharSet = CharSet.Unicode)]
+ public static extern int LV_TimeBrightness(ref COMMUNICATIONINFO pCommunicationInfo, ref BRIGHTNESSTIMEINFO pBrightnessTimeInfo);
+
+ /*********************************************************************************************
+ * LV_LedTest LED测试
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * TestValue 测试值
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_LedTest", CharSet = CharSet.Unicode)]
+ public static extern int LV_LedTest(ref COMMUNICATIONINFO pCommunicationInfo, int TestValue);
+
+ /*********************************************************************************************
+ * LV_TimeLocker LED定时锁屏
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * LockerYear 锁屏年
+ * LockerMonth 锁屏月
+ * LockerDay 锁屏日
+ * LockerHour 锁屏时
+ * LockerMinute 锁屏分
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_TimeLocker", CharSet = CharSet.Unicode)]
+ public static extern int LV_TimeLocker(ref COMMUNICATIONINFO pCommunicationInfo, int LockerYear, int LockerMonth, int LockerDay, int LockerHour, int LockerMinute);
+
+ /*********************************************************************************************
+ * LV_CancelLocker 取消定时锁屏
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_CancelLocker", CharSet = CharSet.Unicode)]
+ public static extern int LV_CancelLocker(ref COMMUNICATIONINFO pCommunicationInfo);
+
+ /*********************************************************************************************
+ * LV_SetLedCommunicationParameter 设置LED通讯参数
+ *
+ * 参数说明
+ * pCommunicationInfo 通讯参数,赋值方式见COMMUNICATIONINFO结构体注示
+ * pLedCommunicationParameter 详见LEDCOMMUNICATIONPARAMETER结构体注示
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_SetLedCommunicationParameter", CharSet = CharSet.Unicode)]
+ public static extern int LV_SetLedCommunicationParameter(ref COMMUNICATIONINFO pCommunicationInfo, ref LEDCOMMUNICATIONPARAMETER pLedCommunicationParameter);
+ /*********************************************************************************************
+ * LV_LedInitServer 启动控制卡心跳包服务 注:C2M、C4M才支持
+ *
+ * 参数说明
+ * port 监听的端口
+ * 返回值
+ * 0 成功
+ * 非0 失败,调用LV_GetError来获取错误信息
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_LedInitServer", CharSet = CharSet.Unicode)]
+ public static extern int LV_LedInitServer(int port);
+ /*********************************************************************************************
+ * LV_LedShudownServer 断开控制卡心跳包服务 注:C2M、C4M才支持
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_LedShudownServer", CharSet = CharSet.Unicode)]
+ public static extern int LV_LedShudownServer();
+ /*********************************************************************************************
+ * LV_RegisterLedServerCallback 注册回调函数 注:C2M、C4M才支持
+ *
+ * 参数说明
+ * serverCallback 回调函数
+ ********************************************************************************************/
+ [DllImport("lv_led_64.dll", EntryPoint = "LV_RegisterLedServerCallback", CharSet = CharSet.Unicode)]
+ public static extern int LV_RegisterLedServerCallback(SERVERINFOCALLBACK serverCallback);
+
+ /*********************************************************************************************
+ * LV_GetError 获取错误信息(只支持中文)
+ *
+ * 参数说明
+ * nErrCode 函数执行返回的错误代码
+ * 返回值
+ * 错误信息字符串
+ ********************************************************************************************/
+ public static string LS_GetError(int nErrCode)
+ {
+ string ErrStr = nErrCode switch
+ {
+ -1 => "无效的节目句柄。",
+ -2 => "节目已经存在。",
+ -3 => "指定的节目不存在。",
+ -4 => "定的区域不存在。",
+ -5 => "创建socket失败。",
+ -6 => "错误的回复包。",
+ -7 => "不支持的文件类型。",
+ -8 => "IP网关掩码或MAC字符串格式错误。",
+ -9 => "错误的波特率。",
+ -10 => "文件路径不存在。",
+ -11 => "区域重叠。",
+ -12 => "打开文件失败。",
+ -14 => "区域已存在。",
+ -15 => "无效的发送类型。",
+ -16 => "绘图失败。",
+ -17 => "创建文件夹失败。",
+ -30 => "打开串口失败。",
+ -31 => "设置串口超时失败。",
+ -32 => "设置串口缓冲区失败。",
+ -33 => "串口发送数据失败。",
+ -34 => "串口接收数据失败。",
+ -35 => "串口设置失败。",
+ -36 => "串口接收数据超时。",
+ -37 => "USB不支持群发。",
+ -38 => "发送取消。",
+ -100 => "网络连接失败。",
+ -101 => "网络发送失败。",
+ -102 => "网络接收数据失败。",
+ -103 => "bind失败。",
+ -104 => "无可用网卡。",
+ 0xc140 => "Logo与参屏大小不适应。",
+ 0xdaa3 => "控制器繁忙。",
+ 0xd5b0 => "固件程序型号不匹配。",
+ 0xd5b4 => "不是有效的固件程序。",
+ 0xdab8 => "节目颜色或屏宽高与控制卡屏参设定值不一致。",
+ 0xc1ba => "超出控制卡带载。",
+ 0xdab5 => "节目数据大小超过允许的最大值。",
+ _ => "未定义错误。",
+ };
+ return ErrStr;
+ }
+
+}
\ No newline at end of file
diff --git a/Tools/LedSimple/LedSimple.csproj b/Tools/LedSimple/LedSimple.csproj
new file mode 100644
index 0000000..e49f24c
--- /dev/null
+++ b/Tools/LedSimple/LedSimple.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+ true
+
+
+
+
+ Always
+
+
+ Always
+
+
+
+
diff --git a/Tools/LedSimple/lv_led_64.dll b/Tools/LedSimple/lv_led_64.dll
new file mode 100644
index 0000000..fabcd78
Binary files /dev/null and b/Tools/LedSimple/lv_led_64.dll differ
diff --git a/Tools/LogTool/LogTool.csproj b/Tools/LogTool/LogTool.csproj
new file mode 100644
index 0000000..0191b67
--- /dev/null
+++ b/Tools/LogTool/LogTool.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+
+
+
diff --git a/Tools/LogTool/WcsLog.cs b/Tools/LogTool/WcsLog.cs
new file mode 100644
index 0000000..2286ebc
--- /dev/null
+++ b/Tools/LogTool/WcsLog.cs
@@ -0,0 +1,104 @@
+using System.Text;
+
+namespace LogTool;
+
+public class WcsLog
+{
+ private static WcsLog? instance;
+
+ public static WcsLog Instance()
+ {
+ instance ??= new WcsLog();
+ return instance;
+ }
+
+
+ private static readonly object writeLog = new();
+ ///
+ /// 通用写日志类
+ ///
+ /// 文件夹名称
+ /// 日志内容
+ /// 是否在日志中自动添加时间
+ public void WriteLog(string LogName, string strLog, bool addTime = true)
+ {
+ Task.Factory.StartNew(() =>
+ {
+ lock (writeLog)
+ {
+ string LogAddress = AppDomain.CurrentDomain.BaseDirectory + "Log\\" + LogName;
+ DirectoryInfo di = new(LogAddress);
+ if (di.Exists == false) { di.Create(); }
+ StringBuilder logBuilder = new();
+ if (addTime)
+ {
+ logBuilder.AppendLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff}]");
+ }
+ logBuilder.AppendLine($"{strLog}");
+ string logFileName = LogAddress + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + ".log";
+ using FileStream fs = new(logFileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
+ using StreamWriter sw = new(fs);
+ try
+ {
+ sw.Write(logBuilder);
+ }
+ catch (Exception ex)
+ {
+ _ = ex;
+ }
+ }
+ });
+ }
+
+ ///
+ /// 写系统日志
+ ///
+ ///
+ public void WriteSystemLog(string strLog) => WriteLog("系统日志", strLog);
+
+ ///
+ /// 写事件日志
+ ///
+ ///
+ public void WriteEventLog(string strLog) => WriteLog("事件日志", strLog);
+ ///
+ /// 写事件日志
+ ///
+ ///
+ public void WriteEventLog(StringBuilder strLog) => WriteLog("事件日志", strLog.ToString(), false);
+
+ ///
+ /// 写入Tcp日志
+ ///
+ ///
+ public void WriteTcpLog(StringBuilder strLog) => WriteLog("Tcp日志", strLog.ToString(), false);
+
+ ///
+ /// 写接口日志
+ ///
+ ///
+ public void WriteApiRequestLog(string strLog) => WriteLog("接口请求日志", strLog);
+
+ ///
+ /// 写异常日志
+ ///
+ ///
+ public void WriteExceptionLog(string strLog) => WriteLog("异常日志", strLog);
+ ///
+ /// 写异常日志
+ ///
+ ///
+ public void WriteExceptionLog(StringBuilder strLog) => WriteLog("异常日志", strLog.ToString(), false);
+
+ ///
+ /// 写数据库日志
+ ///
+ ///
+ public void WriteSQLLog(string strLog) => WriteLog("数据库日志", strLog);
+
+ ///
+ /// 写接口接收日志
+ ///
+ ///
+ public void WriteApiAcceptLog(string strLog) => WriteLog("接口接收日志", strLog);
+}
\ No newline at end of file
diff --git a/Tools/PlcTool/PlcTool.csproj b/Tools/PlcTool/PlcTool.csproj
new file mode 100644
index 0000000..dc01f7f
--- /dev/null
+++ b/Tools/PlcTool/PlcTool.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+
+
+
+
+
+
+
+
diff --git a/Tools/PlcTool/Siemens/DataConvert.cs b/Tools/PlcTool/Siemens/DataConvert.cs
new file mode 100644
index 0000000..ba3d8e6
--- /dev/null
+++ b/Tools/PlcTool/Siemens/DataConvert.cs
@@ -0,0 +1,72 @@
+using HslCommunication;
+using HslCommunication.Profinet.Siemens;
+using PlcTool.Siemens.Entity;
+
+namespace PlcTool.Siemens;
+
+///
+/// 数据转换类
+///
+public static class DataConvert
+{
+
+ ///
+ /// 将string转化为西门子PLC类型
+ /// 不满足条件的转化为1200
+ /// 支持的string:
+ /// 1500
+ /// 1200
+ /// 300
+ /// 400
+ /// 200
+ /// 200s
+ ///
+ ///
+ ///
+ public static SiemensPLCS ToPlcKind(this string? plcKandStr)
+ {
+ return plcKandStr switch
+ {
+ "1500" => SiemensPLCS.S1500,
+ "1200" => SiemensPLCS.S1200,
+ "400" => SiemensPLCS.S400,
+ "300" => SiemensPLCS.S300,
+ "200s" => SiemensPLCS.S200Smart,
+ "200" => SiemensPLCS.S200,
+ _ => SiemensPLCS.S1200,
+ };
+ }
+
+ ///
+ /// PLC读写固定返回类
+ /// 返回一个新的类,
+ ///
+ ///
+ ///
+ public static SemS7Result ToSemS7Result(this OperateResult operateResult)
+ {
+ return new SemS7Result()
+ {
+ Success = operateResult.IsSuccess,
+ ErrCode = operateResult.ErrorCode,
+ Message = operateResult.Message
+ };
+ }
+ ///
+ /// PLC读写固定返回类
+ /// 返回一个新的类,
+ ///
+ ///
+ ///
+ ///
+ public static SemS7Result ToSemS7Result(this OperateResult operateResult)
+ {
+ return new SemS7Result()
+ {
+ Success = operateResult.IsSuccess,
+ ErrCode = operateResult.ErrorCode,
+ Message = operateResult.Message,
+ Value = operateResult.Content
+ };
+ }
+}
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/Entity/PlcDBName.cs b/Tools/PlcTool/Siemens/Entity/PlcDBName.cs
new file mode 100644
index 0000000..defbf4f
--- /dev/null
+++ b/Tools/PlcTool/Siemens/Entity/PlcDBName.cs
@@ -0,0 +1,13 @@
+namespace PlcTool.Siemens.Entity;
+
+///
+/// DB 信息
+///
+public class PlcDBName
+{
+ public uint? PlcId { get; set; }
+
+ public string? DBName { get; set; }
+
+ public string? DBAddress { get; set; }
+}
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/Entity/SemS7Result.cs b/Tools/PlcTool/Siemens/Entity/SemS7Result.cs
new file mode 100644
index 0000000..65cd207
--- /dev/null
+++ b/Tools/PlcTool/Siemens/Entity/SemS7Result.cs
@@ -0,0 +1,32 @@
+using Newtonsoft.Json;
+using System.Text;
+
+namespace PlcTool.Siemens.Entity;
+
+public class SemS7Result
+{
+
+ public bool Success { get; set; } = false;
+
+ public int? ErrCode { get; set; }
+
+ public string? Message { get; set; }
+
+ public override string ToString()
+ {
+ return JsonConvert.SerializeObject(this);
+ }
+}
+
+///
+/// PLC操作的返回泛型类
+///
+///
+public class SemS7Result : SemS7Result
+{
+ public T? Value { get; set; }
+ public override string ToString()
+ {
+ return JsonConvert.SerializeObject(this);
+ }
+}
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/Entity/SiemensS7Connection.cs b/Tools/PlcTool/Siemens/Entity/SiemensS7Connection.cs
new file mode 100644
index 0000000..59eb467
--- /dev/null
+++ b/Tools/PlcTool/Siemens/Entity/SiemensS7Connection.cs
@@ -0,0 +1,19 @@
+using HslCommunication.Profinet.Siemens;
+
+namespace PlcTool.Siemens.Entity;
+
+///
+/// PLC 连接信息类
+///
+public class SiemensS7Connection
+{
+ ///
+ /// PLC 的编号
+ ///
+ public int? PlcId { get; set; }
+
+ ///
+ /// 连接信息
+ ///
+ public SiemensS7Net? SiemensS7 { get; set; }
+}
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/PLCAttribute/PlcDBAddressAttribute.cs b/Tools/PlcTool/Siemens/PLCAttribute/PlcDBAddressAttribute.cs
new file mode 100644
index 0000000..2b0233e
--- /dev/null
+++ b/Tools/PlcTool/Siemens/PLCAttribute/PlcDBAddressAttribute.cs
@@ -0,0 +1,7 @@
+namespace PlcTool.Siemens.PLCAttribute;
+
+///
+/// 用于标记 PLC 通讯地址
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class PlcDBAddressAttribute : Attribute { }
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/PLCAttribute/PlcDBNameAttribute.cs b/Tools/PlcTool/Siemens/PLCAttribute/PlcDBNameAttribute.cs
new file mode 100644
index 0000000..6489a52
--- /dev/null
+++ b/Tools/PlcTool/Siemens/PLCAttribute/PlcDBNameAttribute.cs
@@ -0,0 +1,7 @@
+namespace PlcTool.Siemens.PLCAttribute;
+
+///
+/// 用于标记 PLC 通讯地址的名称
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class PlcDBNameAttribute : Attribute { }
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/PLCAttribute/PlcIPAttribute.cs b/Tools/PlcTool/Siemens/PLCAttribute/PlcIPAttribute.cs
new file mode 100644
index 0000000..33db43b
--- /dev/null
+++ b/Tools/PlcTool/Siemens/PLCAttribute/PlcIPAttribute.cs
@@ -0,0 +1,7 @@
+namespace PlcTool.Siemens.PLCAttribute;
+
+///
+/// 用于标记 PLC 的IP
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class PlcIPAttribute : Attribute { }
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/PLCAttribute/PlcIdAttribute.cs b/Tools/PlcTool/Siemens/PLCAttribute/PlcIdAttribute.cs
new file mode 100644
index 0000000..9ca844b
--- /dev/null
+++ b/Tools/PlcTool/Siemens/PLCAttribute/PlcIdAttribute.cs
@@ -0,0 +1,7 @@
+namespace PlcTool.Siemens.PLCAttribute;
+
+///
+/// 用于标记 PLC 的编号
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class PlcIdAttribute : Attribute { }
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/PLCAttribute/PlcKindAttribute.cs b/Tools/PlcTool/Siemens/PLCAttribute/PlcKindAttribute.cs
new file mode 100644
index 0000000..2f6b7ec
--- /dev/null
+++ b/Tools/PlcTool/Siemens/PLCAttribute/PlcKindAttribute.cs
@@ -0,0 +1,16 @@
+namespace PlcTool.Siemens.PLCAttribute;
+
+///
+/// 用于标记PLC的系列
+///
+///
+/// 支持的string:
+/// 1500
+/// 1200
+/// 300
+/// 400
+/// 200
+/// 200s
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class PlcKindAttribute : Attribute { }
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/PLCAttribute/RackAttribute.cs b/Tools/PlcTool/Siemens/PLCAttribute/RackAttribute.cs
new file mode 100644
index 0000000..a2fa896
--- /dev/null
+++ b/Tools/PlcTool/Siemens/PLCAttribute/RackAttribute.cs
@@ -0,0 +1,7 @@
+namespace PlcTool.Siemens.PLCAttribute;
+
+///
+/// plc 机架
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class RackAttribute : Attribute { }
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/PLCAttribute/SlotAttribute.cs b/Tools/PlcTool/Siemens/PLCAttribute/SlotAttribute.cs
new file mode 100644
index 0000000..4d33bb4
--- /dev/null
+++ b/Tools/PlcTool/Siemens/PLCAttribute/SlotAttribute.cs
@@ -0,0 +1,7 @@
+namespace PlcTool.Siemens.PLCAttribute;
+
+///
+/// plc 插槽
+///
+[AttributeUsage(AttributeTargets.Property)]
+public class SlotAttribute : Attribute { }
\ No newline at end of file
diff --git a/Tools/PlcTool/Siemens/SiemensS7.cs b/Tools/PlcTool/Siemens/SiemensS7.cs
new file mode 100644
index 0000000..993af77
--- /dev/null
+++ b/Tools/PlcTool/Siemens/SiemensS7.cs
@@ -0,0 +1,842 @@
+using System.Reflection;
+using System.Text;
+using HslCommunication;
+using HslCommunication.Profinet.Siemens;
+using PlcTool.Siemens.Entity;
+using PlcTool.Siemens.PLCAttribute;
+
+namespace PlcTool.Siemens;
+
+public class SiemensS7
+{
+
+ /*
+ * 作者:菻蔃
+ *
+ * 版本时间:2023年4月15日
+ *
+ */
+
+ private const string tip = "致其他开发者,此组件为收费组件,若您有意使用,请自行联系作者购买授权,擅自使用本公司激活码将承担责任";
+
+ ///
+ /// 存储PLC连接
+ ///
+ readonly List siemensS7Connections = [];
+
+ ///
+ /// 存储DB块具体在哪个PLC中
+ ///
+ readonly List plcDBNames = [];
+
+
+
+ ///
+ /// 操作PLC的类,传入PLC类型,地址,和组件激活码。
+ ///
+ ///
+ ///
+ public SiemensS7(string? authorizationCode = null)
+ {
+ if (string.IsNullOrEmpty(authorizationCode))
+ {
+ /*致本公司开发者,此为 10.6.1 版本激活码,若激活失败,尝试使用此版本*/
+ /*致其他开发者,此组件为收费组件,若您有意使用,请自行联系作者购买授权,擅自使用本公司激活码将承担责任*/
+ authorizationCode = "f562cc4c-4772-4b32-bdcd-f3e122c534e3";
+ }
+ bool isAuthorization = Authorization.SetAuthorizationCode(authorizationCode);
+ if (!isAuthorization)
+ {
+ /*这里抛出异常,一定记得提醒开发者注册*/
+ throw new Exception("组件未激活,上述激活码可能会因为版本更新而失效,请联系公司获取最新激活码,测试时可注释此行,未激活将只能使用24小时,切记上线前一定记得激活!!!");
+ }
+ }
+
+ ///
+ /// 添加PLC信息
+ ///
+ ///
+ ///
+ ///
+ public SiemensS7 SetPlcs(List plcs) where T : class
+ {
+ if (plcs == null || plcs.Count == 0)
+ {
+ throw new Exception("传入数据为空。");
+ }
+ Type type = typeof(T);
+ var properties = type.GetProperties();
+ /*定义两个存储属性的变量*/
+ PropertyInfo? plcIdProperty = null;
+ PropertyInfo? plcIPProperty = null;
+ PropertyInfo? plcKindProperty = null;
+ PropertyInfo? rackProperty = null;
+ PropertyInfo? soltindProperty = null;
+ /*轮询查找到的属性给变量赋值*/
+ foreach (var property in properties)
+ {
+ var plcIdattributes = property.GetCustomAttributes(typeof(PlcIdAttribute), false);
+ if (plcIdattributes.Length != 0)
+ {
+ plcIdProperty = property;
+ }
+ var plcIPattributes = property.GetCustomAttributes(typeof(PlcIPAttribute), false);
+ if (plcIPattributes.Length != 0)
+ {
+ plcIPProperty = property;
+ }
+ var plcKindattributes = property.GetCustomAttributes(typeof(PlcKindAttribute), false);
+ if (plcKindattributes.Length != 0)
+ {
+ plcKindProperty = property;
+ }
+ var rackattributes = property.GetCustomAttributes(typeof(RackAttribute), false);
+ if (rackattributes.Length != 0)
+ {
+ rackProperty = property;
+ }
+ var soltattributes = property.GetCustomAttributes(typeof(SlotAttribute), false);
+ if (soltattributes.Length != 0)
+ {
+ soltindProperty = property;
+ }
+ }
+ /*判断是否有对应的特性*/
+ if (plcIdProperty == null || plcIPProperty == null || plcKindProperty == null)
+ {
+ throw new Exception("未正确识别类中的属性特性,需要同时添加 PlcIdAttribution、PlcIPAttribute 和 PlcKindAttribute 三个特性。");
+ }
+ /*添加对应的值*/
+ foreach (T plc in plcs)
+ {
+ var plckind = plcKindProperty.GetValue(plc)!.ToString().ToPlcKind();
+ var plcip = plcIPProperty.GetValue(plc)!.ToString();
+
+ SiemensS7Connection siemensS7Connection = new()
+ {
+ PlcId = Convert.ToInt32(plcIdProperty.GetValue(plc)),
+ SiemensS7 = new SiemensS7Net(plckind, plcip)
+ };
+ siemensS7Connection.SiemensS7.Rack = Convert.ToByte(rackProperty!.GetValue(plc));
+ siemensS7Connection.SiemensS7.Slot = Convert.ToByte(soltindProperty!.GetValue(plc));
+ siemensS7Connections.Add(siemensS7Connection);
+ }
+ return this;
+ }
+
+ ///
+ /// 添加PLC的Db地址信息
+ ///
+ ///
+ ///
+ ///
+ public SiemensS7 SetPlcDB(List? dbNames) where T : class
+ {
+ if (dbNames == default || dbNames.Count == 0)
+ {
+ throw new Exception("传入的数据为空");
+ }
+ Type type = typeof(T);
+ var properties = type.GetProperties();
+ /*定义两个存储属性的变量*/
+ PropertyInfo? plcIdProperty = null;
+ PropertyInfo? dbNameProperty = null;
+ PropertyInfo? dbAddressProperty = null;
+ /*轮询查找到的属性给变量赋值*/
+ foreach (var property in properties)
+ {
+ var plcIdattributes = property.GetCustomAttributes(typeof(PlcIdAttribute), false);
+ if (plcIdattributes.Length != 0)
+ {
+ plcIdProperty = property;
+ }
+ var dbNameattributes = property.GetCustomAttributes(typeof(PlcDBNameAttribute), false);
+ if (dbNameattributes.Length != 0)
+ {
+ dbNameProperty = property;
+ }
+ var dbAddressattributes = property.GetCustomAttributes(typeof(PlcDBAddressAttribute), false);
+ if (dbAddressattributes.Length != 0)
+ {
+ dbAddressProperty = property;
+ }
+ }
+ /*判断是否有对应的特性*/
+ if (plcIdProperty == null || dbNameProperty == null || dbAddressProperty == null)
+ {
+ throw new Exception("未正确识别类中的属性特性,需要同时添加 PlcIdAttribute、PlcDBNameAttribute、PlcDBAddressAttribute 三个特性。");
+ }
+ /*添加对应的值*/
+ foreach (T dbName in dbNames)
+ {
+ PlcDBName plcDBName = new()
+ {
+ PlcId = Convert.ToUInt32(plcIdProperty.GetValue(dbName)),
+ DBName = dbNameProperty.GetValue(dbName)!.ToString(),
+ };
+ var dbaddress = dbAddressProperty.GetValue(dbName);
+ plcDBName.DBAddress = dbaddress == null ? "" : dbaddress.ToString();
+ plcDBNames.Add(plcDBName);
+ }
+ return this;
+ }
+
+
+ ///
+ /// 连接PLC
+ ///
+ ///
+ /// 请使用异步重载方法
+ ///
+ public SemS7Result ConnectPlcs()
+ {
+ if (siemensS7Connections.Count == 0)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = "没有设置PLC连接,请先调用 SetPlcs 方法。"
+ };
+ }
+ /*连接PLC*/
+ foreach (SiemensS7Connection siemensS7Connection in siemensS7Connections)
+ {
+ if (siemensS7Connection.SiemensS7 == default)
+ {
+ continue;
+ }
+ siemensS7Connection.SiemensS7.ConnectTimeOut = 2000;
+ var connectResult = siemensS7Connection.SiemensS7.ConnectServer();
+ if (!connectResult.IsSuccess)
+ {
+ // 只要有一个连接失败,直接返回错误信息
+ connectResult.Message =
+ $"PLC:{siemensS7Connection.SiemensS7.IpAddress} 连接失败,异常信息:{connectResult.Message}";
+ return connectResult.ToSemS7Result();
+ }
+ }
+ return new SemS7Result()
+ {
+ Success = true,
+ ErrCode = 0,
+ Message = "所有PLC连接成功"
+ };
+ }
+
+ #region 根据名称读写PLC数据
+
+
+ ///
+ /// 根据名称写入PLC值,目前不支持 string
+ /// 写入前请提前转换好对应的数据格式
+ ///
+ ///
+ ///
+ ///
+ public (SemS7Result result, byte[]? bytes) WritePlcWhithName(string plcDBName, params object[] values)
+ {
+ if (values.Length == 0)
+ {
+ return (new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 997,
+ Message = $"写入失败,传入的值为空。"
+ }, default);
+ }
+ /*根据名称获取地址*/
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return (new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ }, default);
+ }
+ (Exception? Ex, byte[]? bytes) getByte = GetPlcBytes(values);
+ if (getByte.Ex != null)
+ {
+ return (new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 996,
+ Message = $"{getByte.Ex.Message}"
+ }, default);
+ }
+ byte[]? bytes = getByte.bytes;//获取转化成功的数组
+ OperateResult operateResult = siemensS7.Write(dbAddress, bytes);
+ return (operateResult.ToSemS7Result(), bytes);
+ }
+
+ ///
+ /// 写入bool值
+ ///
+ ///
+ ///
+ ///
+ public SemS7Result WriteBoolWhithName(string plcDBName, params bool[] values)
+ {
+ if (values.Length == 0)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 997,
+ Message = $"写入失败,传入的值为空。"
+ };
+ }
+ /*根据名称获取地址*/
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ OperateResult operateResult = siemensS7.Write(dbAddress, values);
+ return operateResult.ToSemS7Result();
+ }
+
+ ///
+ /// 根据地址写入值
+ ///
+ /// ///
+ ///
+ ///
+ ///
+ public SemS7Result WritePlcWhithAddress(int plcNo, string plcDBAddress, params object[] values)
+ {
+ if (values.Length == 0)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 997,
+ Message = $"写入失败,传入的值为空。"
+ };
+ }
+ /*根据名称获取地址*/
+ SiemensS7Net? siemensS7 = GetSiemensS7(plcNo);
+ if (siemensS7 == default)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = "找不到该PLC连接"
+ };
+ }
+ (Exception? Ex, byte[]? bytes) getByte = GetPlcBytes(values);
+ if (getByte.Ex != null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 996,
+ Message = $"{getByte.Ex.Message}"
+ };
+ }
+ byte[]? bytes = getByte.bytes;//获取转化成功的数组
+ OperateResult operateResult = siemensS7.Write(plcDBAddress, bytes);
+ return operateResult.ToSemS7Result();
+ }
+
+
+
+ ///
+ /// 根据名称写入PLC值,写入string
+ /// 写入前请提前转换好对应的数据格式
+ ///
+ ///
+ ///
+ /// 自定的编码信息,一般System.Text.Encoding.ASCII即可,中文需要 Encoding.GetEncoding("gb2312")
+ ///
+ public SemS7Result WriteStringWhithName(string plcDBName, string value, Encoding encoding)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.Write(dbAddress, value, encoding).ToSemS7Result();
+ }
+
+ ///
+ /// 读取一个Byte数组
+ ///
+ ///
+ ///
+ ///
+ public SemS7Result ReadByteWithName(string plcDBName, ushort length)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.Read(dbAddress, length).ToSemS7Result();
+ }
+
+ ///
+ /// 读取一个Byte
+ ///
+ ///
+ ///
+ public SemS7Result ReadByteWithName(string plcDBName)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ SemS7Result actionResult = ReadByteWithName(dbAddress!, 1);
+ if (!actionResult.Success)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = actionResult.ErrCode,
+ Message = actionResult.Message
+ };
+ }
+
+ var values = actionResult.Value;
+ if (values == default || values.Length == 0)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = actionResult.ErrCode,
+ Message = actionResult.Message
+ };
+ }
+ return new SemS7Result()
+ {
+ Success = true,
+ ErrCode = actionResult.ErrCode,
+ Message = actionResult.Message,
+ Value = values[0]
+ };
+ }
+
+
+ ///
+ /// 根据名称读取一定数量的Int16值
+ /// 对应PLC数据类型为 W,int,
+ ///
+ ///
+ ///
+ ///
+ public SemS7Result ReadInt16WithName(string plcDBName, ushort length)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadInt16(dbAddress, length).ToSemS7Result();
+ }
+
+
+
+ ///
+ /// 根据名称读取一个Int16值
+ /// 对应PLC数据类型为 W,int,
+ ///
+ ///
+ ///
+ public SemS7Result ReadInt16WithName(string plcDBName)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadInt16(dbAddress).ToSemS7Result();
+ }
+
+ ///
+ /// 根据名称读取一定数量的Int32值
+ /// 对应PLC数据类型为 DW,Dint,
+ ///
+ ///
+ ///
+ ///
+ public SemS7Result ReadInt32WithName(string plcDBName, ushort length)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadInt32(dbAddress, length).ToSemS7Result();
+ }
+
+ ///
+ /// 根据名称读取一个Int32值
+ /// 对应PLC数据类型为 DW,Dint,
+ ///
+ ///
+ ///
+ public SemS7Result ReadInt32WithName(string plcDBName)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadInt32(dbAddress).ToSemS7Result();
+ }
+
+ public SemS7Result ReadUInt32WithName(string plcDBName)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadUInt32(dbAddress).ToSemS7Result();
+ }
+
+ ///
+ /// 根据名称读取一定数量的bool值
+ /// 对应PLC数据类型为 X
+ ///
+ ///
+ /// ///
+ ///
+ public SemS7Result ReadBoolWithName(string plcDBName, ushort length)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadBool(dbAddress, length).ToSemS7Result();
+ }
+
+ ///
+ /// 根据名称读取一个Int32值
+ /// 对应PLC数据类型为 X
+ ///
+ ///
+ ///
+ public SemS7Result ReadBoolWithName(string plcDBName)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadBool(dbAddress).ToSemS7Result();
+ }
+
+ ///
+ /// 根据名称读取string值
+ /// 对应PLC数据类型为 string
+ ///
+ ///
+ ///
+ /// 自定的编码信息,一般System.Text.Encoding.ASCII即可,中文需要 Encoding.GetEncoding("gb2312")
+ ///
+ public SemS7Result ReadStringWithName(string plcDBName, ushort length, Encoding encoding)
+ {
+ (SiemensS7Net? siemensS7, string? dbAddress, string? errText) = GetSiemensS7(plcDBName);
+ if (siemensS7 == null)
+ {
+ return new SemS7Result()
+ {
+ Success = false,
+ ErrCode = 999,
+ Message = errText
+ };
+ }
+ return siemensS7.ReadString(dbAddress, length, encoding).ToSemS7Result();
+ }
+
+
+ ///
+ /// 根据DB名称查找其对应的连接
+ ///
+ ///
+ ///
+ private (SiemensS7Net? siemensS7, string? dbAddress, string? errText) GetSiemensS7(string dbName)
+ {
+ if (plcDBNames.Count == 0 || siemensS7Connections.Count == 0)
+ {
+ return (null, null, "未设置 plc 或者 未设置 DB地址,请调用 SetPlcs 方法设置 plc 或者 调用 SetPlcDB 方法设置 DB地址");
+ }
+ /*找出该地址对应的ID*/
+ PlcDBName? plcDBName = plcDBNames.Find(f => f.DBName == dbName);
+ if (plcDBName == default)
+ {
+ return (null, null, "该DB地址不存在,请核实wcs数据录入是否正确");
+ }
+ /*找出该ID对应的连接*/
+ SiemensS7Connection? siemensS7Connection = siemensS7Connections.Find(f => f.PlcId == plcDBName.PlcId);
+ if (siemensS7Connection == default)
+ {
+ return (null, null, "该PLC连接不存在,请核实wcs数据录入是否正确");
+ }
+ return (siemensS7Connection.SiemensS7, plcDBName.DBAddress, null);
+ }
+
+
+ ///
+ /// 根据plcNo 返回连接信息
+ ///
+ ///
+ ///
+ private SiemensS7Net? GetSiemensS7(int plcNo)
+ {
+ /*找出该ID对应的连接*/
+ SiemensS7Connection? siemensS7Connection = siemensS7Connections.Find(f => f.PlcId == plcNo);
+ if (siemensS7Connection == default)
+ {
+ return default;
+ }
+ return siemensS7Connection.SiemensS7;
+ }
+
+ #endregion
+
+
+ //NetworkDoubleBase dataTransfrom = new NetworkDoubleBase();
+ private readonly SiemensS7Net dataTransfrom = new(SiemensPLCS.S1500);
+
+ #region 将 byte 数组转化为值
+
+
+ ///
+ /// 将数组转化为值
+ ///
+ ///
+ ///
+ ///
+ ///
+ public object? Trans(byte[] bytes, int index) where T : struct
+ {
+ Type type = typeof(T);
+ if (type == typeof(short))
+ {
+ return dataTransfrom.ByteTransform.TransInt16(bytes, index);
+ }
+ else if (type == typeof(int))
+ {
+ return dataTransfrom.ByteTransform.TransInt32(bytes, index);
+ }
+ else if (type == typeof(bool))
+ {
+ return dataTransfrom.ByteTransform.TransBool(bytes, index);
+ }
+ else if (type == typeof(double))
+ {
+ return dataTransfrom.ByteTransform.TransDouble(bytes, index);
+ }
+ else if (type == typeof(float))
+ {
+ return dataTransfrom.ByteTransform.TransSingle(bytes, index);
+ }
+ else if (type == typeof(uint))
+ {
+ return dataTransfrom.ByteTransform.TransUInt32(bytes, index);
+ }
+ else if (type == typeof(ushort))
+ {
+ return dataTransfrom.ByteTransform.TransUInt16(bytes, index);
+ }
+ else
+ {
+ return null; // 不支持的数据类型
+ }
+
+ }
+
+ #endregion
+
+
+ #region 将传入的值转化成 byte 数组
+ ///
+ /// 将传入的值转化成byte数组
+ ///
+ ///
+ ///
+ public (Exception? Ex, byte[]? bytes) GetPlcBytes(object[] values)
+ {
+ List bytes = [];
+ foreach (object value in values)
+ {
+ Type type = value.GetType();
+ if (type == typeof(short))
+ {
+ short va = Convert.ToInt16(value);
+ byte[] data = dataTransfrom.ByteTransform.TransByte(va);
+ bytes.AddRange(data);
+ }
+ else if (type == typeof(int))
+ {
+ int va = Convert.ToInt32(value);
+ byte[] data = dataTransfrom.ByteTransform.TransByte(va);
+ bytes.AddRange(data);
+ }
+ else if (type == typeof(bool))
+ {
+ bool va = Convert.ToBoolean(value);
+ byte[] data = dataTransfrom.ByteTransform.TransByte(va);
+ bytes.AddRange(data);
+ }
+ else if (type == typeof(double))
+ {
+ double va = Convert.ToDouble(value);
+ byte[] data = dataTransfrom.ByteTransform.TransByte(va);
+ bytes.AddRange(data);
+ }
+ else if (type == typeof(float))
+ {
+ float va = Convert.ToSingle(value);
+ byte[] data = dataTransfrom.ByteTransform.TransByte(va);
+ bytes.AddRange(data);
+ }
+ else if (type == typeof(uint))
+ {
+ uint va = Convert.ToUInt32(value);
+ byte[] data = dataTransfrom.ByteTransform.TransByte(va);
+ bytes.AddRange(data);
+ }
+ else if (type == typeof(ushort))
+ {
+ ushort va = Convert.ToUInt16(value);
+ byte[] data = dataTransfrom.ByteTransform.TransByte(va);
+ bytes.AddRange(data);
+ }
+ else
+ {
+ return (new Exception($"传入的数据中有不支持的数据类型 {type.Name} "), null);
+ }
+ }
+ return (null, [.. bytes]);
+ }
+
+ #endregion
+
+
+ #region 根据名称和偏移量返回地址
+
+ ///
+ /// 根据名称和偏移量返回地址
+ ///
+ ///
+ ///
+ ///
+ public string GetAddressWithNameAndBit(string dbName, int moveBit)
+ {
+ /*
+ * 1、判断有几个点
+ * 有一个点的不是bool值
+ * 有两个点的是bool值
+ * 必须写全,如DB100等价于DB100.0,但不允许写DB100,因为容易识别错误
+ */
+ if (plcDBNames.Count == 0)
+ {
+ return string.Empty; // 没有注册DB地址,
+ }
+ /*找出该地址对应的ID*/
+ PlcDBName? plcDBName = plcDBNames.Find(f => f.DBName == dbName);
+ if (plcDBName == default)
+ {
+ return string.Empty; // 找不到DB地址
+ }
+
+ string startDBAddress = plcDBName.DBAddress ?? string.Empty;
+ string[] dbInfos = startDBAddress.Split('.');
+ if (dbInfos.Length == 2)
+ {
+ // 只有一个点,判断为非Bool值
+ int startPoint = Convert.ToInt32(dbInfos[1]);
+ string newDBAddress = $"{dbInfos[0]}.{startPoint + moveBit}";
+ return newDBAddress;
+ }
+ else if (dbInfos.Length == 3)
+ {
+ // 有两个点,判断为bool值
+ int bigAddress = Convert.ToInt32(dbInfos[1]);
+ int smallAddress = Convert.ToInt32(dbInfos[2]);
+ while (moveBit > 0)
+ {
+ smallAddress++;
+ if (smallAddress >= 8)
+ {
+ bigAddress++;
+ smallAddress = 0;
+ }
+ moveBit--;
+ }
+
+ return $"{dbInfos[0]}.{bigAddress}.{smallAddress}";
+ }
+
+ return string.Empty;
+ }
+
+
+ #endregion
+
+
+
+}
\ No newline at end of file
diff --git a/Tools/SocketTool/Entity/ExecuteResult.cs b/Tools/SocketTool/Entity/ExecuteResult.cs
new file mode 100644
index 0000000..bbcd00a
--- /dev/null
+++ b/Tools/SocketTool/Entity/ExecuteResult.cs
@@ -0,0 +1,68 @@
+namespace SocketTool.Entity;
+
+public class ExecuteResult
+{
+ public ExecuteResult() { }
+
+ public ExecuteResult(bool? isSuccess, string? errMeg)
+ {
+ IsSuccess = isSuccess;
+ ErrorMessage = errMeg;
+ }
+ ///
+ /// 是否成功
+ ///
+ public bool? IsSuccess
+ {
+ get;
+ set;
+ }
+ ///
+ /// 错误信息
+ ///
+ public string? ErrorMessage
+ {
+ get;
+ set;
+ }
+ ///
+ /// 返回信息
+ ///
+ public object? ReturnInfo
+ {
+ get;
+ set;
+ }
+}
+
+///
+/// 信息的返回类
+///
+/// 返回的结果泛型
+public class ExecuteResult where T : class
+{
+ ///
+ /// 是否成功
+ ///
+ public bool? IsSuccess
+ {
+ get;
+ set;
+ }
+ ///
+ /// 错误信息
+ ///
+ public string? ErrorMessage
+ {
+ get;
+ set;
+ }
+ ///
+ /// 返回信息
+ ///
+ public T? ReturnInfo
+ {
+ get;
+ set;
+ }
+}
\ No newline at end of file
diff --git a/Tools/SocketTool/Entity/ScanCodeClass.cs b/Tools/SocketTool/Entity/ScanCodeClass.cs
new file mode 100644
index 0000000..2883314
--- /dev/null
+++ b/Tools/SocketTool/Entity/ScanCodeClass.cs
@@ -0,0 +1,44 @@
+namespace SocketTool.Entity;
+
+public class ScanCodeClass
+{
+ ///
+ /// 传入数据的IP地址
+ ///
+ public string? IpAddress
+ {
+ get;
+ set;
+ }
+ ///
+ /// 整数性扫码编号,请勿混淆
+ ///
+ public int ScanID
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// 条码
+ ///
+ public string? Code
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// 字符串格式的扫码编号,请勿混淆
+ ///
+ public string? StrScanID
+ {
+ get;
+ set;
+ }
+
+ public override string ToString()
+ {
+ return $"({StrScanID}){Code}";
+ }
+}
\ No newline at end of file
diff --git a/Tools/SocketTool/Entity/SocketModel.cs b/Tools/SocketTool/Entity/SocketModel.cs
new file mode 100644
index 0000000..a4d3473
--- /dev/null
+++ b/Tools/SocketTool/Entity/SocketModel.cs
@@ -0,0 +1,41 @@
+using System.Net;
+using System.Net.Sockets;
+
+namespace SocketTool.Entity;
+
+public class SocketModel
+{
+
+ ///
+ /// socket信息
+ ///
+ public Socket? Socket
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// 连接的远端IP
+ ///
+ public IPEndPoint? HostEP { get; set; }
+
+ ///
+ /// 这个socket所在的线程
+ ///
+ public Thread? Thread
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// 连接的socket地址
+ ///
+ public string? SocketIp { get; set; }
+
+ ///
+ /// 是否连接
+ ///
+ public bool IsConnected { get; set; }
+}
\ No newline at end of file
diff --git a/Tools/SocketTool/SocketClient.cs b/Tools/SocketTool/SocketClient.cs
new file mode 100644
index 0000000..c325dbc
--- /dev/null
+++ b/Tools/SocketTool/SocketClient.cs
@@ -0,0 +1,362 @@
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Text.RegularExpressions;
+using SocketTool.Entity;
+
+namespace SocketTool;
+
+///
+/// socket 客户端 .net6 版
+///
+public class SocketClient
+{
+ #region 全局变量
+
+ private List NeedConnectSockets = []; // 需要连接的socket
+
+ int IPCount;//传入的连接数
+
+ #endregion
+
+ #region 全局属性
+ ///
+ /// 字符串解析格式
+ ///
+ private Encoding? Encod { get; set; }
+ #endregion
+
+ ///
+ /// socket连接类,自带自动重连功能
+ /// 传入参数示例:127.0.0.1:8090
+ ///
+ ///
+ ///
+ ///
+ public SocketClient(Encoding? encoding, params string?[] IPPorts)
+ {
+ Encod = encoding;
+ IPCount = IPPorts.Length;//数量赋值
+ foreach (string? IPPort in IPPorts)
+ {
+ if (string.IsNullOrEmpty(IPPort))
+ {
+ continue;
+ }
+ string ipAndPort = IPPort.Replace(":", ":");//将中文冒号替换成英文冒号
+ if (!ipAndPort.Contains(':'))
+ {
+ // 不含有端口号的直接抛异常,必须处理
+ throw new Exception($"地址:{IPPort} 格式不正确,必须处理以后才能正常运行。");
+ }
+ string[] ipp = ipAndPort.Split(':');
+ if (ipp.Length != 2 || string.IsNullOrEmpty(ipp[0]) || string.IsNullOrEmpty(ipp[1]))
+ {
+ // 拆分后没有地址或者端口号的直接抛异常,必须处理
+ throw new Exception($"地址:{IPPort} 格式不正确,必须处理以后才能正常运行。");
+ }
+ string IP = ipp[0];
+ int Port = CheckIP(IP, ipp[1]);
+ if (Port != 0)
+ {
+ Socket socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ NeedConnectSockets.Add(new SocketModel()
+ {
+ Socket = socket,
+ SocketIp = IPPort,
+ IsConnected = false,
+ HostEP = new IPEndPoint(IPAddress.Parse(IP), Port)
+ });
+ }
+ }
+ }
+ ///
+ /// 检查IP地址和端口号是否满足格式
+ /// 如果格式错误返回0,否则返回Int格式的端口号
+ ///
+ ///
+ ///
+ ///
+ private static int CheckIP(string? IP, string? Portstr)
+ {
+ if (string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(Portstr))
+ {
+ throw new Exception("传入的IP或者端口存在异常");
+ }
+ int Port;//int格式的端口号
+ try
+ {
+ Port = Convert.ToInt32(Portstr);
+ }
+ catch
+ {
+ return 0;
+ }
+ string CheckString = "^((1[0-9][0-9]\\.)|(2[0-4][0-9]\\.)|(25[0-5]\\.)|([1-9][0-9]\\.)|([0-9]\\.)){3}((1[0-9][0-9])|(2[0-4][0-9])|(25[0-5])|([1-9][0-9])|([0-9]))$";
+ bool IsIPOK = Regex.IsMatch(IP, CheckString);
+ if (!IsIPOK || Port < 1 || Port > 65535)
+ {
+ throw new Exception($"地址:{IP} 的端口号:{Portstr} 格式不正确,必须处理以后才能正常运行。");
+ }
+ return Port;
+ }
+
+ ///
+ /// 连接事件,需要调用
+ ///
+ public void Connect()
+ {
+ if (NeedConnectSockets.Count < 1)
+ {
+ return;
+ }
+ // 连接 socket
+ foreach (SocketModel needConnectSocket in NeedConnectSockets)
+ {
+ Thread connectSocket = new(() =>
+ {
+ ConnectSocket(needConnectSocket);
+ })
+ {
+ IsBackground = true
+ };
+ connectSocket.Start();
+ //Task.Factory.StartNew(()=>ConnectSocket(needConnectSocket));
+ }
+ // 启用重连
+ Thread reConnectSocket = new(ReConnectSocket)
+ {
+ IsBackground = true
+ };
+ reConnectSocket.Start();
+ //Task.Factory.StartNew(ReConnectSocket);
+ }
+ ///
+ /// 连接 socket
+ ///
+ ///
+ private void ConnectSocket(SocketModel socketInfo)
+ {
+ while (true)//此循环经本人考虑再三后加上,去掉此循环将导致=>在服务端未开启的情况下开启客户端,后面服务端开启,虽然可以通过下方重连连上服务端,但无法接受数据
+ {
+ try
+ {
+ SocketConnecting?.Invoke(socketInfo.SocketIp ?? "");//触发连接中事件
+ socketInfo.Socket!.Connect(socketInfo.HostEP!);//尝试连接
+ SocketOnline?.Invoke(socketInfo.SocketIp ?? "");//触发连接成功事件
+ socketInfo.Thread = Thread.CurrentThread;
+ socketInfo.IsConnected = true;
+ break;
+ }
+ catch (Exception ex)
+ {
+ SocketConnectFail?.Invoke(socketInfo.SocketIp ?? "", ex);//出发连接中事件
+ Thread.Sleep(2000);
+ }
+ }
+ Socket socket = socketInfo.Socket; // 拉取地址
+ while (true)
+ {
+ byte[] recvBytes = new byte[1024 * 1024];
+ try
+ {
+ int bytes = socket.Receive(recvBytes, recvBytes.Length, SocketFlags.None);
+ if (bytes <= 0) continue;
+ GetTcpData?.BeginInvoke(recvBytes, socketInfo.SocketIp ?? "", null, null);
+ if (GetTcpData != null) continue;
+ string? recvStr = Encod?.GetString(recvBytes, 0, bytes); //此处编码方式请根据服务端发送的编码方式修改对应,否则可能造成部分字符乱码
+ if (string.IsNullOrEmpty(recvStr)) continue;
+ if (recvStr.Trim().Length > 0)
+ {
+ GetSocketMessage?.Invoke(recvStr, socketInfo.SocketIp ?? "");
+ if (HandleCodeInfo != null)
+ {
+ ManCode(recvStr, socketInfo.SocketIp ?? ""); //处理条码并触发其他事件
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _ = ex;
+ RecevErrEvent?.Invoke(socketInfo.SocketIp ?? "", ex);
+ socketInfo.IsConnected = false;
+ return;
+ }
+ }
+ }
+
+
+ ///
+ /// 重新连接 Socket
+ ///
+ private void ReConnectSocket()
+ {
+ Thread.Sleep(5000);
+ while (true)
+ {
+ foreach (SocketModel needConnectSocket in NeedConnectSockets)
+ {
+ Socket socket = needConnectSocket.Socket!;
+ Thread.Sleep(300);
+ try
+ {
+ try
+ {
+ socket.SendTimeout = 1000;
+ socket.Send(Encoding.ASCII.GetBytes(" "));
+ if (!socket.Connected)
+ {
+ needConnectSocket.IsConnected = false;
+ }
+ }
+ catch (Exception ex)
+ {
+ _ = ex.ToString();
+ SocketOffline?.Invoke(needConnectSocket.SocketIp ?? ""); //触发掉线事件
+ try
+ {
+ socket.Close(); //关闭已经断开的socket
+ }
+ catch (Exception exception)
+ {
+ _ = exception;
+ }
+
+ Thread connectSocket = new(() =>
+ {
+ ConnectSocket(needConnectSocket);
+ })
+ {
+ IsBackground = true
+ };
+ connectSocket.Start();
+ //Task.Factory.StartNew(() => ConnectSocket(needConnectSocket));
+ }
+ }
+ catch (Exception ex)
+ {
+ _ = ex.ToString();
+ }
+ }
+ }
+
+ }
+
+
+
+
+
+ ///
+ /// 处理收到的条码,并引发事件
+ ///
+ ///
+ ///
+ private void ManCode(string? code, string? IPAddress)
+ {
+ //多线程处理,增加程序运行速度
+ ThreadPool.QueueUserWorkItem((useless) =>
+ {
+ List? scanCodeClasses = SplitCode(code, IPAddress);
+ if (scanCodeClasses != default)
+ {
+ foreach (ScanCodeClass scc in scanCodeClasses)
+ {
+ HandleCodeInfo?.Invoke(scc);
+ }
+ }
+ });
+ }
+ ///
+ /// 拆条码,将前缀和条码拆下来
+ ///
+ ///
+ ///
+ ///
+ private List? SplitCode(string? GetCode, string? Ipaddress)
+ {
+ if (string.IsNullOrEmpty(GetCode) || string.IsNullOrEmpty(Ipaddress))
+ {
+ return default;
+ }
+ if (!GetCode.Contains('('))
+ {
+ return default;
+ }
+ List sccs = [];
+ string[] GetCodeCuts = GetCode.Split('(');
+ foreach (string GetCodeCut in GetCodeCuts)
+ {
+ if (GetCodeCut == "" || GetCodeCut.Trim().Length == 0 || !GetCodeCut.Contains(')')) { continue; }
+ string[] ScanCode = GetCodeCut.Split(')');
+ if (ScanCode.Length < 2) { continue; }
+ ScanCodeClass scc = new()
+ {
+ IpAddress = Ipaddress,
+ ScanID = Convert.ToInt32(ScanCode[0]),
+ StrScanID = ScanCode[0],
+ Code = ScanCode[1]
+ };
+ sccs.Add(scc);
+ }
+ return sccs;
+ }
+
+ #region 事件
+
+ public delegate void HandleInfo(ScanCodeClass scc);
+ ///
+ /// 条码处理事件,
+ /// ScanID或者ScanIDStr为null的是没有前缀的条码
+ ///
+ public event HandleInfo? HandleCodeInfo;
+
+
+
+ public delegate void GetMessage(string Message, string IPAddress);
+ ///
+ /// 条码处理事件,
+ ///
+ public event GetMessage? GetSocketMessage;
+
+
+ public delegate void GetData(byte[] data, string IPAddress);
+ ///
+ /// 字节返回事件
+ ///
+ public event GetData? GetTcpData;
+
+
+ public delegate void OffLine(string IPAddress);
+ ///
+ /// 当有地址掉线时触发
+ ///
+ public event OffLine? SocketOffline;
+
+ public delegate void OnLine(string IPAddress);
+ ///
+ /// 当地址连接成功时触发
+ ///
+ public event OnLine? SocketOnline;
+
+ public delegate void Connecting(string IPAddress);
+ ///
+ /// 当地址连接正在连接时触发
+ ///
+ public event Connecting? SocketConnecting;
+
+ public delegate void ConnectFail(string IPAddress, Exception ex);
+ ///
+ /// 当地址连接正在连接时触发
+ ///
+ public event ConnectFail? SocketConnectFail;
+
+ public delegate void RecevErr(string IPAddress, Exception ex);
+ ///
+ /// 当地址连接接收数据异常时触发
+ ///
+ public event RecevErr? RecevErrEvent;
+ #endregion
+
+
+
+}
\ No newline at end of file
diff --git a/Tools/SocketTool/SocketTool.csproj b/Tools/SocketTool/SocketTool.csproj
new file mode 100644
index 0000000..22e1b2e
--- /dev/null
+++ b/Tools/SocketTool/SocketTool.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0
+ enable
+ enable
+ AnyCPU;x64;x86
+
+
+
diff --git a/WcsMain/.config/dotnet-tools.json b/WcsMain/.config/dotnet-tools.json
new file mode 100644
index 0000000..6b93cca
--- /dev/null
+++ b/WcsMain/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "7.0.3",
+ "commands": [
+ "dotnet-ef"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/WcsMain/ApiClient/DataEntity/WmsEntity/ApplyInRequest.cs b/WcsMain/ApiClient/DataEntity/WmsEntity/ApplyInRequest.cs
new file mode 100644
index 0000000..a96c3da
--- /dev/null
+++ b/WcsMain/ApiClient/DataEntity/WmsEntity/ApplyInRequest.cs
@@ -0,0 +1,28 @@
+namespace WcsMain.ApiClient.DataEntity.WmsEntity;
+
+///
+/// 申请入库
+///
+public class ApplyInRequest
+{
+ ///
+ /// 申请点位
+ ///
+ public string? Point { get; set; }
+
+ ///
+ /// 载具号
+ ///
+ public string? VehicleNo { get; set; }
+
+ ///
+ /// 条码信息
+ ///
+ public string? CodeMessage { get; set; }
+
+ ///
+ /// 备注
+ ///
+ public string? Remark { get; set; }
+
+}
\ No newline at end of file
diff --git a/WcsMain/ApiClient/DataEntity/WmsEntity/SendWmsTaskStatusRequest.cs b/WcsMain/ApiClient/DataEntity/WmsEntity/SendWmsTaskStatusRequest.cs
new file mode 100644
index 0000000..16600c6
--- /dev/null
+++ b/WcsMain/ApiClient/DataEntity/WmsEntity/SendWmsTaskStatusRequest.cs
@@ -0,0 +1,40 @@
+using System.Text.Json.Serialization;
+
+namespace WcsMain.ApiClient.DataEntity.WmsEntity;
+
+///
+/// 发送WMS任务状态请求实体
+///
+public class SendWmsTaskStatusRequest
+{
+ ///
+ /// 任务号
+ ///
+ [JsonPropertyName("taskId")]
+ public string? TaskId { get; set; }
+
+ ///
+ /// 任务状态
+ ///
+ [JsonPropertyName("taskStatus")]
+ public int? TaskStatus { get; set; }
+
+ ///
+ /// 任务类型
+ ///
+ [JsonPropertyName("destination")]
+ public string? Destination { get; set; }
+
+ ///
+ /// 载具号
+ ///
+ [JsonPropertyName("vehicleNo")]
+ public string? VehicleNo { get; set; }
+
+ ///
+ /// 信息
+ ///
+ [JsonPropertyName("message")]
+ public string? Message { get; set; }
+
+}
\ No newline at end of file
diff --git a/WcsMain/ApiClient/DataEntity/WmsEntity/UploadPickStandRequest.cs b/WcsMain/ApiClient/DataEntity/WmsEntity/UploadPickStandRequest.cs
new file mode 100644
index 0000000..07be159
--- /dev/null
+++ b/WcsMain/ApiClient/DataEntity/WmsEntity/UploadPickStandRequest.cs
@@ -0,0 +1,27 @@
+using System.Text.Json.Serialization;
+
+namespace WcsMain.ApiClient.DataEntity.WmsEntity;
+
+///
+/// 上传箱子到达拣选口的请求类
+///
+public class UploadPickStandRequest
+{
+ ///
+ /// 载具号
+ ///
+ [JsonPropertyName("vehicleNo")]
+ public string? VehicleNo { get; set; }
+
+ ///
+ /// 拣选站台
+ ///
+ [JsonPropertyName("pickStand")]
+ public string? PickStand { get; set; }
+
+ ///
+ /// 备注
+ ///
+ [JsonPropertyName("remark")]
+ public string? Remark { get; set; }
+}
\ No newline at end of file
diff --git a/WcsMain/ApiClient/DataEntity/WmsEntity/WmsResponse.cs b/WcsMain/ApiClient/DataEntity/WmsEntity/WmsResponse.cs
new file mode 100644
index 0000000..ba6fec1
--- /dev/null
+++ b/WcsMain/ApiClient/DataEntity/WmsEntity/WmsResponse.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace WcsMain.ApiClient.DataEntity.WmsEntity;
+
+public class WmsResponse
+{
+ ///
+ /// 代码
+ ///
+ [JsonPropertyName("code")]
+ public int? Code { get; set; }
+
+ ///
+ /// 信息
+ ///
+ [JsonPropertyName("message")]
+ public string? Message { get; set; }
+}
\ No newline at end of file
diff --git a/WcsMain/ApiServe/ControllerFilter/ExceptionFilter/WcsExceptionFilterAttribute.cs b/WcsMain/ApiServe/ControllerFilter/ExceptionFilter/WcsExceptionFilterAttribute.cs
new file mode 100644
index 0000000..bed7e56
--- /dev/null
+++ b/WcsMain/ApiServe/ControllerFilter/ExceptionFilter/WcsExceptionFilterAttribute.cs
@@ -0,0 +1,27 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using WcsMain.ApiServe.Factory;
+
+namespace WcsMain.ApiServe.ControllerFilter.ExceptionFilter;
+
+///
+/// Wcs 接口异常处理
+///
+public class WcsExceptionFilterAttribute : ExceptionFilterAttribute
+{
+ public override void OnException(ExceptionContext context)
+ {
+ base.OnException(context);
+ if (context.ExceptionHandled == false)
+ {
+ var response = WcsApiResponseFactory.ServiceErr($"服务器异常,参考信息:{context.Exception}");
+ context.Result = new ObjectResult(response)
+ {
+ // 返回状态码设置为200,表示成功
+ StatusCode = StatusCodes.Status200OK,
+ };
+ }
+ context.ExceptionHandled = true;
+ }
+
+}
\ No newline at end of file
diff --git a/WcsMain/ApiServe/ControllerFilter/ResponseFilterAttribute.cs b/WcsMain/ApiServe/ControllerFilter/ResponseFilterAttribute.cs
new file mode 100644
index 0000000..d9819c8
--- /dev/null
+++ b/WcsMain/ApiServe/ControllerFilter/ResponseFilterAttribute.cs
@@ -0,0 +1,118 @@
+using LogTool;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Newtonsoft.Json;
+using WcsMain.DataBase.Dao;
+using WcsMain.DataBase.TableEntity;
+using WcsMain.DataService;
+using WcsMain.WcsAttribute.AutoFacAttribute;
+
+namespace WcsMain.ApiServe.ControllerFilter;
+
+///
+/// 过滤器,记录日志数据
+///
+[Component]
+public class ResponseFilterAttribute(AppApiAcceptDao acceptDao, DataBaseData dataBaseData) : ActionFilterAttribute
+{
+ private readonly DataBaseData _dataBaseData = dataBaseData;
+ private readonly AppApiAcceptDao _acceptDao = acceptDao;
+
+ public override void OnActionExecuting(ActionExecutingContext context)
+ {
+ base.OnActionExecuting(context);
+ //请求的方法,GET,POST
+ string requestMethod = context.HttpContext.Request.Method.ToUpper();
+ //记录进入请求的时间
+ context.RouteData.Values.Add("StartTime", DateTime.Now);
+ string requestStr = string.Empty; // 记录请求值
+ switch (requestMethod)
+ {
+ case "GET":
+ requestStr = JsonConvert.SerializeObject(context.ActionArguments);
+ break;
+ case "POST":
+ bool isHaveRequestObj = context.ActionArguments.TryGetValue("request", out object? requestObj);
+ if (isHaveRequestObj)
+ {
+ requestStr = JsonConvert.SerializeObject(requestObj);
+ }
+ break;
+ case "PUT":
+ goto case "GET";
+ case "PUSH":
+ goto case "GET";
+ case "DELETE":
+ goto case "GET";
+ }
+ context.RouteData.Values.Add("requestData", requestStr);
+ }
+
+
+ public override void OnActionExecuted(ActionExecutedContext context)
+ {
+ base.OnActionExecuted(context);
+
+ /* 获取返回值,封装成JSON返回 */
+ ObjectResult? response = (ObjectResult?)context.Result;
+ var responseValue = response?.Value;
+ string responseStr = JsonConvert.SerializeObject(responseValue); // 返回的JSON字符串
+
+ /* 获取请求值,记下请求日志 */
+ HttpRequest request = context.HttpContext.Request;
+ AppApiAccept accept = new()
+ {
+ AcceptId = _dataBaseData.GetNewUUID(),
+ Path = request.Path.ToString(),
+ Method = request.Method,
+ MediaType = request.ContentType,
+ ClientAddress =
+ $"{context.HttpContext.Connection.RemoteIpAddress}:{context.HttpContext.Connection.RemotePort}",
+ };
+
+ RouteValueDictionary keyValues = request.RouteValues;
+ // 获取请求时间,和当前时间比较,计算接口执行时间
+ bool isHaveStartTime = keyValues.TryGetValue("StartTime", out object? startTimeObj);
+ DateTime endTime = DateTime.Now;
+ if (isHaveStartTime)
+ {
+ DateTime startTime = (DateTime)(startTimeObj ?? new DateTime(1900, 1, 1));
+ accept.RequestTime = startTime;
+ accept.ResponseTime = endTime;
+ TimeSpan span = endTime - startTime;
+ double useTime = span.TotalMilliseconds; //接口用时
+ accept.UseTime = useTime;
+ }
+ else
+ {
+ accept.RequestTime = new DateTime(1900, 1, 1);
+ accept.ResponseTime = endTime;
+ accept.UseTime = 0;
+ }
+ // 获取请求数据,和返回数据
+ var isHaveRequestObject = keyValues.TryGetValue("requestData", out object? requestObj);
+ if (isHaveRequestObject)
+ {
+ string reqMsg = $"{requestObj}";
+ accept.RequestMsg = reqMsg;
+ }
+ else
+ {
+ accept.RequestMsg = "未抓取到请求数据。";
+ }
+ string respMsg = $"{responseStr}";
+ accept.ResponseMsg = respMsg;
+
+ if (context.Exception != null)
+ {
+ accept.ErrMsg = context.Exception.Message;
+ }
+ Task.Factory.StartNew(() =>
+ {
+ WcsLog.Instance().WriteApiAcceptLog(accept.ToString());
+ _acceptDao.Insert(accept); // 插入数据库
+ });
+ }
+
+
+}
\ No newline at end of file
diff --git a/WcsMain/ApiServe/ControllerFilter/WmsApiExceptionFilterAttribute.cs b/WcsMain/ApiServe/ControllerFilter/WmsApiExceptionFilterAttribute.cs
new file mode 100644
index 0000000..38fafbc
--- /dev/null
+++ b/WcsMain/ApiServe/ControllerFilter/WmsApiExceptionFilterAttribute.cs
@@ -0,0 +1,31 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using WcsMain.ApiServe.Controllers.Dto.WMSEntity;
+
+namespace WcsMain.ApiServe.ControllerFilter;
+
+///
+/// 全局异常处理
+///
+public class WmsApiExceptionFilterAttribute : ExceptionFilterAttribute
+{
+
+ public override void OnException(ExceptionContext context)
+ {
+ base.OnException(context);
+ if (context.ExceptionHandled == false)
+ {
+ WmsApiResponse