using MainShell.Common; using MainShell.Hardware; using MainShell.Log; using MainShell.ParaSetting.Model; using MainShell.Vision; using MaxwellFramework.Core.Interfaces; using MwFramework.Device; using MwFramework.ManagerService; using System; using System.Globalization; using System.Reflection; using System.Windows; namespace MainShell.Process { public class DefaultWaferMachineAdapter : IWaferMachineAdapter { private readonly HardwareManager _hardwareManager; private readonly IParamList _parameterList; public DefaultWaferMachineAdapter(HardwareManager hardwareManager, IParameterManager parameterManager) { _hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager)); _parameterList = parameterManager as IParamList; } public CameraType GetCameraSource(WaferDiePositionContext context) { return CameraType.TopPositionCamera; } public MwCamera GetCamera(WaferDiePositionContext context) { return ResolveCamera(GetCameraSource(context)); } public Point GetCameraFieldOfView(WaferDiePositionContext context) { DeviceFoundationSetting deviceFoundationSetting = GetDeviceFoundationSetting(); CameraFovSettingItem cameraFovSettingItem = GetCameraFovSettingItem(deviceFoundationSetting, GetCameraSource(context)); if (cameraFovSettingItem == null || cameraFovSettingItem.FovX <= 0d || cameraFovSettingItem.FovY <= 0d) { LogManager.LogProcessInfo("晶圆定位:DefaultWaferMachineAdapter 正在使用相机视野默认回退值。"); return new Point(1.0d, 1.0d); } return new Point(cameraFovSettingItem.FovX, cameraFovSettingItem.FovY); } public double GetExposureTimeMilliseconds(WaferDiePositionContext context) { MwCamera camera = GetCamera(context); if (camera == null) { return 0d; } try { double exposureTime = 0d; DriverLibResult result = camera.GetExposureTime(ref exposureTime); if (result != DriverLibResult.DriverLibNoError || double.IsNaN(exposureTime) || double.IsInfinity(exposureTime) || exposureTime < 0d) { return 0d; } return exposureTime; } catch (Exception) { return 0d; } } public CameraCaptureOptions CreateSoftTriggerCaptureOptions(WaferDiePositionContext context) { CameraCaptureOptions options = CameraCaptureOptions.CreateSoftTrigger(5000); options.TriggerDelay = 20d; return options; } public Point AdjustPointWithinSoftLimit(Point candidatePoint, WaferDiePositionContext context, double offsetMm, out bool adjusted, out string reason) { IAxis axisX = _hardwareManager.Axis_PHS_X1; IAxis axisY = _hardwareManager.Axis_Stage_Y3; double adjustedX = candidatePoint.X; double adjustedY = candidatePoint.Y; bool adjustedXFlag = TryClampByAxisSoftLimit(axisX, adjustedX, offsetMm, out adjustedX, out string adjustedXReason); bool adjustedYFlag = TryClampByAxisSoftLimit(axisY, adjustedY, offsetMm, out adjustedY, out string adjustedYReason); adjusted = adjustedXFlag || adjustedYFlag; if (!adjusted) { reason = string.Empty; return candidatePoint; } reason = BuildAdjustmentReason(adjustedXReason, adjustedYReason); return new Point(adjustedX, adjustedY); } private DeviceFoundationSetting GetDeviceFoundationSetting() { return _parameterList == null ? null : _parameterList.GetParameter(); } private MwCamera ResolveCamera(CameraType cameraType) { MwCameraExtend cameraExtend = GetCameraExtend(cameraType); if (cameraExtend == null) { return null; } return cameraExtend.Camera; } private MwCameraExtend GetCameraExtend(CameraType cameraType) { return _hardwareManager.GetCamera(cameraType); } private static CameraFovSettingItem GetCameraFovSettingItem(DeviceFoundationSetting deviceFoundationSetting, CameraType cameraType) { if (deviceFoundationSetting == null || deviceFoundationSetting.CameraSettingItem == null) { return null; } deviceFoundationSetting.CameraSettingItem.EnsureDefaultCameras(); switch (cameraType) { case CameraType.TopWideCamera: return deviceFoundationSetting.CameraSettingItem.DownCamera; case CameraType.MapCamera: return deviceFoundationSetting.CameraSettingItem.MapCamera; case CameraType.TopPositionCamera: default: return deviceFoundationSetting.CameraSettingItem.UpCamera; } } private static bool TryClampByAxisSoftLimit(IAxis axis, double candidateValue, double offsetMm, out double adjustedValue, out string reason) { adjustedValue = candidateValue; reason = string.Empty; if (axis == null) { return false; } bool hasNegativeLimit = TryGetAxisLimit(axis, true, out double negativeLimit); bool hasPositiveLimit = TryGetAxisLimit(axis, false, out double positiveLimit); if (!hasNegativeLimit && !hasPositiveLimit) { return false; } double minLimit = hasNegativeLimit && hasPositiveLimit ? Math.Min(negativeLimit, positiveLimit) : negativeLimit; double maxLimit = hasNegativeLimit && hasPositiveLimit ? Math.Max(negativeLimit, positiveLimit) : positiveLimit; double minAllowed = hasNegativeLimit ? minLimit + Math.Max(0d, offsetMm) : double.NegativeInfinity; double maxAllowed = hasPositiveLimit ? maxLimit - Math.Max(0d, offsetMm) : double.PositiveInfinity; if (candidateValue < minAllowed) { adjustedValue = minAllowed; reason = string.Format( CultureInfo.InvariantCulture, "{0}: clamp to negative soft limit {1:F3} with offset {2:F3}.", axis.Name, adjustedValue, offsetMm); return true; } if (candidateValue > maxAllowed) { adjustedValue = maxAllowed; reason = string.Format( CultureInfo.InvariantCulture, "{0}: clamp to positive soft limit {1:F3} with offset {2:F3}.", axis.Name, adjustedValue, offsetMm); return true; } return false; } private static bool TryGetAxisLimit(IAxis axis, bool isNegativeLimit, out double limitValue) { limitValue = 0d; if (axis == null) { return false; } try { double axisLimit = 0d; MotionErrorCode errorCode = isNegativeLimit ? axis.GetSoftMel(ref axisLimit) : axis.GetSoftPel(ref axisLimit); if (errorCode != MotionErrorCode.NoError) { return false; } limitValue = axisLimit; if (double.IsNaN(limitValue) || double.IsInfinity(limitValue)) { return false; } return true; } catch (Exception) { } return false; } private static string BuildAdjustmentReason(string adjustedXReason, string adjustedYReason) { if (string.IsNullOrWhiteSpace(adjustedXReason)) { return adjustedYReason ?? string.Empty; } if (string.IsNullOrWhiteSpace(adjustedYReason)) { return adjustedXReason; } return adjustedXReason + " | " + adjustedYReason; } } }