using MECF.Framework.Common.CommonData; using SicUI.Controls.Common; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; namespace SicUI.Controls.M2C4Parts { /// /// RobotEfemTray.xaml 的交互逻辑 /// public partial class RobotEfemTray : UserControl, INotifyPropertyChanged { private int moveTime = 300; private const int AnimationTimeout = 3000; // ms private string CurrentPosition { get; set; } private RobotAction CurrentAction { get; set; } public int MoveTime { get => moveTime; set { moveTime = value; } } public bool ShowDock { get { return (bool)GetValue(ShowDockProperty); } set { SetValue(ShowDockProperty, value); } } // Using a DependencyProperty as the backing store for ShowDock. This enables animation, styling, binding, etc... public static readonly DependencyProperty ShowDockProperty = DependencyProperty.Register("ShowDock", typeof(bool), typeof(RobotEfemTray), new PropertyMetadata(false)); // Using a DependencyProperty as the backing store for RotateAngel. This enables animation, styling, binding, etc... public static readonly DependencyProperty RotateAngleProperty = DependencyProperty.Register("RotateAngel", typeof(int), typeof(RobotEfemTray), new PropertyMetadata(0)); public int TranslateX { get { return (int)GetValue(TranslateXProperty); } set { SetValue(TranslateXProperty, value); } } // Using a DependencyProperty as the backing store for TranslateX. This enables animation, styling, binding, etc... public static readonly DependencyProperty TranslateXProperty = DependencyProperty.Register("TranslateX", typeof(int), typeof(RobotEfemTray), new PropertyMetadata(0)); public MECF.Framework.UI.Client.ClientBase.WaferInfo Wafer1 { get { return (MECF.Framework.UI.Client.ClientBase.WaferInfo)GetValue(Wafer1Property); } set { SetValue(Wafer1Property, value); } } // Using a DependencyProperty as the backing store for Wafer1. This enables animation, styling, binding, etc... public static readonly DependencyProperty Wafer1Property = DependencyProperty.Register("Wafer1", typeof(MECF.Framework.UI.Client.ClientBase.WaferInfo), typeof(RobotEfemTray), new PropertyMetadata(null)); //public Visibility IsArmWater => Wafer1 == null ? Visibility.Hidden : Wafer1.IsVisibility; public MECF.Framework.UI.Client.ClientBase.WaferInfo Wafer2 { get { return (MECF.Framework.UI.Client.ClientBase.WaferInfo)GetValue(Wafer2Property); } set { SetValue(Wafer2Property, value); } } // Using a DependencyProperty as the backing store for Wafer2. This enables animation, styling, binding, etc... public static readonly DependencyProperty Wafer2Property = DependencyProperty.Register("Wafer2", typeof(MECF.Framework.UI.Client.ClientBase.WaferInfo), typeof(RobotEfemTray), new PropertyMetadata(null)); public string Station { get { return (string)GetValue(StationProperty); } set { SetValue(StationProperty, value); } } // Using a DependencyProperty as the backing store for Station. This enables animation, styling, binding, etc... public static readonly DependencyProperty StationProperty = DependencyProperty.Register("Station", typeof(string), typeof(RobotEfemTray), new PropertyMetadata("Robot")); public RobotMoveInfo RobotMoveInfo { get { return (RobotMoveInfo)GetValue(RobotMoveInfoProperty); } set { SetValue(RobotMoveInfoProperty, value); } } public static readonly DependencyProperty RobotMoveInfoProperty = DependencyProperty.Register("RobotMoveInfo", typeof(RobotMoveInfo), typeof(RobotEfemTray), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)); public bool WaferPresentA { get { return (bool)GetValue(WaferPresentAProperty); } set { SetValue(WaferPresentAProperty, value); } } // Using a DependencyProperty as the backing store for WaferPresent. This enables animation, styling, binding, etc... public static readonly DependencyProperty WaferPresentAProperty = DependencyProperty.Register("WaferPresentA", typeof(bool), typeof(RobotEfemTray), new PropertyMetadata(false)); public bool WaferPresentB { get { return (bool)GetValue(WaferPresentBProperty); } set { SetValue(WaferPresentBProperty, value); } } // Using a DependencyProperty as the backing store for WaferPresent. This enables animation, styling, binding, etc... public static readonly DependencyProperty WaferPresentBProperty = DependencyProperty.Register("WaferPresentB", typeof(bool), typeof(RobotEfemTray), new PropertyMetadata(false)); public ICommand CreateDeleteWaferCommand { get { return (ICommand)GetValue(CreateDeleteWaferCommandProperty); } set { SetValue(CreateDeleteWaferCommandProperty, value); } } // Using a DependencyProperty as the backing store for CreateDeleteWaferCommand. This enables animation, styling, binding, etc... public static readonly DependencyProperty CreateDeleteWaferCommandProperty = DependencyProperty.Register("CreateDeleteWaferCommand", typeof(ICommand), typeof(RobotEfemTray), new PropertyMetadata(null)); public ICommand MoveWaferCommand { get { return (ICommand)GetValue(MoveWaferCommandProperty); } set { SetValue(MoveWaferCommandProperty, value); } } // Using a DependencyProperty as the backing store for MoveWaferCommand. This enables animation, styling, binding, etc... public static readonly DependencyProperty MoveWaferCommandProperty = DependencyProperty.Register("MoveWaferCommand", typeof(ICommand), typeof(RobotEfemTray), new PropertyMetadata(null)); public Dictionary StationPosition { get { return (Dictionary)GetValue(StationPositionProperty); } set { SetValue(StationPositionProperty, value); } } // Using a DependencyProperty as the backing store for StationPosition. This enables animation, styling, binding, etc... new PropertyMetadata(null, StationPositionChangedCallback) public static readonly DependencyProperty StationPositionProperty = DependencyProperty.Register("StationPosition", typeof(Dictionary), typeof(RobotEfemTray), new PropertyMetadata(null, StationPositionChangedCallback)); public Visibility HasWafer { get { return (Visibility)GetValue(HasWaferProperty); } set { SetValue(HasWaferProperty, value); } } // Using a DependencyProperty as the backing store for Station. This enables animation, styling, binding, etc... public static readonly DependencyProperty HasWaferProperty = DependencyProperty.Register("HasWafer", typeof(Visibility), typeof(RobotEfemTray), new PropertyMetadata(Visibility.Hidden)); public Visibility HasTray { get { return (Visibility)GetValue(HasTrayProperty); } set { SetValue(HasTrayProperty, value); } } // Using a DependencyProperty as the backing store for Station. This enables animation, styling, binding, etc... public static readonly DependencyProperty HasTrayProperty = DependencyProperty.Register("HasTray", typeof(Visibility), typeof(RobotEfemTray), new PropertyMetadata(Visibility.Hidden)); private List menu; public event PropertyChangedEventHandler PropertyChanged; public List Menu { get { return menu; } set { menu = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Menu")); } } private ICommand MoveCommand { get; set; } private void MoveTo(object target) { MoveRobot((RobotMoveInfo)target); } public RobotEfemTray() { InitializeComponent(); root.DataContext = this; MoveCommand = new RelayCommand(MoveTo); CurrentPosition = "ArmA.System"; canvas1.Rotate(45); canvas2.Rotate(120); canvas3.Rotate(120); StationPosition = new Dictionary { { "ArmA.System",new StationPosition() { StartPosition= new RobotPosition() { Z=0, Root=45, Arm=120, Hand=120 }, EndPosition= new RobotPosition() { Root=45, Arm=120, Hand=120 } } }, { "ArmA.CassBL",new StationPosition() //ArmA.PerHeat { StartPosition= new RobotPosition() { Z=0, Root = -195, Arm = 120, Hand = 120 }, EndPosition= new RobotPosition() { Root = -315, Arm = 360, Hand = 0 } } }, { "ArmA.LoadLock",new StationPosition() { StartPosition= new RobotPosition() { Z=0, Root = -60, Arm = 120, Hand = 120 }, EndPosition= new RobotPosition() { Root = -180, Arm = 360, Hand = 0 } } },{ "System",new StationPosition() { StartPosition= new RobotPosition() { Z=0, Root=45, Arm=120, Hand=120 }, EndPosition= new RobotPosition() { Root=45, Arm=120, Hand=120 } } }, { "CassBL",new StationPosition() { StartPosition= new RobotPosition() { Z=0, Root = -195, Arm = 120, Hand = 120 }, EndPosition= new RobotPosition() { Root = -315, Arm = 360, Hand = 0 } } }, { "LoadLock",new StationPosition() { StartPosition= new RobotPosition() { Z=0, Root = -60, Arm = 120, Hand = 120 }, EndPosition= new RobotPosition() { Root = -180, Arm = 360, Hand = 0 } } }, }; } static void StationPositionChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = (RobotEfemTray)d; var positions = (Dictionary)e.NewValue; var menus = new List(); foreach (var position in positions) { var m = new MenuItem() { Header = position.Key }; Enum.TryParse(position.Key.Split('.')[0], out RobotArm arm); m.Items.Add(new MenuItem() { Header = "Pick", Command = self.MoveCommand, CommandParameter = new RobotMoveInfo() { BladeTarget = position.Key, Action = RobotAction.Picking, ArmTarget = arm } }); m.Items.Add(new MenuItem() { Header = "Place", Command = self.MoveCommand, CommandParameter = new RobotMoveInfo() { BladeTarget = position.Key, Action = RobotAction.Placing, ArmTarget = arm } }); m.Items.Add(new MenuItem() { Header = "Move", Command = self.MoveCommand, CommandParameter = new RobotMoveInfo() { BladeTarget = position.Key, Action = RobotAction.Moving, ArmTarget = arm } }); menus.Add(m); } self.Menu = menus; self.MoveTo(new RobotMoveInfo() { BladeTarget = positions.First().Key, Action = RobotAction.None }); } protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); if (DesignerProperties.GetIsInDesignMode(this)) { return; } if (RobotMoveInfo != null) { var needMove = CurrentPosition != RobotMoveInfo.BladeTarget || CurrentAction != RobotMoveInfo.Action; if (needMove) { LogMsg($" RobotMoveInfo, action:{RobotMoveInfo.Action} armTarget:{RobotMoveInfo.ArmTarget} bladeTarget:{RobotMoveInfo.BladeTarget}"); Invoke(() => MoveRobot(RobotMoveInfo)); CurrentAction = RobotMoveInfo.Action; CurrentPosition = RobotMoveInfo.BladeTarget; } } } private void Invoke(Action action) { Dispatcher.Invoke(action); } private void LogMsg(string msg) { var source = "ATM Robot"; Console.WriteLine("{0} {1}", source, msg); } private void MoveRobot(RobotMoveInfo moveInfo) { canvas1.Stop(); canvas2.Stop(); canvas3.Stop(); //canvas21.Stop(); //canvas22.Stop(); //canvas23.Stop(); if (String.IsNullOrEmpty(CurrentPosition)) { CurrentPosition = "ArmA.System"; } var target = moveInfo.BladeTarget; var arm = moveInfo.ArmTarget; MoveToStart(arm, CurrentPosition , () => TranslateTo(target, () => MoveToStart(arm, target, () => { if (moveInfo.Action != RobotAction.Moving) { MoveToEnd(arm, target, () => UpdateWafer(moveInfo)); } }))); } private void RotateTo(string station, Action onComplete = null) { var position = StationPosition[station]; LogMsg($"Rotate to {position.StartPosition.X}"); } private void TranslateTo(string station, Action onComplete = null) { var position = StationPosition[station]; LogMsg($"Translate to {position.StartPosition.Z}"); Translate(StationPosition[CurrentPosition].StartPosition.Z, position.StartPosition.Z, onComplete); } private void MoveToStart(RobotArm arm, string station, Action onComplete = null) { LogMsg($"{arm} Move to start {station}"); var position = StationPosition[station]; var storyboard = new Storyboard(); storyboard.Completed += (s, e) => onComplete?.Invoke(); var needRotate = new List(); //if (arm == RobotArm.ArmA) { needRotate.Add(canvas1.Rotate(storyboard, position.StartPosition.Root, true, MoveTime)); needRotate.Add(canvas2.Rotate(storyboard, position.StartPosition.Arm, true, MoveTime)); needRotate.Add(canvas3.Rotate(storyboard, position.StartPosition.Hand, true, MoveTime)); } //else if (arm == RobotArm.ArmB) { //needRotate.Add(canvas21.Rotate(storyboard, position.StartPosition.Root, true, MoveTime)); //needRotate.Add(canvas22.Rotate(storyboard, position.StartPosition.Arm, true, MoveTime)); //needRotate.Add(canvas23.Rotate(storyboard, position.StartPosition.Hand, true, MoveTime)); } if (needRotate.Any(x => x)) { storyboard.Begin(); } else { onComplete?.Invoke(); } CurrentPosition = station; } private void MoveToEnd(RobotArm arm, string station, Action onComplete = null) { LogMsg($"{arm} move to end {station}"); var position = StationPosition[station]; var storyboard = new Storyboard(); storyboard.Completed += (s, e) => onComplete?.Invoke(); var needRotate = new List(); if (arm == RobotArm.ArmA || arm == RobotArm.Both) { needRotate.Add(canvas1.Rotate(storyboard, position.EndPosition.Root, true, MoveTime)); needRotate.Add(canvas2.Rotate(storyboard, position.EndPosition.Arm, true, MoveTime)); needRotate.Add(canvas3.Rotate(storyboard, position.EndPosition.Hand, true, MoveTime)); } if (arm == RobotArm.ArmB || arm == RobotArm.Both) { //needRotate.Add(canvas21.Rotate(storyboard, position.EndPosition.Root, true, MoveTime)); //needRotate.Add(canvas22.Rotate(storyboard, position.EndPosition.Arm, true, MoveTime)); //needRotate.Add(canvas23.Rotate(storyboard, position.EndPosition.Hand, true, MoveTime)); } if (needRotate.Any(x => x)) { storyboard.Begin(); } else { onComplete?.Invoke(); } CurrentPosition = station; } private void UpdateWafer(RobotMoveInfo moveInfo) { var waferPresent = false; switch (moveInfo.Action) { case RobotAction.None: case RobotAction.Moving: return; case RobotAction.Picking: waferPresent = true; break; case RobotAction.Placing: waferPresent = false; break; default: break; } switch (moveInfo.ArmTarget) { case RobotArm.ArmA: WaferPresentA = waferPresent; break; case RobotArm.ArmB: WaferPresentB = waferPresent; break; case RobotArm.Both: WaferPresentA = waferPresent; WaferPresentB = waferPresent; break; default: break; } } private void Translate(int start, int target, Action onComplete = null) { AnimationHelper.TranslateX(root, start, target, MoveTime, onComplete); } } }