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` 接口,便于日志的配置和输出。
- 代码中包含了一些异常处理逻辑,确保在发生错误时能够记录日志并重新抛出异常以触发重试。
浙公网安备 33010602011771号