添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,355 @@
|
||||
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}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
using System;
|
||||
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents one ACS controller address definition.
|
||||
/// Used to describe read/write address, data type, length, and note.
|
||||
/// </summary>
|
||||
public sealed class AcsAddressDefinition
|
||||
{
|
||||
public AcsAddressDefinition(string name, int address, Type dataType, int length = 1, string description = "")
|
||||
: this(name, dataType, length, description, address, null)
|
||||
{
|
||||
}
|
||||
|
||||
public AcsAddressDefinition(string name, string symbolicAddress, Type dataType, int length = 1, string description = "")
|
||||
: this(name, dataType, length, description, null, symbolicAddress)
|
||||
{
|
||||
}
|
||||
|
||||
private AcsAddressDefinition(string name, Type dataType, int length, string description, int? address, string symbolicAddress)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new ArgumentException("ACS address name cannot be empty.", nameof(name));
|
||||
}
|
||||
|
||||
if (dataType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dataType));
|
||||
}
|
||||
|
||||
if (length <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, "ACS address length must be greater than 0.");
|
||||
}
|
||||
|
||||
if (address.HasValue && address.Value < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(address), address, "ACS address cannot be less than 0.");
|
||||
}
|
||||
|
||||
if (!address.HasValue && string.IsNullOrWhiteSpace(symbolicAddress))
|
||||
{
|
||||
throw new ArgumentException("ACS address cannot be empty.", nameof(symbolicAddress));
|
||||
}
|
||||
|
||||
Name = name;
|
||||
Address = address;
|
||||
SymbolicAddress = symbolicAddress ?? string.Empty;
|
||||
DataType = dataType;
|
||||
Length = length;
|
||||
Description = description ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Semantic name, for example ServoOn or ActualPosition.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Numeric address in the ACS controller.
|
||||
/// </summary>
|
||||
public int? Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Symbolic address in the ACS controller, for example AP_SAPos1.
|
||||
/// </summary>
|
||||
public string SymbolicAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Data type mapped to this address.
|
||||
/// </summary>
|
||||
public Type DataType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Continuous address length. Default is 1.
|
||||
/// </summary>
|
||||
public int Length { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Address description for maintenance and diagnostics.
|
||||
/// </summary>
|
||||
public string Description { get; }
|
||||
|
||||
public bool HasNumericAddress
|
||||
{
|
||||
get { return Address.HasValue; }
|
||||
}
|
||||
|
||||
public bool HasSymbolicAddress
|
||||
{
|
||||
get { return !string.IsNullOrWhiteSpace(SymbolicAddress); }
|
||||
}
|
||||
|
||||
public bool IsBoolean
|
||||
{
|
||||
get { return DataType == typeof(bool); }
|
||||
}
|
||||
|
||||
public bool IsInteger
|
||||
{
|
||||
get { return DataType == typeof(short) || DataType == typeof(ushort) || DataType == typeof(int) || DataType == typeof(uint) || DataType == typeof(long) || DataType == typeof(ulong); }
|
||||
}
|
||||
|
||||
public bool IsFloatingPoint
|
||||
{
|
||||
get { return DataType == typeof(float) || DataType == typeof(double) || DataType == typeof(decimal); }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (HasNumericAddress)
|
||||
{
|
||||
return $"{Name} [Address={Address.Value}, Type={DataType.Name}, Length={Length}]";
|
||||
}
|
||||
|
||||
return $"{Name} [Symbol={SymbolicAddress}, Type={DataType.Name}, Length={Length}]";
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateBool(string name, int address, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, address, typeof(bool), 1, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateBool(string name, int address, int length, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, address, typeof(bool), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateInt32(string name, int address, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, address, typeof(int), 1, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateInt32(string name, int address, int length, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, address, typeof(int), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateDouble(string name, int address, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, address, typeof(double), 1, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateDouble(string name, int address, int length, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, address, typeof(double), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateSymbol(string name, string symbolicAddress, Type dataType, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, symbolicAddress, dataType, length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateSymbol(string name, Type dataType, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, name, dataType, length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateBoolSymbol(string name, string symbolicAddress, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, symbolicAddress, typeof(bool), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateBoolSymbol(string name, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, name, typeof(bool), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateInt32Symbol(string name, string symbolicAddress, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, symbolicAddress, typeof(int), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateInt32Symbol(string name, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, name, typeof(int), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateDoubleSymbol(string name, string symbolicAddress, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, symbolicAddress, typeof(double), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateDoubleSymbol(string name, int length = 1, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, name, typeof(double), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateString(string name, int address, int length, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, address, typeof(string), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateStringSymbol(string name, string symbolicAddress, int length, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, symbolicAddress, typeof(string), length, description);
|
||||
}
|
||||
|
||||
public static AcsAddressDefinition CreateStringSymbol(string name, int length, string description = "")
|
||||
{
|
||||
return new AcsAddressDefinition(name, name, typeof(string), length, description);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using MaxwellFramework.Core.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
[Singleton]
|
||||
public sealed class AcsAddressRepository
|
||||
{
|
||||
private readonly object _syncRoot = new object();
|
||||
private readonly Dictionary<string, AcsBondingCommunicationAdress> _bondingCommunicationDataCache = new Dictionary<string, AcsBondingCommunicationAdress>(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, AcsBondingLogAdress> _bondingLogDataCache = new Dictionary<string, AcsBondingLogAdress>(StringComparer.Ordinal);
|
||||
private readonly Lazy<AcsCommonAdress> _commonData = new Lazy<AcsCommonAdress>(() => new AcsCommonAdress());
|
||||
private readonly Lazy<AcsInterferometerCompensationAdress> _interferometerCompensationData = new Lazy<AcsInterferometerCompensationAdress>(() => new AcsInterferometerCompensationAdress());
|
||||
private readonly Lazy<AcsHomeOffsetAdress> _homeOffsetData = new Lazy<AcsHomeOffsetAdress>(() => new AcsHomeOffsetAdress());
|
||||
private readonly Lazy<AcsHomeSettingAdress> _homeSettingData = new Lazy<AcsHomeSettingAdress>(() => new AcsHomeSettingAdress());
|
||||
private readonly Lazy<AcsBondingAdress> _newBondingData = new Lazy<AcsBondingAdress>(() => new AcsBondingAdress());
|
||||
|
||||
public AcsBondingCommunicationAdress GetBondingCommunicationData(string addressSuffix)
|
||||
{
|
||||
string normalizedSuffix = NormalizeAddressSuffix(addressSuffix);
|
||||
AcsBondingCommunicationAdress communicationData;
|
||||
if (_bondingCommunicationDataCache.TryGetValue(normalizedSuffix, out communicationData))
|
||||
{
|
||||
return communicationData;
|
||||
}
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_bondingCommunicationDataCache.TryGetValue(normalizedSuffix, out communicationData))
|
||||
{
|
||||
return communicationData;
|
||||
}
|
||||
|
||||
communicationData = new AcsBondingCommunicationAdress(normalizedSuffix);
|
||||
_bondingCommunicationDataCache[normalizedSuffix] = communicationData;
|
||||
return communicationData;
|
||||
}
|
||||
}
|
||||
|
||||
public AcsBondingLogAdress GetBondingLogData(string addressSuffix)
|
||||
{
|
||||
string normalizedSuffix = NormalizeAddressSuffix(addressSuffix);
|
||||
AcsBondingLogAdress logData;
|
||||
if (_bondingLogDataCache.TryGetValue(normalizedSuffix, out logData))
|
||||
{
|
||||
return logData;
|
||||
}
|
||||
|
||||
lock (_syncRoot)
|
||||
{
|
||||
if (_bondingLogDataCache.TryGetValue(normalizedSuffix, out logData))
|
||||
{
|
||||
return logData;
|
||||
}
|
||||
|
||||
logData = new AcsBondingLogAdress(normalizedSuffix);
|
||||
_bondingLogDataCache[normalizedSuffix] = logData;
|
||||
return logData;
|
||||
}
|
||||
}
|
||||
|
||||
public AcsInterferometerCompensationAdress GetInterferometerCompensationData()
|
||||
{
|
||||
return _interferometerCompensationData.Value;
|
||||
}
|
||||
|
||||
public AcsCommonAdress GetCommonData()
|
||||
{
|
||||
return _commonData.Value;
|
||||
}
|
||||
|
||||
public AcsHomeOffsetAdress GetHomeOffsetData()
|
||||
{
|
||||
return _homeOffsetData.Value;
|
||||
}
|
||||
|
||||
public AcsHomeSettingAdress GetHomeSettingData()
|
||||
{
|
||||
return _homeSettingData.Value;
|
||||
}
|
||||
|
||||
public AcsBondingAdress GetNewBondingData()
|
||||
{
|
||||
return _newBondingData.Value;
|
||||
}
|
||||
|
||||
private static string NormalizeAddressSuffix(string addressSuffix)
|
||||
{
|
||||
if (addressSuffix == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(addressSuffix));
|
||||
}
|
||||
|
||||
string normalizedSuffix = addressSuffix.Trim();
|
||||
if (normalizedSuffix.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("ACS address suffix cannot be empty.", nameof(addressSuffix));
|
||||
}
|
||||
|
||||
return normalizedSuffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public sealed class AcsBondingAdress
|
||||
{
|
||||
public const string SumIndexName = "SumIndex";
|
||||
public const string PA_BondSumRowName = "PA_BondSumRow";
|
||||
public const string PA_DataSendFinishName = "PA_DataSendFinish";
|
||||
public const string PA_FBBondStopName = "PA_FBBondStop";
|
||||
public const string AP_FBBondingFinishName = "AP_FBBondingFinish";
|
||||
public const string PA_HomeAxisName = "PA_HomeAxis";
|
||||
public const string PHSCurrentRowName = "PHSCurrentRow";
|
||||
public const string AP_LogIndexAName = "AP_LogIndexA";
|
||||
public const string AP_LogIndexBName = "AP_LogIndexB";
|
||||
|
||||
public const string AP_LogIndexASymbol = "AP_LogIndexPerA";
|
||||
public const string AP_LogIndexBSymbol = "AP_LogIndexPerB";
|
||||
|
||||
public AcsBondingAdress()
|
||||
{
|
||||
SumIndex = AcsAddressDefinition.CreateInt32Symbol(SumIndexName, 1, "当前固晶计数。");
|
||||
PA_BondSumRow = AcsAddressDefinition.CreateInt32Symbol(PA_BondSumRowName, 1, "固晶总行数。");
|
||||
PA_DataSendFinish = AcsAddressDefinition.CreateInt32Symbol(PA_DataSendFinishName, 1, "数据发送完成标志。");
|
||||
PA_FBBondStop = AcsAddressDefinition.CreateInt32Symbol(PA_FBBondStopName, 1, "固晶停止标志,1 表示停止。");
|
||||
AP_FBBondingFinish = AcsAddressDefinition.CreateInt32Symbol(AP_FBBondingFinishName, 1, "固晶完成状态,0 表示进行中,1 表示完成,-1 表示默认值。");
|
||||
PA_HomeAxis = AcsAddressDefinition.CreateInt32Symbol(PA_HomeAxisName, 1, "回零目标轴号。");
|
||||
PHSCurrentRow = AcsAddressDefinition.CreateInt32Symbol(PHSCurrentRowName, 1, "当前固晶行索引。");
|
||||
AP_LogIndexA = AcsAddressDefinition.CreateInt32Symbol(AP_LogIndexAName, AP_LogIndexASymbol, 1, "A 区固晶日志计数。");
|
||||
AP_LogIndexB = AcsAddressDefinition.CreateInt32Symbol(AP_LogIndexBName, AP_LogIndexBSymbol, 1, "B 区固晶日志计数。");
|
||||
}
|
||||
|
||||
public AcsAddressDefinition SumIndex { get; }
|
||||
|
||||
public AcsAddressDefinition PA_BondSumRow { get; }
|
||||
|
||||
public AcsAddressDefinition PA_DataSendFinish { get; }
|
||||
|
||||
public AcsAddressDefinition PA_FBBondStop { get; }
|
||||
|
||||
public AcsAddressDefinition AP_FBBondingFinish { get; }
|
||||
|
||||
public AcsAddressDefinition PA_HomeAxis { get; }
|
||||
|
||||
public AcsAddressDefinition PHSCurrentRow { get; }
|
||||
|
||||
public AcsAddressDefinition AP_LogIndexA { get; }
|
||||
|
||||
public AcsAddressDefinition AP_LogIndexB { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public sealed class AcsBondingCommunicationAdress
|
||||
{
|
||||
public const string PA_X1PosArrayName = "PA_X1Pos_Array";
|
||||
public const string PA_X2PosArrayName = "PA_X2Pos_Array";
|
||||
public const string PA_Y1PosArrayName = "PA_Y1Pos_Array";
|
||||
public const string PA_Y2PosArrayName = "PA_Y2Pos_Array";
|
||||
public const string PA_RowSumName = "PA_RowSum";
|
||||
public const string PA_RowPointCountArrayName = "PA_RowPointCount_Array";
|
||||
public const string PA_CZIsBondingArrayName = "PA_CZIsBonding_Array";
|
||||
public const string PA_BigChangeRowArrayName = "PA_BigChangeRow_Array";
|
||||
public const string AP_FBStartName = "AP_FBStart";
|
||||
public const string PA_BonDataSendFinishName = "PA_BonDataSendFinish";
|
||||
public const string PA_BonNumberName = "PA_BonNumber";
|
||||
public const string PA_BonEndName = "PA_BonEnd";
|
||||
public const string PA_PadPitchName = "PA_PadPitch";
|
||||
public const string PA_CZoffsetName = "PA_CZoffset";
|
||||
|
||||
public const string PA_X1FBPosSymbol = "PA_X1FBPos";
|
||||
public const string PA_X2FBPosSymbol = "PA_X2FBPos";
|
||||
public const string PA_Y1FBPosSymbol = "PA_Y1FBPos";
|
||||
public const string PA_Y2FBPosSymbol = "PA_Y2FBPos";
|
||||
public const string PA_RowSumSymbol = "PA_RowSum";
|
||||
public const string PA_RowPointCountSymbol = "PA_RowPointCount";
|
||||
public const string PA_CZIsBondingSymbol = "PA_CZIsBonding";
|
||||
public const string PA_BigChangeRowSymbol = "PA_BigChangeRow";
|
||||
public const string AP_FBStartSymbol = "AP_FBStart";
|
||||
public const string PA_BonDataSendFinishSymbol = "PA_BonDataSendFinish";
|
||||
public const string PA_BonNumberSymbol = "PA_BonNumber";
|
||||
public const string PA_BonEndSymbol = "PA_BonEnd";
|
||||
public const string PA_PadPitchSymbol = "PA_PadPitch";
|
||||
public const string PA_CZoffsetSymbol = "PA_CZoffset";
|
||||
|
||||
public AcsBondingCommunicationAdress(string addressSuffix)
|
||||
{
|
||||
if (addressSuffix == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(addressSuffix));
|
||||
}
|
||||
|
||||
PA_X1Pos_Array = AcsAddressDefinition.CreateDoubleSymbol(PA_X1PosArrayName, PA_X1FBPosSymbol + addressSuffix, 10000, "A 区 X1 位置数组,长度为 10000。");
|
||||
PA_X2Pos_Array = AcsAddressDefinition.CreateDoubleSymbol(PA_X2PosArrayName, PA_X2FBPosSymbol + addressSuffix, 10000, "A 区 X2 位置数组,长度为 10000。");
|
||||
PA_Y1Pos_Array = AcsAddressDefinition.CreateDoubleSymbol(PA_Y1PosArrayName, PA_Y1FBPosSymbol + addressSuffix, 10000, "A 区 Y1 位置数组,长度为 10000。");
|
||||
PA_Y2Pos_Array = AcsAddressDefinition.CreateDoubleSymbol(PA_Y2PosArrayName, PA_Y2FBPosSymbol + addressSuffix, 10000, "A 区 Y2 位置数组,长度为 10000。");
|
||||
PA_RowSum = AcsAddressDefinition.CreateInt32Symbol(PA_RowSumName, PA_RowSumSymbol + addressSuffix, 1, "A 区已下发的固晶行数。");
|
||||
PA_RowPointCount_Array = AcsAddressDefinition.CreateInt32Symbol(PA_RowPointCountArrayName, PA_RowPointCountSymbol + addressSuffix, 10000, "A 区每行固晶点数数组。");
|
||||
PA_CZIsBonding_Array = AcsAddressDefinition.CreateBoolSymbol(PA_CZIsBondingArrayName, PA_CZIsBondingSymbol + addressSuffix, 10000, "A 区各点是否处于固晶状态。");
|
||||
PA_BigChangeRow_Array = AcsAddressDefinition.CreateBoolSymbol(PA_BigChangeRowArrayName, PA_BigChangeRowSymbol + addressSuffix, 10000, "A 区大跨行标记数组。");
|
||||
AP_FBStart = AcsAddressDefinition.CreateInt32Symbol(AP_FBStartName, AP_FBStartSymbol + addressSuffix, 1, "A 区固晶启动标志,1 表示启动。");
|
||||
PA_BonDataSendFinish = AcsAddressDefinition.CreateInt32Symbol(PA_BonDataSendFinishName, PA_BonDataSendFinishSymbol + addressSuffix, 1, "补固数据发送完成标志。");
|
||||
PA_BonNumber = AcsAddressDefinition.CreateInt32Symbol(PA_BonNumberName, PA_BonNumberSymbol + addressSuffix, 1, "各区补固次数。");
|
||||
PA_BonEnd = AcsAddressDefinition.CreateInt32Symbol(PA_BonEndName, PA_BonEndSymbol + addressSuffix, 1, "补固结束标志。");
|
||||
PA_PadPitch = AcsAddressDefinition.CreateDoubleSymbol(PA_PadPitchName, PA_PadPitchSymbol + addressSuffix, 1, "焊盘间距参数。");
|
||||
PA_CZoffset = AcsAddressDefinition.CreateDoubleSymbol(PA_CZoffsetName, PA_CZoffsetSymbol + addressSuffix, 1, "CZ 偏移量。");
|
||||
}
|
||||
|
||||
public AcsAddressDefinition PA_X1Pos_Array { get; }
|
||||
|
||||
public AcsAddressDefinition PA_X2Pos_Array { get; }
|
||||
|
||||
public AcsAddressDefinition PA_Y1Pos_Array { get; }
|
||||
|
||||
public AcsAddressDefinition PA_Y2Pos_Array { get; }
|
||||
|
||||
public AcsAddressDefinition PA_RowSum { get; }
|
||||
|
||||
public AcsAddressDefinition PA_RowPointCount_Array { get; }
|
||||
|
||||
public AcsAddressDefinition PA_CZIsBonding_Array { get; }
|
||||
|
||||
public AcsAddressDefinition PA_BigChangeRow_Array { get; }
|
||||
|
||||
public AcsAddressDefinition AP_FBStart { get; }
|
||||
|
||||
public AcsAddressDefinition PA_BonDataSendFinish { get; }
|
||||
|
||||
public AcsAddressDefinition PA_BonNumber { get; }
|
||||
|
||||
public AcsAddressDefinition PA_BonEnd { get; }
|
||||
|
||||
public AcsAddressDefinition PA_PadPitch { get; }
|
||||
|
||||
public AcsAddressDefinition PA_CZoffset { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public sealed class AcsBondingLogAdress
|
||||
{
|
||||
public const string AP_SAPosName = "AP_SAPos";
|
||||
public const string AP_SFPosName = "AP_SFPos";
|
||||
public const string AP_SAvelName = "AP_SAvel";
|
||||
public const string AP_SFvelName = "AP_SFvel";
|
||||
public const string AP_SPeName = "AP_SPe";
|
||||
public const string AP_EFPosName = "AP_EFPos";
|
||||
public const string AP_EAvelName = "AP_EAvel";
|
||||
public const string AP_EAPosName = "AP_EAPos";
|
||||
public const string AP_EFvelName = "AP_EFvel";
|
||||
public const string AP_EPeName = "AP_EPe";
|
||||
|
||||
public AcsBondingLogAdress(string addressSuffix)
|
||||
{
|
||||
if (addressSuffix == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(addressSuffix));
|
||||
}
|
||||
|
||||
AP_SAPos = AcsAddressDefinition.CreateDoubleSymbol(AP_SAPosName, AP_SAPosName + addressSuffix, 1, "固晶起始 A 位置日志。");
|
||||
AP_SFPos = AcsAddressDefinition.CreateDoubleSymbol(AP_SFPosName, AP_SFPosName + addressSuffix, 1, "固晶起始 F 位置日志。");
|
||||
AP_SAvel = AcsAddressDefinition.CreateDoubleSymbol(AP_SAvelName, AP_SAvelName + addressSuffix, 1, "固晶起始 A 速度日志。");
|
||||
AP_SFvel = AcsAddressDefinition.CreateDoubleSymbol(AP_SFvelName, AP_SFvelName + addressSuffix, 1, "固晶起始 F 速度日志。");
|
||||
AP_SPe = AcsAddressDefinition.CreateDoubleSymbol(AP_SPeName, AP_SPeName + addressSuffix, 1, "固晶起始误差日志。");
|
||||
AP_EFPos = AcsAddressDefinition.CreateDoubleSymbol(AP_EFPosName, AP_EFPosName + addressSuffix, 1, "固晶结束 F 位置日志。");
|
||||
AP_EAvel = AcsAddressDefinition.CreateDoubleSymbol(AP_EAvelName, AP_EAvelName + addressSuffix, 1, "固晶结束 A 速度日志。");
|
||||
AP_EAPos = AcsAddressDefinition.CreateDoubleSymbol(AP_EAPosName, AP_EAPosName + addressSuffix, 1, "固晶结束 A 位置日志。");
|
||||
AP_EFvel = AcsAddressDefinition.CreateDoubleSymbol(AP_EFvelName, AP_EFvelName + addressSuffix, 1, "固晶结束 F 速度日志。");
|
||||
AP_EPe = AcsAddressDefinition.CreateDoubleSymbol(AP_EPeName, AP_EPeName + addressSuffix, 1, "固晶结束误差日志。");
|
||||
}
|
||||
|
||||
public AcsAddressDefinition AP_SAPos { get; }
|
||||
|
||||
public AcsAddressDefinition AP_SFPos { get; }
|
||||
|
||||
public AcsAddressDefinition AP_SAvel { get; }
|
||||
|
||||
public AcsAddressDefinition AP_SFvel { get; }
|
||||
|
||||
public AcsAddressDefinition AP_SPe { get; }
|
||||
|
||||
public AcsAddressDefinition AP_EFPos { get; }
|
||||
|
||||
public AcsAddressDefinition AP_EAvel { get; }
|
||||
|
||||
public AcsAddressDefinition AP_EAPos { get; }
|
||||
|
||||
public AcsAddressDefinition AP_EFvel { get; }
|
||||
|
||||
public AcsAddressDefinition AP_EPe { get; }
|
||||
|
||||
public IReadOnlyList<AcsAddressDefinition> GetAddresses()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
AP_SAPos,
|
||||
AP_SFPos,
|
||||
AP_SAvel,
|
||||
AP_SFvel,
|
||||
AP_SPe,
|
||||
AP_EFPos,
|
||||
AP_EAvel,
|
||||
AP_EAPos,
|
||||
AP_EFvel,
|
||||
AP_EPe
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public sealed class AcsCommonAdress
|
||||
{
|
||||
public const string AP_ComSupMotionResName = "AP_ComSupMotionRes";
|
||||
public const string PA_ComSupMotionTypeName = "PA_ComSupMotionType";
|
||||
public const string PA_ChangeParaIndexName = "PA_ChangeParaIndex";
|
||||
|
||||
public const string AP_ComSupMotionResSymbol = "AP_ComSupMotionRes";
|
||||
public const string PA_ComSupMotionTypeSymbol = "PA_ComSupMotionType";
|
||||
public const string PA_ChangeParaIndexSymbol = "PA_ChangeParaIndex";
|
||||
|
||||
public AcsCommonAdress()
|
||||
{
|
||||
AP_ComSupMotionRes = AcsAddressDefinition.CreateInt32Symbol(AP_ComSupMotionResName, AP_ComSupMotionResSymbol, 1, "Result flag for ACS common communication command.");
|
||||
PA_ComSupMotionType = AcsAddressDefinition.CreateInt32Symbol(PA_ComSupMotionTypeName, PA_ComSupMotionTypeSymbol, 1, "Communication action type such as data set, home, alarm clear, or PID sync.");
|
||||
PA_ChangeParaIndex = AcsAddressDefinition.CreateInt32Symbol(PA_ChangeParaIndexName, PA_ChangeParaIndexSymbol, 1, "PID parameter index. 0=fast bonding PID, 1=fly-shot PID.");
|
||||
}
|
||||
|
||||
public AcsAddressDefinition AP_ComSupMotionRes { get; }
|
||||
|
||||
public AcsAddressDefinition PA_ComSupMotionType { get; }
|
||||
|
||||
public AcsAddressDefinition PA_ChangeParaIndex { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public sealed class AcsHomeOffsetAdress
|
||||
{
|
||||
private const int AxisIndexedArrayLength = 32;
|
||||
|
||||
public const string PA_HomeOffsetName = "PA_HomeOffset";
|
||||
public const string PA_HomeOffsetSymbol = "PA_HomeOffset";
|
||||
|
||||
public AcsHomeOffsetAdress()
|
||||
{
|
||||
PA_HomeOffset = AcsAddressDefinition.CreateDoubleSymbol(PA_HomeOffsetName, PA_HomeOffsetSymbol, AxisIndexedArrayLength, "Homing offset array, indexed by axis number.");
|
||||
}
|
||||
|
||||
public AcsAddressDefinition PA_HomeOffset { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public sealed class AcsHomeSettingAdress
|
||||
{
|
||||
private const int AxisIndexedArrayLength = 32;
|
||||
|
||||
public const string PA_HomeModeName = "PA_HomeMode";
|
||||
public const string PA_HomeVelName = "PA_HomeVel";
|
||||
public const string PA_HomeOrderName = "PA_HomeOrder";
|
||||
|
||||
public AcsHomeSettingAdress()
|
||||
{
|
||||
PA_HomeMode = AcsAddressDefinition.CreateInt32Symbol(PA_HomeModeName, AxisIndexedArrayLength, "回零模式数组,按轴号索引<E7B4A2><E5BC95>?");
|
||||
PA_HomeVel = AcsAddressDefinition.CreateDoubleSymbol(PA_HomeVelName, AxisIndexedArrayLength, "回零速度数组,按轴号索引<E7B4A2><E5BC95>?");
|
||||
PA_HomeOrder = AcsAddressDefinition.CreateInt32Symbol(PA_HomeOrderName, AxisIndexedArrayLength, "回零顺序数组,按轴号索引<E7B4A2><E5BC95>?");
|
||||
}
|
||||
|
||||
public AcsAddressDefinition PA_HomeMode { get; }
|
||||
|
||||
public AcsAddressDefinition PA_HomeVel { get; }
|
||||
|
||||
public AcsAddressDefinition PA_HomeOrder { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public sealed class AcsInterferometerCompensationAdress
|
||||
{
|
||||
private const int AxisIndexedArrayLength = 32;
|
||||
|
||||
public const string PA_CorrectionX1Name = "PA_Correction_X1";
|
||||
public const string PA_CorrectionY1Name = "PA_Correction_Y1";
|
||||
public const string PA_CorrectionX2Name = "PA_Correction_X2";
|
||||
public const string PA_CorrectionY2Name = "PA_Correction_Y2";
|
||||
public const string PA_StartPosName = "PA_StartPos";
|
||||
public const string PA_StepLenName = "PA_Step_len";
|
||||
public const string PA_CorrectionOpenName = "PA_CorrectionOpen";
|
||||
|
||||
public const string PA_CorrectionX1Symbol = "PA_Correction_X1";
|
||||
public const string PA_CorrectionY1Symbol = "PA_Correction_Y1";
|
||||
public const string PA_CorrectionX2Symbol = "PA_Correction_X2";
|
||||
public const string PA_CorrectionY2Symbol = "PA_Correction_Y2";
|
||||
public const string PA_StartPosSymbol = "PA_StartPos";
|
||||
public const string PA_StepLenSymbol = "PA_StepLen";
|
||||
public const string PA_CorrectionOpenSymbol = "PA_CorrectionOpen";
|
||||
|
||||
public AcsInterferometerCompensationAdress()
|
||||
{
|
||||
PA_Correction_X1 = AcsAddressDefinition.CreateDoubleSymbol(PA_CorrectionX1Name, PA_CorrectionX1Symbol, AxisIndexedArrayLength, "Interferometer compensation array for X1 axis.");
|
||||
PA_Correction_Y1 = AcsAddressDefinition.CreateDoubleSymbol(PA_CorrectionY1Name, PA_CorrectionY1Symbol, AxisIndexedArrayLength, "Interferometer compensation array for Y1 axis.");
|
||||
PA_Correction_X2 = AcsAddressDefinition.CreateDoubleSymbol(PA_CorrectionX2Name, PA_CorrectionX2Symbol, AxisIndexedArrayLength, "Interferometer compensation array for X2 axis.");
|
||||
PA_Correction_Y2 = AcsAddressDefinition.CreateDoubleSymbol(PA_CorrectionY2Name, PA_CorrectionY2Symbol, AxisIndexedArrayLength, "Interferometer compensation array for Y2 axis.");
|
||||
PA_StartPos = AcsAddressDefinition.CreateDoubleSymbol(PA_StartPosName, PA_StartPosSymbol, AxisIndexedArrayLength, "Compensation start position array, indexed by axis number.");
|
||||
PA_Step_len = AcsAddressDefinition.CreateDoubleSymbol(PA_StepLenName, PA_StepLenSymbol, AxisIndexedArrayLength, "Compensation step length array, indexed by axis number.");
|
||||
PA_CorrectionOpen = AcsAddressDefinition.CreateBoolSymbol(PA_CorrectionOpenName, PA_CorrectionOpenSymbol, AxisIndexedArrayLength, "Whether interferometer compensation is enabled per axis.");
|
||||
}
|
||||
|
||||
public AcsAddressDefinition PA_Correction_X1 { get; }
|
||||
|
||||
public AcsAddressDefinition PA_Correction_Y1 { get; }
|
||||
|
||||
public AcsAddressDefinition PA_Correction_X2 { get; }
|
||||
|
||||
public AcsAddressDefinition PA_Correction_Y2 { get; }
|
||||
|
||||
public AcsAddressDefinition PA_StartPos { get; }
|
||||
|
||||
public AcsAddressDefinition PA_Step_len { get; }
|
||||
|
||||
public AcsAddressDefinition PA_CorrectionOpen { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public class CorrectionItem
|
||||
{
|
||||
public string AxisName { get; set; }
|
||||
|
||||
public int AxisIndex { get; set; }
|
||||
|
||||
public double StepLength { get; set; }
|
||||
|
||||
public double StartPos { get; set; }
|
||||
|
||||
public ObservableCollection<CorrectionData> CorrectionDatas { get; set; }
|
||||
|
||||
public bool Enable { get; set; }
|
||||
|
||||
public int HomeMode { get; set; }
|
||||
|
||||
public double HomeSpeed { get; set; }
|
||||
|
||||
public int HomeOrder { get; set; }
|
||||
}
|
||||
|
||||
public class CorrectionData
|
||||
{
|
||||
public double ScaleData { get; set; }
|
||||
|
||||
public double ScaleNegativeData { get; set; }
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public double StepData { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
using MainShell.Common;
|
||||
using MainShell.PageCalib.OriginCalib.Model;
|
||||
using MaxwellFramework.Core.Attributes;
|
||||
using MwFramework.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace MainShell.Hardware.Acs
|
||||
{
|
||||
public interface IAcsStartupInitializationService
|
||||
{
|
||||
bool IsInitialized { get; }
|
||||
|
||||
void Initialize();
|
||||
|
||||
void WriteOriginCalibrationHomeOffsets();
|
||||
}
|
||||
|
||||
public sealed class AcsStartupInitializationService : IAcsStartupInitializationService
|
||||
{
|
||||
private const int CorrectionArrayLength = 100;
|
||||
private const int StartupPollingIntervalMilliseconds = 100;
|
||||
private const int StartupTimeoutMilliseconds = 10000;
|
||||
private const string InterferometerConfigRelativePath = @"Configuration\Card\Acs\Interferometer.xml";
|
||||
private const string WorkspaceInterferometerConfigRelativePath = @"Bin\Configuration\Card\Acs\Interferometer.xml";
|
||||
private readonly object _syncRoot = new object();
|
||||
private readonly IAcsAddressAccessService _acsAddressAccessService;
|
||||
private readonly AcsAddressRepository _acsAddressRepository;
|
||||
private readonly HardwareManager _hardwareManager;
|
||||
private bool _isInitialized;
|
||||
|
||||
public AcsStartupInitializationService(
|
||||
IAcsAddressAccessService acsAddressAccessService,
|
||||
AcsAddressRepository acsAddressRepository,
|
||||
HardwareManager hardwareManager)
|
||||
{
|
||||
_acsAddressAccessService = acsAddressAccessService ?? throw new ArgumentNullException(nameof(acsAddressAccessService));
|
||||
_acsAddressRepository = acsAddressRepository ?? throw new ArgumentNullException(nameof(acsAddressRepository));
|
||||
_hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
|
||||
}
|
||||
|
||||
public bool IsInitialized
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isInitialized;
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
lock (_syncRoot)
|
||||
{
|
||||
WriteInterferometerStartupParameters();
|
||||
WriteOriginCalibrationHomeOffsetsCore();
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteOriginCalibrationHomeOffsets()
|
||||
{
|
||||
WriteOriginCalibrationHomeOffsetsCore();
|
||||
}
|
||||
|
||||
private static void ValidateAxisIndex(int axisIndex, int axisCount)
|
||||
{
|
||||
if (axisIndex < 0 || axisIndex >= axisCount)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(axisIndex), axisIndex, "Axis index is outside the loaded ACS startup parameter range.");
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteInterferometerStartupParameters()
|
||||
{
|
||||
ObservableCollection<CorrectionItem> corrections = LoadInterferometerCorrections();
|
||||
AcsCommonAdress commonData = _acsAddressRepository.GetCommonData();
|
||||
AcsInterferometerCompensationAdress interferometerData = _acsAddressRepository.GetInterferometerCompensationData();
|
||||
AcsHomeSettingAdress homeSettingData = _acsAddressRepository.GetHomeSettingData();
|
||||
|
||||
int axisCount = homeSettingData.PA_HomeMode.Length;
|
||||
double[] startPositions = new double[axisCount];
|
||||
double[] stepLengths = new double[axisCount];
|
||||
int[] correctionOpens = new int[axisCount];
|
||||
int[] homeModes = new int[axisCount];
|
||||
double[] homeVelocities = new double[axisCount];
|
||||
int[] homeOrders = new int[axisCount];
|
||||
|
||||
foreach (CorrectionItem correctionItem in corrections)
|
||||
{
|
||||
if (correctionItem == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ValidateAxisIndex(correctionItem.AxisIndex, axisCount);
|
||||
|
||||
double[] correctionValues = BuildCorrectionArray(correctionItem);
|
||||
startPositions[correctionItem.AxisIndex] = correctionItem.StartPos;
|
||||
stepLengths[correctionItem.AxisIndex] = correctionItem.StepLength;
|
||||
correctionOpens[correctionItem.AxisIndex] = correctionItem.Enable ? 1 : 0;
|
||||
homeModes[correctionItem.AxisIndex] = correctionItem.HomeMode;
|
||||
homeVelocities[correctionItem.AxisIndex] = correctionItem.HomeSpeed;
|
||||
homeOrders[correctionItem.AxisIndex] = correctionItem.HomeOrder;
|
||||
|
||||
AcsAddressDefinition correctionBufferAddress;
|
||||
if (TryGetCorrectionBufferAddress(correctionItem.AxisName, interferometerData, out correctionBufferAddress))
|
||||
{
|
||||
_acsAddressAccessService.Write(correctionBufferAddress, correctionValues);
|
||||
}
|
||||
}
|
||||
|
||||
_acsAddressAccessService.Write(interferometerData.PA_StartPos, startPositions);
|
||||
_acsAddressAccessService.Write(interferometerData.PA_Step_len, stepLengths);
|
||||
_acsAddressAccessService.Write(interferometerData.PA_CorrectionOpen, correctionOpens);
|
||||
_acsAddressAccessService.Write(homeSettingData.PA_HomeMode, homeModes);
|
||||
_acsAddressAccessService.Write(homeSettingData.PA_HomeVel, homeVelocities);
|
||||
_acsAddressAccessService.Write(homeSettingData.PA_HomeOrder, homeOrders);
|
||||
_acsAddressAccessService.Write(commonData.PA_ComSupMotionType, (int)ComSupMotionType.Interfere);
|
||||
|
||||
WaitForStartupWriteResult(commonData);
|
||||
}
|
||||
|
||||
private ObservableCollection<CorrectionItem> LoadInterferometerCorrections()
|
||||
{
|
||||
string configPath = ResolveInterferometerConfigPath();
|
||||
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ObservableCollection<CorrectionItem>));
|
||||
|
||||
using (FileStream fileStream = File.OpenRead(configPath))
|
||||
{
|
||||
ObservableCollection<CorrectionItem> corrections = xmlSerializer.Deserialize(fileStream) as ObservableCollection<CorrectionItem>;
|
||||
if (corrections == null)
|
||||
{
|
||||
throw new InvalidOperationException("The interferometer configuration could not be deserialized.");
|
||||
}
|
||||
|
||||
return corrections;
|
||||
}
|
||||
}
|
||||
|
||||
private static double[] BuildCorrectionArray(CorrectionItem correctionItem)
|
||||
{
|
||||
double[] correctionValues = new double[CorrectionArrayLength];
|
||||
if (correctionItem.CorrectionDatas == null)
|
||||
{
|
||||
return correctionValues;
|
||||
}
|
||||
|
||||
int count = Math.Min(correctionItem.CorrectionDatas.Count, correctionValues.Length);
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
CorrectionData correctionData = correctionItem.CorrectionDatas[index];
|
||||
if (correctionData == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
correctionValues[index] = correctionData.ScaleData;
|
||||
}
|
||||
|
||||
return correctionValues;
|
||||
}
|
||||
|
||||
private void WriteOriginCalibrationHomeOffsetsCore()
|
||||
{
|
||||
OriginCalibSetting setting = OriginCalibSetting.LoadOrCreate();
|
||||
AcsHomeOffsetAdress homeOffsetData = _acsAddressRepository.GetHomeOffsetData();
|
||||
double[] homeOffsets = new double[homeOffsetData.PA_HomeOffset.Length];
|
||||
|
||||
WriteHomeOffset(homeOffsets, _hardwareManager.Axis_X1, GetCalibrationOffset(setting, OriginCalibModuleNames.GantryX1Y1, AxisName.Axis_PHS_X1));
|
||||
WriteHomeOffset(homeOffsets, _hardwareManager.Axis_Y1, GetCalibrationOffset(setting, OriginCalibModuleNames.GantryX1Y1, AxisName.Axis_PHS_Y1));
|
||||
WriteHomeOffset(homeOffsets, _hardwareManager.Axis_X2, GetCalibrationOffset(setting, OriginCalibModuleNames.GantryX2, AxisName.Axis_PHS_X2));
|
||||
WriteHomeOffset(homeOffsets, _hardwareManager.Axis_Stage_Y3, GetCalibrationOffset(setting, OriginCalibModuleNames.StageY2, AxisName.Axis_Stage_Y3));
|
||||
WriteHomeOffset(homeOffsets, _hardwareManager.Axis_WS_X3, GetCalibrationOffset(setting, OriginCalibModuleNames.WSX3, AxisName.Axis_WS_X3));
|
||||
|
||||
_acsAddressAccessService.Write(homeOffsetData.PA_HomeOffset, homeOffsets);
|
||||
}
|
||||
|
||||
private static double GetCalibrationOffset(OriginCalibSetting setting, string moduleName, string axisName)
|
||||
{
|
||||
if (setting == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(setting));
|
||||
}
|
||||
|
||||
OriginCalibModuleItem module = setting.Modules.Find(item =>
|
||||
item != null && string.Equals(item.ModuleName, moduleName, StringComparison.OrdinalIgnoreCase));
|
||||
if (module == null || module.CalibrationAxes == null)
|
||||
{
|
||||
return 0d;
|
||||
}
|
||||
|
||||
CalibrationAxisItem calibrationAxis = module.CalibrationAxes.Find(item =>
|
||||
item != null && string.Equals(item.AxisName, axisName, StringComparison.OrdinalIgnoreCase));
|
||||
if (calibrationAxis == null)
|
||||
{
|
||||
return 0d;
|
||||
}
|
||||
|
||||
return calibrationAxis.Offset;
|
||||
}
|
||||
|
||||
private static void WriteHomeOffset(double[] homeOffsets, IAxis axis, double offset)
|
||||
{
|
||||
if (homeOffsets == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(homeOffsets));
|
||||
}
|
||||
|
||||
if (axis == null)
|
||||
{
|
||||
throw new InvalidOperationException("The target axis for origin calibration home offset was not found.");
|
||||
}
|
||||
|
||||
int axisIndex = axis.AxisIndex;
|
||||
ValidateAxisIndex(axisIndex, homeOffsets.Length);
|
||||
homeOffsets[axisIndex] = offset;
|
||||
}
|
||||
|
||||
private void WaitForStartupWriteResult(AcsCommonAdress commonData)
|
||||
{
|
||||
if (commonData == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(commonData));
|
||||
}
|
||||
|
||||
DateTime deadline = DateTime.Now.AddMilliseconds(StartupTimeoutMilliseconds);
|
||||
int result = 0;
|
||||
|
||||
while (DateTime.Now <= deadline)
|
||||
{
|
||||
object rawResult = _acsAddressAccessService.Read(commonData.AP_ComSupMotionRes);
|
||||
if (rawResult != null)
|
||||
{
|
||||
result = Convert.ToInt32(rawResult);
|
||||
if (result == -1)
|
||||
{
|
||||
throw new InvalidOperationException("Writing interferometer startup parameters to ACS failed.");
|
||||
}
|
||||
|
||||
if (result == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(StartupPollingIntervalMilliseconds);
|
||||
}
|
||||
|
||||
throw new TimeoutException("Writing interferometer startup parameters to ACS timed out.");
|
||||
}
|
||||
|
||||
private static string ResolveInterferometerConfigPath()
|
||||
{
|
||||
List<string> candidatePaths = new List<string>
|
||||
{
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, InterferometerConfigRelativePath),
|
||||
Path.Combine(Environment.CurrentDirectory, WorkspaceInterferometerConfigRelativePath),
|
||||
Path.Combine(Environment.CurrentDirectory, InterferometerConfigRelativePath)
|
||||
};
|
||||
|
||||
foreach (string candidatePath in candidatePaths)
|
||||
{
|
||||
if (File.Exists(candidatePath))
|
||||
{
|
||||
return candidatePath;
|
||||
}
|
||||
}
|
||||
|
||||
throw new FileNotFoundException("The interferometer startup configuration file was not found.");
|
||||
}
|
||||
|
||||
private static bool TryGetCorrectionBufferAddress(
|
||||
string axisName,
|
||||
AcsInterferometerCompensationAdress interferometerData,
|
||||
out AcsAddressDefinition correctionBufferAddress)
|
||||
{
|
||||
if (interferometerData == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(interferometerData));
|
||||
}
|
||||
|
||||
correctionBufferAddress = null;
|
||||
if (string.IsNullOrWhiteSpace(axisName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string normalizedAxisName = axisName.Trim().ToUpperInvariant();
|
||||
switch (normalizedAxisName)
|
||||
{
|
||||
case "X1":
|
||||
case "X11":
|
||||
correctionBufferAddress = interferometerData.PA_Correction_X1;
|
||||
return true;
|
||||
case "Y1":
|
||||
case "Y11":
|
||||
correctionBufferAddress = interferometerData.PA_Correction_Y1;
|
||||
return true;
|
||||
case "X2":
|
||||
case "X21":
|
||||
correctionBufferAddress = interferometerData.PA_Correction_X2;
|
||||
return true;
|
||||
case "Y2":
|
||||
case "Y21":
|
||||
correctionBufferAddress = interferometerData.PA_Correction_Y2;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static int ResolveInterfereMotionTypeValue()
|
||||
{
|
||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (Assembly assembly in assemblies)
|
||||
{
|
||||
Type[] types;
|
||||
try
|
||||
{
|
||||
types = assembly.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
types = ex.Types;
|
||||
}
|
||||
|
||||
foreach (Type type in types)
|
||||
{
|
||||
if (type == null || !type.IsEnum || !string.Equals(type.Name, "ComSupMotionType", StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(type, "Interfere"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
object enumValue = Enum.Parse(type, "Interfere");
|
||||
return Convert.ToInt32(enumValue);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("The ComSupMotionType.Interfere enumeration value could not be resolved.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user