using DocumentFormat.OpenXml.Bibliography; using DocumentFormat.OpenXml.Drawing; using Elastic.Clients.Elasticsearch; using Furion.Logging; using IoTClient; using IoTClient.Clients.Modbus; using IoTClient.Clients.PLC; using IoTClient.Common.Enums; using IoTClient.Enums; using IoTClient.Interfaces; using System.Text; using System.Text.RegularExpressions; namespace WCS.Application; public class PLCUtil { public readonly long PlcId; public readonly string PlcIP; private SiemensClient _client; private WcsPlc _modPlc; private readonly object OLock = new object(); public PLCUtil(WcsPlc modPlc) { PlcId = modPlc.Id; PlcIP = modPlc.IP; _modPlc = modPlc; _client = new SiemensClient((SiemensVersion)modPlc.PLCType, modPlc.IP, modPlc.Port); _client.Open(); } public bool Connected { get { return _client.Connected; } } public IoTClient.Result Open() { return _client.Open(); } public IoTClient.Result Close() { return _client.Close(); } /// /// 读取PLC值 /// /// DB区指定值 /// 字符类型 /// 偏移量/地址 /// 长度(字符串) /// public (IoTClient.Result, dynamic value) GetPlcDBValue(PLCDataTypeEnum PosType, string DbNumber, string Pos, int? Length = 0) { lock (OLock) { string address; if (DbNumber.StartsWith("DB")) address = DbNumber + "." + Pos; else address = DbNumber + Pos; return this.GetPlcDBValue(PosType, address, Length); } } /// /// 读取PLC值 /// /// 字符类型 /// 偏移量/地址 /// 长度(字符串) /// public (IoTClient.Result, dynamic value) GetPlcDBValue(PLCDataTypeEnum PosType, string Pos, int? Length = 0) { lock (OLock) { dynamic result = null; switch (PosType) { case PLCDataTypeEnum.Bit: result = _client.ReadBoolean(Pos); break; case PLCDataTypeEnum.Byte: result = _client.ReadByte(Pos); break; case PLCDataTypeEnum.Short: result = _client.ReadInt16(Pos); break; case PLCDataTypeEnum.UShort: result = _client.ReadUInt16(Pos); break; case PLCDataTypeEnum.Int: result = _client.ReadInt32(Pos); break; case PLCDataTypeEnum.UInt: result = _client.ReadUInt32(Pos); break; case PLCDataTypeEnum.Long: result = _client.ReadInt64(Pos); break; case PLCDataTypeEnum.ULong: result = _client.ReadUInt64(Pos); break; case PLCDataTypeEnum.Float: result = _client.ReadFloat(Pos); break; case PLCDataTypeEnum.Double: result = _client.ReadDouble(Pos); break; case PLCDataTypeEnum.String: { string dpos = IncrementCode(Pos); Result result1 = _client.ReadString(Pos, 2); if (result1.IsSucceed) { //wxw改 if ((ushort)(result1.Value[1]) > (ushort)(result1.Value[0])) { break; } ushort let = (ushort)(result1.Value[1]);//(ushort)(result1.Value[0]) 备注:result1.Value[0]取的是设置的最大长度,result1.Value[0]取的是实际值长度 Result result2 = _client.ReadString(dpos, let); Result result3 = new Result(result2); if (result3.IsSucceed) { result3.Value = Encoding.ASCII.GetString(result2.Value, 0, let).Replace("\0", ""); result = result3; } } else { result = result1; } } break; default: result = new IoTClient.Result(); break; } return (result, result.Value); } } public static string IncrementCode(string code, int index = 2) { // 使用正则表达式解析字符串 var match = Regex.Match(code, @"([A-Za-z]+)(\d+)(?:\.(\d+))?"); if (match.Success) { // 提取字母部分 string prefix = match.Groups[1].Value; // 提取数字部分 int number1 = int.Parse(match.Groups[2].Value); int number2 = match.Groups[3].Success ? int.Parse(match.Groups[3].Value) : 0; // 处理规则 if (match.Groups[3].Success) { // 如果有小数点分隔部分,增加2 number2 += index; return $"{prefix}{number1}.{number2:D3}"; } else { // 没有小数点分隔部分的,增加2 number1 += index; return $"{prefix}{number1}"; } } // 如果不匹配,返回原字符串 return code; } /// /// 批量读取PLC值 /// /// public Result> GetPlcBatchDBValue(Dictionary listaddress) { lock (OLock) { Dictionary addresses = new Dictionary(); foreach (var address in listaddress) { switch (address.Value) { case PLCDataTypeEnum.Bit: addresses.Add(address.Key, DataTypeEnum.Bool); break; case PLCDataTypeEnum.Byte: addresses.Add(address.Key, DataTypeEnum.Byte); break; case PLCDataTypeEnum.Short: addresses.Add(address.Key, DataTypeEnum.Int16); break; case PLCDataTypeEnum.UShort: addresses.Add(address.Key, DataTypeEnum.UInt16); break; case PLCDataTypeEnum.Int: addresses.Add(address.Key, DataTypeEnum.Int32); break; case PLCDataTypeEnum.UInt: addresses.Add(address.Key, DataTypeEnum.UInt32); break; case PLCDataTypeEnum.Long: addresses.Add(address.Key, DataTypeEnum.Int64); break; case PLCDataTypeEnum.ULong: addresses.Add(address.Key, DataTypeEnum.UInt64); break; case PLCDataTypeEnum.Float: addresses.Add(address.Key, DataTypeEnum.Float); break; case PLCDataTypeEnum.Double: addresses.Add(address.Key, DataTypeEnum.Double); break; case PLCDataTypeEnum.String: addresses.Add(address.Key, DataTypeEnum.String); break; default: break; } } return _client.BatchRead(addresses); } } /// /// 循环写入PLC值(并读取值判断和写入的值是否一致,写入控制字不能用此方法) /// public IoTClient.Result SetPlcDBValueRepeat(PLCDataTypeEnum PosType, string DbNumber, string Pos, string Value) { IoTClient.Result _result = new IoTClient.Result(); int setCount = 0;//写入次数 while (setCount < 5) { string address; if (DbNumber.StartsWith("DB")) address = DbNumber + "." + Pos; else address = DbNumber + Pos; _result = this.SetPlcDBValue(PosType, address, Value);//写入值 //累计写入次数 setCount++; if (_result.IsSucceed) { //读取写入的值 var (res, val) = GetPlcDBValue(PosType, DbNumber, Pos); if (val.ToString() == Value) { //读取的值和写入的值一致,直接跳出循环 break; } } } //写入日志 Log.Information($"66666666写入PLC,DbNumber:{DbNumber},Pos:{Pos},Value:{Value},setCount:{setCount}"); return _result; } /// /// 写入PLC值 /// /// /// /// /// /// public IoTClient.Result SetPlcDBValue(PLCDataTypeEnum PosType, string DbNumber, string Pos, string Value) { Log.Information($"66666666写入PLC,DbNumber:{DbNumber},Pos:{Pos},Value:{Value}"); string address; if (DbNumber.StartsWith("DB")) address = DbNumber + "." + Pos; else address = DbNumber + Pos; return this.SetPlcDBValue(PosType, address, Value); } /// /// 写入PLC值 /// public IoTClient.Result SetPlcDBValue(PLCDataTypeEnum PosType, string Pos, string Value) { switch (PosType) { case PLCDataTypeEnum.Bit: if (!bool.TryParse(Value, out bool bit)) { if (Value == "0") bit = false; else if (Value == "1") bit = true; else { throw new Exception("写入值错误"); } } return _client.Write(Pos, bit); case PLCDataTypeEnum.Byte: return _client.Write(Pos, byte.Parse(Value)); case PLCDataTypeEnum.Short: return _client.Write(Pos, short.Parse(Value)); case PLCDataTypeEnum.UShort: return _client.Write(Pos, ushort.Parse(Value)); case PLCDataTypeEnum.Int: return _client.Write(Pos, int.Parse(Value)); case PLCDataTypeEnum.UInt: return _client.Write(Pos, uint.Parse(Value)); case PLCDataTypeEnum.Long: return _client.Write(Pos, long.Parse(Value)); case PLCDataTypeEnum.ULong: return _client.Write(Pos, ulong.Parse(Value)); case PLCDataTypeEnum.Float: return _client.Write(Pos, float.Parse(Value)); case PLCDataTypeEnum.Double: return _client.Write(Pos, float.Parse(Value)); case PLCDataTypeEnum.String: { string dpos = IncrementCode(Pos, 1); return _client.Write(dpos, Value); } default: return new IoTClient.Result(); } } /// /// 批量写入PLC值 /// public IoTClient.Result SetPlcBatchDBValue(Dictionary> listaddress) { Dictionary addresses = new Dictionary(); foreach (var address in listaddress) { switch (address.Value.Value) { case PLCDataTypeEnum.Bit: if (!bool.TryParse(address.Value.Key, out bool bit)) { if (address.Value.Key == "0") bit = false; else if (address.Value.Key == "1") bit = true; else { throw new Exception("写入值错误"); } } addresses.Add(address.Key, bit); break; case PLCDataTypeEnum.Byte: addresses.Add(address.Key, byte.Parse(address.Value.Key)); break; case PLCDataTypeEnum.Short: addresses.Add(address.Key, short.Parse(address.Value.Key)); break; case PLCDataTypeEnum.UShort: addresses.Add(address.Key, ushort.Parse(address.Value.Key)); break; case PLCDataTypeEnum.Int: addresses.Add(address.Key, int.Parse(address.Value.Key)); break; case PLCDataTypeEnum.UInt: addresses.Add(address.Key, uint.Parse(address.Value.Key)); break; case PLCDataTypeEnum.Long: addresses.Add(address.Key, long.Parse(address.Value.Key)); break; case PLCDataTypeEnum.ULong: addresses.Add(address.Key, ulong.Parse(address.Value.Key)); break; case PLCDataTypeEnum.Float: addresses.Add(address.Key, float.Parse(address.Value.Key)); break; case PLCDataTypeEnum.Double: addresses.Add(address.Key, double.Parse(address.Value.Key)); break; case PLCDataTypeEnum.String: addresses.Add(address.Key, address.Value.Key); break; default: break; } } return _client.BatchWrite(addresses); } }