using Google.Protobuf.Collections; using RealTimeGraphEx.Controllers; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; using Tango.Core.Helpers; using Tango.Editors; using Tango.Integration.Observables; using Tango.Integration.Operators; using Tango.MachineStudio.Common.StudioApplication; using Tango.MachineStudio.Technician.Editors; using Tango.MachineStudio.Technician.TechItems; using Tango.PMR.Diagnostics; using Tango.SharedUI; namespace Tango.MachineStudio.Technician.ViewModels { public class MachineTechViewVM : ViewModel { private List _diagnoticsDataProperties; private Dictionary _singleControllers; private Dictionary _multiControllers; private static object _elementsLock = new object(); private ObservableCollection _elements; public ObservableCollection Elements { get { return _elements; } set { _elements = value; RaisePropertyChangedAuto(); } } private ObservableCollection _availableTechItems; public ObservableCollection AvailableTechItems { get { return _availableTechItems; } set { _availableTechItems = value; RaisePropertyChangedAuto(); } } private TechItem _selectedTechItem; public TechItem SelectedTechItem { get { return _selectedTechItem; } set { _selectedTechItem = value; RaisePropertyChangedAuto(); } } public ObservablesEntitiesAdapter Adapter { get; set; } public IStudioApplicationManager ApplicationManager { get; set; } private IMachineOperator _machineOperator; public IMachineOperator MachineOperator { get { return _machineOperator; } set { _machineOperator = value; RaisePropertyChangedAuto(); } } public MachineTechViewVM(IStudioApplicationManager applicationManager) { _singleControllers = new Dictionary(); _multiControllers = new Dictionary(); AvailableTechItems = TechItem.GetAvailableTechItems().ToObservableCollection(); SelectedTechItem = AvailableTechItems.FirstOrDefault(); _diagnoticsDataProperties = typeof(PushDiagnosticsResponse).GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList(); ApplicationManager = applicationManager; ApplicationManager.ConnectedMachineChanged += ApplicationManager_ConnectedMachineChanged; Adapter = ObservablesEntitiesAdapter.Instance; //Adapter.Initialize(); //TODO: Remove on Machine Studio. Elements = new ObservableCollection(); } private void ApplicationManager_ConnectedMachineChanged(object sender, Integration.Services.IExternalBridgeClient machine) { MachineOperator = machine; if (MachineOperator != null) { MachineOperator.DiagnosticsDataAvailable -= MachineOperator_DiagnosticsDataAvailable; MachineOperator.DiagnosticsDataAvailable += MachineOperator_DiagnosticsDataAvailable; } } private void MachineOperator_DiagnosticsDataAvailable(object sender, PushDiagnosticsResponse response) { PopulateDiagnosticsData(response); } private void PopulateDiagnosticsData(PushDiagnosticsResponse data) { lock (_elementsLock) { var elements = Elements.ToList(); foreach (var item in elements.Select(x => x.HostedElement as TechItem)) { if (item.GetType() == typeof(MonitorItem)) { MonitorItem monitorItem = item as MonitorItem; if (DateTime.Now > monitorItem.LastUpdateTime.AddMilliseconds(monitorItem.UpdateInterval)) { var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == monitorItem.TechMonitor.Name); if (prop != null) { monitorItem.Value = GetLastMonitorValue(monitorItem.TechMonitor, prop.GetValue(data)); } } } else if (item.GetType() == typeof(IOItem)) { IOItem ioItem = item as IOItem; if (ioItem.Port < data.GPIO.Count) { ioItem.EffectiveValue = data.GPIO[ioItem.Port]; } } else if (item.GetType() == typeof(MeterItem)) { MeterItem meterItem = item as MeterItem; if (DateTime.Now > meterItem.LastUpdateTime.AddMilliseconds(meterItem.UpdateInterval)) { var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == meterItem.TechMonitor.Name); if (prop != null) { meterItem.Value = GetLastMonitorValue(meterItem.TechMonitor, prop.GetValue(data)); } } } else if (item.GetType() == typeof(SingleGraphItem)) { SingleGraphItem graphItem = item as SingleGraphItem; var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == graphItem.TechMonitor.Name); if (prop != null) { GraphController controller = null; if (_singleControllers.TryGetValue(graphItem, out controller)) { controller.PushData(GetSingleGraphValues(graphItem.TechMonitor, prop.GetValue(data))); } } } else if (item.GetType() == typeof(MultiGraphItem)) { MultiGraphItem graphItem = item as MultiGraphItem; var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == graphItem.TechMonitor.Name); if (prop != null) { GraphMultiController controller = null; if (_multiControllers.TryGetValue(graphItem, out controller)) { controller.PushData(GetMultiGraphValues(graphItem.TechMonitor, prop.GetValue(data))); } } } } } } private double GetLastMonitorValue(TechMonitor monitor, object value) { if (!monitor.MultiChannel) { RepeatedField arr = value as RepeatedField; return arr.LastOrDefault(); } else { RepeatedField arr = value as RepeatedField; return arr.Last().Data.Last(); } } private List GetSingleGraphValues(TechMonitor monitor, object value) { return (value as RepeatedField).ToList(); } private List> GetMultiGraphValues(TechMonitor monitor, object value) { DoubleArray[] arrayOfDoubles = Enumerable.ToArray(value as IEnumerable); return arrayOfDoubles.Select(x => x.Data.ToList()).ToList(); } public void AddElement(Rect bounds) { if (SelectedTechItem is MonitorItem) { var monitorItem = new MonitorItem(Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault()); MonitorElementEditor editor = new MonitorElementEditor(monitorItem, bounds); Elements.Add(editor); } else if (SelectedTechItem is MeterItem) { var meterItem = new MeterItem(Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault()); MeterElementEditor editor = new MeterElementEditor(meterItem, bounds); Elements.Add(editor); } else if (SelectedTechItem is SingleGraphItem) { var graphItem = new SingleGraphItem(Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault()); SingleGraphElementEditor editor = new SingleGraphElementEditor(graphItem, bounds); editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(graphItem.TechMonitor.PointsPerFrame); graphItem.Editor = editor; GraphController controller = new GraphController(); editor.InnerGraph.Controller = controller; _singleControllers.Add(graphItem, controller); Elements.Add(editor); } else if (SelectedTechItem is MultiGraphItem) { var graphItem = new MultiGraphItem(Adapter.TechMonitors.Where(x => x.MultiChannel).FirstOrDefault()); MultiGraphElementEditor editor = new MultiGraphElementEditor(graphItem, bounds); editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(graphItem.TechMonitor.PointsPerFrame); graphItem.Editor = editor; GraphMultiController controller = new GraphMultiController(); for (int i = 0; i < graphItem.TechMonitor.ChannelCount; i++) { controller.AddSeries(new RealTimeGraphEx.DataSeries.DataYSeries() { UseFillAndStroke = true, Name = graphItem.TechMonitor.Name.First() + (i + 1).ToString(), Stroke = new SolidColorBrush(ColorHelper.GetRandomColor()), }); } editor.InnerGraph.Controller = controller; _multiControllers.Add(graphItem, controller); Elements.Add(editor); } else if (SelectedTechItem is MotorItem) { var motorItem = new MotorItem(Adapter.TechMotors.FirstOrDefault()); MotorElementEditor editor = new MotorElementEditor(motorItem, bounds); Elements.Add(editor); InitMotorItem(motorItem); } else if (SelectedTechItem is DispenserItem) { var dispenserItem = new DispenserItem(Adapter.TechDispensers.FirstOrDefault()); DispenserElementEditor editor = new DispenserElementEditor(dispenserItem, bounds); Elements.Add(editor); InitDispenserItem(dispenserItem); } else if (SelectedTechItem is IOItem) { var ioItem = new IOItem(0); IOElementEditor editor = new IOElementEditor(ioItem, bounds); Elements.Add(editor); InitIOItem(ioItem); } } public void OnElementsRemoved(List elements) { //foreach (var element in elements) //{ // if (element.HostedElement is SingleGraphItem) // { // _singleControllers.Remove(element.HostedElement as SingleGraphItem); // (element.HostedElement as SingleGraphItem).Editor.InnerGraph.InnerGraph.Dispose(); // } // else if (element.HostedElement is MultiGraphItem) // { // _multiControllers.Remove(element.HostedElement as MultiGraphItem); // (element.HostedElement as MultiGraphItem).Editor.InnerGraph.InnerGraph.Dispose(); // } //} } public void OnElementsPasted(List elements) { foreach (var element in elements) { if (element is SingleGraphElementEditor) { var graphItem = element.HostedElement as SingleGraphItem; var editor = element as SingleGraphElementEditor; graphItem.Editor = editor; editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(graphItem.TechMonitor.PointsPerFrame); GraphController controller = new GraphController(); editor.InnerGraph.Controller = controller; _singleControllers.Add(graphItem, controller); } else if (element is MultiGraphElementEditor) { var graphItem = element.HostedElement as MultiGraphItem; var editor = element as MultiGraphElementEditor; editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(graphItem.TechMonitor.PointsPerFrame); graphItem.Editor = editor; GraphMultiController controller = new GraphMultiController(); for (int i = 0; i < graphItem.TechMonitor.ChannelCount; i++) { controller.AddSeries(new RealTimeGraphEx.DataSeries.DataYSeries() { UseFillAndStroke = true, Name = graphItem.TechMonitor.Name.First() + (i + 1).ToString(), Stroke = new SolidColorBrush(ColorHelper.GetRandomColor()), }); } editor.InnerGraph.Controller = controller; _multiControllers.Add(graphItem, controller); } } } private void InitMotorItem(MotorItem item) { item.ActionExecuted += async (x, action) => { if (action == MotorActionType.ForwardPressed) { await MachineOperator.StartMotorJogging(new MotorJoggingRequest() { Code = item.TechMotor.Code, Direction = MotorDirection.Forward, }); } else if (action == MotorActionType.ForwardReleased) { await MachineOperator.StopMotorJogging(new MotorAbortJoggingRequest() { Code = item.TechMotor.Code, }); } else if (action == MotorActionType.BackwardPressed) { await MachineOperator.StartMotorJogging(new MotorJoggingRequest() { Code = item.TechMotor.Code, Direction = MotorDirection.Backward, }); } else if (action == MotorActionType.BackwardReleased) { await MachineOperator.StopMotorJogging(new MotorAbortJoggingRequest() { Code = item.TechMotor.Code, }); } else if (action == MotorActionType.HomingStarted) { item.HomingProgress = 0; item.IsHoming = true; item.IsHomingCompleted = false; MachineOperator.StartMotorHoming(new MotorHomingRequest() { Code = item.TechMotor.Code }) .Subscribe((response) => { item.HomingMaximumProgress = response.Message.MaxProgress; item.HomingProgress = response.Message.Progress; }, () => { item.IsHoming = false; item.IsHomingCompleted = true; }); } else if (action == MotorActionType.HomingStopped) { await MachineOperator.StopMotorHoming(new MotorAbortHomingRequest() { Code = item.TechMotor.Code, }); item.IsHoming = false; } }; } private void InitDispenserItem(DispenserItem item) { item.ActionExecuted += async (x, action) => { if (action == MotorActionType.ForwardPressed) { await MachineOperator.StartDispenserJogging(new DispenserJoggingRequest() { Code = item.TechDispenser.Code, Direction = MotorDirection.Forward, }); } else if (action == MotorActionType.ForwardReleased) { await MachineOperator.StopDispenserJogging(new DispenserAbortJoggingRequest() { Code = item.TechDispenser.Code, }); } else if (action == MotorActionType.BackwardPressed) { await MachineOperator.StartDispenserJogging(new DispenserJoggingRequest() { Code = item.TechDispenser.Code, Direction = MotorDirection.Backward, }); } else if (action == MotorActionType.BackwardReleased) { await MachineOperator.StopDispenserJogging(new DispenserAbortJoggingRequest() { Code = item.TechDispenser.Code, }); } else if (action == MotorActionType.HomingStarted) { item.HomingProgress = 0; item.IsHoming = true; item.IsHomingCompleted = false; MachineOperator.StartDispenserHoming(new DispenserHomingRequest() { Code = item.TechDispenser.Code }) .Subscribe((response) => { item.HomingMaximumProgress = response.Message.MaxProgress; item.HomingProgress = response.Message.Progress; }, () => { item.IsHoming = false; item.IsHomingCompleted = true; }); } else if (action == MotorActionType.HomingStopped) { await MachineOperator.StopDispenserHoming(new DispenserAbortHomingRequest() { Code = item.TechDispenser.Code, }); item.IsHoming = false; } }; } private void InitIOItem(IOItem item) { item.ValueChanged += async (x, value) => { try { await MachineOperator.SetGPIOState(new SetGPIOStateRequest() { Port = item.Port, Value = value }); } catch (Exception ex) { //TODO: Show Exception. } }; } } }