using HslCommunication.Profinet.Siemens;
using HslCommunication;
using System; using System.Threading; using Microsoft.Extensions.Logging; using HslCommunication.Profinet.Siemens; using HslCommunication; using SamplePreparation_System.Common; using SamplePreparation_System.Models; using System.Collections.Generic; using System.Text.Json; using System.Text; using HslCommunication.LogNet; using System.Windows.Interop; using System.Threading.Tasks; using System.Runtime.CompilerServices; namespace System.PLC { public class Plc { private readonly object Lockobj = new object(); // 用于PLC写入时先锁定再写入 private readonly ExponentialBackoff _backoff; private readonly int _maxRetryCount = 5; // 最大重试次数 private readonly int _maxRetryDelay = 100; // 最大重试延迟时间(毫秒) private readonly int _baseConnectTimeOutDelay = 500; // 基础延迟时间(毫秒) // private readonly string ipAddress_SamplePreparationPLC = "192.168.1.1"; private readonly string ipAddress_SamplePreparationPLC = System.Configuration.ConfigurationManager.AppSettings["ZyPlcIp"] ?? "172.21.38.100"; // HslCommunication.LogNet. //private readonly ILogNet logNet = new LogNetDateTime(AppContext.BaseDirectory + "PLCLogs", GenerateMode.ByEveryDay);//按每天; // 日志 public SiemensS7Net SiemensS7_SamplePreparation { get; set; } readonly ILogger<SamplePreparationPlc> _logger; public SamplePreparationPlc(ILogger<SamplePreparationPlc> logger) { _logger = logger; SiemensS7_SamplePreparation = new SiemensS7Net(SiemensPLCS.S1200, ipAddress_SamplePreparationPLC) { ConnectTimeOut = _baseConnectTimeOutDelay }; SiemensS7_SamplePreparation.ConnectServer(); _backoff = new ExponentialBackoff(_maxRetryDelay, logger); // 基础延迟 100 毫秒 } /// <summary> /// 读取PLC /// </summary> /// <param name="address">点位</param> /// <param name="type">类型</param> /// <returns></returns> public string PlcRead(string address, string type) { string data = ""; _backoff.SendWithBackoff(() => { switch (type.ToLower()) { case "bool": var result = SiemensS7_SamplePreparation.ReadBool(address); if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } data = result.Content.ToString(); break; case "float": var result1 = SiemensS7_SamplePreparation.ReadFloat(address); if (!result1.IsSuccess) { _logger.LogError(result1.Message); //Thread.Sleep(1000); //continue; throw new Exception(result1.Message); // 抛出异常以触发重试 } data = result1.Content.ToString(); break; case "datetime": var result2 = SiemensS7_SamplePreparation.ReadDateTime(address); if (!result2.IsSuccess) { _logger.LogError(result2.Message); //Thread.Sleep(1000); //continue; throw new Exception(result2.Message); // 抛出异常以触发重试 } data = result2.Content.ToString(); break; case "int32": case "int": var result3 = SiemensS7_SamplePreparation.ReadInt32(address); if (!result3.IsSuccess) { _logger.LogError(result3.Message); //Thread.Sleep(1000); //continue; throw new Exception(result3.Message); // 抛出异常以触发重试 } data = result3.Content.ToString(); break; case "int16": var result4 = SiemensS7_SamplePreparation.ReadInt16(address); if (!result4.IsSuccess) { _logger.LogError(result4.Message); //Thread.Sleep(1000); //continue; throw new Exception(result4.Message); // 抛出异常以触发重试 } data = result4.Content.ToString(); break; case "string": var result5 = SiemensS7_SamplePreparation.ReadString(address); if (!result5.IsSuccess) { _logger.LogError(result5.Message); //Thread.Sleep(1000); //continue; throw new Exception(result5.Message); // 抛出异常以触发重试 } data = result5.Content.ToString(); break; case "double": var result6 = SiemensS7_SamplePreparation.ReadDouble(address); if (!result6.IsSuccess) { _logger.LogError(result6.Message); //Thread.Sleep(1000); //continue; throw new Exception(result6.Message); // 抛出异常以触发重试 } data = result6.Content.ToString(); break; case "byte": var result7 = SiemensS7_SamplePreparation.ReadByte(address); if (!result7.IsSuccess) { _logger.LogError(result7.Message); //Thread.Sleep(1000); //continue; throw new Exception(result7.Message); // 抛出异常以触发重试 } data = result7.Content.ToString(); break; default: throw new ArgumentException("Unsupported type"); } }, maxRetries: _maxRetryCount); // 最大重试次数 return data; } /// <summary> /// 读取PLC /// </summary> /// <param name="address">点位</param> /// <param name="type">类型</param> /// <returns></returns> public async Task<string> PlcReadAsync(string address, string type) { string data = ""; _backoff.SendWithBackoff(async () => { switch (type.ToLower()) { case "bool": var result = await SiemensS7_SamplePreparation.ReadBoolAsync(address); if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } data = result.Content.ToString(); break; case "float": var result1 = await SiemensS7_SamplePreparation.ReadFloatAsync(address); if (!result1.IsSuccess) { _logger.LogError(result1.Message); //Thread.Sleep(1000); //continue; throw new Exception(result1.Message); // 抛出异常以触发重试 } data = result1.Content.ToString(); break; case "datetime": var result2 = await SiemensS7_SamplePreparation.ReadDateTimeAsync(address); if (!result2.IsSuccess) { _logger.LogError(result2.Message); //Thread.Sleep(1000); //continue; throw new Exception(result2.Message); // 抛出异常以触发重试 } data = result2.Content.ToString(); break; case "int32": case "int": var result3 = await SiemensS7_SamplePreparation.ReadInt32Async(address); if (!result3.IsSuccess) { _logger.LogError(result3.Message); //Thread.Sleep(1000); //continue; throw new Exception(result3.Message); // 抛出异常以触发重试 } data = result3.Content.ToString(); break; case "int16": var result4 = await SiemensS7_SamplePreparation.ReadInt16Async(address); if (!result4.IsSuccess) { _logger.LogError(result4.Message); //Thread.Sleep(1000); //continue; throw new Exception(result4.Message); // 抛出异常以触发重试 } data = result4.Content.ToString(); break; case "string": var result5 = await SiemensS7_SamplePreparation.ReadStringAsync(address); if (!result5.IsSuccess) { _logger.LogError(result5.Message); //Thread.Sleep(1000); //continue; throw new Exception(result5.Message); // 抛出异常以触发重试 } data = result5.Content.ToString(); break; case "double": var result6 = await SiemensS7_SamplePreparation.ReadDoubleAsync(address); if (!result6.IsSuccess) { _logger.LogError(result6.Message); //Thread.Sleep(1000); //continue; throw new Exception(result6.Message); // 抛出异常以触发重试 } data = result6.Content.ToString(); break; case "byte": var result7 = await SiemensS7_SamplePreparation.ReadByteAsync(address); if (!result7.IsSuccess) { _logger.LogError(result7.Message); //Thread.Sleep(1000); //continue; throw new Exception(result7.Message); // 抛出异常以触发重试 } data = result7.Content.ToString(); break; default: throw new ArgumentException("Unsupported type"); } }, maxRetries: _maxRetryCount); // 最大重试次数 return data; } /// <summary> /// 写入PLC /// </summary> /// <param name="address">点位</param> /// <param name="value">值</param> /// <param name="type">类型</param> /// <returns></returns> public OperateResult PlcWrite(string address, object value, string type) { lock(Lockobj) { var result = new OperateResult(); //while (true) //{ _backoff.SendWithBackoff(() => { try { switch (type.ToLower()) { case "bool": result = SiemensS7_SamplePreparation.Write(address, Convert.ToBoolean(value)); break; case "float": result = SiemensS7_SamplePreparation.Write(address, Convert.ToSingle(value)); break; case "datetime": result = SiemensS7_SamplePreparation.Write(address, Convert.ToDateTime(value)); break; case "int32": case "int": result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt32(value)); break; case "int16": result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt16(value)); break; case "string": result = SiemensS7_SamplePreparation.Write(address, Convert.ToString(value)); break; case "byte": result = SiemensS7_SamplePreparation.Write(address, Convert.ToByte(value)); break; default: throw new ArgumentException("Unsupported type"); } if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } //return result; } catch (Exception ex) { _logger.LogError(ex.Message + ex.StackTrace); throw; // 重新抛出异常以便重试 } }, maxRetries: _maxRetryCount); // 最大重试次数 return result; //Thread.Sleep(1000); //} } } /// <summary> /// 写入PLC /// </summary> /// <param name="address">点位</param> /// <param name="value">值</param> /// <param name="type">类型</param> /// <returns></returns> public async Task<OperateResult> PlcWriteAsync(string address, object value, string type) { //lock (Lockobj) //{ var result = new OperateResult(); //while (true) //{ _backoff.SendWithBackoff(async () => { try { switch (type.ToLower()) { case "bool": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToBoolean(value)); break; case "float": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToSingle(value)); break; case "datetime": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToDateTime(value)); break; case "int32": case "int": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt32(value)); break; case "int16": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt16(value)); break; case "string": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToString(value)); break; case "byte": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToByte(value)); break; default: throw new ArgumentException("Unsupported type"); } if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } //return result; } catch (Exception ex) { _logger.LogError(ex.Message + ex.StackTrace); throw; // 重新抛出异常以便重试 } }, maxRetries: _maxRetryCount); // 最大重试次数 return result; //Thread.Sleep(1000); //} //} } /// <summary> /// 批量读取PLC点位值. /// Batches the read. /// </summary> /// <param name="pointList">The point list.</param> /// <returns></returns> public List<PLCPointData> BatchRead(List<PLCPointData> pointList) { List<string> plcAddress = new List<string>(); ushort[] dataLength = new ushort[pointList.Count]; int index = 0; foreach (var point in pointList) { dataLength[index] = (ushort)point.DataLength; index++; plcAddress.Add(point.Address); } OperateResult<byte[]> resultData = SiemensS7_SamplePreparation.Read(plcAddress.ToArray(), dataLength); if (resultData.IsSuccess) { index = 0; for (int i = 0; i < pointList.Count; i++) { ByteTrans(resultData.Content, pointList[i], index); index += pointList[i].DataLength; } } else { PLCPointData pointData = new PLCPointData(); pointData = pointList[0]; pointData.ResultMsg = resultData.Message; pointList.Clear(); pointList.Add(pointData); } return pointList; } /// <summary> /// 批量读取PLC点位值. /// Batches the read. /// </summary> /// <param name="pointList">The point list.</param> /// <returns></returns> public async Task<List<PLCPointData>> BatchReadAsync(List<PLCPointData> pointList) { List<string> plcAddress = new List<string>(); ushort[] dataLength = new ushort[pointList.Count]; int index = 0; foreach (var point in pointList) { dataLength[index] = (ushort)point.DataLength; index++; plcAddress.Add(point.Address); } OperateResult<byte[]> resultData = await SiemensS7_SamplePreparation.ReadAsync(plcAddress.ToArray(), dataLength); if (resultData.IsSuccess) { index = 0; for (int i = 0; i < pointList.Count; i++) { ByteTrans(resultData.Content, pointList[i], index); index += pointList[i].DataLength; } } else { PLCPointData pointData = new PLCPointData(); pointData = pointList[0]; pointData.ResultMsg = resultData.Message; pointList.Clear(); pointList.Add(pointData); } return pointList; } /// <summary> /// 写入PLC点位值. /// the write. /// </summary> /// <param name="pLCPoint">The p lc point.</param> /// <returns></returns> public PLCPointData Write(PLCPointData pLCPoint) { lock (Lockobj) { if (pLCPoint.ResultData is JsonElement) { pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData); } if (pLCPoint.ResultData == null) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"参数中缺少ResultData值"; return pLCPoint; } var result = new OperateResult(); try { Type type = ConvertPointDataType(pLCPoint.DataType); string value = pLCPoint.ResultData.ToString(); if (type == typeof(bool)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, bool.Parse(value)); } else if (type == typeof(byte)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, byte.Parse(value)); } else if (type == typeof(float)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, float.Parse(value)); } else if (type == typeof(double)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, double.Parse(value)); } else if (type == typeof(DateTime)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, DateTime.Parse(value)); } else if (type == typeof(int)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, int.Parse(value)); } else if (type == typeof(short)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, Convert.ToInt16(value)); } else { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, value, pLCPoint.DataLength); } pLCPoint.ResultCode = result.IsSuccess ? 1 : 0; pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message; return pLCPoint; } catch (Exception ex) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}"; return pLCPoint; } } } /// <summary> /// 写入PLC点位值. /// the write. /// </summary> /// <param name="pLCPoint">The p lc point.</param> /// <returns></returns> public async Task<PLCPointData> WriteAsync(PLCPointData pLCPoint) { //lock (Lockobj) //{ if (pLCPoint.ResultData is JsonElement) { pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData); } if (pLCPoint.ResultData == null) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"参数中缺少ResultData值"; return pLCPoint; } var result = new OperateResult(); try { Type type = ConvertPointDataType(pLCPoint.DataType); string value = pLCPoint.ResultData.ToString(); if (type == typeof(bool)) { result = await SiemensS7_SamplePreparation.WaitAsync(pLCPoint.Address, bool.Parse(value)); } else if (type == typeof(byte)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, byte.Parse(value)); } else if (type == typeof(float)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, float.Parse(value)); } else if (type == typeof(double)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, double.Parse(value)); } else if (type == typeof(DateTime)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, DateTime.Parse(value)); } else if (type == typeof(int)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, int.Parse(value)); } else if (type == typeof(short)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, Convert.ToInt16(value)); } else { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, value, pLCPoint.DataLength); } pLCPoint.ResultCode = result.IsSuccess ? 1 : 0; pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message; return pLCPoint; } catch (Exception ex) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}"; return pLCPoint; } //} } /// <summary> /// Bytes the trans. /// </summary> /// <param name="content">The content.</param> /// <param name="pLCPoint">The p lc point.</param> /// <param name="index">The index.</param> private void ByteTrans(byte[] content, PLCPointData pLCPoint, int index) { try { Type type = ConvertPointDataType(pLCPoint.DataType); if (type == typeof(bool)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransBool(content, index); } else if (type == typeof(byte)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransByte(content, index); } else if (type == typeof(float)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransSingle(content, index); } else if (type == typeof(double)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransDouble(content, index); } else if (type == typeof(int)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransInt32(content, index); } else { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransString(content, index, pLCPoint.DataLength, Encoding.ASCII).Replace("\0", "").Replace("\u0001", ""); } } catch (Exception ex) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"(读取)错误:{ex.Message}{ex.StackTrace}"; } } /// <summary> /// 数据类型转换 /// </summary> /// <param name="dataType"></param> /// <returns></returns> private Type ConvertPointDataType(string dataType) { Type type = null; switch (dataType.Trim().ToLower()) { case "bool": type = typeof(bool); break; case "byte": type = typeof(byte); break; case "int": type = typeof(int); break; case "datetime": type = typeof(DateTime); break; case "dint": type = typeof(int); break; case "real": type = typeof(float); break; case "lreal": type = typeof(double); break; case "lint": type = typeof(long); break; case "string": type = typeof(string); break; case "short": type = typeof(short); break; default: { AddSysError(SiemensS7_SamplePreparation.IpAddress, $"{dataType}数据类型不存在"); //throw new ArgumentOutOfRangeException(dataType, "数据类型不存在"); break; } } return type; } /// <summary> /// Converts the kind of the value. /// </summary> /// <param name="element">The element.</param> /// <returns></returns> private object? ConvertValueKind(JsonElement element) { switch (element.ValueKind) { case JsonValueKind.String: return element.GetString(); case JsonValueKind.Null: return null; case JsonValueKind.False: return false; case JsonValueKind.True: return true; case JsonValueKind.Number: return element.GetDouble(); case JsonValueKind.Object: return element.ValueKind.ToString(); default: break; } return element; } /// <summary> /// Adds the system message. /// </summary> /// <param name="msg">The MSG.</param> private void AddSysMessage(string msg) { //logNet.WriteInfo(msg); _logger.LogInformation(msg); } /// <summary> /// Adds the system error. /// </summary> /// <param name="plcIp">The PLC ip.</param> /// <param name="error">The error.</param> private void AddSysError(string plcIp, string error) { //logNet.WriteError(plcIp, error); _logger.LogError(plcIp + ", error:" + error); } } public class PlcEx { private readonly object Lockobj = new object(); // 用于PLC写入时先锁定再写入 private readonly ExponentialBackoff _backoff; private readonly int _maxRetryCount = 5; // 最大重试次数 private readonly int _maxRetryDelay = 100; // 最大重试延迟时间(毫秒) private readonly int _baseConnectTimeOutDelay = 500; // 基础延迟时间(毫秒) // private readonly string ipAddress_SamplePreparationPLC = "192.168.1.1"; private readonly string ipAddress_SamplePreparationPLC = System.Configuration.ConfigurationManager.AppSettings["HygpPlcIp"] ?? "172.21.38.101"; // HslCommunication.LogNet. //private readonly ILogNet logNet = new LogNetDateTime(AppContext.BaseDirectory + "PLCLogs", GenerateMode.ByEveryDay);//按每天; // 日志 public SiemensS7Net SiemensS7_SamplePreparation { get; set; } readonly ILogger<SamplePreparationPlc> _logger; public Hygp_SamplePreparationPlc(ILogger<SamplePreparationPlc> logger) { _logger = logger; SiemensS7_SamplePreparation = new SiemensS7Net(SiemensPLCS.S1200, ipAddress_SamplePreparationPLC) { ConnectTimeOut = _baseConnectTimeOutDelay }; SiemensS7_SamplePreparation.ConnectServer(); _backoff = new ExponentialBackoff(_maxRetryDelay, logger); // 基础延迟 100 毫秒 } /// <summary> /// 读取PLC /// </summary> /// <param name="address">点位</param> /// <param name="type">类型</param> /// <returns></returns> public string PlcRead(string address, string type) { string data = ""; _backoff.SendWithBackoff(() => { switch (type.ToLower()) { case "bool": var result = SiemensS7_SamplePreparation.ReadBool(address); if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } data = result.Content.ToString(); break; case "float": var result1 = SiemensS7_SamplePreparation.ReadFloat(address); if (!result1.IsSuccess) { _logger.LogError(result1.Message); //Thread.Sleep(1000); //continue; throw new Exception(result1.Message); // 抛出异常以触发重试 } data = result1.Content.ToString(); break; case "datetime": var result2 = SiemensS7_SamplePreparation.ReadDateTime(address); if (!result2.IsSuccess) { _logger.LogError(result2.Message); //Thread.Sleep(1000); //continue; throw new Exception(result2.Message); // 抛出异常以触发重试 } data = result2.Content.ToString(); break; case "int32": case "int": var result3 = SiemensS7_SamplePreparation.ReadInt32(address); if (!result3.IsSuccess) { _logger.LogError(result3.Message); //Thread.Sleep(1000); //continue; throw new Exception(result3.Message); // 抛出异常以触发重试 } data = result3.Content.ToString(); break; case "int16": var result4 = SiemensS7_SamplePreparation.ReadInt16(address); if (!result4.IsSuccess) { _logger.LogError(result4.Message); //Thread.Sleep(1000); //continue; throw new Exception(result4.Message); // 抛出异常以触发重试 } data = result4.Content.ToString(); break; case "string": var result5 = SiemensS7_SamplePreparation.ReadString(address); if (!result5.IsSuccess) { _logger.LogError(result5.Message); //Thread.Sleep(1000); //continue; throw new Exception(result5.Message); // 抛出异常以触发重试 } data = result5.Content.ToString(); break; case "double": var result6 = SiemensS7_SamplePreparation.ReadDouble(address); if (!result6.IsSuccess) { _logger.LogError(result6.Message); //Thread.Sleep(1000); //continue; throw new Exception(result6.Message); // 抛出异常以触发重试 } data = result6.Content.ToString(); break; case "byte": var result7 = SiemensS7_SamplePreparation.ReadByte(address); if (!result7.IsSuccess) { _logger.LogError(result7.Message); //Thread.Sleep(1000); //continue; throw new Exception(result7.Message); // 抛出异常以触发重试 } data = result7.Content.ToString(); break; default: throw new ArgumentException("Unsupported type"); } }, maxRetries: _maxRetryCount); // 最大重试次数 return data; } /// <summary> /// 读取PLC /// </summary> /// <param name="address">点位</param> /// <param name="type">类型</param> /// <returns></returns> public async Task<string> PlcReadAsync(string address, string type) { string data = ""; _backoff.SendWithBackoff(async () => { switch (type.ToLower()) { case "bool": var result = await SiemensS7_SamplePreparation.ReadBoolAsync(address); if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } data = result.Content.ToString(); break; case "float": var result1 = await SiemensS7_SamplePreparation.ReadFloatAsync(address); if (!result1.IsSuccess) { _logger.LogError(result1.Message); //Thread.Sleep(1000); //continue; throw new Exception(result1.Message); // 抛出异常以触发重试 } data = result1.Content.ToString(); break; case "datetime": var result2 = await SiemensS7_SamplePreparation.ReadDateTimeAsync(address); if (!result2.IsSuccess) { _logger.LogError(result2.Message); //Thread.Sleep(1000); //continue; throw new Exception(result2.Message); // 抛出异常以触发重试 } data = result2.Content.ToString(); break; case "int32": case "int": var result3 = await SiemensS7_SamplePreparation.ReadInt32Async(address); if (!result3.IsSuccess) { _logger.LogError(result3.Message); //Thread.Sleep(1000); //continue; throw new Exception(result3.Message); // 抛出异常以触发重试 } data = result3.Content.ToString(); break; case "int16": var result4 = await SiemensS7_SamplePreparation.ReadInt16Async(address); if (!result4.IsSuccess) { _logger.LogError(result4.Message); //Thread.Sleep(1000); //continue; throw new Exception(result4.Message); // 抛出异常以触发重试 } data = result4.Content.ToString(); break; case "string": var result5 = await SiemensS7_SamplePreparation.ReadStringAsync(address); if (!result5.IsSuccess) { _logger.LogError(result5.Message); //Thread.Sleep(1000); //continue; throw new Exception(result5.Message); // 抛出异常以触发重试 } data = result5.Content.ToString(); break; case "double": var result6 = await SiemensS7_SamplePreparation.ReadDoubleAsync(address); if (!result6.IsSuccess) { _logger.LogError(result6.Message); //Thread.Sleep(1000); //continue; throw new Exception(result6.Message); // 抛出异常以触发重试 } data = result6.Content.ToString(); break; case "byte": var result7 = await SiemensS7_SamplePreparation.ReadByteAsync(address); if (!result7.IsSuccess) { _logger.LogError(result7.Message); //Thread.Sleep(1000); //continue; throw new Exception(result7.Message); // 抛出异常以触发重试 } data = result7.Content.ToString(); break; default: throw new ArgumentException("Unsupported type"); } }, maxRetries: _maxRetryCount); // 最大重试次数 return data; } /// <summary> /// 写入PLC /// </summary> /// <param name="address">点位</param> /// <param name="value">值</param> /// <param name="type">类型</param> /// <returns></returns> public OperateResult PlcWrite(string address, object value, string type) { lock (Lockobj) { var result = new OperateResult(); //while (true) //{ _backoff.SendWithBackoff(() => { try { switch (type.ToLower()) { case "bool": result = SiemensS7_SamplePreparation.Write(address, Convert.ToBoolean(value)); break; case "float": result = SiemensS7_SamplePreparation.Write(address, Convert.ToSingle(value)); break; case "datetime": result = SiemensS7_SamplePreparation.Write(address, Convert.ToDateTime(value)); break; case "int32": case "int": result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt32(value)); break; case "int16": result = SiemensS7_SamplePreparation.Write(address, Convert.ToInt16(value)); break; case "string": result = SiemensS7_SamplePreparation.Write(address, Convert.ToString(value)); break; case "byte": result = SiemensS7_SamplePreparation.Write(address, Convert.ToByte(value)); break; default: throw new ArgumentException("Unsupported type"); } if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } //return result; } catch (Exception ex) { _logger.LogError(ex.Message + ex.StackTrace); throw; // 重新抛出异常以便重试 } }, maxRetries: _maxRetryCount); // 最大重试次数 return result; //Thread.Sleep(1000); //} } } /// <summary> /// 写入PLC /// </summary> /// <param name="address">点位</param> /// <param name="value">值</param> /// <param name="type">类型</param> /// <returns></returns> public async Task<OperateResult> PlcWriteAsync(string address, object value, string type) { //lock (Lockobj) //{ var result = new OperateResult(); //while (true) //{ _backoff.SendWithBackoff(async () => { try { switch (type.ToLower()) { case "bool": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToBoolean(value)); break; case "float": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToSingle(value)); break; case "datetime": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToDateTime(value)); break; case "int32": case "int": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt32(value)); break; case "int16": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToInt16(value)); break; case "string": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToString(value)); break; case "byte": result = await SiemensS7_SamplePreparation.WriteAsync(address, Convert.ToByte(value)); break; default: throw new ArgumentException("Unsupported type"); } if (!result.IsSuccess) { _logger.LogError(result.Message); //Thread.Sleep(1000); //continue; throw new Exception(result.Message); // 抛出异常以触发重试 } //return result; } catch (Exception ex) { _logger.LogError(ex.Message + ex.StackTrace); throw; // 重新抛出异常以便重试 } }, maxRetries: _maxRetryCount); // 最大重试次数 return result; //Thread.Sleep(1000); //} //} } /// <summary> /// 批量读取PLC点位值. /// Batches the read. /// </summary> /// <param name="pointList">The point list.</param> /// <returns></returns> public List<PLCPointData> BatchRead(List<PLCPointData> pointList) { List<string> plcAddress = new List<string>(); ushort[] dataLength = new ushort[pointList.Count]; int index = 0; foreach (var point in pointList) { dataLength[index] = (ushort)point.DataLength; index++; plcAddress.Add(point.Address); } OperateResult<byte[]> resultData = SiemensS7_SamplePreparation.Read(plcAddress.ToArray(), dataLength); if (resultData.IsSuccess) { index = 0; for (int i = 0; i < pointList.Count; i++) { ByteTrans(resultData.Content, pointList[i], index); index += pointList[i].DataLength; } } else { PLCPointData pointData = new PLCPointData(); pointData = pointList[0]; pointData.ResultMsg = resultData.Message; pointList.Clear(); pointList.Add(pointData); } return pointList; } /// <summary> /// 批量读取PLC点位值. /// Batches the read. /// </summary> /// <param name="pointList">The point list.</param> /// <returns></returns> public async Task<List<PLCPointData>> BatchReadAsync(List<PLCPointData> pointList) { List<string> plcAddress = new List<string>(); ushort[] dataLength = new ushort[pointList.Count]; int index = 0; foreach (var point in pointList) { dataLength[index] = (ushort)point.DataLength; index++; plcAddress.Add(point.Address); } OperateResult<byte[]> resultData = await SiemensS7_SamplePreparation.ReadAsync(plcAddress.ToArray(), dataLength); if (resultData.IsSuccess) { index = 0; for (int i = 0; i < pointList.Count; i++) { ByteTrans(resultData.Content, pointList[i], index); index += pointList[i].DataLength; } } else { PLCPointData pointData = new PLCPointData(); pointData = pointList[0]; pointData.ResultMsg = resultData.Message; pointList.Clear(); pointList.Add(pointData); } return pointList; } /// <summary> /// 写入PLC点位值. /// the write. /// </summary> /// <param name="pLCPoint">The p lc point.</param> /// <returns></returns> public PLCPointData Write(PLCPointData pLCPoint) { lock (Lockobj) { if (pLCPoint.ResultData is JsonElement) { pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData); } if (pLCPoint.ResultData == null) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"参数中缺少ResultData值"; return pLCPoint; } var result = new OperateResult(); try { Type type = ConvertPointDataType(pLCPoint.DataType); string value = pLCPoint.ResultData.ToString(); if (type == typeof(bool)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, bool.Parse(value)); } else if (type == typeof(byte)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, byte.Parse(value)); } else if (type == typeof(float)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, float.Parse(value)); } else if (type == typeof(double)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, double.Parse(value)); } else if (type == typeof(DateTime)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, DateTime.Parse(value)); } else if (type == typeof(int)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, int.Parse(value)); } else if (type == typeof(short)) { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, Convert.ToInt16(value)); } else { result = SiemensS7_SamplePreparation.Write(pLCPoint.Address, value, pLCPoint.DataLength); } pLCPoint.ResultCode = result.IsSuccess ? 1 : 0; pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message; return pLCPoint; } catch (Exception ex) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}"; return pLCPoint; } } } /// <summary> /// 写入PLC点位值. /// the write. /// </summary> /// <param name="pLCPoint">The p lc point.</param> /// <returns></returns> public async Task<PLCPointData> WriteAsync(PLCPointData pLCPoint) { //lock (Lockobj) //{ if (pLCPoint.ResultData is JsonElement) { pLCPoint.ResultData = ConvertValueKind(pLCPoint.ResultData); } if (pLCPoint.ResultData == null) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"参数中缺少ResultData值"; return pLCPoint; } var result = new OperateResult(); try { Type type = ConvertPointDataType(pLCPoint.DataType); string value = pLCPoint.ResultData.ToString(); if (type == typeof(bool)) { result = await SiemensS7_SamplePreparation.WaitAsync(pLCPoint.Address, bool.Parse(value)); } else if (type == typeof(byte)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, byte.Parse(value)); } else if (type == typeof(float)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, float.Parse(value)); } else if (type == typeof(double)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, double.Parse(value)); } else if (type == typeof(DateTime)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, DateTime.Parse(value)); } else if (type == typeof(int)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, int.Parse(value)); } else if (type == typeof(short)) { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, Convert.ToInt16(value)); } else { result = await SiemensS7_SamplePreparation.WriteAsync(pLCPoint.Address, value, pLCPoint.DataLength); } pLCPoint.ResultCode = result.IsSuccess ? 1 : 0; pLCPoint.ResultMsg = result.IsSuccess ? "Success" : result.Message; return pLCPoint; } catch (Exception ex) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"(写入)失败:{ex.Message}{ex.StackTrace}"; return pLCPoint; } //} } /// <summary> /// Bytes the trans. /// </summary> /// <param name="content">The content.</param> /// <param name="pLCPoint">The p lc point.</param> /// <param name="index">The index.</param> private void ByteTrans(byte[] content, PLCPointData pLCPoint, int index) { try { Type type = ConvertPointDataType(pLCPoint.DataType); if (type == typeof(bool)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransBool(content, index); } else if (type == typeof(byte)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransByte(content, index); } else if (type == typeof(float)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransSingle(content, index); } else if (type == typeof(double)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransDouble(content, index); } else if (type == typeof(int)) { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransInt32(content, index); } else { pLCPoint.ResultCode = 1; pLCPoint.ResultMsg = "Success"; pLCPoint.ResultData = SiemensS7_SamplePreparation.ByteTransform.TransString(content, index, pLCPoint.DataLength, Encoding.ASCII).Replace("\0", "").Replace("\u0001", ""); } } catch (Exception ex) { pLCPoint.ResultCode = 0; pLCPoint.ResultMsg = $"(读取)错误:{ex.Message}{ex.StackTrace}"; } } /// <summary> /// 数据类型转换 /// </summary> /// <param name="dataType"></param> /// <returns></returns> private Type ConvertPointDataType(string dataType) { Type type = null; switch (dataType.Trim().ToLower()) { case "bool": type = typeof(bool); break; case "byte": type = typeof(byte); break; case "int": type = typeof(int); break; case "datetime": type = typeof(DateTime); break; case "dint": type = typeof(int); break; case "real": type = typeof(float); break; case "lreal": type = typeof(double); break; case "lint": type = typeof(long); break; case "string": type = typeof(string); break; case "short": type = typeof(short); break; default: { AddSysError(SiemensS7_SamplePreparation.IpAddress, $"{dataType}数据类型不存在"); //throw new ArgumentOutOfRangeException(dataType, "数据类型不存在"); break; } } return type; } /// <summary> /// Converts the kind of the value. /// </summary> /// <param name="element">The element.</param> /// <returns></returns> private object? ConvertValueKind(JsonElement element) { switch (element.ValueKind) { case JsonValueKind.String: return element.GetString(); case JsonValueKind.Null: return null; case JsonValueKind.False: return false; case JsonValueKind.True: return true; case JsonValueKind.Number: return element.GetDouble(); case JsonValueKind.Object: return element.ValueKind.ToString(); default: break; } return element; } /// <summary> /// Adds the system message. /// </summary> /// <param name="msg">The MSG.</param> private void AddSysMessage(string msg) { //logNet.WriteInfo(msg); _logger.LogInformation(msg); } /// <summary> /// Adds the system error. /// </summary> /// <param name="plcIp">The PLC ip.</param> /// <param name="error">The error.</param> private void AddSysError(string plcIp, string error) { //logNet.WriteError(plcIp, error); _logger.LogError(plcIp + ", error:" + error); } } }
这段代码定义了一个名为 `SamplePreparationPlc` 的类,用于与西门子S7-1200 PLC进行通信。该类提供了读取和写入PLC点位的方法,并支持异步操作。下面是对代码的详细解释:
### 类成员变量
- `Lockobj`:一个 `object` 类型的对象,用于在写入PLC时进行锁定,防止多线程同时写入。
- `_backoff`:一个 `ExponentialBackoff` 对象,用于实现指数退避重试机制。
- `_maxRetryCount`:最大重试次数。
- `_maxRetryDelay`:最大重试延迟时间(毫秒)。
- `_baseConnectTimeOutDelay`:基础连接超时时间(毫秒)。
- `ipAddress_SamplePreparationPLC`:PLC的IP地址,从配置文件中读取,如果没有配置则使用默认值。
- `SiemensS7_SamplePreparation`:一个 `SiemensS7Net` 对象,用于与PLC进行通信。
- `_logger`:一个 `ILogger<SamplePreparationPlc>` 对象,用于记录日志。
### 构造函数
- 在构造函数中,初始化 `_logger` 对象,并创建 `SiemensS7Net` 对象,并尝试连接到PLC。如果连接失败,则记录错误日志。
### 方法
1. **PlcRead(string address, string type)**:同步读取PLC点位数据。
- 根据点位类型(如 `bool`、`float` 等)调用相应的 `Read` 方法。
- 如果读取失败,记录错误日志并抛出异常以触发重试。
- 返回读取到的数据。
2. **PlcReadAsync(string address, string type)**:异步读取PLC点位数据。
- 与 `PlcRead` 方法类似,但使用异步方法进行读取。
3. **PlcWrite(string address, object value, string type)**:同步写入PLC点位数据。
- 使用 `lock` 确保写入操作的线程安全。
- 根据点位类型调用相应的 `Write` 方法。
- 如果写入失败,记录错误日志并抛出异常以触发重试。
- 返回操作结果。
4. **PlcWriteAsync(string address, object value, string type)**:异步写入PLC点位数据。
- 与 `PlcWrite` 方法类似,但使用异步方法进行写入。
5. **BatchRead(List<PLCPointData> pointList)**:批量读取PLC点位数据。
- 将点位地址和数据长度转换为数组,调用 `Read` 方法进行批量读取。
- 根据读取到的数据,填充 `PLCPointData` 对象并返回。
6. **BatchReadAsync(List<PLCPointData> pointList)**:异步批量读取PLC点位数据。
- 与 `BatchRead` 方法类似,但使用异步方法进行读取。
7. **Write(PLCPointData pLCPoint)**:同步写入PLC点位数据。
- 使用 `lock` 确保写入操作的线程安全。
- 根据点位类型调用相应的 `Write` 方法。
- 返回操作结果。
8. **WriteAsync(PLCPointData pLCPoint)**:异步写入PLC点位数据。
- 与 `Write` 方法类似,但使用异步方法进行写入。
9. **ByteTrans(byte[] content, PLCPointData pLCPoint, int index)**:字节转换方法。
- 根据点位类型,将字节数组转换为相应的数据类型,并填充到 `PLCPointData` 对象中。
10. **ConvertPointDataType(string dataType)**:数据类型转换方法。
- 将字符串类型的数据类型转换为 `Type` 对象。
11. **ConvertValueKind(JsonElement element)**:值类型转换方法。
- 将 `JsonElement` 对象转换为相应的值类型。
12. **AddSysMessage(string msg)**:添加系统消息日志。
- 记录系统消息日志。
13. **AddSysError(string plcIp, string error)**:添加系统错误日志。
- 记录系统错误日志。
### 注意事项
- 代码中使用了 `lock` 关键字来确保写入操作的线程安全。
- 使用了指数退避重试机制来处理读取和写入操作中的异常情况。
- 日志记录使用了 `ILogger` 接口,便于日志的配置和输出。
- 代码中包含了一些异常处理逻辑,确保在发生错误时能够记录日志并重新抛出异常以触发重试。
标签:类库,case,HslCommunication,type,SiemensS7,Siemens,pLCPoint,result,SamplePreparatio From: https://www.cnblogs.com/Leo_wl/p/18653031