Files
WCS/Plugins/Driver/Cowain.Driver/ReadWriteExtensions.cs
2026-03-02 09:08:20 +08:00

198 lines
8.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
};
}
}