Files
Shi.Ji e31d3560bb 添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
2026-05-18 11:43:09 +08:00

356 lines
13 KiB
C#

using MaxwellFramework.Core.Attributes;
using MainShell.Hardware;
using MwFramework.Device;
using System;
namespace MainShell.Hardware.Acs
{
public interface IAcsAddressAccessService
{
bool IsReady { get; }
object Read(AcsAddressDefinition addressDefinition);
object Read(AcsAddressDefinition addressDefinition, int index1, int index2);
object ReadRange(AcsAddressDefinition addressDefinition, int from1, int to1, int from2, int to2);
T Read<T>(AcsAddressDefinition addressDefinition);
bool Write(AcsAddressDefinition addressDefinition, object value);
bool Write(AcsAddressDefinition addressDefinition, object value, int index1, int index2);
bool WriteRange(AcsAddressDefinition addressDefinition, object value, int from1, int to1, int from2, int to2);
}
[Singleton]
public sealed class AcsAddressAccessService : IAcsAddressAccessService
{
private const int DefaultBufferId = -1;
private readonly HardwareManager _hardwareManager;
public AcsAddressAccessService(HardwareManager hardwareManager)
{
_hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
}
public bool IsReady
{
get
{
return _hardwareManager.AcsCard != null
&& _hardwareManager.AcsCard.Controller != null
&& _hardwareManager.AcsCard.IsOpen;
}
}
public object Read(AcsAddressDefinition addressDefinition)
{
AcsAddressDefinition validatedAddress = ValidateAddress(addressDefinition);
IMotionController controller = GetController();
string variableName = ResolveVariableName(validatedAddress);
bool result= controller.ReadVariableBuffer(DefaultBufferId, variableName,out object val);
if (!result)
{
throw CreateReadWriteException("Read", validatedAddress);
}
return val;
}
public object Read(AcsAddressDefinition addressDefinition, int index1, int index2)
{
AcsAddressDefinition validatedAddress = ValidateAddress(addressDefinition);
ValidateIndex(index1, nameof(index1));
ValidateIndex(index2, nameof(index2));
IMotionController controller = GetController();
string variableName = ResolveVariableName(validatedAddress);
bool result = controller.ReadVariableBuffer(DefaultBufferId, variableName, out object val, index1, index2);
if (!result)
{
throw CreateReadWriteException("Read", validatedAddress);
}
return val;
}
public object ReadRange(AcsAddressDefinition addressDefinition, int from1, int to1, int from2, int to2)
{
AcsAddressDefinition validatedAddress = ValidateAddress(addressDefinition);
ValidateRange(from1, to1, nameof(from1), nameof(to1));
ValidateRange(from2, to2, nameof(from2), nameof(to2));
IMotionController controller = GetController();
string variableName = ResolveVariableName(validatedAddress);
object value;
bool result = controller.ReadVariableBuffer(DefaultBufferId, variableName, out value, from1, to1, from2, to2);
if (!result)
{
throw CreateReadWriteException("Read", validatedAddress);
}
return value;
}
public T Read<T>(AcsAddressDefinition addressDefinition)
{
AcsAddressDefinition validatedAddress = ValidateAddress(addressDefinition);
ValidateTypeCompatibility(validatedAddress, typeof(T));
object value = Read(validatedAddress);
return ConvertValue<T>(value, validatedAddress);
}
public bool Write(AcsAddressDefinition addressDefinition, object value)
{
AcsAddressDefinition validatedAddress = ValidateAddress(addressDefinition);
ValidateWriteValue(validatedAddress, value);
IMotionController controller = GetController();
string variableName = ResolveVariableName(validatedAddress);
bool result = controller.WriteVariableBuffer(DefaultBufferId, variableName, value);
if (!result)
{
throw CreateReadWriteException("Write", validatedAddress);
}
return true;
}
public bool Write(AcsAddressDefinition addressDefinition, object value, int index1, int index2)
{
AcsAddressDefinition validatedAddress = ValidateAddress(addressDefinition);
ValidateWriteValue(validatedAddress, value);
ValidateIndex(index1, nameof(index1));
ValidateIndex(index2, nameof(index2));
IMotionController controller = GetController();
string variableName = ResolveVariableName(validatedAddress);
bool result = controller.WriteVariableBuffer(DefaultBufferId, variableName, value, index1, index2);
if (!result)
{
throw CreateReadWriteException("Write", validatedAddress);
}
return true;
}
public bool WriteRange(AcsAddressDefinition addressDefinition, object value, int from1, int to1, int from2, int to2)
{
AcsAddressDefinition validatedAddress = ValidateAddress(addressDefinition);
ValidateWriteValue(validatedAddress, value);
ValidateRange(from1, to1, nameof(from1), nameof(to1));
ValidateRange(from2, to2, nameof(from2), nameof(to2));
IMotionController controller = GetController();
string variableName = ResolveVariableName(validatedAddress);
bool result = controller.WriteVariableBuffer(DefaultBufferId, variableName, value, from1, to1, from2, to2);
if (!result)
{
throw CreateReadWriteException("Write", validatedAddress);
}
return true;
}
private IMotionController GetController()
{
if (!IsReady)
{
throw new InvalidOperationException("ACS controller is not ready. Ensure AcsCard is initialized and opened.");
}
return _hardwareManager.AcsCard.Controller;
}
private static AcsAddressDefinition ValidateAddress(AcsAddressDefinition addressDefinition)
{
if (addressDefinition == null)
{
throw new ArgumentNullException(nameof(addressDefinition));
}
if (!addressDefinition.HasNumericAddress && !addressDefinition.HasSymbolicAddress)
{
throw new ArgumentException("ACS address definition does not contain a usable address.", nameof(addressDefinition));
}
return addressDefinition;
}
private static string ResolveVariableName(AcsAddressDefinition addressDefinition)
{
if (addressDefinition.HasSymbolicAddress)
{
return addressDefinition.SymbolicAddress;
}
return addressDefinition.Address.Value.ToString();
}
private static void ValidateTypeCompatibility(AcsAddressDefinition addressDefinition, Type targetType)
{
if (targetType == null)
{
throw new ArgumentNullException(nameof(targetType));
}
Type nonNullableTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
if (nonNullableTargetType == typeof(object))
{
return;
}
if (addressDefinition.DataType == nonNullableTargetType)
{
return;
}
if (addressDefinition.IsInteger && IsIntegerType(nonNullableTargetType))
{
return;
}
if (addressDefinition.IsFloatingPoint && IsFloatingPointType(nonNullableTargetType))
{
return;
}
throw new InvalidOperationException($"Address {addressDefinition.Name} is defined as {addressDefinition.DataType.Name} and cannot be read as {nonNullableTargetType.Name}.");
}
private static T ConvertValue<T>(object value, AcsAddressDefinition addressDefinition)
{
if (value == null)
{
return default(T);
}
if (value is T typedValue)
{
return typedValue;
}
Type targetType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
try
{
if (targetType == typeof(bool))
{
return (T)(object)ConvertToBoolean(value);
}
object convertedValue = Convert.ChangeType(value, targetType);
return (T)convertedValue;
}
catch (Exception ex)
{
throw new InvalidCastException($"The value of address {addressDefinition.Name} cannot be converted to {targetType.Name}.", ex);
}
}
private static bool ConvertToBoolean(object value)
{
if (value is bool boolValue)
{
return boolValue;
}
if (value is string stringValue)
{
if (string.Equals(stringValue, "1", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (string.Equals(stringValue, "0", StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
return Convert.ToDouble(value) != 0d;
}
private static void ValidateWriteValue(AcsAddressDefinition addressDefinition, object value)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (addressDefinition.Length > 1)
{
return;
}
Type valueType = value.GetType();
if (addressDefinition.DataType.IsAssignableFrom(valueType))
{
return;
}
if (addressDefinition.IsBoolean && IsBooleanCompatibleType(valueType))
{
return;
}
if (addressDefinition.IsInteger && IsIntegerType(valueType))
{
return;
}
if (addressDefinition.IsFloatingPoint && (IsFloatingPointType(valueType) || IsIntegerType(valueType)))
{
return;
}
throw new InvalidOperationException($"Address {addressDefinition.Name} is defined as {addressDefinition.DataType.Name}, but the current value type is {valueType.Name}.");
}
private static bool IsBooleanCompatibleType(Type type)
{
return type == typeof(bool) || IsIntegerType(type);
}
private static bool IsIntegerType(Type type)
{
return type == typeof(byte)
|| type == typeof(sbyte)
|| type == typeof(short)
|| type == typeof(ushort)
|| type == typeof(int)
|| type == typeof(uint)
|| type == typeof(long)
|| type == typeof(ulong);
}
private static bool IsFloatingPointType(Type type)
{
return type == typeof(float)
|| type == typeof(double)
|| type == typeof(decimal);
}
private static void ValidateIndex(int index, string parameterName)
{
if (index < 0)
{
throw new ArgumentOutOfRangeException(parameterName, index, "ACS index cannot be less than 0.");
}
}
private static void ValidateRange(int from, int to, string fromName, string toName)
{
ValidateIndex(from, fromName);
ValidateIndex(to, toName);
if (to < from)
{
throw new ArgumentException($"Parameter {toName} cannot be less than {fromName}.", toName);
}
}
private static Exception CreateReadWriteException(string operationName, AcsAddressDefinition addressDefinition)
{
string addressText = addressDefinition.HasSymbolicAddress
? addressDefinition.SymbolicAddress
: addressDefinition.Address.Value.ToString();
return new InvalidOperationException($"{operationName} ACS address failed: {addressDefinition.Name}, address={addressText}.");
}
}
}