diff --git a/Sln.Wcs.Common/Sln.Wcs.Common.csproj b/Sln.Wcs.Common/Sln.Wcs.Common.csproj
index fa71b7a..b7cbb41 100644
--- a/Sln.Wcs.Common/Sln.Wcs.Common.csproj
+++ b/Sln.Wcs.Common/Sln.Wcs.Common.csproj
@@ -6,4 +6,8 @@
enable
+
+
+
+
diff --git a/Sln.Wcs.Common/StringChange.cs b/Sln.Wcs.Common/StringChange.cs
new file mode 100644
index 0000000..1060768
--- /dev/null
+++ b/Sln.Wcs.Common/StringChange.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2024 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:LAPTOP-E0N2L34V
+* 命名空间:SlnMesnac.Common
+* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82
+*
+* 创建者:WenJY
+* 电子邮箱:wenjy@mesnac.com
+* 创建时间:2024-03-27 21:58:35
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+namespace Sln.Wcs.Common
+{
+ public class StringChange
+ {
+ ///
+ /// 将字符串强制转换成int,转换失败则返回0
+ ///
+ ///
+ ///
+ public int ParseToInt(string str)
+ {
+ int returnInt = 0;
+ if (str == null || str.Trim().Length < 1)
+ {
+ return returnInt;
+ }
+ if (int.TryParse(str, out returnInt))
+ {
+ return returnInt;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// char数组转Array
+ ///
+ ///
+ ///
+ ///
+ public string CharArrayToString(char[] cha, int len)
+ {
+ string str = "";
+ for (int i = 0; i < len; i++)
+ {
+ str += string.Format("{0}", cha[i]);
+ }
+
+ return str;
+ }
+
+ public string bytesToHexStr(byte[] bytes, int iLen)//e.g. { 0x01, 0x01} ---> " 01 01"
+ {
+ string returnStr = "";
+ if (bytes != null)
+ {
+ for (int i = 0; i < iLen; i++)
+ {
+ returnStr += bytes[i].ToString("X2");
+ }
+ }
+ return returnStr;
+ }
+
+ public byte[] HexStrTorbytes(string strHex)//e.g. " 01 01" ---> { 0x01, 0x01}
+ {
+ strHex = strHex.Replace(" ", "");
+ if ((strHex.Length % 2) != 0)
+ strHex += " ";
+ byte[] returnBytes = new byte[strHex.Length / 2];
+ for (int i = 0; i < returnBytes.Length; i++)
+ returnBytes[i] = Convert.ToByte(strHex.Substring(i * 2, 2), 16);
+ return returnBytes;
+ }
+
+ public string StringToHexString(string s, Encoding encode)
+ {
+ byte[] b = encode.GetBytes(s); //按照指定编码将string编程字节数组
+ string result = string.Empty;
+ for (int i = 0; i < b.Length; i++) //逐字节变为16进制字符,以%隔开
+ {
+ result += "%" + Convert.ToString(b[i], 16);
+ }
+ return result;
+ }
+
+ public string HexStringToString(string hs, Encoding encode)
+ {
+ //以%分割字符串,并去掉空字符
+ string[] chars = hs.Split(new char[] { '%' }, StringSplitOptions.RemoveEmptyEntries);
+ byte[] b = new byte[chars.Length];
+ //逐个字符变为16进制字节数据
+ for (int i = 0; i < chars.Length; i++)
+ {
+ b[i] = Convert.ToByte(chars[i], 16);
+ }
+ //按照指定编码将字节数组变为字符串
+ return encode.GetString(b);
+ }
+
+ public byte[] Swap16Bytes(byte[] OldU16)
+ {
+ byte[] ReturnBytes = new byte[2];
+ ReturnBytes[1] = OldU16[0];
+ ReturnBytes[0] = OldU16[1];
+ return ReturnBytes;
+ }
+
+ /// 64Base码
+ /// 保存路径
+ /// 文件名称
+ ///
+ public bool Base64ToImage(string strbase64, string path, string filename)
+ {
+ bool Flag = false;
+ try
+ {
+ //base64编码的文本 转为 图片
+ //图片名称
+ byte[] arr = Convert.FromBase64String(strbase64);//将指定的字符串(它将二进制数据编码为 Base64 数字)转换为等效的 8 位无符号整数数组。
+ using (MemoryStream ms = new MemoryStream(arr))
+ {
+ Bitmap bmp = new Bitmap(ms);//加载图像
+ if (!Directory.Exists(path))//判断保存目录是否存在
+ {
+ Directory.CreateDirectory(path);
+ }
+ bmp.Save((path + "\\" + filename + ".png"), System.Drawing.Imaging.ImageFormat.Png);//将图片以JPEG格式保存在指定目录(可以选择其他图片格式)
+ ms.Close();//关闭流并释放
+ if (File.Exists(path + "\\" + filename + ".png"))//判断是否存在
+ {
+ Flag = true;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("图片保存失败:" + ex.Message);
+ }
+ return Flag;
+ }
+
+ ///
+ /// 获取时间戳
+ ///
+ ///
+ public long GetTimeStamp()
+ {
+ TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
+ return Convert.ToInt64(ts.TotalSeconds);
+ }
+
+ public byte[] ConvertFloatToINt(byte[] floatBytes)
+ {
+ byte[] intBytes = new byte[floatBytes.Length / 2];
+ for (int i = 0; i < intBytes.Length; i++)
+ {
+ intBytes[i] = floatBytes[i * 2];
+ }
+ return intBytes;
+ }
+
+ //CRC异或校验
+ public byte CalculateVerify(byte[] pMessage, int iLength)
+ {
+ UInt16 i;
+ byte iVerify = 0;
+
+ iVerify = pMessage[0];
+ for (i = 1; i < iLength; i++)
+ {
+ iVerify = (byte)(iVerify ^ pMessage[i]);
+ }
+ return iVerify;
+ }
+
+ public int HexStringToNegative(string strNumber)
+ {
+ int iNegate = 0;
+ int iNumber = Convert.ToInt32(strNumber, 16);
+ if (iNumber > 127)
+ {
+ int iComplement = iNumber - 1;
+ string strNegate = string.Empty;
+ char[] binchar = Convert.ToString(iComplement, 2).PadLeft(8, '0').ToArray();
+ foreach (char ch in binchar)
+ {
+ if (Convert.ToInt32(ch) == 48)
+ {
+ strNegate += "1";
+ }
+ else
+ {
+ strNegate += "0";
+ }
+ }
+ iNegate = -Convert.ToInt32(strNegate, 2);
+ }
+ return iNegate;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Wcs.Model/Sln.Wcs.Model.csproj b/Sln.Wcs.Model/Sln.Wcs.Model.csproj
index 040a94a..5f695b9 100644
--- a/Sln.Wcs.Model/Sln.Wcs.Model.csproj
+++ b/Sln.Wcs.Model/Sln.Wcs.Model.csproj
@@ -8,7 +8,6 @@
-
diff --git a/Sln.Wcs.Plc/Factory/InovanceFactory.cs b/Sln.Wcs.Plc/Factory/InovanceFactory.cs
new file mode 100644
index 0000000..1a00778
--- /dev/null
+++ b/Sln.Wcs.Plc/Factory/InovanceFactory.cs
@@ -0,0 +1,366 @@
+using HslCommunication;
+using HslCommunication.Profinet.Inovance;
+using Sln.Wcs.Common;
+using System;
+using System.Threading.Tasks;
+
+#region << 版 本 注 释 >>
+
+/*--------------------------------------------------------------------
+* 版权所有 (c) 2024 WenJY 保留所有权利。
+* CLR版本:4.0.30319.42000
+* 机器名称:LAPTOP-E0N2L34V
+* 命名空间:SlnMesnac.Plc.Factory
+* 唯一标识:496f8d2b-70e3-4a05-ae18-a9b0fcd06b82
+*
+* 创建者:WenJY
+* 电子邮箱:wenjy@mesnac.com
+* 创建时间:2024-03-27 21:58:35
+* 版本:V1.0.0
+* 描述:
+*
+*--------------------------------------------------------------------
+* 修改人:
+* 时间:
+* 修改说明:
+*
+* 版本:V1.0.0
+*--------------------------------------------------------------------*/
+
+#endregion << 版 本 注 释 >>
+
+namespace Sln.Wcs.Plc.Factory
+{
+ public class InovanceFactory : PlcAbsractFactory
+ {
+ private StringChange _stringChange;
+
+ private InovanceTcpNet inovanceTcp = null;
+
+ public InovanceFactory(StringChange stringChange)
+ {
+ _stringChange = stringChange;
+
+ this.inovanceTcp = new InovanceTcpNet();
+ this.inovanceTcp.ConnectTimeOut = 2000;
+ }
+
+ public override bool IsConnected { get; set; }
+
+ ///
+ /// 建立连接
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool Connect(string ip, int port)
+ {
+ try
+ {
+ inovanceTcp?.ConnectClose();
+ if (inovanceTcp != null)
+ {
+ inovanceTcp.IpAddress = ip;
+ inovanceTcp.Port = port;
+ inovanceTcp.DataFormat = HslCommunication.Core.DataFormat.CDAB;
+
+ OperateResult connect = inovanceTcp.ConnectServer();
+ this.IsConnected = connect.IsSuccess;
+ if (!connect.IsSuccess)
+ {
+ throw new InvalidOperationException($"汇川PLC连接失败:{connect.Message}");
+ }
+
+ return connect.IsSuccess;
+ }
+ else
+ {
+ throw new ArgumentException($"汇川PLC实例inovanceTcp为null");
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"汇川PLC连接异常:{ex.Message}");
+ return false;
+ }
+ }
+
+ ///
+ /// 断开连接
+ ///
+ ///
+ ///
+ public override bool DisConnect()
+ {
+ try
+ {
+ OperateResult disConnect = inovanceTcp.ConnectClose();
+ this.IsConnected = false;
+ if (!disConnect.IsSuccess)
+ {
+ throw new InvalidOperationException($"汇川PLC断开连接失败:{disConnect.Message}");
+ }
+ return disConnect.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"汇川PLC断开连接异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据地址读取指定长度数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override byte[] readValueByAddress(string address, int len)
+ {
+ try
+ {
+ OperateResult read = inovanceTcp.Read(address, (ushort)(len));
+ if (!read.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取指定长度数据失败:{read.Message}");
+ }
+ return _stringChange.ConvertFloatToINt(read.Content);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取指定长度数据异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据地址读取int16数据
+ ///
+ ///
+ ///
+ ///
+ public override int readInt16ByAddress(string address)
+ {
+ try
+ {
+ OperateResult read = inovanceTcp.ReadInt16(address);
+ if (!read.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取int16数据失败:{read.Content}");
+ }
+ return read.Content;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取int16数据异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 根据地址写入int16数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool writeInt16ByAddress(string address, int value)
+ {
+ try
+ {
+ OperateResult operateResult = new OperateResult();
+ int s = 0;
+ string[] strArry = address.Split('.');
+
+ //先读取整个块的内容
+ var info = inovanceTcp.ReadInt16(strArry[0]);
+ if (info.Content == 0)
+ {
+ int length = _stringChange.ParseToInt(strArry[1]) + 1;
+ string[] array = new string[length];
+ for (int i = 0; i < length; i++)
+ {
+ if (i == _stringChange.ParseToInt(strArry[1]))
+ {
+ array[i] = value.ToString();
+ }
+ else
+ {
+ array[i] = "0";
+ }
+ }
+ //反转
+ Array.Reverse(array);
+ byte[] buffer = new byte[array.Length];
+ string result = "";
+ for (int i = 0; i < array.Length; i++)
+ {
+ result += (byte)Convert.ToInt32(array[i], 16);
+ }
+ s = Convert.ToInt32(result.Trim(), 2);
+ operateResult = inovanceTcp.Write(strArry[0], (ushort)s);
+ }
+ else
+ {
+ var inf2 = Convert.ToString(info.Content, 2);
+ string[] infoArray = new string[inf2.Length];
+ for (int i = 0; i < inf2.Length; i++)
+ {
+ infoArray[i] = inf2.Substring(i, 1);
+ }
+ Array.Reverse(infoArray);
+ infoArray[_stringChange.ParseToInt(strArry[1])] = value.ToString();
+ string result = "";
+ foreach (var item in infoArray)
+ {
+ result = result + item;
+ }
+ s = Convert.ToInt32(result.Trim(), 10);
+ operateResult = inovanceTcp.Write(strArry[0], s);
+ }
+ if (!operateResult.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入int16数据失败:{operateResult.Message}");
+ }
+ return operateResult.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入int16数据异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 通过PLC地址读取string类型数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override string readStringByAddress(string address, ushort length)
+ {
+ try
+ {
+ OperateResult read = inovanceTcp.ReadString(address, length);
+ if (!read.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取string数据失败:{read.Content}");
+ }
+ return read.Content;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取string数据异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 通过PLC地址写入String类型数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool writeStringByAddress(string address, string value)
+ {
+ try
+ {
+ OperateResult operateResult = inovanceTcp.Write(address, value);
+ if (!operateResult.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入string数据失败:{operateResult.Message}");
+ }
+ return operateResult.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入string数据异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 通过PLC地址读取Bool类型数据
+ ///
+ ///
+ ///
+ ///
+ public override bool readBoolByAddress(string address)
+ {
+ try
+ {
+ OperateResult read = inovanceTcp.ReadBool(address);
+ if (!read.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取bool数据失败:{read.Content}");
+ }
+ return read.Content;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};读取bool数据异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 通过PLC地址写入Bool类型数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool writeBoolByAddress(string address, bool value)
+ {
+ try
+ {
+ OperateResult operateResult = inovanceTcp.Write(address, short.Parse(_stringChange.ParseToInt(value ? "1" : "0").ToString()));
+ if (!operateResult.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入bool数据失败:{operateResult.Message}");
+ }
+ return operateResult.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入bool数据异常:{ex.Message}");
+ }
+ }
+
+ ///
+ /// 通过PLC地址写入Double类型数据
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool writeDoubleByAddress(string address, int value)
+ {
+ try
+ {
+ OperateResult operateResult = inovanceTcp.Write(address, Convert.ToDouble(value));
+ if (!operateResult.IsSuccess)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入double数据失败:{operateResult.Message}");
+ }
+ return operateResult.IsSuccess;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"根据地址:{address};写入double数据异常:{ex.Message}");
+ }
+ }
+
+ public override bool readHeartByAddress(string address)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Task ConnectAsync(string ip, int port)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool writeStringByAddress(string address, string value, int length)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Sln.Wcs.Plc/Sln.Wcs.Plc.csproj b/Sln.Wcs.Plc/Sln.Wcs.Plc.csproj
index 9e8136b..58acb25 100644
--- a/Sln.Wcs.Plc/Sln.Wcs.Plc.csproj
+++ b/Sln.Wcs.Plc/Sln.Wcs.Plc.csproj
@@ -15,8 +15,4 @@
-
-
-
-