添加 MX-PD-盘古 项目文件

将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
Shi.Ji
2026-05-18 11:43:09 +08:00
parent 03632a379d
commit e31d3560bb
739 changed files with 99783 additions and 0 deletions

View File

@@ -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}.");
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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
};
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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.");
}
}
}

View File

@@ -0,0 +1,309 @@
using MainShell.EventArgsFolder;
using MainShell.Log;
using MainShell.Motion;
using MaxwellFramework.Core.Attributes;
using MwFramework.Device;
using MwFramework.Device.Delta;
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MainShell.Hardware
{
[Singleton]
public sealed class AxisHomeService : IHandle<OriginCalibDataChangedEventArgs>
{
private readonly HardwareManager _hardwareManager;
private readonly SafeAxisMotion _safeAxisMotion;
private readonly IDeltaAxisExtend _deltaAxisExtend;
private readonly Dictionary<string, double> _latestOriginCalibOffsets = new Dictionary<string, double>(StringComparer.Ordinal);
public IReadOnlyDictionary<string, double> LatestOriginCalibOffsets
{
get
{
return _latestOriginCalibOffsets;
}
}
public AxisHomeService(HardwareManager hardwareManager, SafeAxisMotion safeAxisMotion, IEventAggregator eventAggregator)
{
_hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
_safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion));
if (eventAggregator == null)
{
throw new ArgumentNullException(nameof(eventAggregator));
}
eventAggregator.Subscribe(this);
_deltaAxisExtend=_hardwareManager.TdCard as IDeltaAxisExtend;
SetHomeDoneEvent(AxisName.Axis_PHS_Z1);
SetHomeDoneEvent(AxisName.Axis_PHS_Z3);
SetHomeDoneEvent(AxisName.Axis_PHS_Z4);
SetHomeDoneEvent(AxisName.Axis_PHS_Z5);
SetHomeDoneEvent(AxisName.Axis_PHS_Z6);
}
private void SetHomeDoneEvent(string axisName)
{
var axis = ResolveAxis(axisName);
if (axis != null && axis is IDeltaAxisEvent deltaAxis)
{
deltaAxis.HomeFinished -= DeltaAxis_HomeFinished;
deltaAxis.HomeFinished += DeltaAxis_HomeFinished;
}
}
private void DeltaAxis_HomeFinished(IAxis arg1, bool arg2)
{
if(arg2)
{
}
}
private void SetHomeOffset(IAxis axis, double offset)
{
if (_deltaAxisExtend != null)
{
_deltaAxisExtend.SetAxisCurrentPosition(axis, offset);
}
}
public void Home(string axisName)
{
Home(axisName, CancellationToken.None);
}
public void Home(string axisName, CancellationToken cancellationToken)
{
HomeAsync(axisName, MotionController.DefaultTimeoutMilliseconds, cancellationToken).GetAwaiter().GetResult().EnsureSuccess();
}
public void Home(IAxis axis)
{
Home(axis, CancellationToken.None);
}
public void Home(IAxis axis, CancellationToken cancellationToken)
{
HomeAsync(axis, MotionController.DefaultTimeoutMilliseconds, cancellationToken).GetAwaiter().GetResult().EnsureSuccess();
}
public void Home(params string[] axisNames)
{
Home(CancellationToken.None, axisNames);
}
public void Home(CancellationToken cancellationToken, params string[] axisNames)
{
HomeAsync(MotionController.DefaultTimeoutMilliseconds, cancellationToken, axisNames).GetAwaiter().GetResult().EnsureSuccess();
}
public async Task<MotionResult> HomeAsync(string axisName, int timeoutMilliseconds = MotionController.DefaultTimeoutMilliseconds, CancellationToken cancellationToken = default(CancellationToken), int? alarmId = null)
{
if (string.IsNullOrWhiteSpace(axisName))
{
throw new ArgumentNullException(nameof(axisName));
}
IAxis axis = ResolveAxis(axisName);
return await HomeAsync(axis, timeoutMilliseconds, cancellationToken, alarmId).ConfigureAwait(false);
}
public async Task<MotionResult> HomeAsync(IAxis axis, int timeoutMilliseconds = MotionController.DefaultTimeoutMilliseconds, CancellationToken cancellationToken = default(CancellationToken), int? alarmId = null)
{
IAxis resolvedAxis = axis ?? throw new ArgumentNullException(nameof(axis));
string axisName = resolvedAxis.Name ?? string.Empty;
DateTime startedAt = DateTime.Now;
string.Format("Axis home started. Axis:{0}", axisName).LogInfo();
try
{
MotionResult result = await _safeAxisMotion.HomeAsync(resolvedAxis, timeoutMilliseconds, cancellationToken, alarmId).ConfigureAwait(false);
if (result.Succeeded)
{
string.Format("Axis home completed. Axis:{0} Duration:{1}ms", axisName, (DateTime.Now - startedAt).TotalMilliseconds.ToString("F0")).LogInfo();
}
else if (result.Cancelled)
{
string.Format("Axis home cancelled. Axis:{0}", axisName).LogInfo();
}
else
{
string failureMessage = string.IsNullOrWhiteSpace(result.Message) ? "Unknown axis home failure." : result.Message;
string.Format("Axis home failed. Axis:{0} Error:{1}", axisName, failureMessage).LogSysError();
}
return result;
}
catch (Exception ex)
{
string.Format("Axis home exception. Axis:{0} Error:{1}", axisName, ex.Message).LogSysError();
throw;
}
}
public Task<MotionBatchResult> HomeAsync(params string[] axisNames)
{
return HomeAsync(MotionController.DefaultTimeoutMilliseconds, CancellationToken.None, axisNames);
}
public Task<MotionBatchResult> HomeAsync(CancellationToken cancellationToken, params string[] axisNames)
{
return HomeAsync(MotionController.DefaultTimeoutMilliseconds, cancellationToken, axisNames);
}
public async Task<MotionBatchResult> HomeAsync(int timeoutMilliseconds, CancellationToken cancellationToken, params string[] axisNames)
{
string[] normalizedAxisNames = NormalizeAxisNames(axisNames);
if (normalizedAxisNames.Length == 0)
{
return new MotionBatchResult(Array.Empty<MotionResult>());
}
IAxis[] axes = normalizedAxisNames.Select(ResolveAxis).ToArray();
return await HomeAsync(timeoutMilliseconds, cancellationToken, axes).ConfigureAwait(false);
}
public Task<MotionBatchResult> HomeAsync(params IAxis[] axes)
{
return HomeAsync(MotionController.DefaultTimeoutMilliseconds, CancellationToken.None, axes);
}
public Task<MotionBatchResult> HomeAsync(CancellationToken cancellationToken, params IAxis[] axes)
{
return HomeAsync(MotionController.DefaultTimeoutMilliseconds, cancellationToken, axes);
}
public async Task<MotionBatchResult> HomeAsync(int timeoutMilliseconds, CancellationToken cancellationToken, params IAxis[] axes)
{
IAxis[] normalizedAxes = NormalizeAxes(axes);
if (normalizedAxes.Length == 0)
{
return new MotionBatchResult(Array.Empty<MotionResult>());
}
List<MotionResult> results = new List<MotionResult>(normalizedAxes.Length);
foreach (IAxis axis in normalizedAxes)
{
MotionResult result = await HomeAsync(axis, timeoutMilliseconds, cancellationToken).ConfigureAwait(false);
results.Add(result);
}
return new MotionBatchResult(results);
}
public Task<MotionBatchResult> SafeHomeAsync(params string[] axisNames)
{
return SafeHomeAsync(CancellationToken.None, axisNames);
}
public async Task<MotionBatchResult> SafeHomeAsync(CancellationToken cancellationToken, params string[] axisNames)
{
string[] normalizedAxisNames = NormalizeAxisNames(axisNames);
if (normalizedAxisNames.Length == 0)
{
return new MotionBatchResult(Array.Empty<MotionResult>());
}
string.Format("Batch axis home started. Axes:{0}", string.Join(", ", normalizedAxisNames)).LogInfo();
try
{
MotionBatchResult result = await _safeAxisMotion.SafeHomeAsync(cancellationToken, normalizedAxisNames).ConfigureAwait(false);
if (result.Succeeded)
{
string.Format("Batch axis home completed. Axes:{0}", string.Join(", ", normalizedAxisNames)).LogInfo();
}
else
{
IEnumerable<string> failedAxes = result.Results.Where(x => x != null && !x.Succeeded).Select(x => x.AxisName ?? string.Empty);
string.Format("Batch axis home failed. Axes:{0}", string.Join(", ", failedAxes)).LogSysError();
}
return result;
}
catch (Exception ex)
{
string.Format("Batch axis home exception. Axes:{0} Error:{1}", string.Join(", ", normalizedAxisNames), ex.Message).LogSysError();
throw;
}
}
public IAxis GetAxis(string axisName)
{
return ResolveAxis(axisName);
}
public bool TryGetOriginCalibOffset(string axisName, out double offset)
{
offset = 0;
if (string.IsNullOrWhiteSpace(axisName))
{
return false;
}
return _latestOriginCalibOffsets.TryGetValue(axisName, out offset);
}
private IAxis ResolveAxis(string axisName)
{
IAxis axis = _hardwareManager.GetAxisByName(axisName);
if (axis == null)
{
throw new ArgumentException(string.Format("Axis with name {0} was not found.", axisName), nameof(axisName));
}
return axis;
}
private static string[] NormalizeAxisNames(IEnumerable<string> axisNames)
{
return (axisNames ?? Enumerable.Empty<string>())
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct(StringComparer.Ordinal)
.ToArray();
}
private static IAxis[] NormalizeAxes(IEnumerable<IAxis> axes)
{
return (axes ?? Enumerable.Empty<IAxis>())
.Where(x => x != null)
.GroupBy(x => x.Name ?? string.Empty, StringComparer.Ordinal)
.Select(x => x.First())
.ToArray();
}
public void Handle(OriginCalibDataChangedEventArgs eventArgs)
{
if (eventArgs == null)
{
return;
}
_latestOriginCalibOffsets.Clear();
if (eventArgs.Axes != null)
{
foreach (OriginCalibAxisOffsetChangedItem axis in eventArgs.Axes)
{
if (axis == null || string.IsNullOrWhiteSpace(axis.AxisName))
{
continue;
}
_latestOriginCalibOffsets[axis.AxisName] = axis.Offset;
}
}
string.Format(
"Origin calibration data changed received. AxisCount:{0}",
_latestOriginCalibOffsets.Count).LogInfo();
}
}
}

View File

@@ -0,0 +1,343 @@
using MainShell.DeviceMaintance.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MainShell.Hardware
{
public interface IDeviceCylinderService
{
IReadOnlyList<CylinderDefinition> Definitions { get; }
bool TryGetDefinition(string name, out CylinderDefinition definition);
bool TryExtend(string name);
bool TryExtend(string name, out string failureReason);
bool TryRetract(string name);
bool TryRetract(string name, out string failureReason);
Task<bool> TryExtendAndWaitAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> TryRetractAndWaitAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<CylinderExecutionResult> TryExtendAndWaitResultAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<CylinderExecutionResult> TryRetractAndWaitResultAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
}
public class DeviceCylinderService : IDeviceCylinderService
{
private readonly IDeviceIoMonitorService _ioMonitorService;
private readonly Dictionary<string, CylinderDefinition> _definitionsByName;
private static readonly StringComparer PointReferenceComparer = StringComparer.OrdinalIgnoreCase;
private static readonly TimeSpan ActiveRefreshTimeout = TimeSpan.FromMilliseconds(120);
private static readonly TimeSpan FeedbackRetryInterval = TimeSpan.FromMilliseconds(50);
public IReadOnlyList<CylinderDefinition> Definitions { get; }
public DeviceCylinderService(IDeviceIoMonitorService ioMonitorService)
{
_ioMonitorService = ioMonitorService;
Definitions = CylinderDefinitionLoader.LoadDefinitions();
_definitionsByName = Definitions.ToDictionary(x => x.Name, x => x, StringComparer.OrdinalIgnoreCase);
}
public bool TryGetDefinition(string name, out CylinderDefinition definition)
{
return _definitionsByName.TryGetValue(name, out definition);
}
public bool TryExtend(string name)
{
string failureReason;
return TryExtend(name, out failureReason);
}
public bool TryExtend(string name, out string failureReason)
{
CylinderDefinition definition;
if (!TryGetDefinition(name, out definition))
{
failureReason = "未找到对应气缸定义。";
return false;
}
return Execute(definition, true, out failureReason);
}
public bool TryRetract(string name)
{
string failureReason;
return TryRetract(name, out failureReason);
}
public bool TryRetract(string name, out string failureReason)
{
CylinderDefinition definition;
if (!TryGetDefinition(name, out definition))
{
failureReason = "未找到对应气缸定义。";
return false;
}
return Execute(definition, false, out failureReason);
}
public async Task<bool> TryExtendAndWaitAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
var result = await TryExtendAndWaitResultAsync(name, timeout, cancellationToken);
return result.Success;
}
public async Task<bool> TryRetractAndWaitAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
var result = await TryRetractAndWaitResultAsync(name, timeout, cancellationToken);
return result.Success;
}
public async Task<CylinderExecutionResult> TryExtendAndWaitResultAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
CylinderDefinition definition;
string failureReason;
if (!TryGetDefinition(name, out definition))
{
return CreateFailureResult("未找到对应气缸定义。");
}
if (!Execute(definition, true, out failureReason))
{
return CreateFailureResult(failureReason);
}
return await WaitForFeedbackResultAsync(definition.ExtendedFeedbackPoints, definition.RetractedFeedbackPoints, timeout, cancellationToken);
}
public async Task<CylinderExecutionResult> TryRetractAndWaitResultAsync(string name, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
CylinderDefinition definition;
string failureReason;
if (!TryGetDefinition(name, out definition))
{
return CreateFailureResult("未找到对应气缸定义。");
}
if (!Execute(definition, false, out failureReason))
{
return CreateFailureResult(failureReason);
}
return await WaitForFeedbackResultAsync(definition.RetractedFeedbackPoints, definition.ExtendedFeedbackPoints, timeout, cancellationToken);
}
private bool Execute(CylinderDefinition definition, bool extend, out string failureReason)
{
if (!TryValidateConditions(definition, extend, out failureReason))
{
return false;
}
List<DeviceIoOutputWriteRequest> requests;
if (!TryBuildWriteRequests(definition, extend, out requests, out failureReason))
{
return false;
}
string failurePointReference;
var result = _ioMonitorService.TrySetOutputStates(requests, out failurePointReference);
failureReason = result
? string.Empty
: string.IsNullOrWhiteSpace(failurePointReference)
? "输出控制执行失败。"
: $"输出控制执行失败:{failurePointReference}";
return result;
}
private bool TryValidateConditions(CylinderDefinition definition, bool extend, out string failureReason)
{
failureReason = string.Empty;
var conditions = extend ? definition.ExtendConditions : definition.RetractConditions;
if (conditions == null || conditions.Count == 0)
{
return true;
}
_ioMonitorService.TryRefreshNow(ActiveRefreshTimeout);
foreach (var condition in conditions)
{
DeviceIoPointState point;
if (!TryGetPoint(condition.PointReference, out point))
{
failureReason = !string.IsNullOrWhiteSpace(condition.Message)
? condition.Message
: $"条件 IO {condition.PointReference} 状态不可用。";
return false;
}
if (point.Value != condition.ExpectedState)
{
failureReason = !string.IsNullOrWhiteSpace(condition.Message)
? condition.Message
: $"条件 IO {point.Name} 未满足,要求 {(condition.ExpectedState ? "ON" : "OFF")}。";
return false;
}
}
return true;
}
private async Task<CylinderExecutionResult> WaitForFeedbackResultAsync(IReadOnlyList<string> requiredOnPoints, IReadOnlyList<string> requiredOffPoints, TimeSpan timeout, CancellationToken cancellationToken)
{
var normalizedOnPoints = NormalizePointReferences(requiredOnPoints);
var normalizedOffPoints = NormalizePointReferences(requiredOffPoints);
if (normalizedOnPoints.Count == 0 && normalizedOffPoints.Count == 0)
{
return CreateSuccessResult();
}
var start = DateTime.UtcNow;
while (DateTime.UtcNow - start < timeout)
{
cancellationToken.ThrowIfCancellationRequested();
var remaining = timeout - (DateTime.UtcNow - start);
var refreshTimeout = remaining < ActiveRefreshTimeout ? remaining : ActiveRefreshTimeout;
if (refreshTimeout > TimeSpan.Zero)
{
await _ioMonitorService.TryRefreshNowAsync(refreshTimeout, cancellationToken);
}
var onReady = normalizedOnPoints.All(IsPointOn);
var offReady = normalizedOffPoints.All(pointReference => !IsPointOn(pointReference));
if (onReady && offReady)
{
return CreateSuccessResult();
}
await Task.Delay(FeedbackRetryInterval, cancellationToken);
}
return CreateFeedbackTimeoutResult(normalizedOnPoints, normalizedOffPoints);
}
private bool TryBuildWriteRequests(CylinderDefinition definition, bool extend, out List<DeviceIoOutputWriteRequest> requests, out string failureReason)
{
requests = new List<DeviceIoOutputWriteRequest>();
failureReason = string.Empty;
var desiredStates = new Dictionary<string, bool>(PointReferenceComparer);
if (!AddOutputRequests(desiredStates, definition.ExtendOutputPoints, extend, out failureReason) ||
!AddOutputRequests(desiredStates, definition.RetractOutputPoints, !extend, out failureReason))
{
return false;
}
requests.AddRange(desiredStates.Select(x => new DeviceIoOutputWriteRequest
{
PointReference = x.Key,
OutputOn = x.Value
}));
if (requests.Count > 0)
{
return true;
}
failureReason = "未配置输出控制点。";
return false;
}
private bool AddOutputRequests(IDictionary<string, bool> desiredStates, IEnumerable<string> pointReferences, bool outputOn, out string failureReason)
{
failureReason = string.Empty;
if (pointReferences == null)
{
return true;
}
foreach (var pointReference in pointReferences.Where(x => !string.IsNullOrWhiteSpace(x)))
{
bool existingState;
if (desiredStates.TryGetValue(pointReference, out existingState))
{
if (existingState != outputOn)
{
failureReason = $"气缸输出配置冲突:{pointReference} 同时要求为 {(existingState ? "ON" : "OFF")} 和 {(outputOn ? "ON" : "OFF")}。";
return false;
}
continue;
}
desiredStates[pointReference] = outputOn;
}
return true;
}
private static List<string> NormalizePointReferences(IEnumerable<string> pointReferences)
{
return (pointReferences ?? Enumerable.Empty<string>())
.Where(x => !string.IsNullOrWhiteSpace(x))
.Distinct(PointReferenceComparer)
.ToList();
}
private bool TryGetPoint(string pointReference, out DeviceIoPointState point)
{
return _ioMonitorService.TryGetPoint(pointReference, out point)
|| _ioMonitorService.TryGetPointByPointKey(pointReference, out point);
}
private bool IsPointOn(string pointReference)
{
return _ioMonitorService.IsPointOn(pointReference)
|| _ioMonitorService.IsPointOnByPointKey(pointReference);
}
private CylinderExecutionResult CreateFeedbackTimeoutResult(IReadOnlyList<string> requiredOnPoints, IReadOnlyList<string> requiredOffPoints)
{
var missingOnPoints = requiredOnPoints.Where(pointReference => !IsPointOn(pointReference)).ToList();
var missingOffPoints = requiredOffPoints.Where(IsPointOn).ToList();
var messages = new List<string>();
if (missingOnPoints.Count > 0)
{
messages.Add("以下反馈未到位(期望ON)" + string.Join("", missingOnPoints.Select(GetPointDisplayName)));
}
if (missingOffPoints.Count > 0)
{
messages.Add("以下反馈未复位(期望OFF)" + string.Join("", missingOffPoints.Select(GetPointDisplayName)));
}
var failurePoints = missingOnPoints.Concat(missingOffPoints).Distinct(PointReferenceComparer).ToList();
return new CylinderExecutionResult
{
Success = false,
FailureReason = messages.Count > 0 ? string.Join("", messages) : "等待气缸反馈超时。",
FailurePointReferences = failurePoints
};
}
private string GetPointDisplayName(string pointReference)
{
DeviceIoPointState point;
return TryGetPoint(pointReference, out point) ? point.Name : pointReference;
}
private static CylinderExecutionResult CreateSuccessResult()
{
return new CylinderExecutionResult
{
Success = true,
FailureReason = string.Empty
};
}
private static CylinderExecutionResult CreateFailureResult(string failureReason)
{
return new CylinderExecutionResult
{
Success = false,
FailureReason = failureReason ?? string.Empty
};
}
}
}

View File

@@ -0,0 +1,950 @@
using MainShell.EventArgsFolder;
using Stylet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MainShell.Hardware
{
public interface IDeviceIoMonitorService
{
event EventHandler<DeviceIoChangedEventArgs> IoChanged;
IReadOnlyList<DeviceIoPointDefinition> Definitions { get; }
IReadOnlyDictionary<string, List<DeviceIoPointDefinition>> DefinitionsByModule { get; }
IReadOnlyDictionary<string, DeviceIoPointState> LatestPoints { get; }
bool IsOnline { get; }
bool TryGetPoint(int id, out DeviceIoPointState point);
bool TryGetPoint(string name, out DeviceIoPointState point);
bool TryGetPointByPointKey(string pointKey, out DeviceIoPointState point);
bool IsPointOn(int id);
bool IsPointOn(string name);
bool IsPointOnByPointKey(string pointKey);
Task<bool> WaitForPointStateAsync(int id, bool expectedState, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> WaitForPointStateAsync(string name, bool expectedState, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> WaitForPointStateByPointKeyAsync(string pointKey, bool expectedState, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
IReadOnlyList<DeviceIoPointState> GetPointsByModule(string module);
void Start();
void Stop();
void RequestRefresh();
bool TryRefreshNow(TimeSpan timeout);
Task<bool> TryRefreshNowAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
bool TrySetOutputState(int id, bool outputOn);
bool TrySetOutputState(string name, bool outputOn);
bool TrySetOutputStateByPointKey(string pointKey, bool outputOn);
bool TrySetOutputStates(IReadOnlyList<DeviceIoOutputWriteRequest> requests, out string failurePointReference);
bool TrySetOutputStatesByPointKey(IReadOnlyDictionary<string, bool> outputStates, out string failurePointKey);
}
public class DeviceIoMonitorService : IDeviceIoMonitorService
{
private readonly HardwareManager _hardwareManager;
private readonly AutoResetEvent _refreshSignal = new AutoResetEvent(false);
private readonly TimeSpan _pollInterval = TimeSpan.FromMilliseconds(100);
private readonly object _syncRoot = new object();
private readonly List<DeviceIoPointDefinition> _definitions = new List<DeviceIoPointDefinition>();
private readonly Dictionary<string, List<DeviceIoPointDefinition>> _definitionsByModule = new Dictionary<string, List<DeviceIoPointDefinition>>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, DeviceIoPointDefinition> _definitionsByName = new Dictionary<string, DeviceIoPointDefinition>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, DeviceIoPointDefinition> _definitionsByPointKey = new Dictionary<string, DeviceIoPointDefinition>(StringComparer.OrdinalIgnoreCase);
private readonly object _refreshWaitersSyncRoot = new object();
private readonly List<TaskCompletionSource<bool>> _refreshWaiters = new List<TaskCompletionSource<bool>>();
private const string DeviceIoConfigFileName = "DeviceIoPoints.csv";
private readonly Dictionary<string, DeviceIoPointState> _latestPoints = new Dictionary<string, DeviceIoPointState>(StringComparer.OrdinalIgnoreCase);
private CancellationTokenSource _cts;
public event EventHandler<DeviceIoChangedEventArgs> IoChanged;
public IReadOnlyList<DeviceIoPointDefinition> Definitions => _definitions;
public IReadOnlyDictionary<string, List<DeviceIoPointDefinition>> DefinitionsByModule => _definitionsByModule;
public IReadOnlyDictionary<string, DeviceIoPointState> LatestPoints => GetLatestPointsSnapshot();
public bool IsOnline => _hardwareManager.TdCard != null || _hardwareManager.AcsCard != null;
public DeviceIoMonitorService(HardwareManager hardwareManager)
{
_hardwareManager = hardwareManager;
LoadIoPointDefinitions();
}
public void Start()
{
if (_cts != null)
{
return;
}
LoadIoPointDefinitions();
_cts = new CancellationTokenSource();
var token = _cts.Token;
Task.Run(async () =>
{
while (!token.IsCancellationRequested)
{
_refreshSignal.WaitOne(_pollInterval);
if (token.IsCancellationRequested)
{
break;
}
IList<DeviceIoPointState> readPoints;
if (!TryReadIoPoints(out readPoints) || readPoints == null || readPoints.Count == 0)
{
CompleteRefreshWaiters(false);
await Task.Yield();
continue;
}
var changed = CollectChangedPoints(readPoints);
CompleteRefreshWaiters(true);
if (changed.Count == 0)
{
await Task.Yield();
continue;
}
var handler = IoChanged;
if (handler != null)
{
var changedCopy = changed.Select(x => x.Clone()).ToList();
var allCopy = GetLatestPointsSnapshot();
Execute.OnUIThread(() => handler(this, new DeviceIoChangedEventArgs(changedCopy, allCopy)));
}
await Task.Yield();
}
}, token);
}
public void Stop()
{
if (_cts == null)
{
return;
}
_cts.Cancel();
_refreshSignal.Set();
CompleteRefreshWaiters(false);
_cts.Dispose();
_cts = null;
}
public void RequestRefresh()
{
_refreshSignal.Set();
}
public bool TryRefreshNow(TimeSpan timeout)
{
return TryRefreshNowAsync(timeout).GetAwaiter().GetResult();
}
public async Task<bool> TryRefreshNowAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
Start();
var waiter = new TaskCompletionSource<bool>();
CancellationTokenRegistration registration = default(CancellationTokenRegistration);
lock (_refreshWaitersSyncRoot)
{
_refreshWaiters.Add(waiter);
}
if (cancellationToken.CanBeCanceled)
{
registration = cancellationToken.Register(() => waiter.TrySetCanceled());
}
try
{
RequestRefresh();
if (timeout <= TimeSpan.Zero)
{
timeout = _pollInterval;
}
var completedTask = await Task.WhenAny(waiter.Task, Task.Delay(timeout, cancellationToken));
if (completedTask != waiter.Task)
{
RemoveRefreshWaiter(waiter);
return false;
}
return await waiter.Task;
}
finally
{
registration.Dispose();
}
}
public bool TrySetOutputState(int id, bool outputOn)
{
var definition = ResolveUniqueDefinitionById(id, IoPointType.Output);
if (definition == null)
{
return false;
}
var result = _hardwareManager.TryWriteIoPointValue(definition, outputOn);
if (result)
{
RequestRefresh();
}
return result;
}
public bool TrySetOutputStateByPointKey(string pointKey, bool outputOn)
{
DeviceIoPointDefinition definition;
if (!_definitionsByPointKey.TryGetValue(pointKey ?? string.Empty, out definition) || definition.Type != IoPointType.Output || !definition.Enabled)
{
return false;
}
var result = _hardwareManager.TryWriteIoPointValue(definition, outputOn);
if (result)
{
RequestRefresh();
}
return result;
}
public bool TrySetOutputStates(IReadOnlyList<DeviceIoOutputWriteRequest> requests, out string failurePointReference)
{
failurePointReference = string.Empty;
if (requests == null || requests.Count == 0)
{
return true;
}
var definitions = new List<Tuple<DeviceIoPointDefinition, bool, string>>();
foreach (var request in requests)
{
if (request == null || string.IsNullOrWhiteSpace(request.PointReference))
{
failurePointReference = string.Empty;
return false;
}
DeviceIoPointDefinition definition;
if (!TryResolveOutputDefinition(request.PointReference, out definition))
{
failurePointReference = request.PointReference;
return false;
}
definitions.Add(Tuple.Create(definition, request.OutputOn, request.PointReference));
}
foreach (var item in definitions)
{
if (!_hardwareManager.TryWriteIoPointValue(item.Item1, item.Item2))
{
failurePointReference = item.Item3;
return false;
}
}
RequestRefresh();
return true;
}
public bool TrySetOutputStatesByPointKey(IReadOnlyDictionary<string, bool> outputStates, out string failurePointKey)
{
failurePointKey = string.Empty;
if (outputStates == null || outputStates.Count == 0)
{
return true;
}
var definitions = new List<Tuple<DeviceIoPointDefinition, bool, string>>();
foreach (var item in outputStates)
{
DeviceIoPointDefinition definition;
if (!_definitionsByPointKey.TryGetValue(item.Key ?? string.Empty, out definition) || definition.Type != IoPointType.Output || !definition.Enabled)
{
failurePointKey = item.Key;
return false;
}
definitions.Add(Tuple.Create(definition, item.Value, item.Key));
}
foreach (var item in definitions)
{
if (!_hardwareManager.TryWriteIoPointValue(item.Item1, item.Item2))
{
failurePointKey = item.Item3;
return false;
}
}
RequestRefresh();
return true;
}
public bool TrySetOutputState(string name, bool outputOn)
{
DeviceIoPointDefinition definition;
if (!_definitionsByName.TryGetValue(name ?? string.Empty, out definition) || definition.Type != IoPointType.Output || !definition.Enabled)
{
return false;
}
var result = _hardwareManager.TryWriteIoPointValue(definition, outputOn);
if (result)
{
RequestRefresh();
}
return result;
}
public bool TryGetPoint(int id, out DeviceIoPointState point)
{
var definition = ResolveUniqueDefinitionById(id, null);
if (definition == null)
{
point = null;
return false;
}
lock (_syncRoot)
{
if (_latestPoints.TryGetValue(definition.PointKey, out point))
{
point = point.Clone();
return true;
}
}
point = null;
return false;
}
public bool TryGetPointByPointKey(string pointKey, out DeviceIoPointState point)
{
lock (_syncRoot)
{
if (_latestPoints.TryGetValue(pointKey ?? string.Empty, out point))
{
point = point.Clone();
return true;
}
}
point = null;
return false;
}
public bool IsPointOn(int id)
{
DeviceIoPointState point;
return TryGetPoint(id, out point) && point.Value;
}
public bool IsPointOn(string name)
{
DeviceIoPointState point;
return TryGetPoint(name, out point) && point.Value;
}
public bool IsPointOnByPointKey(string pointKey)
{
DeviceIoPointState point;
return TryGetPointByPointKey(pointKey, out point) && point.Value;
}
public async Task<bool> WaitForPointStateAsync(int id, bool expectedState, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
var start = DateTime.UtcNow;
while (DateTime.UtcNow - start < timeout)
{
cancellationToken.ThrowIfCancellationRequested();
var remaining = timeout - (DateTime.UtcNow - start);
var refreshTimeout = remaining < _pollInterval ? remaining : _pollInterval;
if (refreshTimeout > TimeSpan.Zero)
{
await TryRefreshNowAsync(refreshTimeout, cancellationToken);
}
if (IsPointOn(id) == expectedState)
{
return true;
}
await Task.Delay(50, cancellationToken);
}
return false;
}
public async Task<bool> WaitForPointStateByPointKeyAsync(string pointKey, bool expectedState, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
var start = DateTime.UtcNow;
while (DateTime.UtcNow - start < timeout)
{
cancellationToken.ThrowIfCancellationRequested();
var remaining = timeout - (DateTime.UtcNow - start);
var refreshTimeout = remaining < _pollInterval ? remaining : _pollInterval;
if (refreshTimeout > TimeSpan.Zero)
{
await TryRefreshNowAsync(refreshTimeout, cancellationToken);
}
if (IsPointOnByPointKey(pointKey) == expectedState)
{
return true;
}
await Task.Delay(50, cancellationToken);
}
return false;
}
public async Task<bool> WaitForPointStateAsync(string name, bool expectedState, TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
var start = DateTime.UtcNow;
while (DateTime.UtcNow - start < timeout)
{
cancellationToken.ThrowIfCancellationRequested();
var remaining = timeout - (DateTime.UtcNow - start);
var refreshTimeout = remaining < _pollInterval ? remaining : _pollInterval;
if (refreshTimeout > TimeSpan.Zero)
{
await TryRefreshNowAsync(refreshTimeout, cancellationToken);
}
if (IsPointOn(name) == expectedState)
{
return true;
}
await Task.Delay(50, cancellationToken);
}
return false;
}
public bool TryGetPoint(string name, out DeviceIoPointState point)
{
DeviceIoPointDefinition definition;
if (!_definitionsByName.TryGetValue(name ?? string.Empty, out definition) && !_definitionsByPointKey.TryGetValue(name ?? string.Empty, out definition))
{
point = null;
return false;
}
lock (_syncRoot)
{
if (_latestPoints.TryGetValue(definition.PointKey, out point))
{
point = point.Clone();
return true;
}
}
point = null;
return false;
}
public IReadOnlyList<DeviceIoPointState> GetPointsByModule(string module)
{
lock (_syncRoot)
{
return _latestPoints.Values
.Where(x => string.Equals(x.Module, module, StringComparison.OrdinalIgnoreCase))
.Select(x => x.Clone())
.ToList();
}
}
private bool TryReadIoPoints(out IList<DeviceIoPointState> points)
{
points = new List<DeviceIoPointState>();
if (Definitions == null || Definitions.Count == 0)
{
return false;
}
Dictionary<string, bool> readValues;
bool hasBatchValues = _hardwareManager.TryReadIoPointValues(Definitions, out readValues);
foreach (DeviceIoPointDefinition definition in Definitions)
{
bool value;
if (!definition.Enabled)
{
value = definition.DefaultValue;
}
else if (hasBatchValues && readValues != null && readValues.TryGetValue(definition.PointKey, out value))
{
}
else if (!_hardwareManager.TryReadIoPointValue(definition, out value))
{
value = definition.DefaultValue;
}
DeviceIoPointState state;
if (definition.Type == IoPointType.Output)
{
state = new DeviceOutputPointState
{
Id = definition.Id,
PointKey = definition.PointKey,
Module = definition.Module,
Name = definition.Name,
Card = definition.Card,
StationNo = definition.StationNo,
LineNo = definition.LineNo,
Value = value,
IsInverse = definition.IsInverse,
CommandValue = value
};
}
else
{
state = new DeviceInputPointState
{
Id = definition.Id,
PointKey = definition.PointKey,
Module = definition.Module,
Name = definition.Name,
Card = definition.Card,
StationNo = definition.StationNo,
LineNo = definition.LineNo,
Value = value,
IsInverse = definition.IsInverse
};
}
points.Add(state);
}
return points.Count > 0;
}
private void LoadIoPointDefinitions()
{
_definitions.Clear();
_definitionsByModule.Clear();
_definitionsByName.Clear();
_definitionsByPointKey.Clear();
var pointKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var names = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var path = ResolveConfigPath();
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
{
return;
}
var lines = File.ReadAllLines(path, Encoding.UTF8);
for (var i = 0; i < lines.Length; i++)
{
var raw = lines[i];
if (string.IsNullOrWhiteSpace(raw))
{
continue;
}
var line = raw.Trim();
if (line.StartsWith("#"))
{
continue;
}
if (i == 0 && line.IndexOf("Id", StringComparison.OrdinalIgnoreCase) >= 0)
{
continue;
}
var cols = line.Split(',');
if (cols.Length < 11)
{
continue;
}
int id;
if (!int.TryParse(cols[0].Trim(), out id))
{
continue;
}
var moduleIndex = 1;
var nameIndex = 2;
var typeIndex = 3;
var cardIndex = 4;
var stationIndex = 5;
var indexColumnIndex = 6;
var subIndexColumnIndex = 7;
var lineNoIndex = 8;
var enabledIndex = 9;
var defaultValueIndex = 10;
var isInverseIndex = cols.Length >= 12 ? 11 : -1;
var descriptionIndex = isInverseIndex >= 0 ? 12 : 11;
var name = cols[nameIndex].Trim();
if (string.IsNullOrWhiteSpace(name))
{
continue;
}
var module = cols[moduleIndex].Trim();
if (string.IsNullOrWhiteSpace(module))
{
module = "Default";
}
var type = ParseIoPointType(cols[typeIndex]);
var card = ParseIoCardType(cols[cardIndex]);
var stationNo = ParseInt(cols[stationIndex]);
var index = ParseInt(cols[indexColumnIndex]);
var subIndex = ParseInt(cols[subIndexColumnIndex]);
var lineNo = cols[lineNoIndex].Trim();
var pointKey = DeviceIoPointDefinition.BuildPointKey(type, card, stationNo, index, subIndex, lineNo);
if (!pointKeys.Add(pointKey) || !names.Add(name))
{
continue;
}
var definition = new DeviceIoPointDefinition
{
Id = id,
PointKey = pointKey,
Module = module,
Name = name,
Type = type,
Card = card,
StationNo = stationNo,
Index = index,
SubIndex = subIndex,
LineNo = lineNo,
Enabled = ParseBoolean(cols[enabledIndex], true),
DefaultValue = ParseBoolean(cols[defaultValueIndex], false),
IsInverse = isInverseIndex >= 0 && isInverseIndex < cols.Length && ParseBoolean(cols[isInverseIndex], false),
Description = cols.Length > descriptionIndex ? string.Join(",", cols.Skip(descriptionIndex)).Trim() : string.Empty
};
_definitions.Add(definition);
_definitionsByName[definition.Name] = definition;
_definitionsByPointKey[definition.PointKey] = definition;
List<DeviceIoPointDefinition> moduleDefinitions;
if (!_definitionsByModule.TryGetValue(module, out moduleDefinitions))
{
moduleDefinitions = new List<DeviceIoPointDefinition>();
_definitionsByModule[module] = moduleDefinitions;
}
moduleDefinitions.Add(definition);
}
}
private static int ParseInt(string raw)
{
int value;
return int.TryParse((raw ?? string.Empty).Trim(), out value) ? value : 0;
}
private static IoPointType ParseIoPointType(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return IoPointType.Input;
}
var text = raw.Trim();
if (string.Equals(text, "Output", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "OUT", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "DO", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "O", StringComparison.OrdinalIgnoreCase))
{
return IoPointType.Output;
}
return IoPointType.Input;
}
private static IoCardType ParseIoCardType(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return IoCardType.Td;
}
var text = raw.Trim();
if (string.Equals(text, "Acs", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "ACS", StringComparison.OrdinalIgnoreCase))
{
return IoCardType.Acs;
}
return IoCardType.Td;
}
private static bool ParseBoolean(string raw, bool defaultValue)
{
if (string.IsNullOrWhiteSpace(raw))
{
return defaultValue;
}
var text = raw.Trim();
if (string.Equals(text, "1", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "true", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "yes", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "y", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (string.Equals(text, "0", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "false", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "no", StringComparison.OrdinalIgnoreCase) ||
string.Equals(text, "n", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return defaultValue;
}
private DeviceIoPointDefinition ResolveUniqueDefinitionById(int id, IoPointType? pointType)
{
var matches = _definitions
.Where(x => x.Id == id && (!pointType.HasValue || x.Type == pointType.Value))
.Take(2)
.ToList();
return matches.Count == 1 ? matches[0] : null;
}
private void CompleteRefreshWaiters(bool result)
{
List<TaskCompletionSource<bool>> waiters;
lock (_refreshWaitersSyncRoot)
{
if (_refreshWaiters.Count == 0)
{
return;
}
waiters = _refreshWaiters.ToList();
_refreshWaiters.Clear();
}
foreach (var waiter in waiters)
{
waiter.TrySetResult(result);
}
}
private void RemoveRefreshWaiter(TaskCompletionSource<bool> waiter)
{
lock (_refreshWaitersSyncRoot)
{
_refreshWaiters.Remove(waiter);
}
}
private bool TryResolveOutputDefinition(string pointReference, out DeviceIoPointDefinition definition)
{
definition = null;
if (string.IsNullOrWhiteSpace(pointReference))
{
return false;
}
if (_definitionsByPointKey.TryGetValue(pointReference, out definition))
{
return definition.Type == IoPointType.Output && definition.Enabled;
}
if (_definitionsByName.TryGetValue(pointReference, out definition))
{
return definition.Type == IoPointType.Output && definition.Enabled;
}
int id;
if (int.TryParse(pointReference, out id))
{
definition = ResolveUniqueDefinitionById(id, IoPointType.Output);
return definition != null && definition.Enabled;
}
return false;
}
private static string ResolveConfigPath()
{
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
var localPath = Path.Combine(baseDir, "Configuration", DeviceIoConfigFileName);
var sourcePath = ResolveRootConfigPath(baseDir);
if (TrySyncConfigToLocal(sourcePath, localPath))
{
return localPath;
}
return File.Exists(localPath) ? localPath : null;
}
private static string ResolveRootConfigPath(string baseDir)
{
var current = new DirectoryInfo(baseDir);
while (current != null)
{
var rootConfigDir = Path.Combine(current.FullName, "Configuration");
if (Directory.Exists(rootConfigDir) && Directory.Exists(Path.Combine(current.FullName, "MainShell")))
{
var path = Path.Combine(rootConfigDir, DeviceIoConfigFileName);
if (File.Exists(path))
{
return path;
}
}
current = current.Parent;
}
return null;
}
private static bool TrySyncConfigToLocal(string sourcePath, string localPath)
{
if (string.IsNullOrWhiteSpace(sourcePath) || !File.Exists(sourcePath))
{
return false;
}
if (!string.Equals(Path.GetFullPath(sourcePath), Path.GetFullPath(localPath), StringComparison.OrdinalIgnoreCase))
{
var localDir = Path.GetDirectoryName(localPath);
if (!string.IsNullOrWhiteSpace(localDir))
{
Directory.CreateDirectory(localDir);
}
if (!File.Exists(localPath) || File.GetLastWriteTimeUtc(localPath) < File.GetLastWriteTimeUtc(sourcePath))
{
File.Copy(sourcePath, localPath, true);
}
}
return true;
}
private List<DeviceIoPointState> CollectChangedPoints(IList<DeviceIoPointState> readPoints)
{
var changed = new List<DeviceIoPointState>();
lock (_syncRoot)
{
if (_latestPoints.Count == 0)
{
foreach (var point in readPoints)
{
if (point == null)
{
continue;
}
_latestPoints[point.PointKey] = PreparePoint(point.Clone());
}
return changed;
}
foreach (var point in readPoints)
{
if (point == null)
{
continue;
}
if (!_latestPoints.TryGetValue(point.PointKey, out DeviceIoPointState old))
{
_latestPoints[point.PointKey] = PreparePoint(point.Clone());
changed.Add(PreparePoint(point.Clone()));
continue;
}
if (HasPointChanged(old, point))
{
_latestPoints[point.PointKey] = PreparePoint(point.Clone());
changed.Add(PreparePoint(point.Clone()));
}
}
}
return changed;
}
private IReadOnlyDictionary<string, DeviceIoPointState> GetLatestPointsSnapshot()
{
lock (_syncRoot)
{
return _latestPoints.ToDictionary(x => x.Key, x => PreparePoint(x.Value.Clone()));
}
}
private DeviceIoPointState PreparePoint(DeviceIoPointState point)
{
var outputPoint = point as DeviceOutputPointState;
DeviceIoPointDefinition definition;
_definitionsByPointKey.TryGetValue(point.PointKey ?? string.Empty, out definition);
if (outputPoint != null && definition != null && definition.Enabled)
{
outputPoint.BindWriteAction(outputOn => TrySetOutputState(definition.Name, outputOn));
}
return point;
}
private static bool HasPointChanged(DeviceIoPointState oldPoint, DeviceIoPointState newPoint)
{
if (oldPoint == null || newPoint == null)
{
return true;
}
if (oldPoint.Value != newPoint.Value ||
oldPoint.PointType != newPoint.PointType ||
!string.Equals(oldPoint.PointKey, newPoint.PointKey, StringComparison.OrdinalIgnoreCase) ||
!string.Equals(oldPoint.Name, newPoint.Name, StringComparison.OrdinalIgnoreCase) ||
!string.Equals(oldPoint.Module, newPoint.Module, StringComparison.OrdinalIgnoreCase) ||
oldPoint.Card != newPoint.Card)
{
return true;
}
var oldOutput = oldPoint as DeviceOutputPointState;
var newOutput = newPoint as DeviceOutputPointState;
if (oldOutput != null && newOutput != null)
{
return oldOutput.CommandValue != newOutput.CommandValue;
}
return false;
}
}
}

View File

@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MainShell.Hardware
{
public enum IoPointType
{
Input = 0,
Output = 1
}
public enum IoCardType
{
Td = 0,
Acs = 1
}
public class DeviceIoPointDefinition
{
public int Id { get; set; }
public string PointKey { get; set; }
public string Module { get; set; }
public string Name { get; set; }
public IoPointType Type { get; set; }
public IoCardType Card { get; set; }
public int StationNo { get; set; }
public int Index { get; set; }
public int SubIndex { get; set; }
public string LineNo { get; set; }
public bool Enabled { get; set; } = true;
public bool DefaultValue { get; set; }
public bool IsInverse { get; set; }
public string Description { get; set; }
public static string BuildPointKey(IoPointType type, IoCardType card, int stationNo, string lineNo)
{
return BuildPointKey(type, card, stationNo, 0, 0, lineNo);
}
public static string BuildPointKey(IoPointType type, IoCardType card, int stationNo, int index, int subIndex, string lineNo)
{
return string.Format(
"{0}:{1}:{2}:{3}:{4}:{5}",
type,
card,
stationNo,
index,
subIndex,
(lineNo ?? string.Empty).Trim().ToUpperInvariant());
}
}
public class DeviceIoOutputWriteRequest
{
public string PointReference { get; set; }
public bool OutputOn { get; set; }
}
public abstract class DeviceIoPointState
{
public int Id { get; set; }
public string PointKey { get; set; }
public string Module { get; set; }
public string Name { get; set; }
public IoCardType Card { get; set; }
public int StationNo { get; set; }
public string LineNo { get; set; }
public bool Value { get; set; }
public bool IsInverse { get; set; }
public abstract IoPointType PointType { get; }
public abstract DeviceIoPointState Clone();
}
public class DeviceInputPointState : DeviceIoPointState
{
public override IoPointType PointType => IoPointType.Input;
public override DeviceIoPointState Clone()
{
return new DeviceInputPointState
{
Id = Id,
PointKey = PointKey,
Module = Module,
Name = Name,
Card = Card,
StationNo = StationNo,
LineNo = LineNo,
Value = Value,
IsInverse = IsInverse
};
}
}
public class DeviceOutputPointState : DeviceIoPointState
{
private Func<bool, bool> _writeAction;
public bool CommandValue { get; set; }
public bool CanWrite => _writeAction != null;
public override IoPointType PointType => IoPointType.Output;
public void BindWriteAction(Func<bool, bool> writeAction)
{
_writeAction = writeAction;
}
public bool TrySetOutput(bool outputOn)
{
if (_writeAction == null)
{
return false;
}
var result = _writeAction(outputOn);
if (result)
{
CommandValue = outputOn;
}
return result;
}
public bool TryTurnOn()
{
return TrySetOutput(true);
}
public bool TryTurnOff()
{
return TrySetOutput(false);
}
public override DeviceIoPointState Clone()
{
var clone = new DeviceOutputPointState
{
Id = Id,
PointKey = PointKey,
Module = Module,
Name = Name,
Card = Card,
StationNo = StationNo,
LineNo = LineNo,
Value = Value,
CommandValue = CommandValue,
IsInverse = IsInverse
};
clone.BindWriteAction(_writeAction);
return clone;
}
}
public class IoModuleSnapshot
{
public string Module { get; set; }
public IReadOnlyList<DeviceIoPointState> Points { get; set; } = new List<DeviceIoPointState>();
}
public class DeviceIoSnapshot
{
public bool IsValid { get; set; }
public DateTime Timestamp { get; set; } = DateTime.Now;
public IReadOnlyDictionary<string, DeviceIoPointState> AllPoints { get; set; } = new Dictionary<string, DeviceIoPointState>();
public IReadOnlyList<IoModuleSnapshot> Modules
{
get
{
return AllPoints.Values
.GroupBy(x => string.IsNullOrWhiteSpace(x.Module) ? "Default" : x.Module)
.Select(g => new IoModuleSnapshot
{
Module = g.Key,
Points = g.Select(x => x.Clone()).ToList()
})
.ToList();
}
}
}
}

View File

@@ -0,0 +1,331 @@
namespace MainShell.Hardware
{
public static class DeviceIoNames
{
public static class WZ
{
public const string StartButton = "PG.WZ.StartButton";
public const string StopButton = "PG.WZ.StopButton";
public const string ResetButton = "PG.WZ.ResetButton";
public const string EmergencyStopButton = "PG.WZ.EmergencyStopButton";
public const string BlueButton = "PG.WZ.BlueButton";
public const string SafetyDoor1Closed = "PG.WZ.SafetyDoor1Closed";
public const string SafetyDoor2Closed = "PG.WZ.SafetyDoor2Closed";
public const string SafetyDoor3Closed = "PG.WZ.SafetyDoor3Closed";
public const string SafetyDoor4Closed = "PG.WZ.SafetyDoor4Closed";
public const string SecurityDoorShield = "PG.WZ.SecurityDoorShield";
public const string StartButtonLight = "PG.WZ.StartButtonLight";
public const string StopButtonLight = "PG.WZ.StopButtonLight";
public const string ResetButtonLight = "PG.WZ.ResetButtonLight";
public const string BlueButtonLight = "PG.WZ.BlueButtonLight";
public const string WorkLight1 = "PG.WZ.WorkLight1";
public const string StackLightRed = "PG.WZ.StackLightRed";
public const string StackLightYellow = "PG.WZ.StackLightYellow";
public const string StackLightGreen = "PG.WZ.StackLightGreen";
public const string StackLightBlue = "PG.WZ.StackLightBlue";
public const string BuzzerAct = "PG.WZ.BuzzerAct";
public const string SafetyDoor1Open = "PG.WZ.SafetyDoor1Open";
public const string SafetyDoor2Open = "PG.WZ.SafetyDoor2Open";
public const string SafetyDoor3Open = "PG.WZ.SafetyDoor3Open";
public const string SafetyDoor4Open = "PG.WZ.SafetyDoor4Open";
}
public static class Stage
{
public const string ToolSetterSignal = "PG.Stage.ToolSetterSignal";
public const string SubstrateInPlace = "PG.Stage.SubstrateInPlace";
public const string LifterCyl1WorkPos = "PG.Stage.LifterCyl1WorkPos";
public const string LifterCyl1HomePos = "PG.Stage.LifterCyl1HomePos";
public const string LifterCyl2WorkPos = "PG.Stage.LifterCyl2WorkPos";
public const string LifterCyl2HomePos = "PG.Stage.LifterCyl2HomePos";
public const string LifterCyl1Act = "PG.Stage.LifterCyl1Act";
public const string LifterCyl2Act = "PG.Stage.LifterCyl2Act";
public const string BreakingTheVacuum1 = "PG.Stage.BreakingTheVacuum1";
public const string BreakingTheVacuum2 = "PG.Stage.BreakingTheVacuum2";
public const string BreakingTheVacuum3 = "PG.Stage.BreakingTheVacuum3";
public const string BreakingTheVacuum4 = "PG.Stage.BreakingTheVacuum4";
public const string Vacuum1 = "PG.Stage.Vacuum1";
public const string Vacuum2 = "PG.Stage.Vacuum2";
public const string Vacuum3 = "PG.Stage.Vacuum3";
public const string Vacuum4 = "PG.Stage.Vacuum4";
}
public static class WS
{
public const string ThetaClampCyl1WorkPos = "PG.WS.ThetaClampCyl1WorkPos";
public const string ThetaClampCyl1HomePos = "PG.WS.ThetaClampCyl1HomePos";
public const string ThetaClampCyl2WorkPos = "PG.WS.ThetaClampCyl2WorkPos";
public const string ThetaClampCyl2HomePos = "PG.WS.ThetaClampCyl2HomePos";
public const string ThetaClampCyl3WorkPos = "PG.WS.ThetaClampCyl3WorkPos";
public const string ThetaClampCyl3HomePos = "PG.WS.ThetaClampCyl3HomePos";
public const string ThetaClampCyl4WorkPos = "PG.WS.ThetaClampCyl4WorkPos";
public const string ThetaClampCyl4HomePos = "PG.WS.ThetaClampCyl4HomePos";
public const string ThetaTrayPresentSensor1 = "PG.WS.ThetaTrayPresentSensor1";
public const string ThetaTrayPresentSensor2 = "PG.WS.ThetaTrayPresentSensor2";
public const string ThetaTrayPresentSensor3 = "PG.WS.ThetaTrayPresentSensor3";
public const string ThetaTrayPresentSensor4 = "PG.WS.ThetaTrayPresentSensor4";
public const string BondHead1InPlace = "PG.WS.BondHead1InPlace";
public const string BondHead2InPlace = "PG.WS.BondHead2InPlace";
public const string BondHead3InPlace = "PG.WS.BondHead3InPlace";
public const string BondHead4InPlace = "PG.WS.BondHead4InPlace";
public const string ThetaClampCylAct = "PG.WS.ThetaClampCylAct";
public const string ThetaBrakePressCylAct = "PG.WS.ThetaBrakePressCylAct";
}
public static class WEU
{
public const string Z11MaterialSensor1 = "PG.WEU.Z11MaterialSensor1";
public const string Z11MaterialSensor2 = "PG.WEU.Z11MaterialSensor2";
public const string Z12MaterialSensor3 = "PG.WEU.Z12MaterialSensor3";
public const string Z12MaterialSensor4 = "PG.WEU.Z12MaterialSensor4";
public const string IonBarAct1 = "PG.WEU.IonBarAct1";
public const string IonBarAct2 = "PG.WEU.IonBarAct2";
public const string TrayBreakVacuum1 = "PG.WEU.TrayBreakVacuum1";
public const string TrayBreakVacuum2 = "PG.WEU.TrayBreakVacuum2";
public const string TrayVacuum1 = "PG.WEU.TrayVacuum1";
public const string TrayVacuum2 = "PG.WEU.TrayVacuum2";
}
public static class CV
{
public const string UpperInletSensor = "PG.CV.UpperInletSensor";
public const string UpperInPlaceSensor = "PG.CV.UpperInPlaceSensor";
public const string LowerOutletSensor = "PG.CV.LowerOutletSensor";
public const string LowerInPlaceSensor = "PG.CV.LowerInPlaceSensor";
public const string IonWindRodAlarmDetection = "PG.CV.IonWindRodAlarmDetection";
public const string IonBarAct = "PG.CV.IonBarAct";
}
public static class General
{
public const string PhaseLossSensor = "PG.General.PhaseLossSensor";
public const string SafetyCircuitStatus1 = "PG.General.SafetyCircuitStatus1";
public const string SafetyCircuitStatus2 = "PG.General.SafetyCircuitStatus2";
}
public static class EFEM
{
public const string IonWindRodAlarmDetection1 = "PG.EFEM.IonWindRodAlarmDetection1";
public const string IonWindRodAlarmDetection2 = "PG.EFEM.IonWindRodAlarmDetection2";
public const string WorkLight1 = "PG.EFEM.WorkLight1";
}
public static class AxisZ
{
public const string Z1GuideRailBrake = "PG.AxisZ.Z1GuideRailBrake";
public const string Z3CameraAirCooling = "PG.AxisZ.Z3CameraAirCooling";
public const string Z5CameraAirCooling = "PG.AxisZ.Z5CameraAirCooling";
public const string Z10CameraAirCooling = "PG.AxisZ.Z10CameraAirCooling";
public const string Z2BondHeadAirCooling = "PG.AxisZ.Z2BondHeadAirCooling";
public const string Z2BondHeadBreakVacuum = "PG.AxisZ.Z2BondHeadBreakVacuum";
public const string Z2BondHeadVacuum = "PG.AxisZ.Z2BondHeadVacuum";
}
public static class SubstrateLoad
{
public const string SensorIn = "LG.SubstrateLoad.SensorIn";
public const string TrackMotorRun = "LG.SubstrateLoad.TrackMotorRun";
public const string HomeChecked = "LG.SubstrateLoad.HomeChecked";
public const string VacuumOk = "LG.SubstrateLoad.VacuumOk";
}
public static class ChipLoad
{
public const string SensorIn = "LG.ChipLoad.SensorIn";
public const string TrackMotorRun = "LG.ChipLoad.TrackMotorRun";
public const string HomeChecked = "LG.ChipLoad.HomeChecked";
public const string VacuumOk = "LG.ChipLoad.VacuumOk";
}
public static class Cylinder
{
public const string ClampExtended = "LG.Cylinder.Clamp.Extended";
public const string ClampRetracted = "LG.Cylinder.Clamp.Retracted";
public const string StopperExtended = "LG.Cylinder.Stopper.Extended";
public const string StopperRetracted = "LG.Cylinder.Stopper.Retracted";
public const string PressExtended = "LG.Cylinder.Press.Extended";
public const string PressRetracted = "LG.Cylinder.Press.Retracted";
public const string PressSafeSensor = "LG.Cylinder.Press.SafeSensor";
public const string MultiExtended = "LG.Cylinder.Multi.Extended";
public const string MultiRetracted = "LG.Cylinder.Multi.Retracted";
}
}
public static class DeviceIoIds
{
public static class WZ
{
public const int StartButton = 0;
public const int StopButton = 1;
public const int ResetButton = 2;
public const int EmergencyStopButton = 3;
public const int BlueButton = 4;
public const int SafetyDoor1Closed = 4;
public const int SafetyDoor2Closed = 5;
public const int SafetyDoor3Closed = 6;
public const int SafetyDoor4Closed = 7;
public const int SecurityDoorShield = 8;
public const int StartButtonLight = 0;
public const int StopButtonLight = 1;
public const int ResetButtonLight = 2;
public const int BlueButtonLight = 3;
public const int WorkLight1 = 4;
public const int StackLightRed = 8;
public const int StackLightYellow = 9;
public const int StackLightGreen = 10;
public const int StackLightBlue = 11;
public const int BuzzerAct = 12;
public const int SafetyDoor1Open = 1;
public const int SafetyDoor2Open = 2;
public const int SafetyDoor3Open = 3;
public const int SafetyDoor4Open = 4;
}
public static class Stage
{
public const int ToolSetterSignal = 5;
public const int SubstrateInPlace = 6;
public const int LifterCyl1WorkPos = 7;
public const int LifterCyl1HomePos = 8;
public const int LifterCyl2WorkPos = 9;
public const int LifterCyl2HomePos = 10;
public const int LifterCyl1Act = 10;
public const int LifterCyl2Act = 11;
public const int BreakingTheVacuum1 = 0;
public const int BreakingTheVacuum2 = 1;
public const int BreakingTheVacuum3 = 2;
public const int BreakingTheVacuum4 = 3;
public const int Vacuum1 = 7;
public const int Vacuum2 = 8;
public const int Vacuum3 = 9;
public const int Vacuum4 = 10;
}
public static class WS
{
public const int ThetaClampCyl1WorkPos = 11;
public const int ThetaClampCyl1HomePos = 12;
public const int ThetaClampCyl2WorkPos = 13;
public const int ThetaClampCyl2HomePos = 14;
public const int ThetaClampCyl3WorkPos = 15;
public const int ThetaClampCyl3HomePos = 0;
public const int ThetaClampCyl4WorkPos = 1;
public const int ThetaClampCyl4HomePos = 2;
public const int ThetaTrayPresentSensor1 = 3;
public const int ThetaTrayPresentSensor2 = 4;
public const int ThetaTrayPresentSensor3 = 5;
public const int ThetaTrayPresentSensor4 = 6;
public const int BondHead1InPlace = 7;
public const int BondHead2InPlace = 8;
public const int BondHead3InPlace = 9;
public const int BondHead4InPlace = 10;
public const int ThetaClampCylAct = 8;
public const int ThetaBrakePressCylAct = 9;
}
public static class WEU
{
public const int Z11MaterialSensor1 = 11;
public const int Z11MaterialSensor2 = 12;
public const int Z12MaterialSensor3 = 13;
public const int Z12MaterialSensor4 = 14;
public const int IonBarAct1 = 6;
public const int IonBarAct2 = 7;
public const int TrayBreakVacuum1 = 4;
public const int TrayBreakVacuum2 = 5;
public const int TrayVacuum1 = 11;
public const int TrayVacuum2 = 12;
}
public static class CV
{
public const int UpperInletSensor = 0;
public const int UpperInPlaceSensor = 1;
public const int LowerOutletSensor = 2;
public const int LowerInPlaceSensor = 3;
public const int IonWindRodAlarmDetection = 13;
public const int IonBarAct = 5;
}
public static class General
{
public const int PhaseLossSensor = 10;
public const int SafetyCircuitStatus1 = 11;
public const int SafetyCircuitStatus2 = 12;
}
public static class EFEM
{
public const int IonWindRodAlarmDetection1 = 14;
public const int IonWindRodAlarmDetection2 = 15;
public const int WorkLight1 = 6;
}
public static class AxisZ
{
public const int Z1GuideRailBrake = 0;
public const int Z3CameraAirCooling = 1;
public const int Z5CameraAirCooling = 2;
public const int Z10CameraAirCooling = 3;
public const int Z2BondHeadAirCooling = 4;
public const int Z2BondHeadBreakVacuum = 6;
public const int Z2BondHeadVacuum = 13;
}
public static class SubstrateLoad
{
public const int SensorIn = 1001;
public const int TrackMotorRun = 1002;
public const int HomeChecked = 1003;
public const int VacuumOk = 1004;
}
public static class ChipLoad
{
public const int SensorIn = 1101;
public const int TrackMotorRun = 1102;
public const int HomeChecked = 1103;
public const int VacuumOk = 1104;
}
public static class Cylinder
{
public const int ClampExtendCmd = 1701;
public const int ClampExtended = 1702;
public const int ClampRetracted = 1703;
public const int StopperExtendCmd = 1711;
public const int StopperRetractCmd = 1712;
public const int StopperExtended = 1713;
public const int StopperRetracted = 1714;
public const int PressExtendCmd = 1721;
public const int PressExtended = 1722;
public const int PressRetracted = 1723;
public const int PressSafeSensor = 1724;
public const int MultiOutput1 = 1731;
public const int MultiOutput2 = 1732;
public const int MultiOutput3 = 1733;
public const int MultiOutput4 = 1734;
public const int MultiExtended = 1735;
public const int MultiRetracted = 1736;
}
}
public static class DeviceCylinderNames
{
public static class WS
{
public const string ThetaClamp = "WS θ夹紧气缸";
public const string ThetaBrakePress = "WS θ刹车压紧气缸";
}
public static class Stage
{
public const string LifterSync = "Stage 顶升同步气缸";
}
public const string Clamp = "夹爪气缸";
public const string Stopper = "挡停气缸";
public const string Press = "压料气缸";
public const string Multi = "多联气缸";
}
}

View File

@@ -0,0 +1,162 @@
using MainShell.EventArgsFolder;
using MainShell.Log;
using Stylet;
using System;
using System.Threading;
using MwFramework.Device;
namespace MainShell.Hardware
{
public class DiastimeterPollingService : IDisposable
{
private const int DefaultIntervalMilliseconds = 200;
private readonly HardwareManager _hardwareManager;
private readonly IEventAggregator _eventAggregator;
private readonly object _syncRoot = new object();
private Timer _timer;
private bool _isRunning;
private bool _isReading;
private int _intervalMilliseconds;
public DiastimeterPollingService(HardwareManager hardwareManager, IEventAggregator eventAggregator)
{
_hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
_intervalMilliseconds = DefaultIntervalMilliseconds;
}
public bool IsRunning
{
get
{
lock (_syncRoot)
{
return _isRunning;
}
}
}
public int IntervalMilliseconds
{
get
{
lock (_syncRoot)
{
return _intervalMilliseconds;
}
}
}
public void Start()
{
Start(DefaultIntervalMilliseconds);
}
public void Start(int intervalMilliseconds)
{
if (intervalMilliseconds <= 0)
{
throw new ArgumentOutOfRangeException(nameof(intervalMilliseconds));
}
lock (_syncRoot)
{
_intervalMilliseconds = intervalMilliseconds;
if (_timer == null)
{
_timer = new Timer(ReadSample, null, Timeout.Infinite, Timeout.Infinite);
}
_timer.Change(0, _intervalMilliseconds);
_isRunning = true;
}
$"激光测距仪轮询启动,周期={intervalMilliseconds}ms".LogInfo();
}
public void Stop()
{
lock (_syncRoot)
{
if (_timer != null)
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
}
_isRunning = false;
}
"激光测距仪轮询停止。".LogInfo();
}
private void ReadSample(object state)
{
lock (_syncRoot)
{
if (!_isRunning || _isReading)
{
return;
}
_isReading = true;
}
try
{
IDiastimeter diastimeter = _hardwareManager.Diastimeter;
if (diastimeter == null)
{
PublishInvalidSample("激光测距仪未初始化。");
return;
}
if (!diastimeter.IsConnected)
{
PublishInvalidSample("激光测距仪未连接。");
return;
}
double distance;
diastimeter.GetLastSample(out distance);
if (double.IsNaN(distance) || double.IsInfinity(distance))
{
PublishInvalidSample("激光测距仪反馈数据无效。");
return;
}
_eventAggregator.PublishOnUIThread(new DiastimeterSampleChangedEventArgs(distance, DateTime.Now, true, string.Empty));
}
catch (Exception ex)
{
$"激光测距仪轮询读取失败:{ex.Message}".LogSysError();
PublishInvalidSample(ex.Message);
}
finally
{
lock (_syncRoot)
{
_isReading = false;
}
}
}
private void PublishInvalidSample(string message)
{
_eventAggregator.PublishOnUIThread(new DiastimeterSampleChangedEventArgs(0d, DateTime.Now, false, message));
}
public void Dispose()
{
Stop();
lock (_syncRoot)
{
if (_timer != null)
{
_timer.Dispose();
_timer = null;
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
namespace MainShell.Hardware
{
public static class HardwareAlarmIds
{
public const int DeviceNotReady = 15000;
public const int InterlockBlocked = 15001;
public const int IoStateInvalid = 15002;
public const int GenericRuntimeFailure = 15003;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MainShell.Hardware
{
public interface ISubstrateLoadDeviceService
{
bool IsSubstrateAtLoadPosition();
bool IsSubstrateLoadHomeChecked();
bool IsSubstrateLoadVacuumOk();
bool TrySetSubstrateLoadTrackMotor(bool isRunning);
Task<bool> WaitSubstrateAtLoadPositionAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> WaitSubstrateLoadHomeCheckedAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> WaitSubstrateLoadVacuumOkAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
bool TryExtendClamp();
bool TryRetractClamp();
bool TryExtendStopper();
bool TryRetractStopper();
bool TryPressDown();
bool TryReleasePress();
Task<bool> TryExtendClampAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> TryRetractClampAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> TryExtendStopperAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> TryRetractStopperAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> TryPressDownAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
Task<bool> TryReleasePressAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken));
}
public class SubstrateLoadDeviceService : ISubstrateLoadDeviceService
{
private readonly IDeviceIoMonitorService _ioMonitorService;
private readonly IDeviceCylinderService _cylinderService;
public SubstrateLoadDeviceService(IDeviceIoMonitorService ioMonitorService, IDeviceCylinderService cylinderService)
{
_ioMonitorService = ioMonitorService;
_cylinderService = cylinderService;
}
public bool IsSubstrateAtLoadPosition()
{
return _ioMonitorService.IsPointOn(DeviceIoNames.SubstrateLoad.SensorIn);
}
public bool IsSubstrateLoadHomeChecked()
{
return _ioMonitorService.IsPointOn(DeviceIoNames.SubstrateLoad.HomeChecked);
}
public bool IsSubstrateLoadVacuumOk()
{
return _ioMonitorService.IsPointOn(DeviceIoNames.SubstrateLoad.VacuumOk);
}
public bool TrySetSubstrateLoadTrackMotor(bool isRunning)
{
return _ioMonitorService.TrySetOutputState(DeviceIoIds.SubstrateLoad.TrackMotorRun, isRunning);
}
public Task<bool> WaitSubstrateAtLoadPositionAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _ioMonitorService.WaitForPointStateAsync(DeviceIoNames.SubstrateLoad.SensorIn, true, timeout, cancellationToken);
}
public Task<bool> WaitSubstrateLoadHomeCheckedAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _ioMonitorService.WaitForPointStateAsync(DeviceIoNames.SubstrateLoad.HomeChecked, true, timeout, cancellationToken);
}
public Task<bool> WaitSubstrateLoadVacuumOkAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _ioMonitorService.WaitForPointStateAsync(DeviceIoNames.SubstrateLoad.VacuumOk, true, timeout, cancellationToken);
}
public bool TryExtendClamp()
{
return _cylinderService.TryExtend(DeviceCylinderNames.Clamp);
}
public bool TryRetractClamp()
{
return _cylinderService.TryRetract(DeviceCylinderNames.Clamp);
}
public bool TryExtendStopper()
{
return _cylinderService.TryExtend(DeviceCylinderNames.Stopper);
}
public bool TryRetractStopper()
{
return _cylinderService.TryRetract(DeviceCylinderNames.Stopper);
}
public bool TryPressDown()
{
return _cylinderService.TryExtend(DeviceCylinderNames.Press);
}
public bool TryReleasePress()
{
return _cylinderService.TryRetract(DeviceCylinderNames.Press);
}
public Task<bool> TryExtendClampAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _cylinderService.TryExtendAndWaitAsync(DeviceCylinderNames.Clamp, timeout, cancellationToken);
}
public Task<bool> TryRetractClampAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _cylinderService.TryRetractAndWaitAsync(DeviceCylinderNames.Clamp, timeout, cancellationToken);
}
public Task<bool> TryExtendStopperAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _cylinderService.TryExtendAndWaitAsync(DeviceCylinderNames.Stopper, timeout, cancellationToken);
}
public Task<bool> TryRetractStopperAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _cylinderService.TryRetractAndWaitAsync(DeviceCylinderNames.Stopper, timeout, cancellationToken);
}
public Task<bool> TryPressDownAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _cylinderService.TryExtendAndWaitAsync(DeviceCylinderNames.Press, timeout, cancellationToken);
}
public Task<bool> TryReleasePressAndWaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default(CancellationToken))
{
return _cylinderService.TryRetractAndWaitAsync(DeviceCylinderNames.Press, timeout, cancellationToken);
}
}
}