Files

353 lines
14 KiB
C#
Raw Permalink Normal View History

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