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

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

View File

@@ -0,0 +1,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); }
}
}
}

View File

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

View File

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

View File

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

View File

@@ -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()
{
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
{
}
}
}

View File

@@ -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()
{
}
}
}

View File

@@ -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()
{
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
{
}
}
}

View File

@@ -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()
{
}
}
}