198 lines
8.2 KiB
C#
198 lines
8.2 KiB
C#
using Cowain.Base.Helpers;
|
||
using Cowain.Base.Models;
|
||
using HslCommunication;
|
||
using HslCommunication.BasicFramework;
|
||
using HslCommunication.Core;
|
||
using HslCommunication.Profinet.Siemens;
|
||
using Microsoft.Extensions.Logging;
|
||
using System.Text;
|
||
|
||
namespace Plugin.Cowain.Driver;
|
||
|
||
public static class ReadWriteExtensions
|
||
{
|
||
private static readonly ILogger _logger = ServiceLocator.GetRequiredService<ILogger>();
|
||
public static ResultModel<T1> ToResultModel<T1, T2>(OperateResult<T2> read) where T1 : notnull where T2 : notnull
|
||
{
|
||
if (!read.IsSuccess) return ResultModel<T1>.Error(read.Message);
|
||
return ResultModel<T1>.Success((T1)(object)read.Content);
|
||
}
|
||
public static ResultModel ToResultModel(this OperateResult operate)
|
||
{
|
||
if (!operate.IsSuccess) return ResultModel.Error(operate.Message);
|
||
return ResultModel.Success();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 如果S7读取的字符串不对,使用这个方法读取
|
||
/// </summary>
|
||
public static async Task<OperateResult<string>> ReadS7StringAsync(SiemensS7Net plc, string address, ushort length)
|
||
{
|
||
var readBytes = await plc.ReadAsync(address, length);
|
||
if (!readBytes.IsSuccess)
|
||
{
|
||
return new OperateResult<string>(readBytes.Message);
|
||
}
|
||
byte[] data = readBytes.Content;
|
||
if (data.Length > 2)
|
||
{
|
||
byte[] strData = new byte[data[1]];
|
||
Array.Copy(data, 2, strData, 0, strData.Length);
|
||
return OperateResult.CreateSuccessResult<string>(Encoding.ASCII.GetString(strData));
|
||
}
|
||
else
|
||
{
|
||
//读取错误
|
||
return new OperateResult<string>("数据长度错误");
|
||
}
|
||
}
|
||
|
||
public static string GetS7String(this byte[] data)
|
||
{
|
||
if (data.Length > 2)
|
||
{
|
||
if (data.Length < data[1] + 2)
|
||
{
|
||
return string.Empty; // 数据长度不足
|
||
}
|
||
byte[] strData = new byte[data[1]];
|
||
Array.Copy(data, 2, strData, 0, strData.Length);
|
||
return Encoding.ASCII.GetString(strData);
|
||
}
|
||
else
|
||
{
|
||
//读取错误
|
||
return string.Empty;
|
||
}
|
||
}
|
||
|
||
public static string GetS7WString(this byte[] data)
|
||
{
|
||
if (data.Length > 4)
|
||
{
|
||
ushort len = (ushort)(4 + (data[2] * 256 + data[3]) * 2);
|
||
if (data.Length < len + 4)
|
||
{
|
||
return string.Empty; // 数据长度不足
|
||
}
|
||
byte[] strData = new byte[len];
|
||
Array.Copy(data, 4, strData, 0, strData.Length);
|
||
return Encoding.Unicode.GetString(SoftBasic.BytesReverseByWord(strData));
|
||
}
|
||
else
|
||
{
|
||
//读取错误
|
||
return string.Empty;
|
||
}
|
||
}
|
||
|
||
public static async Task<ResultModel> WriteValuesAysnc(this IReadWriteDevice plc, string address, short[] value, int retryCount = 5)
|
||
{
|
||
byte[] bytes = new byte[value.Length * 2];
|
||
for (int i = 0; i < value.Length; i++)
|
||
{
|
||
plc.ByteTransform.TransByte(value[i]).CopyTo(bytes, i * 2);
|
||
}
|
||
return await plc.WriteValuesAysnc(address, bytes, retryCount);
|
||
}
|
||
|
||
public static async Task<ResultModel> WriteValuesAysnc(this IReadWriteDevice plc, string address, byte[] value, int retryCount = 5)
|
||
{
|
||
int baseDelay = 100; // 基础延迟100ms
|
||
var random = new Random();
|
||
ResultModel? result = null;
|
||
for (int retry = 0; retry < retryCount; retry++)
|
||
{
|
||
try
|
||
{
|
||
result = ToResultModel(await plc.WriteAsync(address, value));
|
||
if (result.IsSuccess)
|
||
{
|
||
if (retry > 1)
|
||
{
|
||
_logger.LogInformation($"ReadWriteExtensions写PLC地址:{address} 数据成功,第{retry + 1}次尝试");
|
||
}
|
||
return result;
|
||
}
|
||
else
|
||
{
|
||
_logger.LogWarning($"ReadWriteExtensions写PLC地址:{address} 数据失败:{result.ErrorMessage},第{retry + 1}次尝试");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
result = ResultModel.Error(ex.Message);
|
||
_logger.LogError(ex, $"ReadWriteExtensions写PLC地址:{address} 数据失败:{ex.Message},第{retry + 1}次尝试");
|
||
}
|
||
// 计算指数退避+抖动
|
||
int jitter = random.Next(0, 100); // 0~100ms
|
||
int delay = baseDelay * (int)Math.Pow(2, retry) + jitter;
|
||
await Task.Delay(delay);
|
||
}
|
||
return result ?? ResultModel.Error("未知错误");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 只支持常规数据类型,不支持字符串
|
||
/// </summary>
|
||
public static async Task<ResultModel<T>> ReadValuesAsync<T>(this IReadWriteDevice plc, string address, ushort count = 1) where T : notnull
|
||
{
|
||
Type type = typeof(T);
|
||
|
||
// 处理数组类型
|
||
if (count > 1)
|
||
{
|
||
return await ReadArrayAsync<T>(plc, address, count);
|
||
}
|
||
|
||
// 处理单个值类型
|
||
return type switch
|
||
{
|
||
Type t when t == typeof(bool) => ToResultModel<T, bool>(await plc.ReadBoolAsync(address)),
|
||
Type t when t == typeof(byte) => await ReadByteAsync<T>(plc, address),
|
||
Type t when t == typeof(short) => ToResultModel<T, short>(await plc.ReadInt16Async(address)),
|
||
Type t when t == typeof(ushort) => ToResultModel<T, ushort>(await plc.ReadUInt16Async(address)),
|
||
Type t when t == typeof(int) => ToResultModel<T, int>(await plc.ReadInt32Async(address)),
|
||
Type t when t == typeof(uint) => ToResultModel<T, uint>(await plc.ReadUInt32Async(address)),
|
||
Type t when t == typeof(long) => ToResultModel<T, long>(await plc.ReadInt64Async(address)),
|
||
Type t when t == typeof(ulong) => ToResultModel<T, ulong>(await plc.ReadUInt64Async(address)),
|
||
Type t when t == typeof(float) => ToResultModel<T, float>(await plc.ReadFloatAsync(address)),
|
||
Type t when t == typeof(double) => ToResultModel<T, double>(await plc.ReadDoubleAsync(address)),
|
||
_ => ResultModel<T>.Error("不支持的类型: " + type.Name)
|
||
};
|
||
}
|
||
|
||
// 处理byte类型的特殊读取逻辑
|
||
private static async Task<ResultModel<T>> ReadByteAsync<T>(IReadWriteDevice plc, string address) where T : notnull
|
||
{
|
||
var result = await plc.ReadAsync(address, 1);
|
||
if (!result.IsSuccess) return ResultModel<T>.Error(result.Message);
|
||
return ResultModel<T>.Success((T)(object)result.Content[0]);
|
||
}
|
||
|
||
// 处理数组读取的辅助方法
|
||
private static async Task<ResultModel<T>> ReadArrayAsync<T>(IReadWriteDevice plc, string address, ushort count) where T : notnull
|
||
{
|
||
Type type = typeof(T);
|
||
|
||
// 处理数组类型
|
||
return type switch
|
||
{
|
||
Type t when t == typeof(bool[]) => ToResultModel<T, bool[]>(await plc.ReadBoolAsync(address, (ushort)count)),
|
||
Type t when t == typeof(byte[]) => ToResultModel<T, byte[]>(await plc.ReadAsync(address, (ushort)count)),
|
||
Type t when t == typeof(short[]) => ToResultModel<T, short[]>(await plc.ReadInt16Async(address, (ushort)count)),
|
||
Type t when t == typeof(ushort[]) => ToResultModel<T, ushort[]>(await plc.ReadUInt16Async(address, (ushort)count)),
|
||
Type t when t == typeof(int[]) => ToResultModel<T, int[]>(await plc.ReadInt32Async(address, (ushort)count)),
|
||
Type t when t == typeof(uint[]) => ToResultModel<T, uint[]>(await plc.ReadUInt32Async(address, (ushort)count)),
|
||
Type t when t == typeof(long[]) => ToResultModel<T, long[]>(await plc.ReadInt64Async(address, (ushort)count)),
|
||
Type t when t == typeof(ulong[]) => ToResultModel<T, ulong[]>(await plc.ReadUInt64Async(address, (ushort)count)),
|
||
Type t when t == typeof(float[]) => ToResultModel<T, float[]>(await plc.ReadFloatAsync(address, (ushort)count)),
|
||
Type t when t == typeof(double[]) => ToResultModel<T, double[]>(await plc.ReadDoubleAsync(address, (ushort)count)),
|
||
_ => ResultModel<T>.Error("不支持的数组类型: " + type.Name)
|
||
};
|
||
}
|
||
|
||
|
||
|
||
}
|