353 lines
14 KiB
C#
353 lines
14 KiB
C#
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.");
|
|
}
|
|
}
|
|
}
|