From 592ed68e783095c360ff183323a32528a8cb94b2 Mon Sep 17 00:00:00 2001 From: SL <123@123.com> Date: Thu, 29 Jun 2023 11:58:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=8E8=E5=8F=B7=E6=9C=BA=E7=A7=BB=E6=A4=8DP?= =?UTF-8?q?MProcessView=E8=A7=86=E5=9B=BE=E5=8F=8A=E5=85=B6=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E8=A7=86=E5=9B=BE=EF=BC=8C=E5=B9=B6=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PM/PMProcessGasFlowCounterViewModel.cs | 526 ++++ .../CenterViews/Modules/PM/PMProcessView.xaml | 2214 +++++++++++++++++ .../Modules/PM/PMProcessView.xaml.cs | 21 + .../Modules/PM/PMProcessViewModel.cs | 1719 +++++++++++++ .../Modules/PM/ProcessMonitorView.xaml | 598 +++++ .../Modules/PM/ProcessMonitorView.xaml.cs | 15 + .../Modules/PM/ProcessMonitorViewModel.cs | 212 ++ .../MECF.Framework.UI.Client.csproj | 24 + .../Resources/Images/chamber.png | Bin 0 -> 8408 bytes .../Resources/Images/showerhead.png | Bin 0 -> 12393 bytes .../SicModuleUIViewModelBase.cs | 202 ++ 11 files changed, 5531 insertions(+) create mode 100644 MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessGasFlowCounterViewModel.cs create mode 100644 MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml create mode 100644 MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml.cs create mode 100644 MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessViewModel.cs create mode 100644 MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml create mode 100644 MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml.cs create mode 100644 MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorViewModel.cs create mode 100644 MECF.Framework.UI.Client/Resources/Images/chamber.png create mode 100644 MECF.Framework.UI.Client/Resources/Images/showerhead.png create mode 100644 MECF.Framework.UI.Client/SicModuleUIViewModelBase.cs diff --git a/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessGasFlowCounterViewModel.cs b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessGasFlowCounterViewModel.cs new file mode 100644 index 0000000..d4b838b --- /dev/null +++ b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessGasFlowCounterViewModel.cs @@ -0,0 +1,526 @@ +#define _FAKE_DATA + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Windows.Data; +using Aitex.Core.RT.Log; +using MECF.Framework.Common.DataCenter; +using MECF.Framework.UI.Client.CenterViews.Modules.PM; +using MECF.Framework.UI.Client.ClientBase; +using Sicentury.Core; + +#if FAKE_DATA +using System.Threading; +using System.Threading.Tasks; +#endif + + +namespace SicUI.Models.PMs +{ + public class ObservableQueue : Queue, INotifyCollectionChanged + { + public event NotifyCollectionChangedEventHandler CollectionChanged; + + private readonly object _syncRoot = new object(); + + #region Constructors + + public ObservableQueue() + { + LimitSize = 0; + } + + public ObservableQueue(int capacity) : base(capacity) + { + LimitSize = capacity; + } + + + #endregion + + #region Properties + + public int LimitSize { get; } + + public new virtual void Enqueue(T obj) + { + lock (_syncRoot) + { + base.Enqueue(obj); + + if (LimitSize > 0 && base.Count > LimitSize) + base.Dequeue(); + + CollectionChanged?.Invoke(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, obj)); + } + } + + public new virtual T Dequeue() + { + lock (_syncRoot) + { + var obj = base.Dequeue(); + CollectionChanged?.Invoke(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, obj)); + return obj; + } + } + + + public new virtual void Clear() + { + lock (_syncRoot) + { + base.Clear(); + CollectionChanged?.Invoke(this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + + } + } + + #endregion + } + + public class GasFlowCounter : BindableBase + { + #region Variables + + #endregion + + #region Constructors + + public GasFlowCounter(string gasName) + { + GasName = gasName; + TotalFlow = 0; + } + + public GasFlowCounter(string gasName, double initValue) : this(gasName) + { + TotalFlow = initValue; + } + + #endregion + + #region Properties + + public string GasName { get; } + + public double TotalFlow { get; private set; } + + #endregion + + #region Methods + + public void AddFlow(double increment) + { + TotalFlow += increment; + } + + public override string ToString() + { + return $"{TotalFlow:F1}"; + } + + #endregion + } + + public class PmGasFlowCountInfo : BindableBase + { + #region Variables + + private DateTime _statStart; + private DateTime? _statEnd; + + + #endregion + + #region Constructors + + public PmGasFlowCountInfo(int index, Guid uid, string recipeName, string waferUid, DateTime beginTime, DateTime endTime, double h2, + double ar, + double pn2, double hcl, double sih4, double cxhx, double tcs, double tma) + { + Index = index; + StatisticsUid = uid; + RecipeName = recipeName; + WaferId = waferUid; + StatisticsStart = beginTime; + StatisticsEnd = endTime; + H2 = new GasFlowCounter(nameof(H2), h2); + Ar = new GasFlowCounter(nameof(Ar), ar); + PN2 = new GasFlowCounter(nameof(PN2), pn2); + HCL = new GasFlowCounter(nameof(HCL), hcl); + SiH4 = new GasFlowCounter(nameof(SiH4), sih4); + CxHx = new GasFlowCounter(nameof(CxHx), cxhx); + TCS = new GasFlowCounter(nameof(TCS), tcs); + TMA = new GasFlowCounter(nameof(TMA), tma); + + + } + + public PmGasFlowCountInfo() + { + StatisticsUid = Guid.NewGuid(); + WaferId = string.Empty; + RecipeName = string.Empty; + StatisticsStart = DateTime.Now; + + H2 = new GasFlowCounter(nameof(H2)); + Ar = new GasFlowCounter(nameof(Ar)); + PN2 = new GasFlowCounter(nameof(PN2)); + HCL = new GasFlowCounter(nameof(HCL)); + SiH4 = new GasFlowCounter(nameof(SiH4)); + CxHx = new GasFlowCounter(nameof(CxHx)); + TCS = new GasFlowCounter(nameof(TCS)); + TMA = new GasFlowCounter(nameof(TMA)); + } + + public PmGasFlowCountInfo(string waferId) : this() + { + WaferId = waferId; + } + + #endregion + + #region Properties + + public int Index { get; set; } + + public string WaferId { get; } + + public string RecipeName { get; } + + public Guid StatisticsUid { get; } + + public DateTime StatisticsStart + { + get => _statStart; + set => Set(ref _statStart, value); + } + + public DateTime? StatisticsEnd + { + get => _statEnd; + set => Set(ref _statEnd, value); + } + + public GasFlowCounter H2 { get; } + + public GasFlowCounter Ar { get; } + + public GasFlowCounter PN2 { get; } + + public GasFlowCounter HCL { get; } + + public GasFlowCounter SiH4 { get; } + + public GasFlowCounter CxHx { get; } + + public GasFlowCounter TCS { get; } + + public GasFlowCounter TMA { get; } + + #endregion + } + + public class PMProcessGasFlowCounterViewModel : UiViewModelBase + { + #region Variables + + private const int MAX_ROWS = 10; + + private readonly object _syncObject = new object(); + + private readonly PMProcessViewModel _pmProcessVm; + private string _previousStatus; + + +#if FAKE_DATA + + private readonly Random _randomFlow; + +#endif + + #endregion + + #region Constructors + + public PMProcessGasFlowCounterViewModel(PMProcessViewModel vm) + { + _previousStatus = "Init"; + _pmProcessVm = vm; + _pmProcessVm.PropertyChanged += VmOnPropertyChanged; + + GasFlowCountCollection = new ObservableQueue(MAX_ROWS); + GasFlowCountCollection.CollectionChanged += GasFlowCountCollectionOnCollectionChanged; + + // 加载历史记录。 + ReadLastFlowCounts(); + +#if FAKE_DATA + + _randomFlow = new Random(); + + //for (var i = 0; i < 10; i++) + //{ + // var counter = new PmGasFlowCountInfo(); + // counter.H2.AddFlow(_randomFlow.NextDouble()); + // counter.Ar.AddFlow(_randomFlow.NextDouble()); + // counter.PN2.AddFlow(_randomFlow.NextDouble()); + // counter.HCL.AddFlow(_randomFlow.NextDouble()); + // counter.SiH4.AddFlow(_randomFlow.NextDouble()); + // counter.C3H8.AddFlow(_randomFlow.NextDouble()); + // counter.TCS.AddFlow(_randomFlow.NextDouble()); + // counter.TMA.AddFlow(_randomFlow.NextDouble()); + // counter.StatisticsEnd = DateTime.Now; + + // GasFlowCountCollection.Enqueue(counter); + + // CurrentFlowCounter = counter; + //} + + // Add new Flow Counter every 5s + Task.Run(() => + { + while (true) + { + Thread.Sleep(5000); + if (CurrentFlowCounter != null) + { + // 结束当前的统计,随后开启新统计 + CurrentFlowCounter.StatisticsEnd = DateTime.Now; + SaveFlowCount(CurrentFlowCounter); + } + + var counter = new PmGasFlowCountInfo(); + GasFlowCountCollection.Enqueue(counter); + CurrentFlowCounter = counter; + } + }); + +#endif + + } + + #endregion + + #region Properties + + public ObservableQueue GasFlowCountCollection { get; } + + public PmGasFlowCountInfo CurrentFlowCounter { get; private set; } + + public ICollectionView GasFlowDetailList + { + get + { + var view = CollectionViewSource.GetDefaultView(GasFlowCountCollection.ToList()); + view.SortDescriptions.Add(new SortDescription(nameof(PmGasFlowCountInfo.Index), + ListSortDirection.Ascending)); + return view; + } + } + + #endregion + + #region Methods + + private void GasFlowCountCollectionOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + // 列表发生变化时重新排序。 + if (e.Action == NotifyCollectionChangedAction.Add) + { + var i = 1; + GasFlowCountCollection.ToList().OrderByDescending(x => x.StatisticsStart).ToList().ForEach(x => + { + x.Index = i; + i++; + }); + } + } + + + /// + /// 监测Process的Status属性是否变化,以确定Process的开始和结束时机。 + /// + /// + /// + private void VmOnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(PMProcessViewModel.Status)) + { + var currentStatus = _pmProcessVm.Status; + + if (CheckIfProcessStarted(_previousStatus, currentStatus)) + { + // Process启动 + + lock (_syncObject) + { + CurrentFlowCounter = new PmGasFlowCountInfo(); + GasFlowCountCollection.Enqueue(CurrentFlowCounter); + } + + } + else if (CheckIfProcessStopped(_previousStatus, currentStatus)) + { + lock (_syncObject) + { + // Process结束 + if (CurrentFlowCounter != null) + { + CurrentFlowCounter.StatisticsEnd = DateTime.Now; + + // 写数据库 + SaveFlowCount(CurrentFlowCounter); + + } + } + } + + Debug.WriteLineIf(_previousStatus != currentStatus, + $"PM Process Status: {_previousStatus} to {currentStatus}"); + + _previousStatus = currentStatus; + } + } + + private bool CheckIfProcessStarted(string previousStatus, string currentStatus) + { + if (previousStatus == "ProcessIdle" && + currentStatus == "PreProcess") + + return true; + + return false; + } + + private bool CheckIfProcessStopped(string previousStatus, string currentStatus) + { + if ((previousStatus != "ProcessIdle" && + currentStatus == "ProcessIdle") || + (previousStatus != "Error" && + currentStatus == "Error")) + return true; + + return false; + } + + /// + /// 将统计值保存到数据库。 + /// + /// + private void SaveFlowCount(PmGasFlowCountInfo count) + { + try + { + var c = count; + var sql = $"INSERT INTO process_flow_data " + + $"(process_guid, module_name, recipe_name, wafer_guid, process_begin_time, process_end_time, h2, ar, pn2, hcl, sih4, c3h8, tcs, tma) " + + $"VALUES " + + $"('{c.StatisticsUid:D}', '{_pmProcessVm.SystemName}', '{_pmProcessVm.SelectedRecipe}', '{c.WaferId:D}', " + + $"'{c.StatisticsStart:yyyy/MM/dd HH:mm:ss.fff}', '{c.StatisticsEnd:yyyy/MM/dd HH:mm:ss.fff}', " + + $"{c.H2}, {c.Ar}, {c.PN2}, {c.HCL}, {c.SiH4}, {c.CxHx}, {c.TCS}, {c.TMA})"; + + QueryDataClient.Instance.Service.QueryData(sql); + } + catch (Exception ex) + { + LOG.Error($"Unable to save total gas flow to database, {ex.Message}", ex); + } + } + + /// + /// 从数据库加载指定的记录。 + /// + /// + private void ReadLastFlowCounts(int limit = MAX_ROWS) + { + try + { + var sql = + $"SELECT * FROM process_flow_data where module_name = '{_pmProcessVm.SystemName}' " + + $" ORDER BY process_begin_time DESC LIMIT {limit}"; + var dt = QueryDataClient.Instance.Service.QueryData(sql); + if (dt != null && dt.Rows.Count > 0) + { + for (var i = 0; i < dt.Rows.Count; i++) + { + try + { + var row = dt.Rows[i]; + var uid = Guid.Parse(row["process_guid"].ToString()); + var recipeName = row["recipe_name"].ToString(); + var waferUid = row["wafer_guid"].ToString(); + var beginTime = DateTime.Parse(row["process_begin_time"].ToString()); + var endTime = DateTime.Parse(row["process_end_time"].ToString()); + var h2 = double.Parse(row["h2"].ToString()); + var ar = double.Parse(row["ar"].ToString()); + var pn2 = double.Parse(row["pn2"].ToString()); + var hcl = double.Parse(row["hcl"].ToString()); + var sih4 = double.Parse(row["sih4"].ToString()); + var cxhx = double.Parse(row["c3h8"].ToString()); + var tcs = double.Parse(row["tcs"].ToString()); + var tma = double.Parse(row["tma"].ToString()); + var counter = new PmGasFlowCountInfo(i + 1, uid, recipeName, waferUid, beginTime, endTime, h2, ar, pn2, + hcl, + sih4, cxhx, tcs, tma); + + GasFlowCountCollection.Enqueue(counter); + } + catch (Exception ex) + { + LOG.Error($"Unable to load process flow count history at row {i}, {ex.Message}", ex); + } + } + + } + } + catch (Exception ex) + { + LOG.Error($"Unable to load process flow count history, {ex.Message}", ex); + } + } + + protected override void Poll() + { + base.Poll(); + + lock (_syncObject) + { + if (CurrentFlowCounter != null && CurrentFlowCounter.StatisticsEnd.HasValue == false) + { +#if FAKE_DATA + CurrentFlowCounter.H2.AddFlow(_randomFlow.NextDouble()); + CurrentFlowCounter.Ar.AddFlow(_randomFlow.NextDouble()); + CurrentFlowCounter.PN2.AddFlow(_randomFlow.NextDouble()); + CurrentFlowCounter.HCL.AddFlow(_randomFlow.NextDouble()); + CurrentFlowCounter.SiH4.AddFlow(_randomFlow.NextDouble()); + CurrentFlowCounter.CxHx.AddFlow(_randomFlow.NextDouble()); + CurrentFlowCounter.TCS.AddFlow(_randomFlow.NextDouble()); + CurrentFlowCounter.TMA.AddFlow(_randomFlow.NextDouble()); +#else + + CurrentFlowCounter.H2.AddFlow(_pmProcessVm.H2Flow); + CurrentFlowCounter.Ar.AddFlow(_pmProcessVm.ArFlow); + CurrentFlowCounter.PN2.AddFlow(_pmProcessVm.PN2Flow); + CurrentFlowCounter.HCL.AddFlow(_pmProcessVm.HCLFlow); + CurrentFlowCounter.SiH4.AddFlow(_pmProcessVm.SiH4Flow); + CurrentFlowCounter.CxHx.AddFlow(_pmProcessVm.C2H4Flow); + CurrentFlowCounter.TCS.AddFlow(_pmProcessVm.TCSFlow); + CurrentFlowCounter.TMA.AddFlow(_pmProcessVm.TMAFlow); + +#endif + } + } + } + + #endregion + } +} diff --git a/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml new file mode 100644 index 0000000..ce381d4 --- /dev/null +++ b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml @@ -0,0 +1,2214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml.cs b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml.cs new file mode 100644 index 0000000..52be8bd --- /dev/null +++ b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessView.xaml.cs @@ -0,0 +1,21 @@ +using System.Windows; +using System.Windows.Controls; + +namespace MECF.Framework.UI.Client.CenterViews.Modules.PM +{ + /// + /// PMProcessView.xaml 的交互逻辑 + /// + public partial class PMProcessView : UserControl + { + public PMProcessView() + { + InitializeComponent(); + } + + private void BtnLockRecipe_OnClick(object sender, RoutedEventArgs e) + { + recipeLocker.Lock(); + } + } +} diff --git a/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessViewModel.cs b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessViewModel.cs new file mode 100644 index 0000000..6f7697a --- /dev/null +++ b/MECF.Framework.UI.Client/CenterViews/Modules/PM/PMProcessViewModel.cs @@ -0,0 +1,1719 @@ +using System.Collections.Generic; +using Aitex.Core.Common.DeviceData; +using Aitex.Core.Util; +using Caliburn.Micro; +using MECF.Framework.Common.OperationCenter; +using System; +using MECF.Framework.Common.DataCenter; +using MECF.Framework.UI.Client.CenterViews.Editors.Recipe; +using MECF.Framework.UI.Client.ClientBase; +using System.Windows; +using System.Windows.Controls; +using Caliburn.Micro.Core; +using System.Windows.Media; +using System.Windows.Threading; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using OpenSEMI.ClientBase; +using Sicentury.Core; +using MECF.Framework.UI.Client.CenterViews.Editors; +using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension.CustomColumn; +using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel; +using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params; +using Action = System.Action; +using Newtonsoft.Json; +using System.Dynamic; +using Aitex.Core.RT.Device.PmDevices; +using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MfcCalculation; +using SicUI.Models.PMs; + +namespace MECF.Framework.UI.Client.CenterViews.Modules.PM +{ + public class PMProcessViewModel : SicModuleUIViewModelBase, ISupportMultipleSystem + { + private double _tmaFlowRatio = 1; + private double _tcsFlowRatio = 1; + private double _hclFlowRatio = 1; + private double _C2H4FlowRatio = 1; + private double _sih4FlowRatio = 1; + private double _pn2FlowRatio = 1; + + + private bool _isHideRecipeValue = false; + private bool _allowSaveRecipe = false; + private bool _allowRipRecipe = false; + + private readonly IRecipeGasFlowCalculator _recipeGasFlowCalculator; + private string _currectProcessingRecipe; + private IProgress _progressRecipeStepChanged; + private IProgress _progressLoadRecipe; + private readonly object _lockerLoadingRecipe = new object(); + + + public string title { get; set; } = "123"; + public PMProcessGasFlowCounterViewModel GasFlowCounterVm { get; private set; } + + public PMProcessViewModel() + { + _recipeGasFlowCalculator = IoC.Get(); + } + + #region properties + + public bool IsPermission { get => this.Permission == 3; } + + public bool AllowSaveRecipe + { + get => _allowSaveRecipe; + set + { + _allowSaveRecipe = value; + NotifyOfPropertyChange(); + } + } + + public bool AllowRipRecipe + { + get => _allowRipRecipe; + set + { + _allowRipRecipe = value; + NotifyOfPropertyChange(); + } + } + + [Subscription("IsBusy")] + public bool IsBusy { get; set; } + + [Subscription("Status")] + public string Status { get; set; } + + public bool IsPMProcess => Status == "Process" || Status == "PostProcess" || Status == "Paused" || Status == "PMMacroPause" || Status == "PMMacro" || Status == "PostPMMacro"; + + public bool IsPreProcess => Status == "PreProcess" || Status == "PrePMMacro"; + + [Subscription("IsOnline")] + public bool IsOnline { get; set; } + + [Subscription("Recipe.DeviceData")] + public AITDeviceData Recipe { get; set; } + public float[] RecipeData1 => RecipeData; + public float[] RecipeData = new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + + private string selectedRecipe; + public string SelectedRecipe + { + set + { + selectedRecipe = value; + } + get + { + return selectedRecipe; + } + } + + + [Subscription("SelectedRecipeName")] + public string CurrentProcessingRecipeName + { + get => _currectProcessingRecipe; + set + { + if (_currectProcessingRecipe != value) + { + _currectProcessingRecipe = value; + DisplayingRecipeName = value; + } + } + } + + [Subscription("RecipeStepName")] + public string RecipeStepName { get; set; } + + [Subscription("RecipeStepNumber")] + public int RecipeStepNumber { get; set; } + + [Subscription("ArH2Switch")] + public string ArH2Switch { get; set; } + + [Subscription("N2FlowMode")] + public string N2FlowMode { get; set; } + + [Subscription("RecipeStepElapseTime")] + public int RecipeStepElapseTime { get; set; } + + [Subscription("RecipeStepTime")] + public int RecipeStepTime { get; set; } + + [Subscription("RecipeStepElapseTime2")] + public int RecipeStepElapseTime2 { get; set; } + + [Subscription("RecipeTotalElapseTime")] + public int RecipeTotalElapseTime { get; set; } + + [Subscription("RecipeTotalTime")] + public int RecipeTotalTime { get; set; } + + [Subscription("RecipeTotalElapseTime2")] + public int RecipeTotalElapseTime2 { get; set; } + + public string StepNumber + { + get + { + if (IsPMProcess) + { + return $"{RecipeStepNumber}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + + } + set + { + + } + } + + public string StepName + { + get + { + if (IsPMProcess) + { + return $"{RecipeStepName}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + } + } + + public string StepTime + { + get + { + if (IsPMProcess) + { + return $"{RecipeStepElapseTime}/{RecipeStepTime}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + + } + } + + public string RecipeTime + { + get + { + if (IsPMProcess) + { + return $"{RecipeTotalElapseTime}/{RecipeTotalTime}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + } + } + + private string _displayingRecipeName; + public string DisplayingRecipeName + { + get => _displayingRecipeName; + private set + { + if (_displayingRecipeName != value) + { + _displayingRecipeName = value; + _progressLoadRecipe.Report(value); + NotifyOfPropertyChange(); + } + } + } + + private bool _isRecipeLoading; + + public bool IsRecipeLoading + { + get => _isRecipeLoading; + set + { + if (_isRecipeLoading != value) + { + _isRecipeLoading = value; + NotifyOfPropertyChange(); + } + } + + } + + //qbh 20220523 + private int x = 0; + private DispatcherTimer timer; + + + + + // + public RecipeData CurrentRecipe { get; set; } = new RecipeData(null); + public List Columns { get; set; } = new List(); + + private RecipeFormatBuilder _columnBuilder = new RecipeFormatBuilder(); + + public bool IsSelectButtonEnable => !string.IsNullOrEmpty(Status) && !Status.Equals("Process") + && !Status.Equals("PreProcess") && !Status.Equals("PostProcess") && !Status.Equals("Paused") && !IsOnline && !IsRecipeLoading; + public bool IsStartButtonEnable => !string.IsNullOrEmpty(SelectedRecipe) && !string.IsNullOrEmpty(Status) + && !Status.Equals("Process") && !Status.Equals("PreProcess") && !Status.Equals("PostProcess") && + !Status.Equals("PrePMMacro") && !Status.Equals("PMMacro") && !Status.Equals("PostPMMacro") && + !Status.Equals("Paused") && !IsOnline;// !IsProcessRunning; + public bool IsStopButtonEnable => !string.IsNullOrEmpty(Status) && (Status.Equals("Process") || Status.Equals("PMMacro")) && !IsOnline; + public bool IsAbortButtonEnable => !string.IsNullOrEmpty(Status) && (Status.Equals("Process") || Status.Equals("PMMacro")) && !IsOnline; //|| Status.Equals("PreProcess") || Status.Equals("PostProcess") || Status.Equals("Paused"));//IsProcessRunning; + public bool IsPauseButtonEnable => !string.IsNullOrEmpty(Status) && (Status.Equals("Process") || Status.Equals("PMMacro")) && !IsOnline; + public bool IsSkipButtonEnable => !string.IsNullOrEmpty(Status) && Status.Equals("Process") && !IsOnline; + public bool IsContinueButtonEnable => !string.IsNullOrEmpty(Status) && (Status.Equals("Paused") || Status.Equals("PMMacroPause")) && !IsOnline; + + public WaferInfo MLLWafer + { + get + { + if (ModuleManager.ModuleInfos["LLH"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["LLH"].WaferManager.Wafers[0]; + return null; + } + } + + public bool MLLHasWafer + { + get + { + return MLLWafer.WaferStatus > 0; + } + } + + public WaferInfo PMWafer + { + get + { + if (ModuleManager.ModuleInfos[SystemName].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos[SystemName].WaferManager.Wafers[0]; + return null; + } + } + + public bool PMHasWafer => PMWafer.WaferStatus > 0; + + public Dictionary DicGas { get; set; } + + public int MLLCurrentWafer { get; set; } + public int MLLTotalWafer { get; set; } + + // public bool IsEnableGasMap => !IsBusy && IsMaintainMode; + + //public string SystemName { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public object View { get; set; } + + public string CurrentProcessType { get; set; } + + private bool needLoadRecipe = false; + + #endregion + + /// + /// 获取角色权限配置. + /// + /// + private void LoadRolePermissions() + { + var roleID = BaseApp.Instance.UserContext.RoleID; + _isHideRecipeValue = RoleAccountProvider.Instance.GetMenuPermission(roleID, "Recipe.Behaviour.ShowValueInProcessView") == (int)MenuPermissionEnum.MP_NONE; + AllowSaveRecipe = RoleAccountProvider.Instance.GetMenuPermission(roleID, "Recipe.Behaviour.AllowSaveInProcessView") != (int)MenuPermissionEnum.MP_NONE; + AllowRipRecipe = RoleAccountProvider.Instance.GetMenuPermission(roleID, "Recipe.Behaviour.AllowRipInProcessView") != (int)MenuPermissionEnum.MP_NONE; + + } + + protected override void OnActivate() + { + try + { + LoadRolePermissions(); + + if (string.IsNullOrEmpty(DisplayingRecipeName)) + { + needLoadRecipe = false; + var recipeName = + (string)QueryDataClient.Instance.Service.GetConfig($"PM.{SystemName}.LastRecipeName"); + DisplayingRecipeName = recipeName; + + } + + // 更新Recipe参数值显示状态 + SetRecipeValueVisibilityByCurrentRole(); + + ((PMProcessView)View)?.recipeLocker.Lock(); + + //流量需要乘以此系数 + //_tmaFlowRatio = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SystemName}.TMAFlowRatio"); + //_tcsFlowRatio = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SystemName}.TCSFlowRatio"); + //_hclFlowRatio = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SystemName}.HCLFlowRatio"); + //_C2H4FlowRatio = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SystemName}.C2H4FlowRatio"); + //_sih4FlowRatio = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SystemName}.SiH4FlowRatio"); + //_pn2FlowRatio = (double)QueryDataClient.Instance.Service.GetConfig($"PM.{SystemName}.PN2FlowRatio"); + base.OnActivate(); + } + catch (Exception ex) + { } + } + + protected override void OnDeactivate(bool close) + { + ActiveUpdateData = true; + base.OnDeactivate(close); + } + + protected override void OnInitialize() + { + base.OnInitialize(); + + //权限 + var roleID = BaseApp.Instance.UserContext.RoleID; + stepsVisibility = RoleAccountProvider.Instance.GetMenuPermission(roleID, "PM1.Process.Steps") == 3; + _progressLoadRecipe = new Progress(ProgLoadRecipeOnUiThread); + _progressRecipeStepChanged = new Progress(RecipeStepInProcessChanged); + + UpdateRecipeFormat(); + + GasFlowCounterVm = new PMProcessGasFlowCounterViewModel(this); + GasFlowCounterVm.EnableTimer(true); + + } + + + private bool stepsVisibility; + + public bool StepsVisibility + { + get { return stepsVisibility; } + } + + protected override void Poll() + { + try + { + base.Poll(); + } + catch (Exception ex) + { + + } + } + + protected override void InvokeAfterUpdateProperty(Dictionary data) + { + try + { + if (needLoadRecipe) + { + needLoadRecipe = false; + } + + base.InvokeAfterUpdateProperty(data); + } + catch (Exception ex) + { + + } + } + + + public void ParamsExpanded(ExpanderColumn col) + { + int index = this.Columns.IndexOf(col); + for (var i = index + 1; i < this.Columns.Count; i++) + { + if (this.Columns[i] is ExpanderColumn) + break; + this.Columns[i].Visibility = Visibility.Visible; + } + } + + public void ParamsCollapsed(ExpanderColumn col) + { + int index = this.Columns.IndexOf(col); + for (var i = index + 1; i < this.Columns.Count; i++) + { + if (this.Columns[i] is ExpanderColumn) + break; + this.Columns[i].Visibility = Visibility.Collapsed; + } + } + + protected override void OnViewLoaded(object view) + { + View = view; + base.OnViewLoaded(view); + + ViewWin = (PMProcessView)view; + StartDateTime = DateTime.Now.Date; + EndDateTime = DateTime.Now.Date.AddDays(1).AddTicks(-1); + + string str = "[{\"Name\":\"Ar\",\"RunVolume\":5.8561316539732289,\"VentVolume\":0.078784436017824339},{\"Name\":\"H2\",\"RunVolume\":0.0,\"VentVolume\":0.0},{\"Name\":\"C2H4\",\"RunVolume\":0.0,\"VentVolume\":0.0},{\"Name\":\"SiH4\",\"RunVolume\":0.0,\"VentVolume\":0.0},{\"Name\":\"HCL\",\"RunVolume\":0.0,\"VentVolume\":0.0},{\"Name\":\"PN2\",\"RunVolume\":0.0,\"VentVolume\":0.0},{\"Name\":\"TCS\",\"RunVolume\":0.0,\"VentVolume\":0.0},{\"Name\":\"TMA\",\"RunVolume\":0.0,\"VentVolume\":0.0}]"; + var o= JsonConvert.DeserializeObject>(str); + } + + + public void SelectRecipe() + { + var dialog = new RecipeSelectDialogViewModel(false, false, ProcessTypeFileItem.ProcessFileTypes.Process); + dialog.DisplayName = "Select Recipe"; + + var wm = new WindowManager(); + var bret = wm.ShowDialog(dialog); + + if ((bool)bret) + { + var recipeName = dialog.DialogResult; + + if (recipeName.StartsWith("Sic\\Process")) + { + CurrentProcessType = "Process"; + } + else if (recipeName.StartsWith("Sic\\Routine")) + { + CurrentProcessType = "Routine"; + } + + DisplayingRecipeName = recipeName; + + SelectedRecipe = recipeName; + + InvokeClient.Instance.Service.DoOperation($"{SystemName}.SelectRecipe", recipeName); + InvokeClient.Instance.Service.DoOperation("System.SetConfig", $"PM.{SystemName}.LastRecipeName", + recipeName); + } + + } + + public void DeleteProcessData() + { + + } + + private static void RenderStepsWithSameValue(IReadOnlyList previousStep, IReadOnlyList currentStep) + { + for (var i = 0; i < currentStep.Count; i++) + { + if (currentStep[i] is DoubleParam currDblParam && previousStep[i] is DoubleParam prevDblParam) + { + currDblParam.IsEqualsToPrevious = + GlobalDefs.IsDoubleValueEquals(currDblParam.Value, prevDblParam.Value); + } + + else if (currentStep[i] is ComboxParam currCbxParam && previousStep[i] is ComboxParam prevCbxParam) + { + if (currCbxParam.Value != prevCbxParam.Value) + { + currCbxParam.IsEqualsToPrevious = false; + } + else + { + currCbxParam.IsEqualsToPrevious = true; + } + } + + } + } + + /// + /// 将发生变更的配方推送到当前工艺。 + /// + public void PushRecipeToCurrentProcess() + { + // 如果配方没变,不需要推送 + if (!CurrentRecipe.IsChanged) + { + DialogBox.ShowWarning("The recipe does not change."); + return; + } + + if (!CurrentRecipe.Validate()) + { + var ret = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.WARNING, + $"{CurrentRecipe.ValidationErrorSummary}\r\n Are you sure to push changes to current process?"); + if (ret == DialogButton.No) + return; + /*var mbr = MessageBox.Show($"{errors}\r\n Are you sure to push changes to current process", "Warning", + MessageBoxButton.YesNo, MessageBoxImage.Warning); + if (mbr == MessageBoxResult.No) + return;*/ + } + + var xmlRecipe = CurrentRecipe.GetXmlString(); + InvokeClient.Instance.Service.DoOperation($"PM1.ReloadRecipe", xmlRecipe); + //InvokeClient.Instance.Service.DoOperation($"PM2.ReloadRecipe"); + } + + + public void SaveToBaselineRecipe() + { + if (string.IsNullOrEmpty(CurrentRecipe.Name)) + { + DialogBox.ShowError("Recipe name can't be empty"); + return; + } + + // 如果配方没变,不需要推送 + if (!CurrentRecipe.IsChanged) + { + DialogBox.ShowInfo("The recipe does not change."); + return; + } + + if (!CurrentRecipe.Validate()) + { + var ret = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.WARNING, + $"{CurrentRecipe.ValidationErrorSummary}\r\n Are you sure to save to baseline recipe?"); + if (ret == DialogButton.No) + return; + } + + var result = false; + + + CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName; + CurrentRecipe.ReviseTime = DateTime.Now; + + var recipeProvider = new RecipeProvider(); + result = recipeProvider.WriteRecipeFile(CurrentRecipe.PrefixPath, CurrentRecipe.Name, CurrentRecipe.GetXmlString()); + + if (result) + { + CurrentRecipe.MarkAsSaved(); + } + else + { + MessageBox.Show("Save failed!"); + } + } + + /// + /// 重新加载配方,当前修改的参数被抛弃。 + /// + public void RestoreToBaselineRecipe() + { + // 如果改变,提示 + if (CurrentRecipe.IsChanged) + { + if (DialogBox.Confirm( + "The recipe has changed, are you sure to discard changes and reload baseline recipe?") == false) + return; + } + + if (CurrentRecipe != null + && !string.IsNullOrEmpty(CurrentRecipe.FullName)) + _progressLoadRecipe.Report(CurrentRecipe.FullName); + } + + /// + /// 根据配置获取Cascade方式呈现Recipe的Dispatcher,或返回null。 + /// + /// + private static Dispatcher GetLoadingDispatcher() + { + // 判断Step呈现方式 + var isCascadeLoading = (bool)QueryDataClient.Instance.Service.GetConfig("System.RecipeCascadeLoading"); + var dispatcher = isCascadeLoading ? Application.Current?.Dispatcher : null; + if (dispatcher == null || !dispatcher.CheckAccess()) + return null; + + return dispatcher; + } + + + #region Recipe相关控制函数 + + public void UpdateRecipeFormat() + { + CurrentRecipe = new RecipeData(_recipeGasFlowCalculator); + CurrentRecipe.BuildFormat($"Sic\\Process", "PM1", BaseApp.Instance.UserContext.RoleName); + } + + /// + /// 根据权限设置Recipe参数的可见性。 + /// + private void SetRecipeValueVisibilityByCurrentRole() + { + // 是否在编辑器中隐藏Recipe参数值 + // CurrentRecipe.Steps.IsHideValue = _isHideRecipeValue; // 当权限为None时隐藏,其它时显示。 + + // 白名单的Param显示出来 + ApplyRecipeCellAccessPermissionWhitelist(); + } + + /// + /// 从数据库读取单元格访问白名单。 + /// + /// + private DataTable ReadRecipeCellAccessPermissionWhitelist() + { + if (CurrentRecipe == null) + return null; + + var cmd = $"select * from recipe_cell_access_permission_whitelist where \"recipeName\" = '{CurrentRecipe.FullName}'"; + var dt = QueryDataClient.Instance.Service.QueryData(cmd); + return dt; + } + + /// + /// 如果Recipe参数设置为隐藏,将白名单中的单元格显示出来。 + /// + private void ApplyRecipeCellAccessPermissionWhitelist() + { + /*var dt = ReadRecipeCellAccessPermissionWhitelist(); + + if (dt != null && dt.Rows.Count > 0) + { + foreach (DataRow dataRow in dt.Rows) + { + var stepUid = dataRow["stepUid"].ToString(); + var controlName = dataRow["columnName"].ToString(); + + var step = CurrentRecipe.Steps.FirstOrDefault(s => s.StepUid == stepUid); + var param = step?.FirstOrDefault(p => p.Name == controlName); + if (param != null) + param.IsHideValue = false; + } + }*/ + } + + + /// + /// 正在工艺中的Recipe Step发生改变。 + /// + /// + private void RecipeStepInProcessChanged(int currentStepNum) + { + UpdateRecipeStepProcessedStatus(currentStepNum); + } + + /// + /// 更新Recipe步骤。 + /// + /// + private void UpdateRecipeStepProcessedStatus(int currentStepNum) + { + if (CurrentRecipe == null) + return; + + if (CurrentRecipe.Steps.Count <= 0) + return; + + // Recipe不是当前正在运行的Recipe。 + if (CurrentRecipe.FullName != DisplayingRecipeName) + return; + + foreach (var step in CurrentRecipe.Steps) + { + if (step.StepNo.HasValue) + { + if (step.StepNo < currentStepNum) + step.IsProcessed = true; + else if (step.StepNo == currentStepNum) + { + if (IsPMProcess) + step.IsProcessed = false; + else + step.IsProcessed = true; + } + else + { + step.IsProcessed = false; + } + } + + } + + + // 自动滚到当前做工艺的Step + var dg = ((PMProcessView)View)?.dgCustom; + if (currentStepNum > 0) + { + var stepScrollTo = currentStepNum - 1; + if (stepScrollTo < 0) + stepScrollTo = 0; + + dg?.ScrollToRecipeStep(CurrentRecipe.Steps[stepScrollTo]); + + } + } + + /// + /// 在UI线程加载Recipe + /// + /// + private void ProgLoadRecipeOnUiThread(string recipeName) + { + lock (_lockerLoadingRecipe) + { + if (IsRecipeLoading) + return; + + IsRecipeLoading = true; + NotifyOfPropertyChange(nameof(IsSelectButtonEnable)); + } + + if (recipeName.StartsWith("Sic\\Process")) + { + CurrentProcessType = "Process"; + } + else if (recipeName.StartsWith("Sic\\Routine")) + { + CurrentProcessType = "Routine"; + } + + + //UpdateRecipeFormat(); + LoadRecipe(recipeName).ContinueWith(t => + { + if (!t.IsCanceled && !t.IsFaulted && t.IsCompleted) + { + Application.Current?.Dispatcher.Invoke(() => + { + UpdateRecipeStepProcessedStatus(RecipeStepNumber); + }); + } + }).ContinueWith(t => + { + Application.Current?.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => + { + lock (_lockerLoadingRecipe) + { + IsRecipeLoading = false; + } + })); + }); + + } + + + #endregion + + private async Task LoadRecipe(string selectedRecipePath) + { + CurrentRecipe.Clear(); + + var array = selectedRecipePath.Split(new char[] { '\\' }); + + string recipeName = array[array.Length - 1]; + string prefixPath = selectedRecipePath.Replace(recipeName, "").TrimEnd('\\'); + + var _recipeProvider = new RecipeProvider(); + var recipeContent = _recipeProvider.ReadRecipeFile(prefixPath, recipeName); + + if (string.IsNullOrEmpty(recipeContent)) + { + MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid."); + return; + } + + CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType; + CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion; + + await CurrentRecipe.LoadFile(prefixPath, recipeName, recipeContent, + SystemName, GetLoadingDispatcher()); + + // 显示Cell访问白名单中的参数 + SetRecipeValueVisibilityByCurrentRole(); + } + + public void Start() + { + var ret = DialogBox.ShowWarning("Please Check All Gas Ready Before Start Process!\r\n\r\nAre you sure to start process?"); + if (ret == DialogButton.No) + return; + + var array = DisplayingRecipeName.Split(new char[] { '\\' }); + if (array[1] == "Process") + { + InvokeClient.Instance.Service.DoOperation($"{SystemName}.RunRecipe", DisplayingRecipeName, false, true); + } + else if (array[1] == "Routine") + { + InvokeClient.Instance.Service.DoOperation($"{SystemName}.RunPMMacro", DisplayingRecipeName); + } + } + + public void Skip() + { + InvokeClient.Instance.Service.DoOperation($"{SystemName}.RecipeSkipStep"); + } + + public void Stop() + { + InvokeClient.Instance.Service.DoOperation($"{SystemName}.Abort"); + } + + public void Pause() + { + InvokeClient.Instance.Service.DoOperation($"{SystemName}.Pause"); + } + + public void Continue() + { + InvokeClient.Instance.Service.DoOperation($"{SystemName}.Continue", "Step continue"); + } + + public void Abort() + { + InvokeClient.Instance.Service.DoOperation($"{SystemName}.Abort"); + } + + #region 腔体绑定数据 + [Subscription("TC1.L1InputTempSetPoint")] + public float L1InputTemp { get; set; } + + [Subscription("TC1.L2InputTempSetPoint")] + public float L2InputTemp { get; set; } + + [Subscription("TC1.L3InputTempSetPoint")] + public float L3InputTemp { get; set; } + + [Subscription("TC2.L3InputTempSetPoint")] + public float SCRL3InputTemp { get; set; } + + + [Subscription("TC1.L1TargetSPSetPoint")] + public float L1TargetSP { get; set; } + + [Subscription("TC1.L2TargetSPSetPoint")] + public float L2TargetSP { get; set; } + + [Subscription("TC1.L3TargetSPSetPoint")] + public float L3TargetSP { get; set; } + + [Subscription("TC2.L3TargetSPSetPoint")] + public float SCRL3TargetSP { get; set; } + + [Subscription("TC1.TempCtrlTCIN")] + public float PM1Temprature { get; set; } + + //底部温度 + [Subscription("TC1.TempCtrlTCIN")] + public float TC1Temp2 { get; set; } + + [Subscription("TC1.HeaterModeSetPoint")] + public float TC1HeaterMode { get; set; } + public string TC1Mode + { + get + { + int mode = (int)TC1HeaterMode; + return Enum.GetName(typeof(DicMode.HeaterControlMode), mode); + } + } + + [Subscription("TC2.HeaterModeSetPoint")] + public float TC2HeaterMode { get; set; } + public string TC2Mode + { + get + { + switch (TC2HeaterMode) + { + case 0: return "Power"; + case 1: return "TC"; + case 2: return "Pyro"; + } + return "Power"; + + } + } + + + [Subscription("SCR1.PowerFeedBack")] + public float SCR1Power { get; set; } + + [Subscription("SCR2.PowerFeedBack")] + public float SCR2Power { get; set; } + + [Subscription("SCR3.PowerFeedBack")] + public float SCR3Power { get; set; } + + [Subscription("PSU1.OutputPowerFeedBack")] + public float PSU1Power { get; set; } + + [Subscription("PSU2.OutputPowerFeedBack")] + public float PSU2Power { get; set; } + + [Subscription("PSU3.OutputPowerFeedBack")] + public float PSU3Power { get; set; } + + + [Subscription("PMServo.ActualSpeedFeedback")] + public float ActualSpeedFeedback { get; set; } + + [Subscription("PT1.FeedBack")] + public float PT1Pressure { get; set; } + #endregion 腔体绑定数据 + + #region MFC + [Subscription("Mfc1.DeviceData")] + public AITMfcData Mfc1Data { get; set; } + + [Subscription("Mfc2.DeviceData")] + public AITMfcData Mfc2Data { get; set; } + + [Subscription("Mfc3.DeviceData")] + public AITMfcData Mfc3Data { get; set; } + + [Subscription("Mfc4.DeviceData")] + public AITMfcData Mfc4Data { get; set; } + + [Subscription("Mfc5.DeviceData")] + public AITMfcData Mfc5Data { get; set; } + + [Subscription("Mfc6.DeviceData")] + public AITMfcData Mfc6Data { get; set; } + + [Subscription("Mfc7.DeviceData")] + public AITMfcData Mfc7Data { get; set; } + + [Subscription("Mfc8.DeviceData")] + public AITMfcData Mfc8Data { get; set; } + + [Subscription("Mfc9.DeviceData")] + public AITMfcData Mfc9Data { get; set; } + + [Subscription("Mfc10.DeviceData")] + public AITMfcData Mfc10Data { get; set; } + + [Subscription("Mfc11.DeviceData")] + public AITMfcData Mfc11Data { get; set; } + + [Subscription("Mfc12.DeviceData")] + public AITMfcData Mfc12Data { get; set; } + + [Subscription("Mfc13.DeviceData")] + public AITMfcData Mfc13Data { get; set; } + + [Subscription("Mfc14.DeviceData")] + public AITMfcData Mfc14Data { get; set; } + + [Subscription("Mfc15.DeviceData")] + public AITMfcData Mfc15Data { get; set; } + + [Subscription("Mfc16.DeviceData")] + public AITMfcData Mfc16Data { get; set; } + + + + [Subscription("Mfc19.DeviceData")] + public AITMfcData Mfc19Data { get; set; } + + [Subscription("Mfc20.DeviceData")] + public AITMfcData Mfc20Data { get; set; } + + + + [Subscription("Mfc22.DeviceData")] + public AITMfcData Mfc22Data { get; set; } + + [Subscription("Mfc23.DeviceData")] + public AITMfcData Mfc23Data { get; set; } + + + + [Subscription("Mfc25.DeviceData")] + public AITMfcData Mfc25Data { get; set; } + + [Subscription("Mfc26.DeviceData")] + public AITMfcData Mfc26Data { get; set; } + + [Subscription("Mfc27.DeviceData")] + public AITMfcData Mfc27Data { get; set; } + + [Subscription("Mfc28.DeviceData")] + public AITMfcData Mfc28Data { get; set; } + + [Subscription("Mfc29.DeviceData")] + public AITMfcData Mfc29Data { get; set; } + + + [Subscription("Mfc30.DeviceData")] + public AITMfcData Mfc30Data { get; set; } + + [Subscription("Mfc31.DeviceData")] + public AITMfcData Mfc31Data { get; set; } + + + + [Subscription("Mfc32.DeviceData")] + public AITMfcData Mfc32Data { get; set; } + + [Subscription("Mfc33.DeviceData")] + public AITMfcData Mfc33Data { get; set; } + + + + [Subscription("Mfc35.DeviceData")] + public AITMfcData Mfc35Data { get; set; } + + [Subscription("Mfc36.DeviceData")] + public AITMfcData Mfc36Data { get; set; } + + [Subscription("Mfc37.DeviceData")] + public AITMfcData Mfc37Data { get; set; } + + [Subscription("Mfc38.DeviceData")] + public AITMfcData Mfc38Data { get; set; } + + [Subscription("Mfc40.DeviceData")] + public AITMfcData Mfc40Data { get; set; } + #endregion + + #region Valve + + [Subscription("V27.DeviceData")] + public AITValveData V27 { get; set; } + + [Subscription("V25.DeviceData")] + public AITValveData V25 { get; set; } + + [Subscription("V31.DeviceData")] + public AITValveData V31 { get; set; } + + [Subscription("V32.DeviceData")] + public AITValveData V32 { get; set; } + + [Subscription("V33.DeviceData")] + public AITValveData V33 { get; set; } + + [Subscription("V33s.DeviceData")] + public AITValveData V33s { get; set; } + + [Subscription("V35.DeviceData")] + public AITValveData V35 { get; set; } + + [Subscription("V36.DeviceData")] + public AITValveData V36 { get; set; } + + [Subscription("V37.DeviceData")] + public AITValveData V37 { get; set; } + + [Subscription("V37s.DeviceData")] + public AITValveData V37s { get; set; } + + + [Subscription("V39.DeviceData")] + public AITValveData V39 { get; set; } + + [Subscription("V39s.DeviceData")] + public AITValveData V39s { get; set; } + + [Subscription("V40.DeviceData")] + public AITValveData V40 { get; set; } + + [Subscription("V40s.DeviceData")] + public AITValveData V40s { get; set; } + + + [Subscription("V41.DeviceData")] + public AITValveData V41 { get; set; } + + [Subscription("V41s.DeviceData")] + public AITValveData V41s { get; set; } + + + [Subscription("V42.DeviceData")] + public AITValveData V42 { get; set; } + + [Subscription("V43.DeviceData")] + public AITValveData V43 { get; set; } + + [Subscription("V43s.DeviceData")] + public AITValveData V43s { get; set; } + + + [Subscription("V45.DeviceData")] + public AITValveData V45 { get; set; } + + + [Subscription("V46.DeviceData")] + public AITValveData V46 { get; set; } + + [Subscription("V46s.DeviceData")] + public AITValveData V46s { get; set; } + + [Subscription("V48.DeviceData")] + public AITValveData V48 { get; set; } + + [Subscription("V48s.DeviceData")] + public AITValveData V48s { get; set; } + + + [Subscription("V49.DeviceData")] + public AITValveData V49 { get; set; } + + [Subscription("V50.DeviceData")] + public AITValveData V50 { get; set; } + + [Subscription("V50s.DeviceData")] + public AITValveData V50s { get; set; } + + [Subscription("V51.DeviceData")] + public AITValveData V51 { get; set; } + + [Subscription("V51s.DeviceData")] + public AITValveData V51s { get; set; } + + + [Subscription("V52.DeviceData")] + public AITValveData V52 { get; set; } + + [Subscription("V52s.DeviceData")] + public AITValveData V52s { get; set; } + + [Subscription("V53.DeviceData")] + public AITValveData V53 { get; set; } + + [Subscription("V53s.DeviceData")] + public AITValveData V53s { get; set; } + + [Subscription("V54.DeviceData")] + public AITValveData V54 { get; set; } + + [Subscription("V54s.DeviceData")] + public AITValveData V54s { get; set; } + + [Subscription("V55.DeviceData")] + public AITValveData V55 { get; set; } + + [Subscription("V56.DeviceData")] + public AITValveData V56 { get; set; } + + [Subscription("V58.DeviceData")] + public AITValveData V58 { get; set; } + + [Subscription("V58s.DeviceData")] + public AITValveData V58s { get; set; } + + + + [Subscription("V59.DeviceData")] + public AITValveData V59 { get; set; } + + [Subscription("V60.DeviceData")] + public AITValveData V60 { get; set; } + + [Subscription("V61.DeviceData")] + public AITValveData V61 { get; set; } + + [Subscription("V62.DeviceData")] + public AITValveData V62 { get; set; } + + [Subscription("V63.DeviceData")] + public AITValveData V63 { get; set; } + + //[Subscription("V64.DeviceData")] + //public AITValveData V64 { get; set; } + + //[Subscription("V65.DeviceData")] + //public AITValveData V65 { get; set; } + + + [Subscription("V68.DeviceData")] + public AITValveData V68 { get; set; } + + [Subscription("V69.DeviceData")] + public AITValveData V69 { get; set; } + + [Subscription("V70.DeviceData")] + public AITValveData V70 { get; set; } + + [Subscription("V72.DeviceData")] + public AITValveData V72 { get; set; } + + [Subscription("V73.DeviceData")] + public AITValveData V73 { get; set; } + + [Subscription("V74.DeviceData")] + public AITValveData V74 { get; set; } + + [Subscription("V75.DeviceData")] + public AITValveData V75 { get; set; } + + [Subscription("V76.DeviceData")] + public AITValveData V76 { get; set; } + + [Subscription("V87.DeviceData")] + public AITValveData V87 { get; set; } + + [Subscription("V88.DeviceData")] + public AITValveData V88 { get; set; } + + [Subscription("V89.DeviceData")] + public AITValveData V89 { get; set; } + + [Subscription("V90.DeviceData")] + public AITValveData V90 { get; set; } + + [Subscription("V91.DeviceData")] + public AITValveData V91 { get; set; } + + [Subscription("V92.DeviceData")] + public AITValveData V92 { get; set; } + + [Subscription("V93.DeviceData")] + public AITValveData V93 { get; set; } + + [Subscription("V94.DeviceData")] + public AITValveData V94 { get; set; } + + [Subscription("V95.DeviceData")] + public AITValveData V95 { get; set; } + + [Subscription("V96.DeviceData")] + public AITValveData V96 { get; set; } + + [Subscription("V97.DeviceData")] + public AITValveData V97 { get; set; } + + [Subscription("EPV1.DeviceData")] + public AITValveData EPV1 { get; set; } + + [Subscription("EPV2.DeviceData")] + public AITValveData EPV2 { get; set; } + + [Subscription("V99.DeviceData")] + public AITValveData V99 { get; set; } + + [Subscription("V99s.DeviceData")] + public AITValveData V99s { get; set; } + + + #endregion + + #region Pressure + [Subscription("Pressure1.DeviceData")] + public AITPressureMeterData PT1Data { get; set; } + + [Subscription("Pressure2.DeviceData")] + public AITPressureMeterData PT2Data { get; set; } + [Subscription("Pressure3.DeviceData")] + public AITPressureMeterData PT3Data { get; set; } + + + [Subscription("Pressure4.DeviceData")] + public AITPressureMeterData PT4Data { get; set; } + [Subscription("Pressure5.DeviceData")] + public AITPressureMeterData PT5Data { get; set; } + [Subscription("Pressure6.DeviceData")] + public AITPressureMeterData PT6Data { get; set; } + + [Subscription("Pressure7.DeviceData")] + public AITPressureMeterData PT7Data { get; set; } + + [Subscription("PT1.DeviceData")] + public AITPressureMeterData ChamPress { get; set; } + + [Subscription("PT2.DeviceData")] + public AITPressureMeterData ForelinePress { get; set; } + + + #endregion + + #region 特气显示颜色 + + public SolidColorBrush PN2Color + { + get + { + if (IsPN2RunMode) + { + return new SolidColorBrush(Color.FromRgb(0, 0, 0)); + } + else + { + return new SolidColorBrush(Color.FromRgb(255, 0, 0)); + } + } + } + public SolidColorBrush C2H4Color + { + get + { + if (IsC2H4RunMode) + { + return new SolidColorBrush(Color.FromRgb(0, 0, 0)); + } + else + { + return new SolidColorBrush(Color.FromRgb(255, 0, 0)); + } + } + } + public SolidColorBrush SIH4Color + { + get + { + if (IsSiH4RunMode) + { + return new SolidColorBrush(Color.FromRgb(0, 0, 0)); + } + else + { + return new SolidColorBrush(Color.FromRgb(255, 0, 0)); + } + } + } + public SolidColorBrush HCLColor + { + get + { + if (IsHCLRunMode) + { + return new SolidColorBrush(Color.FromRgb(0, 0, 0)); + } + else + { + return new SolidColorBrush(Color.FromRgb(255, 0, 0)); + } + } + } + + public SolidColorBrush TMAColor + { + get + { + if (IsTMARunMode) + { + return new SolidColorBrush(Color.FromRgb(0, 0, 0)); + } + else + { + return new SolidColorBrush(Color.FromRgb(255, 0, 0)); + } + } + } + + public SolidColorBrush TCSColor + { + get + { + if (IsTCSRunMode) + { + return new SolidColorBrush(Color.FromRgb(0, 0, 0)); + } + else + { + return new SolidColorBrush(Color.FromRgb(255, 0, 0)); + } + } + } + + public SolidColorBrush PN2FlowColor + { + get + { + if (IsPN2RunMode) + { + return new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)); + } + else + { + return new SolidColorBrush(Color.FromArgb(255, 190, 190, 190)); + } + } + } + public SolidColorBrush C2H4FlowColor + { + get + { + if (IsC2H4RunMode) + { + return new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)); + } + else + { + return new SolidColorBrush(Color.FromArgb(255, 190, 190, 190)); + } + } + } + public SolidColorBrush SIH4FlowColor + { + get + { + if (IsSiH4RunMode) + { + return new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)); + } + else + { + return new SolidColorBrush(Color.FromArgb(255, 190, 190, 190)); + } + } + } + public SolidColorBrush HCLFlowColor + { + get + { + if (IsHCLRunMode) + { + return new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)); + } + else + { + return new SolidColorBrush(Color.FromArgb(255, 190, 190, 190)); + } + } + } + + public SolidColorBrush TMAFlowColor + { + get + { + if (IsTMARunMode) + { + return new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)); + } + else + { + return new SolidColorBrush(Color.FromArgb(255, 190, 190, 190)); + } + } + } + + public SolidColorBrush TCSFlowColor + { + get + { + if (IsTCSRunMode) + { + return new SolidColorBrush(Color.FromArgb(255, 0, 255, 255)); + } + else + { + return new SolidColorBrush(Color.FromArgb(255, 190, 190, 190)); + } + } + } + #endregion + + + + public bool IsPN2RunMode => V37s.IsOpen && (V39.IsOpen || V40.IsOpen);//N2FlowMode == "Run";按照洪膺要求修改 2023年6月9日10:34:54 + public bool IsHCLRunMode => V54.IsOpen; + public bool IsSiH4RunMode => V55.IsOpen && !V56.IsOpen; + public bool IsC2H4RunMode => V59.IsOpen && !V60.IsOpen; + public bool IsTCSRunMode => V53.IsOpen; + public bool IsTMARunMode => V41.IsOpen && !V42.IsOpen; + + + [Subscription("Flow.Ar_Run.FeedBack")] + public double ArFlow_Run { get; set; } + [Subscription("Flow.Ar_Vent.FeedBack")] + public double ArFlow_Vent { get; set; } + + public double ArFlow => ArFlow_Run>0 ? ArFlow_Run : ArFlow_Vent; + public double ArMol => GetMol(ArFlow_Run); + + [Subscription("Flow.H2_Run.FeedBack")] + public double H2_Run { get; set; } + [Subscription("Flow.H2_Vent.FeedBack")] + public double H2_Vent { get; set; } + + public double H2Flow => H2_Run>0 ? H2_Run : H2_Vent; + public double H2Mol => GetMol(H2_Run); + + [Subscription("Flow.PN2_Run.FeedBack")] + public double PN2_Run { get; set; } + [Subscription("Flow.PN2_Vent.FeedBackSpecial")] + public double PN2_Vent { get; set; } + + public double PN2Flow => PN2_Run + PN2_Vent;//=> GetPN2MFCFlow(IsPN2RunMode) * _pn2FlowRatio; + public double PN2Mol => GetMol(PN2Flow); + + [Subscription("Flow.HCL_Run.FeedBack")] + public double HCL_Run { get; set; } + [Subscription("Flow.HCL_Vent.FeedBack")] + public double HCL_Vent { get; set; } + + public double HCLFlow => HCL_Run + HCL_Vent; + public double HCLMol => GetMol(HCLFlow); + + [Subscription("Flow.SiH4_Run.FeedBack")] + public double SiH4_Run { get; set; } + [Subscription("Flow.SiH4_Vent.FeedBack")] + public double SiH4_Vent { get; set; } + + public double SiH4Flow => SiH4_Run + SiH4_Vent; + public double SIH4Mol => GetMol(SiH4Flow); + + [Subscription("Flow.C2H4_Run.FeedBack")] + public double C2H4_Run { get; set; } + [Subscription("Flow.C2H4_Vent.FeedBack")] + public double C2H4_Vent { get; set; } + + public double C2H4Flow => C2H4_Run + C2H4_Vent; + public double C2H4Mol => GetMol(C2H4Flow); + + [Subscription("Flow.TCS_Run.FeedBack")] + public double TCS_Run { get; set; } + [Subscription("Flow.TCS_Vent.FeedBack")] + public double TCS_Vent { get; set; } + + public double TCSFlow => TCS_Run + TCS_Vent; + public double TCSMol => GetMol(TCSFlow); + + [Subscription("Flow.TMA_Run.FeedBack")] + public double TMA_Run { get; set; } + [Subscription("Flow.TMA_Vent.FeedBack")] + public double TMA_Vent { get; set; } + + public double TMAFlow => TMA_Run + TMA_Vent; + public double TMAMol => GetMol(TMAFlow); + + public bool ISPN2Flow => PN2Flow > 0 && IsPN2RunMode; + public bool ISHCLFlow => HCLFlow > 0 && IsHCLRunMode; + public bool ISSiH4Flow => SiH4Flow > 0 && IsSiH4RunMode; + public bool ISC2H4Flow => C2H4Flow > 0 && IsC2H4RunMode; + public bool ISArFlow => ArFlow_Run > 0; + public bool ISH2Flow => H2_Run > 0; + public bool ISTCSFlow => TCSFlow > 0 && IsTCSRunMode; + public bool ISTMAFlow => TMAFlow > 0 && IsTMARunMode; + + private double GetMol(double fedback) + { + return fedback / 1000 / 22.4141; + } + + #region 真值表方式统计流量 + /// + /// 返回ViewModel绑定的视图对象。 + /// + public PMProcessView ViewWin { get; private set; } + + public DateTime StartDateTime + { + get => ViewWin.wfTimeFrom.Value; + set + { + ViewWin.wfTimeFrom.Value = value; + } + } + + public DateTime EndDateTime + { + get => ViewWin.wfTimeTo.Value; + set + { + ViewWin.wfTimeTo.Value = value; + } + } + + private string _mfcManagerDataFlow; + + [Subscription("MfcManager.DataFlow")] + public string MfcManagerDataFlow + { + get => _mfcManagerDataFlow; + set + { + if (_mfcManagerDataFlow != value && value != null) + { + DataFlowList = JsonConvert.DeserializeObject>(value); + } + + _mfcManagerDataFlow = value; + } + } + + public List DataFlowList { get; set; } + + public List FlowNameList { get; set; } = new List() + { + "All", + "Ar", + "H2", + "C2H4", + "SiH4", + "HCL", + "PN2", + "TCS", + "TMA" + }; + public string FlowName { get; set; } + + private string CacheName; + private DateTime CacheStartDateTime; + private DateTime CacheEndDateTime; + + public void Query() + { + if (FlowName is null) + { + MessageBox.Show("查询名称为空"); + return; + } + if (CacheStartDateTime== StartDateTime && CacheEndDateTime == EndDateTime && CacheName == FlowName) + { + MessageBox.Show("重复查询"); + return; + } + if (StartDateTime > EndDateTime) + { + MessageBox.Show("time range invalid, start time should be early than end time.", "Error", + MessageBoxButton.OK, + MessageBoxImage.Error); + return; + } + InvokeClient.Instance.Service.DoOperation($"{SystemName}.FlowName.Query", new object[] { FlowName, StartDateTime, EndDateTime }); + CacheStartDateTime = StartDateTime; + CacheEndDateTime = EndDateTime; + CacheName = FlowName; + } + + #endregion + + /// + /// 打开 ProcessMonitor + /// + public void ShowMonitorWindow() + { + var wins = Application.Current.Windows.OfType().ToArray(); + if (wins.Any()) + { + foreach (var w in wins) + { + if (w.WindowState == WindowState.Minimized) + w.WindowState = WindowState.Normal; + w.Show(); + w.Activate(); + } + } + else + { + var wm = new WindowManager(); + var model = new ProcessMonitorViewModel(); + dynamic settings = new ExpandoObject(); + settings.WindowStartupLocation = WindowStartupLocation.CenterOwner; + wm.ShowWindow(model, null, settings); + } + + } + } +} diff --git a/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml b/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml new file mode 100644 index 0000000..280f17f --- /dev/null +++ b/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml.cs b/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml.cs new file mode 100644 index 0000000..67e1ff6 --- /dev/null +++ b/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorView.xaml.cs @@ -0,0 +1,15 @@ +using System.Windows; + +namespace MECF.Framework.UI.Client.CenterViews.Modules.PM +{ + /// + /// ProcessMonitorView.xaml 的交互逻辑 + /// + public partial class ProcessMonitorView : Window + { + public ProcessMonitorView() + { + InitializeComponent(); + } + } +} diff --git a/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorViewModel.cs b/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorViewModel.cs new file mode 100644 index 0000000..4102f59 --- /dev/null +++ b/MECF.Framework.UI.Client/CenterViews/Modules/PM/ProcessMonitorViewModel.cs @@ -0,0 +1,212 @@ +using Aitex.Core.Util; +using Aitex.Core.Common.DeviceData; +using MECF.Framework.UI.Client.ClientBase; +using System; +using Aitex.Core.RT.Device.PmDevices; + +namespace MECF.Framework.UI.Client.CenterViews.Modules.PM +{ + public class ProcessMonitorViewModel : SicModuleUIViewModelBase + { + + public ProcessMonitorViewModel() + { + Pm1Monitor = new MonitorModel() { SystemName = "PM1" }; + Pm2Monitor = new MonitorModel() { SystemName = "PM2" }; + + + } + + public MonitorModel Pm1Monitor { get; set; } + public MonitorModel Pm2Monitor { get; } + + + protected override void OnInitialize() + { + base.OnInitialize(); + + Pm1Monitor.SubscribeKeys(); + Pm2Monitor.SubscribeKeys(); + } + + protected override void OnActivate() + { + base.OnActivate(); + + Pm1Monitor.EnableTimer(true); + Pm2Monitor.EnableTimer(true); + } + + protected override void OnDeactivate(bool close) + { + base.OnDeactivate(close); + + Pm1Monitor.EnableTimer(false); + Pm2Monitor.EnableTimer(false); + } + } + public class MonitorModel : SicModuleUIViewModelBase, ISupportMultipleSystem + { + public string TargetModule { get; set; } + + + [Subscription("SelectedRecipeName")] + public string RecipeName { get; set; } + + [Subscription("RecipeStepNumber")] + public int RecipeStepNumber { get; set; } + + [Subscription("RecipeStepName")] + public string RecipeStepName { get; set; } + + [Subscription("RecipeStepElapseTime")] + public int RecipeStepElapseTime { get; set; } + + [Subscription("RecipeStepTime")] + public int RecipeStepTime { get; set; } + + [Subscription("RecipeTotalElapseTime")] + public int RecipeTotalElapseTime { get; set; } + + [Subscription("RecipeTotalTime")] + public int RecipeTotalTime { get; set; } + + [Subscription("TC1.HeaterModeSetPoint")] + public float TC1HeaterMode { get; set; } + + [Subscription("TC2.HeaterModeSetPoint")] + public float TC2HeaterMode { get; set; } + + [Subscription("SCR1.PowerFeedBack")] + public float SCR1Power { get; set; } + + [Subscription("SCR2.PowerFeedBack")] + public float SCR2Power { get; set; } + + [Subscription("SCR3.PowerFeedBack")] + public float SCR3Power { get; set; } + + [Subscription("PSU1.OutputPowerFeedBack")] + public float PSU1Power { get; set; } + + [Subscription("PSU2.OutputPowerFeedBack")] + public float PSU2Power { get; set; } + + [Subscription("PSU3.OutputPowerFeedBack")] + public float PSU3Power { get; set; } + + [Subscription("TC1.L2InputTempSetPoint")] + public float L2InputTemp { get; set; } + + [Subscription("TC1.L3InputTempSetPoint")] + public float L3InputTemp { get; set; } + + [Subscription("TC2.L3InputTempSetPoint")] + public float SCRL3InputTemp { get; set; } + + [Subscription("PMServo.ActualSpeedFeedback")] + public float ActualSpeedFeedback { get; set; } + + [Subscription("PT1.DeviceData")] + public AITPressureMeterData ChamPress { get; set; } + + [Subscription("TC1.TempCtrlTCIN")] + public float PM1Temprature { get; set; } + + [Subscription("Status")] + public string Status { get; set; } + + public bool IsPMProcess => Status == "Process" || Status == "PostProcess" || Status == "Paused" || + Status == "PMMacroPause" || Status == "PMMacro" || Status == "PostPMMacro"; + + public bool IsPreProcess => Status == "PreProcess" || Status == "PrePMMacro"; + + public string StepNumber + { + get + { + if (IsPMProcess) + { + return $"{RecipeStepNumber}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + + } + set + { + + } + } + + public string StepName + { + get + { + if (IsPMProcess) + { + return $"{RecipeStepName}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + } + } + + public string StepTime + { + get + { + if (IsPMProcess) + { + return $"{RecipeStepElapseTime}/{RecipeStepTime}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + + } + } + + public string RecipeTime + { + get + { + if (IsPMProcess) + { + return $"{RecipeTotalElapseTime}/{RecipeTotalTime}"; + } + else if (IsPreProcess) + { + return "0"; + } + return "--"; + } + } + + public string PsuMode + { + get + { + return Enum.GetName(typeof(DicMode.HeaterControlMode), Convert.ToInt32(TC1HeaterMode)); + } + } + + public string ScrMode + { + get + { + return Enum.GetName(typeof(DicMode.HeaterControlMode), Convert.ToInt32(TC2HeaterMode)); + } + } + + public string ChamberPressureFeedback => ChamPress?.FeedBack.ToString(ChamPress?.FormatString); + } +} diff --git a/MECF.Framework.UI.Client/MECF.Framework.UI.Client.csproj b/MECF.Framework.UI.Client/MECF.Framework.UI.Client.csproj index 1b0b0e7..0299a69 100644 --- a/MECF.Framework.UI.Client/MECF.Framework.UI.Client.csproj +++ b/MECF.Framework.UI.Client/MECF.Framework.UI.Client.csproj @@ -236,6 +236,13 @@ PMJobListView.xaml + + + PMProcessView.xaml + + + + PanelLocker.xaml @@ -790,6 +797,7 @@ + @@ -868,6 +876,14 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -916,6 +932,7 @@ + @@ -923,6 +940,9 @@ + + PreserveNewest + @@ -1787,6 +1807,10 @@ {efad063f-fa97-42b7-87f8-8279eba30d34} MECF.Framework.Common + + {090A1E9C-1087-4C8A-B4E0-FF074459E071} + MECF.Framework.RT.EquipmentLibrary + {2C9E1DF3-1ABA-4972-BE60-41DD9B3C47A7} MECF.Framework.UI.Core diff --git a/MECF.Framework.UI.Client/Resources/Images/chamber.png b/MECF.Framework.UI.Client/Resources/Images/chamber.png new file mode 100644 index 0000000000000000000000000000000000000000..0d3e796d5b8ad9ea84ccf4ec2eba741473894c9b GIT binary patch literal 8408 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 literal 0 HcmV?d00001 diff --git a/MECF.Framework.UI.Client/Resources/Images/showerhead.png b/MECF.Framework.UI.Client/Resources/Images/showerhead.png new file mode 100644 index 0000000000000000000000000000000000000000..518f46e782b14fc920ed729f70afcce39d100c5a GIT binary patch literal 12393 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 MN?Ec-+$8A#0T{n#y#N3J literal 0 HcmV?d00001 diff --git a/MECF.Framework.UI.Client/SicModuleUIViewModelBase.cs b/MECF.Framework.UI.Client/SicModuleUIViewModelBase.cs new file mode 100644 index 0000000..61c1e2c --- /dev/null +++ b/MECF.Framework.UI.Client/SicModuleUIViewModelBase.cs @@ -0,0 +1,202 @@ +using MECF.Framework.UI.Client.ClientBase; +using System.Windows; + +namespace MECF.Framework.UI.Client +{ + public class SicModuleUIViewModelBase : UiViewModelBase + { + public ModuleInfo CassAL + { + get + { + if (ModuleManager.ModuleInfos["CassAL"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["CassAL"]; + return null; + } + } + public ModuleInfo CassAR + { + get + { + if (ModuleManager.ModuleInfos["CassAR"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["CassAR"]; + return null; + } + } + public ModuleInfo CassBL + { + get + { + if (ModuleManager.ModuleInfos["CassBL"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["CassBL"]; + return null; + } + } + + public ModuleInfo Buffer + { + get + { + if (ModuleManager.ModuleInfos["Buffer"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["Buffer"]; + return null; + } + } + + + public ModuleInfo Aligner { get; set; } + public ModuleInfo TMRobot { get; set; } + public ModuleInfo WaferRobot { get; set; } + public ModuleInfo TrayRobot { get; set; } + public ModuleInfo LoadLock { get; set; } + public ModuleInfo UnLoad { get; set; } + public ModuleInfo PM1 { get; set; } + public ModuleInfo PM2 { get; set; } + + + #region Wafer info for machine + + + public WaferInfo BufferWafer + { + get + { + if (ModuleManager.ModuleInfos["Buffer"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["Buffer"].WaferManager.Wafers[0]; + return null; + } + } + + public WaferInfo PM1Wafer + { + get + { + if (ModuleManager.ModuleInfos["PM1"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["PM1"].WaferManager.Wafers[0]; + return null; + } + } + public WaferInfo PM2Wafer + { + get + { + if (ModuleManager.ModuleInfos["PM2"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["PM2"].WaferManager.Wafers[0]; + return null; + } + } + + public WaferInfo Wafer1 + { + get + { + if (ModuleManager.ModuleInfos["TMRobot"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["TMRobot"].WaferManager.Wafers[0]; + return null; + } + } + public WaferInfo TrayRobotWafer + { + get + { + if (ModuleManager.ModuleInfos["TrayRobot"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["TrayRobot"].WaferManager.Wafers[0]; + return null; + } + } + public WaferInfo WaferRobotWafer + { + get + { + if (ModuleManager.ModuleInfos["WaferRobot"].WaferManager.Wafers.Count > 0) + return ModuleManager.ModuleInfos["WaferRobot"].WaferManager.Wafers[0]; + return null; + } + } + + #endregion + + #region Tray Visble + public Visibility TrayRobotHaveTray + { + get + { + if (ModuleManager.ModuleInfos["TrayRobot"].WaferManager.Wafers.Count > 0 && ModuleManager.ModuleInfos["TrayRobot"].WaferManager.Wafers[0].WaferTrayStatus > 0) + { + return Visibility.Visible; + } + return Visibility.Hidden; + } + } + + public Visibility TMRobotHaveTray + { + get + { + if (ModuleManager.ModuleInfos["TMRobot"].WaferManager.Wafers.Count > 0 && ModuleManager.ModuleInfos["TMRobot"].WaferManager.Wafers[0].WaferTrayStatus > 0) + { + return Visibility.Visible; + } + return Visibility.Hidden; + } + } + + public Visibility LoadLockHaveTray + { + get + { + if (ModuleManager.ModuleInfos["LoadLock"].WaferManager.Wafers.Count > 0 && ModuleManager.ModuleInfos["LoadLock"].WaferManager.Wafers[0].WaferTrayStatus > 0) + { + return Visibility.Visible; + } + return Visibility.Hidden; + } + } + + public Visibility UnLoadHaveTray + { + get + { + if (ModuleManager.ModuleInfos["UnLoad"].WaferManager.Wafers.Count > 0 && ModuleManager.ModuleInfos["UnLoad"].WaferManager.Wafers[0].WaferTrayStatus > 0) + { + return Visibility.Visible; + } + return Visibility.Hidden; + } + } + + public Visibility PM1HaveTray + { + get + { + if (ModuleManager.ModuleInfos["PM1"].WaferManager.Wafers.Count > 0 && ModuleManager.ModuleInfos["PM1"].WaferManager.Wafers[0].WaferTrayStatus > 0) + { + return Visibility.Visible; + } + return Visibility.Hidden; + } + } + + public Visibility PM2HaveTray + { + get + { + if (ModuleManager.ModuleInfos["PM2"].WaferManager.Wafers.Count > 0 && ModuleManager.ModuleInfos["PM2"].WaferManager.Wafers[0].WaferTrayStatus > 0) + { + return Visibility.Visible; + } + return Visibility.Hidden; + } + } + #endregion + + + protected void InitPM() + { + TMRobot = ModuleManager.ModuleInfos["TMRobot"]; + PM1 = ModuleManager.ModuleInfos["PM1"]; + PM2 = ModuleManager.ModuleInfos["PM2"]; + } + + } +}