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 @@ - - - -