using MECF.Framework.Common.CommonData; using OpenSEMI.ClientBase; 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; using VirgoUI.Controls.Common; namespace VirgoUI.Client.Models.Controls { /// /// AtmRobot.xaml 的交互逻辑 /// public partial class AtmRobot : 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; } } // 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(AtmRobot), 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(AtmRobot), new PropertyMetadata(0)); public WaferInfo Wafer1 { get { return ( 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( WaferInfo), typeof(AtmRobot), new PropertyMetadata(null)); public WaferInfo Wafer2 { get { return ( 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( WaferInfo), typeof(AtmRobot), 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(AtmRobot), 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(AtmRobot), 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(AtmRobot), 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(AtmRobot), 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(AtmRobot), 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(AtmRobot), 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... public static readonly DependencyProperty StationPositionProperty = DependencyProperty.Register("StationPosition", typeof(Dictionary), typeof(AtmRobot), new PropertyMetadata(null, StationPositionChangedCallback)); 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 AtmRobot() { InitializeComponent(); root.DataContext = this; CurrentPosition = "ArmA.System"; MoveCommand = new RelayCommand(MoveTo); StationPosition = new Dictionary { { "ArmA.System",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=145, Arm= 240, Hand=244 }, EndPosition= new RobotPosition() { Root=145, Arm= 240, Hand=244 } } }, { "ArmB.System",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=035, Arm= 120, Hand=474 }, EndPosition= new RobotPosition() { Root=035, Arm= 120, Hand=474 } } }, { "ArmA.LP1",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=145, Arm= 240, Hand=244 }, EndPosition= new RobotPosition() { Root=133, Arm=278, Hand=38 } } }, { "ArmB.LP1",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=035, Arm= 120, Hand=474 }, EndPosition= new RobotPosition() { Root=58, Arm=82, Hand=310 } } } , { "ArmA.Cooling1",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=145, Arm= 240, Hand=244 }, EndPosition= new RobotPosition() { Root=172, Arm=271, Hand=97 } } }, { "ArmB.Cooling1",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=035, Arm= 120, Hand=474 }, EndPosition= new RobotPosition() { Root=177, Arm=282, Hand=83 } } }, { "ArmA.PMA",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=145, Arm= 240, Hand=244 }, EndPosition= new RobotPosition() { Root=233, Arm=77, Hand=-37 } } }, { "ArmB.PMA",new StationPosition() { StartPosition= new RobotPosition() { X=0, Root=035, Arm= 120, Hand=474 }, EndPosition= new RobotPosition() { Root=-63, Arm=-65, Hand=40 } } }, }; canvas1.Rotate(145); canvas2.Rotate(240); canvas3.Rotate(244); canvas21.Rotate(035); canvas22.Rotate(120); canvas23.Rotate(474); } static void StationPositionChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = (AtmRobot)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; needMove= needMove && (RobotMoveInfo.Action != RobotAction.Retracting) ; 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(); 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}"); container.Rotate((int)position.StartPosition.X, true, MoveTime, 0, 0, onComplete); } 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}"); StationPosition positionA = station.Contains("ArmA") ? StationPosition[station] : StationPosition[station.Replace("ArmB", "ArmA")]; StationPosition positionB = station.Contains("ArmB") ? StationPosition[station] : StationPosition[station.Replace("ArmA", "ArmB")]; var storyboard = new Storyboard(); storyboard.Completed += (s, e) => onComplete?.Invoke(); var needRotate = new List(); needRotate.Add(canvas1.Rotate(storyboard, positionA.StartPosition.Root, true, MoveTime)); needRotate.Add(canvas2.Rotate(storyboard, positionA.StartPosition.Arm, true, MoveTime)); needRotate.Add(canvas3.Rotate(storyboard, positionA.StartPosition.Hand, true, MoveTime)); needRotate.Add(canvas21.Rotate(storyboard, positionB.StartPosition.Root, true, MoveTime)); needRotate.Add(canvas22.Rotate(storyboard, positionB.StartPosition.Arm, true, MoveTime)); needRotate.Add(canvas23.Rotate(storyboard, positionB.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); } } }