添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
using MainShell.EventArgsFolder;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Manual.Model;
|
||||
using MainShell.Manual.ViewModel.State;
|
||||
using MainShell.Resources.CustomControl;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.Manual.ViewModel
|
||||
{
|
||||
public class LogisticsOperationViewModel : OperateViewModelBase
|
||||
{
|
||||
private readonly IDeviceIoMonitorService _ioMonitorService;
|
||||
private readonly Dictionary<string, Action<bool>> _ioNameBindings = new Dictionary<string, Action<bool>>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<int, Action<bool>> _ioIdBindings = new Dictionary<int, Action<bool>>();
|
||||
|
||||
private LogisticsOperationState _state;
|
||||
|
||||
public new LogisticsOperationState State
|
||||
{
|
||||
get { return _state; }
|
||||
set { SetAndNotify(ref _state, value); }
|
||||
}
|
||||
|
||||
public LogisticsOperationViewModel(IDeviceIoMonitorService ioMonitorService)
|
||||
{
|
||||
_ioMonitorService = ioMonitorService;
|
||||
|
||||
State = BuildDefaultState();
|
||||
State.PropertyChanged += OnStatePropertyChanged;
|
||||
|
||||
InitializeIoBindings();
|
||||
|
||||
_ioMonitorService.IoChanged += OnIoSnapshotChanged;
|
||||
_ioMonitorService.Start();
|
||||
|
||||
ApplyEfemMode(State.IsManualWithoutEfem);
|
||||
RequestIoRefresh();
|
||||
}
|
||||
|
||||
private LogisticsOperationState BuildDefaultState()
|
||||
{
|
||||
var state = new LogisticsOperationState
|
||||
{
|
||||
SubstrateLoad = BuildSectionState("SUBSTRATE LOAD / 基板上料", "READY", "开始上料流程", "停止流程"),
|
||||
ChipLoad = BuildSectionState("CHIP LOAD / 芯片上料", "READY", "发送取料指令", "取消流程"),
|
||||
SubstrateOut = BuildSectionState("SUBSTRATE OUT / 基板下料", "IDLE", "开始下料出片", "停止流程"),
|
||||
ChipUnload = BuildSectionState("CHIP UNLOAD / 芯片下料", "AWAITING", "执行内部下料", "取消流程"),
|
||||
MagazineMap = MagazineMapViewModel.CreateDefault(25),
|
||||
FeedbackTitle = "FEEDBACK"
|
||||
};
|
||||
|
||||
state.ChipLoad.PhaseSteps.Add(new PhaseStepState
|
||||
{
|
||||
Title = "Phase 1: EFEM 取料",
|
||||
Status = "READY",
|
||||
ActionText = "发送取料指令",
|
||||
IsEnabled = true,
|
||||
ControlTag = "EFEM HANDOFF",
|
||||
RequiresEfemCommunication = true,
|
||||
TargetLayer = 1
|
||||
});
|
||||
state.ChipLoad.PhaseSteps.Add(new PhaseStepState
|
||||
{
|
||||
Title = "Phase 2: 设备内部吸取",
|
||||
Status = "内部手动",
|
||||
ActionText = "执行内部动作",
|
||||
IsEnabled = false,
|
||||
ControlTag = "INTERNAL",
|
||||
RequiresEfemCommunication = false
|
||||
});
|
||||
|
||||
state.ChipUnload.PhaseSteps.Add(new PhaseStepState
|
||||
{
|
||||
Title = "Phase 1: 内部移出至对接位",
|
||||
Status = "内部手动",
|
||||
ActionText = "执行内部下料",
|
||||
IsEnabled = true,
|
||||
ControlTag = "INTERNAL",
|
||||
RequiresEfemCommunication = false
|
||||
});
|
||||
state.ChipUnload.PhaseSteps.Add(new PhaseStepState
|
||||
{
|
||||
Title = "Phase 2: EFEM 返料到料盒",
|
||||
Status = "AWAITING",
|
||||
ActionText = "发送取料指令",
|
||||
IsEnabled = false,
|
||||
ControlTag = "EFEM HANDOFF",
|
||||
RequiresEfemCommunication = true,
|
||||
TargetLayer = 1
|
||||
});
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
private SectionState BuildSectionState(string title, string status, string primaryAction, string secondaryAction)
|
||||
{
|
||||
return new SectionState
|
||||
{
|
||||
Title = title,
|
||||
Status = status,
|
||||
PrimaryActionText = primaryAction,
|
||||
SecondaryActionText = secondaryAction,
|
||||
Indicators =
|
||||
{
|
||||
new IndicatorState { Name = "进片感应器触发", IsOn = false },
|
||||
new IndicatorState { Name = "轨道电机运行中", IsOn = false },
|
||||
new IndicatorState { Name = "平移机原点检测", IsOn = false },
|
||||
new IndicatorState { Name = "真空吸附确认", IsOn = false }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public async Task ScanAsync()
|
||||
{
|
||||
if (State.IsScanning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
State.IsScanning = true;
|
||||
State.ScanProgress = 0;
|
||||
State.AddFeedback("自动扫码开始。", "INFO");
|
||||
RequestIoRefresh();
|
||||
|
||||
for (var i = 1; i <= 100; i++)
|
||||
{
|
||||
State.ScanProgress = i;
|
||||
await Task.Delay(20);
|
||||
}
|
||||
|
||||
State.IsScanning = false;
|
||||
State.AddFeedback("自动扫码完成,共扫描 25 个槽位。", "INFO");
|
||||
RequestIoRefresh();
|
||||
}
|
||||
|
||||
private void OnStatePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(LogisticsOperationState.IsManualWithoutEfem))
|
||||
{
|
||||
ApplyEfemMode(State.IsManualWithoutEfem);
|
||||
}
|
||||
|
||||
RequestIoRefresh();
|
||||
}
|
||||
|
||||
private void ApplyEfemMode(bool manualWithoutEfem)
|
||||
{
|
||||
if (State.ChipLoad.PhaseSteps.Count > 1)
|
||||
{
|
||||
State.ChipLoad.PhaseSteps[0].IsEnabled = !manualWithoutEfem;
|
||||
State.ChipLoad.PhaseSteps[1].IsEnabled = manualWithoutEfem;
|
||||
}
|
||||
|
||||
if (State.ChipUnload.PhaseSteps.Count > 1)
|
||||
{
|
||||
State.ChipUnload.PhaseSteps[1].IsEnabled = !manualWithoutEfem;
|
||||
}
|
||||
|
||||
RequestIoRefresh();
|
||||
}
|
||||
|
||||
public Task ChipLoadPhase1Async()
|
||||
{
|
||||
if (State.IsManualWithoutEfem)
|
||||
{
|
||||
State.AddFeedback("CHIP LOAD: 无EFEM调试模式,直接执行设备内部芯片上料流程。", "INFO");
|
||||
return ChipLoadPhase2Async();
|
||||
}
|
||||
|
||||
var layer = State.ChipLoad.PhaseSteps[0].TargetLayer;
|
||||
State.AddFeedback(string.Format("CHIP LOAD Phase1: 发送EFEM取料指令,目标料盒层 L{0:D2}(预留通讯接口)。", layer), "INFO");
|
||||
if (State.ChipLoad.PhaseSteps.Count > 1)
|
||||
{
|
||||
State.ChipLoad.PhaseSteps[1].IsEnabled = true;
|
||||
}
|
||||
|
||||
RequestIoRefresh();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ChipLoadPhase2Async()
|
||||
{
|
||||
State.AddFeedback("CHIP LOAD Phase2: 执行设备内部吸取动作。", "INFO");
|
||||
RequestIoRefresh();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ChipUnloadPhase1Async()
|
||||
{
|
||||
State.AddFeedback("CHIP UNLOAD Phase1: 内部移出至对接位。", "INFO");
|
||||
RequestIoRefresh();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ChipUnloadPhase2Async()
|
||||
{
|
||||
var layer = State.ChipUnload.PhaseSteps[1].TargetLayer;
|
||||
State.AddFeedback(string.Format("CHIP UNLOAD Phase2: 发送EFEM返料指令,目标料盒层 L{0:D2}(预留通讯接口)。", layer), "INFO");
|
||||
RequestIoRefresh();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
_ioMonitorService.IoChanged -= OnIoSnapshotChanged;
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
private void InitializeIoBindings()
|
||||
{
|
||||
BindIoName("LG.SubstrateLoad.SensorIn", value => SetIndicator(State.SubstrateLoad, 0, value));
|
||||
BindIoName("LG.SubstrateLoad.TrackMotorRun", value => SetIndicator(State.SubstrateLoad, 1, value));
|
||||
BindIoName("LG.SubstrateLoad.HomeChecked", value => SetIndicator(State.SubstrateLoad, 2, value));
|
||||
BindIoName("LG.SubstrateLoad.VacuumOk", value => SetIndicator(State.SubstrateLoad, 3, value));
|
||||
|
||||
BindIoName("LG.ChipLoad.SensorIn", value => SetIndicator(State.ChipLoad, 0, value));
|
||||
BindIoName("LG.ChipLoad.TrackMotorRun", value => SetIndicator(State.ChipLoad, 1, value));
|
||||
BindIoName("LG.ChipLoad.HomeChecked", value => SetIndicator(State.ChipLoad, 2, value));
|
||||
BindIoName("LG.ChipLoad.VacuumOk", value => SetIndicator(State.ChipLoad, 3, value));
|
||||
|
||||
BindIoName("LG.SubstrateOut.SensorIn", value => SetIndicator(State.SubstrateOut, 0, value));
|
||||
BindIoName("LG.SubstrateOut.TrackMotorRun", value => SetIndicator(State.SubstrateOut, 1, value));
|
||||
BindIoName("LG.SubstrateOut.HomeChecked", value => SetIndicator(State.SubstrateOut, 2, value));
|
||||
BindIoName("LG.SubstrateOut.VacuumOk", value => SetIndicator(State.SubstrateOut, 3, value));
|
||||
|
||||
BindIoName("LG.ChipUnload.SensorIn", value => SetIndicator(State.ChipUnload, 0, value));
|
||||
BindIoName("LG.ChipUnload.TrackMotorRun", value => SetIndicator(State.ChipUnload, 1, value));
|
||||
BindIoName("LG.ChipUnload.HomeChecked", value => SetIndicator(State.ChipUnload, 2, value));
|
||||
BindIoName("LG.ChipUnload.VacuumOk", value => SetIndicator(State.ChipUnload, 3, value));
|
||||
|
||||
BindIoId(1001, value => SetIndicator(State.SubstrateLoad, 0, value));
|
||||
BindIoId(1002, value => SetIndicator(State.SubstrateLoad, 1, value));
|
||||
BindIoId(1003, value => SetIndicator(State.SubstrateLoad, 2, value));
|
||||
BindIoId(1004, value => SetIndicator(State.SubstrateLoad, 3, value));
|
||||
}
|
||||
|
||||
private void BindIoName(string name, Action<bool> setter)
|
||||
{
|
||||
_ioNameBindings[name] = setter;
|
||||
}
|
||||
|
||||
private void BindIoId(int id, Action<bool> setter)
|
||||
{
|
||||
_ioIdBindings[id] = setter;
|
||||
}
|
||||
|
||||
private void OnIoSnapshotChanged(object sender, DeviceIoChangedEventArgs e)
|
||||
{
|
||||
var changedPoints = e.ChangedPoints;
|
||||
for (var i = 0; i < changedPoints.Count; i++)
|
||||
{
|
||||
ApplyIoPoint(changedPoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyIoPoint(DeviceIoPointState point)
|
||||
{
|
||||
if (point == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Action<bool> setter;
|
||||
if (!string.IsNullOrWhiteSpace(point.Name) && _ioNameBindings.TryGetValue(point.Name, out setter))
|
||||
{
|
||||
setter(point.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_ioIdBindings.TryGetValue(point.Id, out setter))
|
||||
{
|
||||
setter(point.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestIoRefresh()
|
||||
{
|
||||
_ioMonitorService.RequestRefresh();
|
||||
}
|
||||
|
||||
private static void SetIndicator(SectionState section, int index, bool isOn)
|
||||
{
|
||||
if (section == null || section.Indicators.Count <= index)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
section.Indicators[index].IsOn = isOn;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user