添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.Models;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public abstract class CameraBaseViewModel : BaseScreen
|
||||
{
|
||||
protected CameraAxisViewModel _cameraAxisViewModel;
|
||||
|
||||
public CameraAxisViewModel CameraAxisViewModel
|
||||
{
|
||||
get { return _cameraAxisViewModel; }
|
||||
set { SetAndNotify(ref _cameraAxisViewModel, value); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class CarrierInfo : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private double _width;
|
||||
public double Width
|
||||
{
|
||||
get { return _width; }
|
||||
set { SetAndNotify(ref _width, value); }
|
||||
}
|
||||
private double _height;
|
||||
public double Height
|
||||
{
|
||||
get { return _height; }
|
||||
set { SetAndNotify(ref _height, value); }
|
||||
}
|
||||
private double _thickness;
|
||||
|
||||
public double Thickness
|
||||
{
|
||||
get { return _thickness; }
|
||||
set { SetAndNotify(ref _thickness, value); }
|
||||
}
|
||||
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class LogisticsParameterItem : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private double _cv1Width;
|
||||
public double CV1Width
|
||||
{
|
||||
get { return _cv1Width; }
|
||||
set { SetAndNotify(ref _cv1Width, value); }
|
||||
}
|
||||
private double _cv2Width;
|
||||
public double CV2Width
|
||||
{
|
||||
get { return _cv2Width; }
|
||||
set { SetAndNotify(ref _cv2Width, value); }
|
||||
}
|
||||
private double _cv3Width;
|
||||
public double CV3Width
|
||||
{
|
||||
get { return _cv3Width; }
|
||||
set { SetAndNotify(ref _cv3Width, value); }
|
||||
}
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class SubstrateSelectInfo : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private string _substrateName;
|
||||
public string SubstrateName
|
||||
{
|
||||
get { return _substrateName; }
|
||||
set { SetAndNotify(ref _substrateName, value); }
|
||||
}
|
||||
private string _description;
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
set { SetAndNotify(ref _description, value); }
|
||||
}
|
||||
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using MwFramework.ManagerService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public sealed class CarrierRecipe : RecipeBase
|
||||
{
|
||||
public override string Dir => System.IO.Path.Combine(MainShell.Filewritable.Paths.CarrierRecipe, RecipeName);
|
||||
|
||||
private ObservableCollection<SubstrateSelectInfo> _substrateSelectInfos = new ObservableCollection<SubstrateSelectInfo>();
|
||||
public ObservableCollection<SubstrateSelectInfo> SubstrateSelectInfos
|
||||
{
|
||||
get { return _substrateSelectInfos; }
|
||||
set { SetProperty(ref _substrateSelectInfos, value); }
|
||||
}
|
||||
|
||||
private LogisticsParameterItem _logisticsParameterItem = new LogisticsParameterItem();
|
||||
|
||||
public LogisticsParameterItem LogisticsParameterItem
|
||||
{
|
||||
get { return _logisticsParameterItem; }
|
||||
set { SetProperty(ref _logisticsParameterItem, value); }
|
||||
}
|
||||
|
||||
private CarrierInfo _carrierInfo=new CarrierInfo();
|
||||
|
||||
public CarrierInfo CarrierInfo
|
||||
{
|
||||
get { return _carrierInfo; }
|
||||
set { SetProperty(ref _carrierInfo, value); }
|
||||
}
|
||||
|
||||
|
||||
public CarrierRecipe(string name) : base(name)
|
||||
{
|
||||
}
|
||||
public CarrierRecipe():base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 晶圆信息。
|
||||
/// </summary>
|
||||
public class WaferInfo : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private string _dieColor;
|
||||
|
||||
/// <summary>
|
||||
/// 芯片颜色。
|
||||
/// </summary>
|
||||
public string DieColor
|
||||
{
|
||||
get { return _dieColor; }
|
||||
set { SetAndNotify(ref _dieColor, value); }
|
||||
}
|
||||
|
||||
private double _dieSizeX;
|
||||
|
||||
/// <summary>
|
||||
/// 芯片 X 尺寸。
|
||||
/// </summary>
|
||||
public double DieSizeX
|
||||
{
|
||||
get { return _dieSizeX; }
|
||||
set { SetAndNotify(ref _dieSizeX, value); }
|
||||
}
|
||||
|
||||
private double _dieSizeY;
|
||||
|
||||
/// <summary>
|
||||
/// 芯片 Y 尺寸。
|
||||
/// </summary>
|
||||
public double DieSizeY
|
||||
{
|
||||
get { return _dieSizeY; }
|
||||
set { SetAndNotify(ref _dieSizeY, value); }
|
||||
}
|
||||
|
||||
private double _diePitchX;
|
||||
|
||||
/// <summary>
|
||||
/// 芯片 X 间距。
|
||||
/// </summary>
|
||||
public double DiePitchX
|
||||
{
|
||||
get { return _diePitchX; }
|
||||
set { SetAndNotify(ref _diePitchX, value); }
|
||||
}
|
||||
|
||||
private double _diePitchY;
|
||||
|
||||
/// <summary>
|
||||
/// 芯片 Y 间距。
|
||||
/// </summary>
|
||||
public double DiePitchY
|
||||
{
|
||||
get { return _diePitchY; }
|
||||
set { SetAndNotify(ref _diePitchY, value); }
|
||||
}
|
||||
|
||||
private double _waferWidth;
|
||||
|
||||
/// <summary>
|
||||
/// 晶圆宽度。
|
||||
/// </summary>
|
||||
public double WaferWidth
|
||||
{
|
||||
get { return _waferWidth; }
|
||||
set { SetAndNotify(ref _waferWidth, value); }
|
||||
}
|
||||
|
||||
private double _waferHeight;
|
||||
|
||||
/// <summary>
|
||||
/// 晶圆高度。
|
||||
/// </summary>
|
||||
public double WaferHeight
|
||||
{
|
||||
get { return _waferHeight; }
|
||||
set { SetAndNotify(ref _waferHeight, value); }
|
||||
}
|
||||
|
||||
private int _waferRowNum;
|
||||
|
||||
/// <summary>
|
||||
/// 晶圆行数。
|
||||
/// </summary>
|
||||
public int WaferRowNum
|
||||
{
|
||||
get { return _waferRowNum; }
|
||||
set { SetAndNotify(ref _waferRowNum, value); }
|
||||
}
|
||||
|
||||
private int _waferColNum;
|
||||
|
||||
/// <summary>
|
||||
/// 晶圆列数。
|
||||
/// </summary>
|
||||
public int WaferColNum
|
||||
{
|
||||
get { return _waferColNum; }
|
||||
set { SetAndNotify(ref _waferColNum, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using MainShell.Common;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class WaferScanSettings : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private double _startPointX;
|
||||
|
||||
public double StartPointX
|
||||
{
|
||||
get { return _startPointX; }
|
||||
set { SetAndNotify(ref _startPointX, value); }
|
||||
}
|
||||
|
||||
private double _startPointY;
|
||||
|
||||
public double StartPointY
|
||||
{
|
||||
get { return _startPointY; }
|
||||
set { SetAndNotify(ref _startPointY, value); }
|
||||
}
|
||||
|
||||
private TransPathDirection _scanDirectionX;
|
||||
|
||||
public TransPathDirection ScanDirectionX
|
||||
{
|
||||
get { return _scanDirectionX; }
|
||||
set { SetAndNotify(ref _scanDirectionX, value); }
|
||||
}
|
||||
|
||||
private TransPathDirection _scanDirectionY;
|
||||
|
||||
public TransPathDirection ScanDirectionY
|
||||
{
|
||||
get { return _scanDirectionY; }
|
||||
set { SetAndNotify(ref _scanDirectionY, value); }
|
||||
}
|
||||
|
||||
private double _overlapRateX;
|
||||
|
||||
public double OverlapRateX
|
||||
{
|
||||
get { return _overlapRateX; }
|
||||
set { SetAndNotify(ref _overlapRateX, value); }
|
||||
}
|
||||
|
||||
private double _overlapRateY;
|
||||
|
||||
public double OverlapRateY
|
||||
{
|
||||
get { return _overlapRateY; }
|
||||
set { SetAndNotify(ref _overlapRateY, value); }
|
||||
}
|
||||
|
||||
private double _softLimitOffsetMm;
|
||||
|
||||
public double SoftLimitOffsetMm
|
||||
{
|
||||
get { return _softLimitOffsetMm; }
|
||||
set { SetAndNotify(ref _softLimitOffsetMm, value); }
|
||||
}
|
||||
|
||||
private int _consumerCount = 2;
|
||||
|
||||
public int ConsumerCount
|
||||
{
|
||||
get { return _consumerCount; }
|
||||
set { SetAndNotify(ref _consumerCount, value); }
|
||||
}
|
||||
|
||||
private int _frameChannelCapacity = 8;
|
||||
|
||||
public int FrameChannelCapacity
|
||||
{
|
||||
get { return _frameChannelCapacity; }
|
||||
set { SetAndNotify(ref _frameChannelCapacity, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public interface IRecipe
|
||||
{
|
||||
string RecipeName { get; set; }
|
||||
/// <summary>
|
||||
/// 配方名改变时通知
|
||||
/// </summary>
|
||||
event Action<IRecipe, string, string> OnRenamed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class AxisFilteringParameter : PropertyChangedBase , IParameterItem
|
||||
{
|
||||
private int _axisIndex;
|
||||
/// <summary>
|
||||
/// 轴ID
|
||||
/// </summary>
|
||||
public int AxisIndex
|
||||
{
|
||||
get { return _axisIndex; }
|
||||
set
|
||||
{
|
||||
if (SetAndNotify(ref _axisIndex, value))
|
||||
{
|
||||
NotifyOfPropertyChange(() => AxisDisplayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string AxisDisplayName
|
||||
{
|
||||
get
|
||||
{
|
||||
string axisName = PidAxisCatalog.GetAxisName(AxisIndex);
|
||||
return string.IsNullOrWhiteSpace(axisName) ? AxisIndex.ToString() : axisName;
|
||||
}
|
||||
}
|
||||
|
||||
private PIDLabel<bool> _isUseNotch = new PIDLabel<bool>() { Name = "PA_SLNothFilth", Value = false };
|
||||
/// <summary>
|
||||
/// 开启陷波滤波
|
||||
/// </summary>
|
||||
public PIDLabel<bool> IsUseNotch
|
||||
{
|
||||
get { return _isUseNotch; }
|
||||
set { SetAndNotify(ref _isUseNotch, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _notchFrequency = new PIDLabel<double>() { Name = "PA_SLVNFRQ", Value = 0 };
|
||||
/// <summary>
|
||||
/// 陷波滤波频率
|
||||
/// </summary>
|
||||
public PIDLabel<double> NotchFrequency
|
||||
{
|
||||
get { return _notchFrequency; }
|
||||
set { SetAndNotify(ref _notchFrequency, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _notchWidth = new PIDLabel<double>() { Name = "PA_SLVNWID", Value = 0 };
|
||||
/// <summary>
|
||||
/// 陷波滤波宽度
|
||||
/// </summary>
|
||||
public PIDLabel<double> NotchWidth
|
||||
{
|
||||
get { return _notchWidth; }
|
||||
set { SetAndNotify(ref _notchWidth, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _notchFalloff = new PIDLabel<double>() { Name = "PA_SLVNATT", Value = 0 };
|
||||
/// <summary>
|
||||
/// 陷波滤波衰减
|
||||
/// </summary>
|
||||
public PIDLabel<double> NotchFalloff
|
||||
{
|
||||
get { return _notchFalloff; }
|
||||
set { SetAndNotify(ref _notchFalloff, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<bool> _isUseFiltering = new PIDLabel<bool>() { Name = "PA_SLLowPass", Value = false };
|
||||
/// <summary>
|
||||
/// 开启低通滤波
|
||||
/// </summary>
|
||||
public PIDLabel<bool> IsUseFiltering
|
||||
{
|
||||
get { return _isUseFiltering; }
|
||||
set { SetAndNotify(ref _isUseFiltering, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _filteringFrequency = new PIDLabel<double>() { Name = "PA_SLVSOF", Value = 0 };
|
||||
/// <summary>
|
||||
/// 低通滤波频率
|
||||
/// </summary>
|
||||
public PIDLabel<double> FilteringFrequency
|
||||
{
|
||||
get { return _filteringFrequency; }
|
||||
set { SetAndNotify(ref _filteringFrequency, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _filteringDamping = new PIDLabel<double>() { Name = "PA_SLVSOFD", Value = 0 };
|
||||
/// <summary>
|
||||
/// 低通滤波阻尼系数
|
||||
/// </summary>
|
||||
public PIDLabel<double> FilteringDamping
|
||||
{
|
||||
get { return _filteringDamping; }
|
||||
set { SetAndNotify(ref _filteringDamping, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return new AxisFilteringParameter
|
||||
{
|
||||
AxisIndex = this.AxisIndex,
|
||||
IsUseNotch = this.IsUseNotch.Clone() as PIDLabel<bool>,
|
||||
NotchFrequency = this.NotchFrequency.Clone() as PIDLabel<double>,
|
||||
NotchWidth = this.NotchWidth.Clone() as PIDLabel<double>,
|
||||
NotchFalloff = this.NotchFalloff.Clone() as PIDLabel<double>,
|
||||
IsUseFiltering = this.IsUseFiltering.Clone() as PIDLabel<bool>,
|
||||
FilteringFrequency = this.FilteringFrequency.Clone() as PIDLabel<double>,
|
||||
FilteringDamping = this.FilteringDamping.Clone() as PIDLabel<double>
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class PidAxisOption
|
||||
{
|
||||
public string AxisName { get; set; }
|
||||
|
||||
public int AxisIndex { get; set; }
|
||||
}
|
||||
|
||||
public static class PidAxisCatalog
|
||||
{
|
||||
private static readonly Dictionary<int, string> _axisNameByIndex = new Dictionary<int, string>();
|
||||
private static readonly Dictionary<string, int> _axisIndexByName = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static void SetAxisOptions(IEnumerable<PidAxisOption> axisOptions)
|
||||
{
|
||||
_axisNameByIndex.Clear();
|
||||
_axisIndexByName.Clear();
|
||||
|
||||
if (axisOptions == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (PidAxisOption axisOption in axisOptions)
|
||||
{
|
||||
if (axisOption == null || string.IsNullOrWhiteSpace(axisOption.AxisName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_axisNameByIndex[axisOption.AxisIndex] = axisOption.AxisName;
|
||||
_axisIndexByName[axisOption.AxisName] = axisOption.AxisIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetAxisName(int axisIndex)
|
||||
{
|
||||
string axisName;
|
||||
return _axisNameByIndex.TryGetValue(axisIndex, out axisName) ? axisName : string.Empty;
|
||||
}
|
||||
|
||||
public static bool TryGetAxisIndex(string axisName, out int axisIndex)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(axisName))
|
||||
{
|
||||
axisIndex = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return _axisIndexByName.TryGetValue(axisName, out axisIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public class AxisPIDParameter : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private bool _isSynchronizingAxis;
|
||||
private string _moduleName;
|
||||
|
||||
public string ModuleName
|
||||
{
|
||||
get { return _moduleName; }
|
||||
set
|
||||
{
|
||||
if (SetAndNotify(ref _moduleName, value))
|
||||
{
|
||||
SyncAxisIndexFromModuleName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _axisIndex;
|
||||
|
||||
public int AxisIndex
|
||||
{
|
||||
get { return _axisIndex; }
|
||||
set
|
||||
{
|
||||
if (SetAndNotify(ref _axisIndex, value))
|
||||
{
|
||||
SyncModuleNameFromAxisIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
private PIDLabel<double> _pA_SLVKP = new PIDLabel<double>() { Name = "PA_SLVKP_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 速度环KP
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLVKP
|
||||
{
|
||||
get { return _pA_SLVKP; }
|
||||
set { SetAndNotify(ref _pA_SLVKP, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLVKI = new PIDLabel<double>() { Name = "PA_SLVKI_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 速度环KI
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLVKI
|
||||
{
|
||||
get { return _pA_SLVKI; }
|
||||
set { SetAndNotify(ref _pA_SLVKI, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLVKPSF = new PIDLabel<double>() { Name = "PA_SLVKPSF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 速度环KP Settle因子
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLVKPSF
|
||||
{
|
||||
get { return _pA_SLVKPSF; }
|
||||
set { SetAndNotify(ref _pA_SLVKPSF, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLVKPIF = new PIDLabel<double>() { Name = "PA_SLVKPIF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 速度环KP Iddle因子
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLVKPIF
|
||||
{
|
||||
get { return _pA_SLVKPIF; }
|
||||
set { SetAndNotify(ref _pA_SLVKPIF, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLVKISF = new PIDLabel<double>() { Name = "PA_SLVKISF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 速度环KI Settle因子
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLVKISF
|
||||
{
|
||||
get { return _pA_SLVKISF; }
|
||||
set { SetAndNotify(ref _pA_SLVKISF, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLVKIIF = new PIDLabel<double>() { Name = "PA_SLVKIIF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 速度环KI Iddle因子
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLVKIIF
|
||||
{
|
||||
get { return _pA_SLVKIIF; }
|
||||
set { SetAndNotify(ref _pA_SLVKIIF, value); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
private PIDLabel<double> _pA_SLPKP = new PIDLabel<double>() { Name = "PA_SLPKP_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 位置环的KP
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLPKP
|
||||
{
|
||||
get { return _pA_SLPKP; }
|
||||
set { SetAndNotify(ref _pA_SLPKP, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLPKPIF = new PIDLabel<double>() { Name = "PA_SLPKPIF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 位置环的KP的Idel因子
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLPKPIF
|
||||
{
|
||||
get { return _pA_SLPKPIF; }
|
||||
set { SetAndNotify(ref _pA_SLPKPIF, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLPKPSF = new PIDLabel<double>() { Name = "PA_SLPKPSF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 位置环的KP的Settle因子
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLPKPSF
|
||||
{
|
||||
get { return _pA_SLPKPSF; }
|
||||
set { SetAndNotify(ref _pA_SLPKPSF, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLAFF = new PIDLabel<double>() { Name = "PA_SLAFF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 加速度前馈
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLAFF
|
||||
{
|
||||
get { return _pA_SLAFF; }
|
||||
set { SetAndNotify(ref _pA_SLAFF, value); }
|
||||
}
|
||||
|
||||
private PIDLabel<double> _pA_SLJFF = new PIDLabel<double>() { Name = "PA_SLJFF_", Value = 0 };
|
||||
/// <summary>
|
||||
/// 加加速度前馈
|
||||
/// </summary>
|
||||
public PIDLabel<double> PA_SLJFF
|
||||
{
|
||||
get { return _pA_SLJFF; }
|
||||
set { SetAndNotify(ref _pA_SLJFF, value); }
|
||||
}
|
||||
|
||||
public AxisPIDParameter()
|
||||
{
|
||||
}
|
||||
public AxisPIDParameter(string moduleName)
|
||||
{
|
||||
ModuleName = moduleName;
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
AxisPIDParameter copy = new AxisPIDParameter
|
||||
{
|
||||
ModuleName = this.ModuleName,
|
||||
AxisIndex = this.AxisIndex,
|
||||
PA_SLVKP = this.PA_SLVKP != null ? (PIDLabel<double>)this.PA_SLVKP.Clone() : new PIDLabel<double>(),
|
||||
PA_SLVKI = this.PA_SLVKI != null ? (PIDLabel<double>)this.PA_SLVKI.Clone() : new PIDLabel<double>(),
|
||||
PA_SLVKPSF = this.PA_SLVKPSF != null ? (PIDLabel<double>)this.PA_SLVKPSF.Clone() : new PIDLabel<double>(),
|
||||
PA_SLVKPIF = this.PA_SLVKPIF != null ? (PIDLabel<double>)this.PA_SLVKPIF.Clone() : new PIDLabel<double>(),
|
||||
PA_SLVKISF = this.PA_SLVKISF != null ? (PIDLabel<double>)this.PA_SLVKISF.Clone() : new PIDLabel<double>(),
|
||||
PA_SLVKIIF = this.PA_SLVKIIF != null ? (PIDLabel<double>)this.PA_SLVKIIF.Clone() : new PIDLabel<double>(),
|
||||
|
||||
PA_SLPKP = this.PA_SLPKP != null ? (PIDLabel<double>)this.PA_SLPKP.Clone() : new PIDLabel<double>(),
|
||||
PA_SLPKPIF = this.PA_SLPKPIF != null ? (PIDLabel<double>)this.PA_SLPKPIF.Clone() : new PIDLabel<double>(),
|
||||
PA_SLPKPSF = this.PA_SLPKPSF != null ? (PIDLabel<double>)this.PA_SLPKPSF.Clone() : new PIDLabel<double>(),
|
||||
PA_SLAFF = this.PA_SLAFF != null ? (PIDLabel<double>)this.PA_SLAFF.Clone() : new PIDLabel<double>(),
|
||||
PA_SLJFF = this.PA_SLJFF != null ? (PIDLabel<double>)this.PA_SLJFF.Clone() : new PIDLabel<double>()
|
||||
};
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
private void SyncAxisIndexFromModuleName()
|
||||
{
|
||||
if (_isSynchronizingAxis)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int axisIndex;
|
||||
if (!PidAxisCatalog.TryGetAxisIndex(ModuleName, out axisIndex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isSynchronizingAxis = true;
|
||||
try
|
||||
{
|
||||
SetAndNotify(ref _axisIndex, axisIndex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSynchronizingAxis = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SyncModuleNameFromAxisIndex()
|
||||
{
|
||||
if (_isSynchronizingAxis)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string axisName = PidAxisCatalog.GetAxisName(AxisIndex);
|
||||
if (string.IsNullOrWhiteSpace(axisName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isSynchronizingAxis = true;
|
||||
try
|
||||
{
|
||||
SetAndNotify(ref _moduleName, axisName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isSynchronizingAxis = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class PIDLabel<T> : PropertyChangedBase , IParameterItem
|
||||
{
|
||||
private string _name;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetAndNotify(ref _name, value); }
|
||||
}
|
||||
|
||||
private T _value;
|
||||
|
||||
public T Value
|
||||
{
|
||||
get { return _value; }
|
||||
set { SetAndNotify(ref _value, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return this.MemberwiseClone() as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using MwFramework.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class PIDOperater
|
||||
{
|
||||
public void SendPIDParameters(AxisPIDParameter axisPIDParameter)
|
||||
{
|
||||
var controller = GetControler();
|
||||
foreach (var property in axisPIDParameter.GetType().GetProperties())
|
||||
{
|
||||
var value = property.GetValue(axisPIDParameter);
|
||||
if (value is PIDLabel<double> pIDLabel)
|
||||
{
|
||||
controller.WriteVariableBuffer(-1, axisPIDParameter.ModuleName + pIDLabel.Name, pIDLabel.Value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public AxisPIDParameter ReadPIDParametersFromDevice(string moduleName)
|
||||
{
|
||||
var controller = GetControler();
|
||||
|
||||
AxisPIDParameter axisPIDParameter = new AxisPIDParameter(moduleName);
|
||||
var props = axisPIDParameter.GetType()
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.CanRead && p.CanWrite);
|
||||
foreach (var property in props)
|
||||
{
|
||||
var value = property.GetValue(axisPIDParameter);
|
||||
if (value is PIDLabel<double> pIDLabel)
|
||||
{
|
||||
controller.ReadVariableBuffer(-1, axisPIDParameter.ModuleName + pIDLabel.Name, out var val);
|
||||
if (val == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pIDLabel.Value = Convert.ToDouble(val);
|
||||
}
|
||||
}
|
||||
return axisPIDParameter;
|
||||
}
|
||||
|
||||
private IMotionController GetControler()
|
||||
{
|
||||
var hw = IoC.Get<Hardware.HardwareManager>();
|
||||
if (hw?.AcsCard?.Controller == null)
|
||||
throw new InvalidOperationException("硬件控制器未初始化 (HardwareManager.AcsCard.Controller is null).");
|
||||
return hw.AcsCard.Controller;
|
||||
}
|
||||
|
||||
public void SendPIDFilteringParameters(AxisFilteringParameter pidFilteringParameter)
|
||||
{
|
||||
var controller = GetControler();
|
||||
foreach (var property in pidFilteringParameter.GetType().GetProperties())
|
||||
{
|
||||
var value = property.GetValue(pidFilteringParameter);
|
||||
if (value is PIDLabel<double> pIDLabel)
|
||||
{
|
||||
controller.WriteVariableBuffer(-1, pIDLabel.Name, pIDLabel.Value);
|
||||
}
|
||||
else if (value is PIDLabel<bool> pIDLabelBool)
|
||||
{
|
||||
var val= pIDLabelBool.Value== true ? 1 : 0;
|
||||
controller.WriteVariableBuffer(-1, pIDLabelBool.Name, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
public AxisFilteringParameter ReadPIDFilteringParametersFromDevice()
|
||||
{
|
||||
var controller = GetControler();
|
||||
var axisFilteringParameter = new AxisFilteringParameter();
|
||||
var props = axisFilteringParameter.GetType()
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.CanRead && p.CanWrite);
|
||||
foreach (var property in props)
|
||||
{
|
||||
var value = property.GetValue(axisFilteringParameter);
|
||||
if (value is PIDLabel<double> pIDLabel)
|
||||
{
|
||||
controller.ReadVariableBuffer(-1, pIDLabel.Name, out var val);
|
||||
if (val == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pIDLabel.Value = Convert.ToDouble(val);
|
||||
}
|
||||
else if (value is PIDLabel<bool> pIDLabelBool)
|
||||
{
|
||||
controller.ReadVariableBuffer(-1, pIDLabelBool.Name, out var val);
|
||||
if (val == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pIDLabelBool.Value = Convert.ToInt32(val) != 0;
|
||||
}
|
||||
}
|
||||
return axisFilteringParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models.PID
|
||||
{
|
||||
public class PIDProfile : PropertyChangedBase
|
||||
{
|
||||
private string _name;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetAndNotify(ref _name, value); }
|
||||
}
|
||||
private string _description;
|
||||
public string Description
|
||||
{
|
||||
get { return _description; }
|
||||
set { SetAndNotify(ref _description, value); }
|
||||
}
|
||||
|
||||
// 每个 profile 下的轴参数集合
|
||||
public ObservableCollection<AxisPIDParameter> Axes { get; set; }
|
||||
|
||||
private ObservableCollection<AxisFilteringParameter> _filteringParameters;
|
||||
public ObservableCollection<AxisFilteringParameter> FilteringParameters
|
||||
{
|
||||
get { return _filteringParameters; }
|
||||
set { SetAndNotify(ref _filteringParameters, value); }
|
||||
}
|
||||
|
||||
public PIDProfile()
|
||||
{
|
||||
Axes = new ObservableCollection<AxisPIDParameter>();
|
||||
FilteringParameters = new ObservableCollection<AxisFilteringParameter>();
|
||||
}
|
||||
|
||||
public PIDProfile(string name)
|
||||
: this()
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void EnsureAxes()
|
||||
{
|
||||
if (Axes == null)
|
||||
{
|
||||
Axes = new ObservableCollection<AxisPIDParameter>();
|
||||
NotifyOfPropertyChange(() => Axes);
|
||||
}
|
||||
|
||||
if (FilteringParameters == null)
|
||||
{
|
||||
FilteringParameters = new ObservableCollection<AxisFilteringParameter>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Stylet;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class ProcessAxisCompensationParameter : PropertyChangedBase
|
||||
{
|
||||
private string _axisName;
|
||||
public string AxisName
|
||||
{
|
||||
get { return _axisName; }
|
||||
set { SetAndNotify(ref _axisName, value); }
|
||||
}
|
||||
|
||||
private double _compensationValue;
|
||||
public double CompensationValue
|
||||
{
|
||||
get { return _compensationValue; }
|
||||
set { SetAndNotify(ref _compensationValue, value); }
|
||||
}
|
||||
|
||||
private double _phsX1Compensation;
|
||||
public double PhsX1Compensation
|
||||
{
|
||||
get { return _phsX1Compensation; }
|
||||
set { SetAndNotify(ref _phsX1Compensation, value); }
|
||||
}
|
||||
|
||||
private double _phsY1Compensation;
|
||||
public double PhsY1Compensation
|
||||
{
|
||||
get { return _phsY1Compensation; }
|
||||
set { SetAndNotify(ref _phsY1Compensation, value); }
|
||||
}
|
||||
|
||||
private double _wsXCompensation;
|
||||
public double WsXCompensation
|
||||
{
|
||||
get { return _wsXCompensation; }
|
||||
set { SetAndNotify(ref _wsXCompensation, value); }
|
||||
}
|
||||
|
||||
private double _stageYCompensation;
|
||||
public double StageYCompensation
|
||||
{
|
||||
get { return _stageYCompensation; }
|
||||
set { SetAndNotify(ref _stageYCompensation, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using MainShell.Filewritable;
|
||||
using MainShell.Recipe.Models.PID;
|
||||
using MwFramework.ManagerService;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class ProcessRecipe : RecipeBase
|
||||
{
|
||||
public override string Dir => Path.Combine(Paths.ProcessRecipe, RecipeName);
|
||||
|
||||
private ObservableCollection<PIDProfile> _axisPIDParameters = new ObservableCollection<PIDProfile>();
|
||||
/// <summary>
|
||||
/// PID参数集合
|
||||
/// </summary>
|
||||
public ObservableCollection<PIDProfile> AxisPIDParameters
|
||||
{
|
||||
get { return _axisPIDParameters; }
|
||||
set { SetProperty(ref _axisPIDParameters, value); }
|
||||
}
|
||||
|
||||
private ProcessAxisCompensationParameter _processAxisCompensationParameter = new ProcessAxisCompensationParameter();
|
||||
/// <summary>
|
||||
/// 轴补偿参数
|
||||
/// </summary>
|
||||
public ProcessAxisCompensationParameter ProcessAxisCompensationParameter
|
||||
{
|
||||
get { return _processAxisCompensationParameter; }
|
||||
set { SetProperty(ref _processAxisCompensationParameter, value); }
|
||||
}
|
||||
|
||||
private ObservableCollection<ProcessAxisCompensationParameter> _processCompensationParameters = new ObservableCollection<ProcessAxisCompensationParameter>();
|
||||
/// <summary>
|
||||
/// 工艺轴补偿参数集合
|
||||
/// </summary>
|
||||
public ObservableCollection<ProcessAxisCompensationParameter> ProcessCompensationParameters
|
||||
{
|
||||
get { return _processCompensationParameters; }
|
||||
set { SetProperty(ref _processCompensationParameters, value); }
|
||||
}
|
||||
|
||||
public ProcessRecipe(string name) : base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public ProcessRecipe() : base()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using MainShell.Filewritable;
|
||||
using MwFramework.ManagerService;
|
||||
using MXJM.FileWritable;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public abstract class RecipeBase :JsonFileWritableBase,IRecipe , INotifyPropertyChanged
|
||||
{
|
||||
private string _recipeName;
|
||||
public virtual string RecipeName
|
||||
{
|
||||
get => _recipeName;
|
||||
set
|
||||
{
|
||||
if (_recipeName != value)
|
||||
{
|
||||
string oldName = _recipeName;
|
||||
_recipeName = value;
|
||||
OnRenamed?.Invoke(this, oldName, _recipeName);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event Action<IRecipe, string, string> OnRenamed;
|
||||
#region
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
/// <summary>
|
||||
/// 通用的 SetProperty 辅助方法,派生类在属性 setter 中可使用以简化通知
|
||||
/// 用法: SetProperty(ref _field, value);
|
||||
/// </summary>
|
||||
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
||||
field = value;
|
||||
OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public string CreateSnapshot()
|
||||
{
|
||||
var settings = new JsonSerializerSettings
|
||||
{
|
||||
Formatting = Formatting.None,
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||
ContractResolver = IgnorePropertiesResolver
|
||||
};
|
||||
|
||||
return JsonConvert.SerializeObject(this, settings);
|
||||
}
|
||||
#endregion
|
||||
protected RecipeBase(string name)
|
||||
{
|
||||
_recipeName = name;
|
||||
}
|
||||
protected RecipeBase()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class RecipeEventArgs : EventArgs
|
||||
{
|
||||
public string RecipeName { get; set; }
|
||||
public string RecipeDescription { get; set; } = string.Empty;
|
||||
public RecipeEventArgs(string recipeName, string recipeDescription = "")
|
||||
{
|
||||
RecipeName = recipeName;
|
||||
RecipeDescription = recipeDescription;
|
||||
}
|
||||
public RecipeEventArgs()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RecipeRenameEventArgs : EventArgs
|
||||
{
|
||||
public string OldRecipeName { get; set; }
|
||||
public string NewRecipeName { get; set; }
|
||||
public RecipeRenameEventArgs(string oldRecipeName, string newRecipeName)
|
||||
{
|
||||
OldRecipeName = oldRecipeName;
|
||||
NewRecipeName = newRecipeName;
|
||||
}
|
||||
public RecipeRenameEventArgs()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
using MainShell.Filewritable;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class RecipeManager
|
||||
{
|
||||
public event EventHandler RecipesChanged;
|
||||
|
||||
// 记录上次加载的基板配方名(放在根目录)
|
||||
private string LastLoadedFile => Path.Combine(Paths.RecipeBasePath, "last_loaded.txt");
|
||||
|
||||
public CarrierRecipe CurrentCarrierRecipe { get; private set; }
|
||||
public SubstrateRecipe CurrentSubstrateRecipe { get; private set; }
|
||||
public WaferRecipe CurrentWaferRecipe { get; private set; }
|
||||
public ProcessRecipe CurrentProcessRecipe { get; private set; }
|
||||
|
||||
public RecipeManager()
|
||||
{
|
||||
var lastLoaded = LoadLastLoadedRecipe();
|
||||
if (!string.IsNullOrWhiteSpace(lastLoaded))
|
||||
{
|
||||
// 构造阶段不主动抛事件,避免初始化期无意义通知
|
||||
SwitchSubstrateRecipeInternal(lastLoaded, cascade: true, notify: false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveLastLoadedRecipe(string recipeName)
|
||||
{
|
||||
var dir = Path.GetDirectoryName(LastLoadedFile);
|
||||
if (!string.IsNullOrWhiteSpace(dir) && !Directory.Exists(dir))
|
||||
{
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
File.WriteAllText(LastLoadedFile, recipeName ?? string.Empty);
|
||||
}
|
||||
|
||||
public string LoadLastLoadedRecipe()
|
||||
{
|
||||
if (!File.Exists(LastLoadedFile))
|
||||
return string.Empty;
|
||||
|
||||
return File.ReadAllText(LastLoadedFile).Trim();
|
||||
}
|
||||
|
||||
public void SwitchCarrierRecipe(string carrierRecipeName)
|
||||
{
|
||||
SwitchCarrierRecipeInternal(carrierRecipeName, notify: true);
|
||||
}
|
||||
|
||||
public void SwitchSubstrateRecipe(string substrateRecipeName)
|
||||
{
|
||||
// 需求:切换基板时自动切换芯片;切换芯片时自动切换工艺
|
||||
SwitchSubstrateRecipeInternal(substrateRecipeName, cascade: true, notify: true);
|
||||
}
|
||||
|
||||
public void SwitchWaferRecipe(string waferRecipeName)
|
||||
{
|
||||
// 需求:切换芯片时自动切换工艺
|
||||
SwitchWaferRecipeInternal(waferRecipeName, cascade: true, notify: true);
|
||||
}
|
||||
|
||||
public void SwitchProcessRecipe(string processRecipeName)
|
||||
{
|
||||
SwitchProcessRecipeInternal(processRecipeName, notify: true);
|
||||
}
|
||||
|
||||
private void SwitchCarrierRecipeInternal(string carrierRecipeName, bool notify)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(carrierRecipeName))
|
||||
return;
|
||||
|
||||
CurrentCarrierRecipe = CurrentCarrierRecipe ?? new CarrierRecipe();
|
||||
CurrentCarrierRecipe.RecipeName = carrierRecipeName;
|
||||
|
||||
var path = Path.Combine(Paths.CarrierRecipe, carrierRecipeName, CurrentCarrierRecipe.FileName);
|
||||
CurrentCarrierRecipe.Read(path);
|
||||
|
||||
var substrateName = GetFirstSubstrateName(CurrentCarrierRecipe);
|
||||
if (!string.IsNullOrWhiteSpace(substrateName))
|
||||
{
|
||||
// 向下级联,但由最外层统一通知
|
||||
SwitchSubstrateRecipeInternal(substrateName, cascade: true, notify: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearSubstrateRecipeInternal(false);
|
||||
}
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private void SwitchSubstrateRecipeInternal(string substrateRecipeName, bool cascade, bool notify)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(substrateRecipeName))
|
||||
return;
|
||||
|
||||
CurrentSubstrateRecipe = CurrentSubstrateRecipe ?? new SubstrateRecipe();
|
||||
CurrentSubstrateRecipe.RecipeName = substrateRecipeName;
|
||||
|
||||
var path = Path.Combine(Paths.SubstrateRecipe, substrateRecipeName, CurrentSubstrateRecipe.FileName);
|
||||
CurrentSubstrateRecipe.Read(path);
|
||||
|
||||
SaveLastLoadedRecipe(substrateRecipeName);
|
||||
|
||||
if (cascade)
|
||||
{
|
||||
var waferName = GetFirstWaferName(CurrentSubstrateRecipe);
|
||||
if (!string.IsNullOrWhiteSpace(waferName))
|
||||
{
|
||||
SwitchWaferRecipeInternal(waferName, cascade: true, notify: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有关联芯片时,清空下游当前引用,避免残留旧状态
|
||||
CurrentWaferRecipe = null;
|
||||
CurrentProcessRecipe = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private void SwitchWaferRecipeInternal(string waferRecipeName, bool cascade, bool notify)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(waferRecipeName))
|
||||
return;
|
||||
|
||||
CurrentWaferRecipe = CurrentWaferRecipe ?? new WaferRecipe();
|
||||
CurrentWaferRecipe.RecipeName = waferRecipeName;
|
||||
|
||||
var path = Path.Combine(Paths.WaferRecipe, waferRecipeName, CurrentWaferRecipe.FileName);
|
||||
CurrentWaferRecipe.Read(path);
|
||||
|
||||
if (cascade)
|
||||
{
|
||||
var processName = CurrentWaferRecipe.ProcessRecipeName;
|
||||
if (!string.IsNullOrWhiteSpace(processName))
|
||||
{
|
||||
SwitchProcessRecipeInternal(processName, notify: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentProcessRecipe = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private void SwitchProcessRecipeInternal(string processRecipeName, bool notify)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(processRecipeName))
|
||||
return;
|
||||
|
||||
CurrentProcessRecipe = CurrentProcessRecipe ?? new ProcessRecipe();
|
||||
CurrentProcessRecipe.RecipeName = processRecipeName;
|
||||
|
||||
var path = Path.Combine(Paths.ProcessRecipe, processRecipeName, CurrentProcessRecipe.FileName);
|
||||
CurrentProcessRecipe.Read(path);
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private static string GetFirstSubstrateName(CarrierRecipe carrierRecipe)
|
||||
{
|
||||
if (carrierRecipe == null ||
|
||||
carrierRecipe.SubstrateSelectInfos == null ||
|
||||
carrierRecipe.SubstrateSelectInfos.Count == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return carrierRecipe.SubstrateSelectInfos[0].SubstrateName;
|
||||
}
|
||||
|
||||
private static string GetFirstWaferName(SubstrateRecipe substrateRecipe)
|
||||
{
|
||||
if (substrateRecipe == null ||
|
||||
substrateRecipe.WaferSelectInfos == null ||
|
||||
substrateRecipe.WaferSelectInfos.Count == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var inUse = substrateRecipe.WaferSelectInfos
|
||||
.FirstOrDefault(x => x != null && x.IsUse && !string.IsNullOrWhiteSpace(x.WaferRecipeName));
|
||||
if (inUse != null)
|
||||
return inUse.WaferRecipeName;
|
||||
|
||||
var firstValid = substrateRecipe.WaferSelectInfos
|
||||
.FirstOrDefault(x => x != null && !string.IsNullOrWhiteSpace(x.WaferRecipeName));
|
||||
return firstValid != null ? firstValid.WaferRecipeName : string.Empty;
|
||||
}
|
||||
|
||||
private void RaiseRecipesChanged()
|
||||
{
|
||||
RecipesChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public void DeleteCarrierRecipe(string recipeName)
|
||||
{
|
||||
DeleteRecipeFolder(Paths.CarrierRecipe, recipeName, out _);
|
||||
}
|
||||
|
||||
public bool DeleteCarrierRecipe(string recipeName, out string error)
|
||||
{
|
||||
return DeleteRecipeFolder(Paths.CarrierRecipe, recipeName, out error);
|
||||
}
|
||||
|
||||
public void DeleteSubstrateRecipe(string recipeName)
|
||||
{
|
||||
DeleteRecipeFolder(Paths.SubstrateRecipe, recipeName, out _);
|
||||
}
|
||||
|
||||
public bool DeleteSubstrateRecipe(string recipeName, out string error)
|
||||
{
|
||||
return DeleteRecipeFolder(Paths.SubstrateRecipe, recipeName, out error);
|
||||
}
|
||||
|
||||
public void DeleteWaferRecipe(string recipeName)
|
||||
{
|
||||
DeleteRecipeFolder(Paths.WaferRecipe, recipeName, out _);
|
||||
}
|
||||
|
||||
public bool DeleteWaferRecipe(string recipeName, out string error)
|
||||
{
|
||||
return DeleteRecipeFolder(Paths.WaferRecipe, recipeName, out error);
|
||||
}
|
||||
|
||||
public void DeleteProcessRecipe(string recipeName)
|
||||
{
|
||||
DeleteRecipeFolder(Paths.ProcessRecipe, recipeName, out _);
|
||||
}
|
||||
|
||||
public bool DeleteProcessRecipe(string recipeName, out string error)
|
||||
{
|
||||
return DeleteRecipeFolder(Paths.ProcessRecipe, recipeName, out error);
|
||||
}
|
||||
|
||||
public bool DeleteRecipeFolder(string baseFolder, string recipeName, out string error)
|
||||
{
|
||||
error = null;
|
||||
if (string.IsNullOrWhiteSpace(baseFolder) || string.IsNullOrWhiteSpace(recipeName))
|
||||
{
|
||||
error = "配方名称不能为空";
|
||||
return false;
|
||||
}
|
||||
|
||||
var path = Path.Combine(baseFolder, recipeName);
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
error = "配方目录不存在";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Directory.Delete(path, true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CopyRecipeFolder(string baseFolder, string sourceRecipeName, string targetRecipeName, out string error)
|
||||
{
|
||||
error = null;
|
||||
if (string.IsNullOrWhiteSpace(baseFolder) || string.IsNullOrWhiteSpace(sourceRecipeName) || string.IsNullOrWhiteSpace(targetRecipeName))
|
||||
{
|
||||
error = "配方名称不能为空";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sourceRecipeName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ||
|
||||
targetRecipeName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
|
||||
{
|
||||
error = "名称包含非法字符";
|
||||
return false;
|
||||
}
|
||||
|
||||
var sourcePath = Path.Combine(baseFolder, sourceRecipeName);
|
||||
var targetPath = Path.Combine(baseFolder, targetRecipeName);
|
||||
|
||||
if (!Directory.Exists(sourcePath))
|
||||
{
|
||||
error = "源文件夹不存在";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Directory.Exists(targetPath))
|
||||
{
|
||||
error = "目标文件夹已存在";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CopyDirectory(sourcePath, targetPath);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.Message;
|
||||
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(targetPath))
|
||||
{
|
||||
Directory.Delete(targetPath, true);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearCarrierRecipe()
|
||||
{
|
||||
ClearCarrierRecipeInternal(true);
|
||||
}
|
||||
|
||||
public void ClearSubstrateRecipe()
|
||||
{
|
||||
ClearSubstrateRecipeInternal(true);
|
||||
}
|
||||
|
||||
public void ClearWaferRecipe()
|
||||
{
|
||||
ClearWaferRecipeInternal(true);
|
||||
}
|
||||
|
||||
public void ClearProcessRecipe()
|
||||
{
|
||||
ClearProcessRecipeInternal(true);
|
||||
}
|
||||
|
||||
private void ClearCarrierRecipeInternal(bool notify)
|
||||
{
|
||||
CurrentCarrierRecipe = null;
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private void ClearSubstrateRecipeInternal(bool notify)
|
||||
{
|
||||
CurrentSubstrateRecipe = null;
|
||||
CurrentWaferRecipe = null;
|
||||
CurrentProcessRecipe = null;
|
||||
SaveLastLoadedRecipe(string.Empty);
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private void ClearWaferRecipeInternal(bool notify)
|
||||
{
|
||||
CurrentWaferRecipe = null;
|
||||
CurrentProcessRecipe = null;
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private void ClearProcessRecipeInternal(bool notify)
|
||||
{
|
||||
CurrentProcessRecipe = null;
|
||||
|
||||
if (notify)
|
||||
RaiseRecipesChanged();
|
||||
}
|
||||
|
||||
private static void CopyDirectory(string sourcePath, string targetPath)
|
||||
{
|
||||
Directory.CreateDirectory(targetPath);
|
||||
|
||||
foreach (var filePath in Directory.GetFiles(sourcePath))
|
||||
{
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
var targetFilePath = Path.Combine(targetPath, fileName);
|
||||
File.Copy(filePath, targetFilePath, false);
|
||||
}
|
||||
|
||||
foreach (var directoryPath in Directory.GetDirectories(sourcePath))
|
||||
{
|
||||
var directoryName = Path.GetFileName(directoryPath);
|
||||
var targetDirectoryPath = Path.Combine(targetPath, directoryName);
|
||||
CopyDirectory(directoryPath, targetDirectoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
public bool RenameFolder(string baseFolder, string oldName, string newName, out string error)
|
||||
{
|
||||
error = null;
|
||||
if (string.IsNullOrWhiteSpace(oldName) || string.IsNullOrWhiteSpace(newName))
|
||||
{
|
||||
error = "名称不能为空";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (oldName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ||
|
||||
newName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
|
||||
{
|
||||
error = "名称包含非法字符";
|
||||
return false;
|
||||
}
|
||||
|
||||
var src = Path.Combine(baseFolder, oldName);
|
||||
var dst = Path.Combine(baseFolder, newName);
|
||||
|
||||
if (!Directory.Exists(src))
|
||||
{
|
||||
error = "源文件夹不存在";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Directory.Exists(dst))
|
||||
{
|
||||
error = "目标文件夹已存在";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (string.Equals(oldName, newName, StringComparison.OrdinalIgnoreCase) &&
|
||||
!string.Equals(oldName, newName, StringComparison.Ordinal))
|
||||
{
|
||||
var temp = Path.Combine(baseFolder, oldName + "_tmp_" + Guid.NewGuid().ToString("N"));
|
||||
Directory.Move(src, temp);
|
||||
Directory.Move(temp, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.Move(src, dst);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class RecipeWrap : PropertyChangedBase
|
||||
{
|
||||
private string _recipeName;
|
||||
|
||||
public string RecipeName
|
||||
{
|
||||
get { return _recipeName; }
|
||||
set { SetAndNotify(ref _recipeName, value); }
|
||||
}
|
||||
private DateTime _createTime;
|
||||
|
||||
public DateTime CreateTime
|
||||
{
|
||||
get { return _createTime; }
|
||||
set { SetAndNotify(ref _createTime, value); }
|
||||
}
|
||||
private DateTime _modifiedTime;
|
||||
|
||||
public DateTime ModifiedTime
|
||||
{
|
||||
get { return _modifiedTime; }
|
||||
set { SetAndNotify(ref _modifiedTime, value); }
|
||||
}
|
||||
|
||||
private bool _isInUse;
|
||||
|
||||
public bool IsInUse
|
||||
{
|
||||
get { return _isInUse; }
|
||||
set { SetAndNotify(ref _isInUse, value); }
|
||||
}
|
||||
private bool _hasError;
|
||||
|
||||
public bool HasError
|
||||
{
|
||||
get { return _hasError; }
|
||||
set { SetAndNotify(ref _hasError, value); }
|
||||
}
|
||||
private bool _needUpdate;
|
||||
/// <summary>
|
||||
/// 重命名&删除时
|
||||
/// </summary>
|
||||
public bool NeedUpdate
|
||||
{
|
||||
get { return _needUpdate; }
|
||||
set { SetAndNotify(ref _needUpdate, value); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using MainShell.Filewritable;
|
||||
using MaxwellFramework.Core.Attributes;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
[Singleton]
|
||||
public class RecipeWrapManager : PropertyChangedBase , IHandle<SubstrateNameChangedEventArgs>
|
||||
{
|
||||
private ObservableCollection<RecipeWrap> _carrierRecipeWraps;
|
||||
|
||||
public ObservableCollection<RecipeWrap> CarrierRecipeWraps
|
||||
{
|
||||
get { return _carrierRecipeWraps; }
|
||||
set { SetAndNotify(ref _carrierRecipeWraps, value); }
|
||||
}
|
||||
|
||||
private ObservableCollection<RecipeWrap> _substrateRecipeWraps;
|
||||
|
||||
public ObservableCollection<RecipeWrap> SubstrateRecipeWraps
|
||||
{
|
||||
get { return _substrateRecipeWraps; }
|
||||
set { SetAndNotify(ref _substrateRecipeWraps, value); }
|
||||
}
|
||||
private ObservableCollection<RecipeWrap> _waferRecipeWraps;
|
||||
|
||||
public ObservableCollection<RecipeWrap> WaferRecipeWraps
|
||||
{
|
||||
get { return _waferRecipeWraps; }
|
||||
set { SetAndNotify(ref _waferRecipeWraps, value); }
|
||||
}
|
||||
private ObservableCollection<RecipeWrap> _processRecipeWraps;
|
||||
|
||||
public ObservableCollection<RecipeWrap> ProcessRecipeWraps
|
||||
{
|
||||
get { return _processRecipeWraps; }
|
||||
set { SetAndNotify(ref _processRecipeWraps, value); }
|
||||
}
|
||||
|
||||
public RecipeWrapManager(IEventAggregator eventAggregator)
|
||||
{
|
||||
CarrierRecipeWraps = new ObservableCollection<RecipeWrap>(LoadRecipes(Paths.CarrierRecipe));
|
||||
SubstrateRecipeWraps = new ObservableCollection<RecipeWrap>(LoadRecipes(Paths.SubstrateRecipe));
|
||||
WaferRecipeWraps = new ObservableCollection<RecipeWrap>(LoadRecipes(Paths.WaferRecipe));
|
||||
ProcessRecipeWraps = new ObservableCollection<RecipeWrap>(LoadRecipes(Paths.ProcessRecipe));
|
||||
eventAggregator.Unsubscribe(this);
|
||||
eventAggregator.Subscribe(this);
|
||||
}
|
||||
private IEnumerable<RecipeWrap> LoadRecipes(string dirPath)
|
||||
{
|
||||
if (!Directory.Exists(dirPath))
|
||||
Directory.CreateDirectory(dirPath);
|
||||
foreach (var dir in Directory.EnumerateDirectories(dirPath))
|
||||
{
|
||||
var name = Path.GetFileNameWithoutExtension(dir);
|
||||
yield return new RecipeWrap
|
||||
{
|
||||
RecipeName = name,
|
||||
CreateTime = Directory.GetCreationTime(dir),
|
||||
ModifiedTime = Directory.GetLastWriteTime(dir),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(SubstrateNameChangedEventArgs message)
|
||||
{
|
||||
CarrierRecipe carrierRecipe = new CarrierRecipe();
|
||||
foreach (var carrierWrap in CarrierRecipeWraps)
|
||||
{
|
||||
carrierRecipe.RecipeName= carrierWrap.RecipeName;
|
||||
carrierRecipe.Read();
|
||||
if(carrierRecipe.SubstrateSelectInfos!=null)
|
||||
{
|
||||
foreach (var item in carrierRecipe.SubstrateSelectInfos)
|
||||
{
|
||||
if(item.SubstrateName==message.OldName)
|
||||
{
|
||||
item.SubstrateName= message.NewName;
|
||||
carrierRecipe.Write();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace MainShell.Recipe.Models.SubstrateParameter
|
||||
{
|
||||
public class MarkCoordinateGenerationState : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private int _rows;
|
||||
public int Rows
|
||||
{
|
||||
get { return _rows; }
|
||||
set { SetAndNotify(ref _rows, value); }
|
||||
}
|
||||
|
||||
private int _cols;
|
||||
public int Cols
|
||||
{
|
||||
get { return _cols; }
|
||||
set { SetAndNotify(ref _cols, value); }
|
||||
}
|
||||
|
||||
private double _pitchX;
|
||||
public double PitchX
|
||||
{
|
||||
get { return _pitchX; }
|
||||
set { SetAndNotify(ref _pitchX, value); }
|
||||
}
|
||||
|
||||
private double _pitchY;
|
||||
public double PitchY
|
||||
{
|
||||
get { return _pitchY; }
|
||||
set { SetAndNotify(ref _pitchY, value); }
|
||||
}
|
||||
|
||||
private ObservableCollection<MarkCoordinatePoint> _points = new ObservableCollection<MarkCoordinatePoint>();
|
||||
public ObservableCollection<MarkCoordinatePoint> Points
|
||||
{
|
||||
get { return _points; }
|
||||
set { SetAndNotify(ref _points, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return new MarkCoordinateGenerationState
|
||||
{
|
||||
Rows = Rows,
|
||||
Cols = Cols,
|
||||
PitchX = PitchX,
|
||||
PitchY = PitchY,
|
||||
Points = new ObservableCollection<MarkCoordinatePoint>(Points.Select(point => point.Clone() as MarkCoordinatePoint))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
|
||||
namespace MainShell.Recipe.Models.SubstrateParameter
|
||||
{
|
||||
public class MarkCoordinatePoint : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private int _index;
|
||||
public int Index
|
||||
{
|
||||
get { return _index; }
|
||||
set { SetAndNotify(ref _index, value); }
|
||||
}
|
||||
|
||||
private string _pointName;
|
||||
public string PointName
|
||||
{
|
||||
get { return _pointName; }
|
||||
set { SetAndNotify(ref _pointName, value); }
|
||||
}
|
||||
|
||||
private int _row;
|
||||
public int Row
|
||||
{
|
||||
get { return _row; }
|
||||
set { SetAndNotify(ref _row, value); }
|
||||
}
|
||||
|
||||
private int _col;
|
||||
public int Col
|
||||
{
|
||||
get { return _col; }
|
||||
set { SetAndNotify(ref _col, value); }
|
||||
}
|
||||
|
||||
private double _theoryX;
|
||||
public double TheoryX
|
||||
{
|
||||
get { return _theoryX; }
|
||||
set { SetAndNotify(ref _theoryX, value); }
|
||||
}
|
||||
|
||||
private double _theoryY;
|
||||
public double TheoryY
|
||||
{
|
||||
get { return _theoryY; }
|
||||
set { SetAndNotify(ref _theoryY, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return new MarkCoordinatePoint
|
||||
{
|
||||
Index = Index,
|
||||
PointName = PointName,
|
||||
Row = Row,
|
||||
Col = Col,
|
||||
TheoryX = TheoryX,
|
||||
TheoryY = TheoryY,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using MainShell.Models;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models.SubstrateParameter
|
||||
{
|
||||
public class MarkData : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private string _templateName;
|
||||
private bool _isEnabled = true;
|
||||
|
||||
public string TemplateName
|
||||
{
|
||||
get { return _templateName; }
|
||||
set { SetAndNotify(ref _templateName, value); }
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get { return _isEnabled; }
|
||||
set { SetAndNotify(ref _isEnabled, value); }
|
||||
}
|
||||
|
||||
private MPoint _basePos;
|
||||
public MPoint BasePos
|
||||
{
|
||||
get { return _basePos; }
|
||||
set { SetAndNotify(ref _basePos, value); }
|
||||
}
|
||||
|
||||
private MPoint _cameraPos;
|
||||
|
||||
public MPoint CameraPos
|
||||
{
|
||||
get { return _cameraPos; }
|
||||
set { SetAndNotify(ref _cameraPos, value); }
|
||||
}
|
||||
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
return new MarkData
|
||||
{
|
||||
IsEnabled = this.IsEnabled,
|
||||
TemplateName = this.TemplateName,
|
||||
BasePos = this.BasePos?.Clone(),
|
||||
CameraPos = this.CameraPos?.Clone()
|
||||
} as IParameterItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using MainShell.Models;
|
||||
using Stylet;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MainShell.Recipe.Models.SubstrateParameter
|
||||
{
|
||||
public enum SubstrateHeightMeasureMode
|
||||
{
|
||||
[Description("标准示教位置")]
|
||||
StandardTeachPosition = 0,
|
||||
|
||||
[Description("行列坐标+偏移补偿")]
|
||||
RowColumnOffset = 1,
|
||||
}
|
||||
|
||||
public class SubstrateHeightMeasurePoint : PropertyChangedBase
|
||||
{
|
||||
private string _pointName;
|
||||
public string PointName
|
||||
{
|
||||
get { return _pointName; }
|
||||
set { SetAndNotify(ref _pointName, value); }
|
||||
}
|
||||
|
||||
private MPoint _teachPosition = new MPoint();
|
||||
public MPoint TeachPosition
|
||||
{
|
||||
get { return _teachPosition; }
|
||||
set { SetAndNotify(ref _teachPosition, value); }
|
||||
}
|
||||
|
||||
private int _rowIndex;
|
||||
public int RowIndex
|
||||
{
|
||||
get { return _rowIndex; }
|
||||
set { SetAndNotify(ref _rowIndex, value); }
|
||||
}
|
||||
|
||||
private int _columnIndex;
|
||||
public int ColumnIndex
|
||||
{
|
||||
get { return _columnIndex; }
|
||||
set { SetAndNotify(ref _columnIndex, value); }
|
||||
}
|
||||
|
||||
private MPoint _offsetCompensation = new MPoint();
|
||||
public MPoint OffsetCompensation
|
||||
{
|
||||
get { return _offsetCompensation; }
|
||||
set { SetAndNotify(ref _offsetCompensation, value); }
|
||||
}
|
||||
}
|
||||
|
||||
public class SubstrateHeightMeasureSetting : PropertyChangedBase
|
||||
{
|
||||
private SubstrateHeightMeasureMode _mode = SubstrateHeightMeasureMode.StandardTeachPosition;
|
||||
public SubstrateHeightMeasureMode Mode
|
||||
{
|
||||
get { return _mode; }
|
||||
set { SetAndNotify(ref _mode, value); }
|
||||
}
|
||||
|
||||
private MPoint _commonOffsetCompensation = new MPoint();
|
||||
public MPoint CommonOffsetCompensation
|
||||
{
|
||||
get { return _commonOffsetCompensation; }
|
||||
set { SetAndNotify(ref _commonOffsetCompensation, value); }
|
||||
}
|
||||
|
||||
private ObservableCollection<SubstrateHeightMeasurePoint> _points = new ObservableCollection<SubstrateHeightMeasurePoint>();
|
||||
public ObservableCollection<SubstrateHeightMeasurePoint> Points
|
||||
{
|
||||
get { return _points; }
|
||||
set { SetAndNotify(ref _points, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using MainShell.Models;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class SubstrateInfo : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
private MxSize _substrateSize = new MxSize();
|
||||
|
||||
public MxSize SubstrateSize
|
||||
{
|
||||
get { return _substrateSize; }
|
||||
set { SetAndNotify(ref _substrateSize, value); }
|
||||
}
|
||||
|
||||
private MxSize _padSize;
|
||||
|
||||
public MxSize PadSize
|
||||
{
|
||||
get { return _padSize; }
|
||||
set { SetAndNotify(ref _padSize, value); }
|
||||
}
|
||||
|
||||
|
||||
private double _thickness;
|
||||
|
||||
public double ThickNess
|
||||
{
|
||||
get { return _thickness; }
|
||||
set { SetAndNotify(ref _thickness, value); }
|
||||
}
|
||||
private double _pitchX;
|
||||
|
||||
public double PitchX
|
||||
{
|
||||
get { return _pitchX; }
|
||||
set { SetAndNotify(ref _pitchX, value); }
|
||||
}
|
||||
private double _pitchY;
|
||||
|
||||
public double PitchY
|
||||
{
|
||||
get { return _pitchY; }
|
||||
set { SetAndNotify(ref _pitchY, value); }
|
||||
}
|
||||
private int _rowNumber;
|
||||
|
||||
public int RowNumber
|
||||
{
|
||||
get { return _rowNumber; }
|
||||
set { SetAndNotify(ref _rowNumber, value); }
|
||||
}
|
||||
private int _colNumber;
|
||||
|
||||
public int ColNumber
|
||||
{
|
||||
get { return _colNumber; }
|
||||
set { SetAndNotify(ref _colNumber, value); }
|
||||
}
|
||||
|
||||
private double _recheckPitch;
|
||||
|
||||
public double RecheckPitch
|
||||
{
|
||||
get { return _recheckPitch; }
|
||||
set { SetAndNotify(ref _recheckPitch, value); }
|
||||
}
|
||||
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
// 1. 首先执行浅拷贝,复制所有值类型字段(如 Thickness, PitchX 等)
|
||||
var clone = this.MemberwiseClone() as SubstrateInfo;
|
||||
|
||||
// 2. 手动深拷贝引用类型对象 (MxSize)
|
||||
// 如果不这样做,clone 和原对象将指向内存中的同一个 MxSize 实例
|
||||
if (this.SubstrateSize != null)
|
||||
{
|
||||
clone.SubstrateSize = new MxSize
|
||||
{
|
||||
Width = this.SubstrateSize.Width,
|
||||
Height = this.SubstrateSize.Height
|
||||
};
|
||||
}
|
||||
|
||||
if (this.PadSize != null)
|
||||
{
|
||||
clone.PadSize = new MxSize
|
||||
{
|
||||
Width = this.PadSize.Width,
|
||||
Height = this.PadSize.Height
|
||||
};
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using MainShell.Models;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models.SubstrateParameter
|
||||
{
|
||||
public class SubtrateMarkPars : PropertyChangedBase, IParameterItem
|
||||
{
|
||||
public CameraConfig MarkVisionConfig { get; set; } = new CameraConfig();
|
||||
public UpCamLightConfig MarkLightConfig { get; set; } = new UpCamLightConfig();
|
||||
public ObservableCollection<MarkData> MarkDatas { get; set; } = new ObservableCollection<MarkData>();
|
||||
public MarkCoordinateGenerationState CoordinateGenerationState { get; set; } = new MarkCoordinateGenerationState();
|
||||
public IParameterItem Clone()
|
||||
{
|
||||
var clone = this.MemberwiseClone() as SubtrateMarkPars;
|
||||
if (clone != null)
|
||||
{
|
||||
clone.MarkVisionConfig = this.MarkVisionConfig.Clone() as CameraConfig;
|
||||
clone.MarkLightConfig = this.MarkLightConfig.Clone() as UpCamLightConfig;
|
||||
clone.MarkDatas = new ObservableCollection<MarkData>(this.MarkDatas.Select(md => md.Clone() as MarkData));
|
||||
clone.CoordinateGenerationState = this.CoordinateGenerationState?.Clone() as MarkCoordinateGenerationState ?? new MarkCoordinateGenerationState();
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models.SubstrateParameter
|
||||
{
|
||||
public class WaferSelectInfo : PropertyChangedBase
|
||||
{
|
||||
private string _waferRecipeName;
|
||||
|
||||
public string WaferRecipeName
|
||||
{
|
||||
get { return _waferRecipeName; }
|
||||
set { SetAndNotify(ref _waferRecipeName, value); }
|
||||
}
|
||||
private double _offsetX;
|
||||
|
||||
public double OffsetX
|
||||
{
|
||||
get { return _offsetX; }
|
||||
set { SetAndNotify(ref _offsetX, value); }
|
||||
}
|
||||
private double _offsetY;
|
||||
|
||||
public double OffsetY
|
||||
{
|
||||
get { return _offsetY; }
|
||||
set { SetAndNotify(ref _offsetY, value); }
|
||||
}
|
||||
|
||||
private bool _isUse;
|
||||
|
||||
public bool IsUse
|
||||
{
|
||||
get { return _isUse; }
|
||||
set { SetAndNotify(ref _isUse, value); }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using MainShell.Models;
|
||||
using MainShell.Recipe.Models.SubstrateParameter;
|
||||
using MwFramework.ManagerService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class SubstrateRecipe : RecipeBase
|
||||
{
|
||||
public override string Dir => System.IO.Path.Combine(Filewritable.Paths.SubstrateRecipe, RecipeName);
|
||||
|
||||
private ObservableCollection<WaferSelectInfo> _waferSelectInfos = new ObservableCollection<WaferSelectInfo>();
|
||||
public ObservableCollection<WaferSelectInfo> WaferSelectInfos
|
||||
{
|
||||
get { return _waferSelectInfos; }
|
||||
set { SetProperty(ref _waferSelectInfos, value); }
|
||||
}
|
||||
private SubstrateInfo _substrateInfo = new SubstrateInfo();
|
||||
public SubstrateInfo SubstrateInfo
|
||||
{
|
||||
get { return _substrateInfo; }
|
||||
set { SetProperty(ref _substrateInfo, value); }
|
||||
}
|
||||
private SubtrateMarkPars _subtrateMarkParameterInfo = new SubtrateMarkPars();
|
||||
|
||||
public SubtrateMarkPars SubtrateMarkParameterInfo
|
||||
{
|
||||
get { return _subtrateMarkParameterInfo; }
|
||||
set { SetProperty(ref _subtrateMarkParameterInfo, value); }
|
||||
}
|
||||
|
||||
private SubstrateHeightMeasureSetting _heightMeasureSetting = new SubstrateHeightMeasureSetting();
|
||||
public SubstrateHeightMeasureSetting HeightMeasureSetting
|
||||
{
|
||||
get { return _heightMeasureSetting; }
|
||||
set { SetProperty(ref _heightMeasureSetting, value); }
|
||||
}
|
||||
|
||||
public SubstratePoint[,] SubstratePoints { get; set; }
|
||||
|
||||
public SubstrateRecipe(string name) : base(name)
|
||||
{
|
||||
}
|
||||
public SubstrateRecipe() : base()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using MainShell.Filewritable;
|
||||
using MwFramework.ManagerService;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Recipe.Models
|
||||
{
|
||||
public class WaferRecipe : RecipeBase
|
||||
{
|
||||
public override string Dir => Path.Combine(Paths.WaferRecipe, RecipeName);
|
||||
|
||||
private WaferInfo _waferInfo = new WaferInfo();
|
||||
|
||||
/// <summary>
|
||||
/// 晶圆信息
|
||||
/// </summary>
|
||||
public WaferInfo WaferInfo
|
||||
{
|
||||
get { return _waferInfo; }
|
||||
set { SetProperty(ref _waferInfo, value); }
|
||||
}
|
||||
|
||||
private WaferScanSettings _scanSettings = new WaferScanSettings();
|
||||
|
||||
public WaferScanSettings ScanSettings
|
||||
{
|
||||
get { return _scanSettings; }
|
||||
set { SetProperty(ref _scanSettings, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工艺参数配方名称
|
||||
/// </summary>
|
||||
private string _processRecipeName;
|
||||
|
||||
public string ProcessRecipeName
|
||||
{
|
||||
get { return _processRecipeName; }
|
||||
set { SetProperty(ref _processRecipeName, value); }
|
||||
}
|
||||
|
||||
public WaferRecipe(string name) : base(name)
|
||||
{
|
||||
}
|
||||
public WaferRecipe() : base()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user