From 4e216a0ca8ad3608b845fa445b73034e1a67b8af Mon Sep 17 00:00:00 2001 From: Roy Ben Shabat Date: Wed, 19 Aug 2020 01:45:02 +0300 Subject: DB: Changed TechMonitors HeadZone5_6HeaterCurrent => HeadZone56HeaterCurrent Working on insights and insights annotations. Added insights events. Added insights settings to PPC advanced settings. Added compression support for transport adapters. Implemented compression support on TCP/SignalR/WebRTC. Added Compression flag to ExternalBridge discovery packet. Added compression setting to PPC advanced settings. Refactored transport layer to use Bson instead of Json for Generic Messages. Added all SciChart referenced assemblies. Registered EF Extensions license for FSE. Added support for FSE PushTask notification cancel button. --- .../Tango.FSE.Insights/Contracts/IInsightsView.cs | 14 + .../Tango.FSE.Insights/SciChart/InsightsChart.cs | 68 + .../SciChart/InsightsRubberBandXYZoomModifier.cs | 24 + .../SciChart/InsightsZoomPanModifier.cs | 22 + .../Tango.FSE.Insights/Tango.FSE.Insights.csproj | 40 + .../Modules/Tango.FSE.Insights/Themes/Generic.xaml | 60 + .../ViewModels/InsightsViewVM.cs | 470 +- .../Tango.FSE.Insights/Views/InsightsView.xaml | 263 +- .../Tango.FSE.Insights/Views/InsightsView.xaml.cs | 30 +- .../EntityFrameworkExtensionsHelper.cs | 22 + .../FSE/Tango.FSE.BL/Tango.FSE.BL.csproj | 1 + .../FSE/Tango.FSE.Common/FSEViewModel.cs | 7 + .../FileSystem/IFileSystemProvider.cs | 14 +- .../Tango.FSE.Common/Insights/IInsightsProvider.cs | 13 + .../Tango.FSE.Common/Insights/InsightsHandler.cs | 103 + .../Insights/InsightsHandlerStatus.cs | 18 + .../Tango.FSE.Common/Insights/InsightsPackage.cs | 22 + .../Insights/InsightsReadyEvent.cs | 20 + .../Insights/InsightsReadyFrame.cs | 27 + .../Notifications/INotificationProvider.cs | 4 +- .../FSE/Tango.FSE.Common/Notifications/TaskItem.cs | 11 +- .../FSE/Tango.FSE.Common/Resources/Converters.xaml | 1 + .../FSE/Tango.FSE.Common/Tango.FSE.Common.csproj | 39 + Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml | 13 + .../Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs | 20 + .../Connection/DefaultMachineProvider.cs | 4 +- .../Controls/NotificationsControl.xaml | 2 +- .../FileSystem/DefaultFileSystemProvider.cs | 40 +- .../Insights/DefaultInsightsProvider.cs | 136 + .../Notifications/DefaultNotificationProvider.cs | 17 +- .../Tango.FSE.UI/Panes/ConnectedMachinePane.xaml | 2 + .../FSE/Tango.FSE.UI/Tango.FSE.UI.csproj | 33 + .../FSE/Tango.FSE.UI/ViewModelLocator.cs | 4 + .../Tango.PPC.MachineSettings/Views/MainView.xaml | 27 +- .../ExternalBridge/PPCExternalBridgeService.cs | 1 + .../FileSystem/DefaultFileSystemService.cs | 8 +- .../Insights/DefaultInsightsService.cs | 3 + .../PPC/Tango.PPC.Common/PPCSettings.cs | 6 + .../PPC/Tango.PPC.Common/Resources/Merged.xaml | 1 + .../SciChart/SciChart.Charting.DrawingTools.dll | Bin 0 -> 184832 bytes .../SciChart/SciChart.Charting.DrawingTools.xml | 1189 + .../SciChart/SciChart.Charting.dll | Bin 0 -> 2637312 bytes .../SciChart/SciChart.Charting.xml | 36951 +++++++++++++++++++ .../SciChart/SciChart.Charting3D.dll | Bin 0 -> 9101312 bytes .../SciChart/SciChart.Charting3D.xml | 13485 +++++++ .../SciChart/SciChart.Core.dll | Bin 0 -> 2162688 bytes .../SciChart/SciChart.Core.xml | 2968 ++ .../SciChart/SciChart.Data.dll | Bin 0 -> 17156608 bytes .../SciChart/SciChart.Data.xml | 2292 ++ .../SciChart/SciChart.Drawing.DirectX.dll | Bin 0 -> 230400 bytes .../SciChart/SciChart.Drawing.DirectX.xml | 274 + .../SciChart/SciChart.Drawing.dll | Bin 0 -> 953344 bytes .../SciChart/SciChart.Drawing.xml | 3370 ++ .../SciChart.Examples.ExternalDependencies.dll | Bin 0 -> 8861696 bytes .../SciChart.Examples.ExternalDependencies.xml | 388 + .../SciChart/SharpDX.D3DCompiler.dll | Bin 0 -> 58880 bytes .../SciChart/SharpDX.DXGI.dll | Bin 0 -> 148480 bytes .../SciChart/SharpDX.Direct3D11.Effects.dll | Bin 0 -> 58880 bytes .../SciChart/SharpDX.Direct3D11.dll | Bin 0 -> 283136 bytes .../SciChart/SharpDX.Direct3D9.dll | Bin 0 -> 338944 bytes .../SciChart/SharpDX.Mathematics.dll | Bin 0 -> 215552 bytes .../Referenced Assemblies/SciChart/SharpDX.dll | Bin 0 -> 274944 bytes .../SciChart/sharpdx_direct3d11_1_effects_x64.dll | Bin 0 -> 358912 bytes .../SciChart/sharpdx_direct3d11_1_effects_x86.dll | Bin 0 -> 298496 bytes .../Tango.BL/Enumerations/TechMonitors.cs | 2 +- .../ExternalBridge/EmulatorExternalBridge.cs | 2 + .../Visual_Studio/Tango.Insights/InsightsEvent.cs | 14 + .../Visual_Studio/Tango.Insights/InsightsFile.cs | 3 + .../Visual_Studio/Tango.Insights/InsightsFrame.cs | 4 +- .../Tango.Insights/InsightsListener.cs | 95 +- .../Tango.Insights/InsightsManager.cs | 29 +- .../Tango.Insights/Tango.Insights.csproj | 12 + .../ExternalBridge/ExternalBridgeScanner.cs | 6 +- .../ExternalBridge/ExternalBridgeService.cs | 8 + .../ExternalBridge/ExternalBridgeSignalRClient.cs | 14 +- .../ExternalBridge/ExternalBridgeTcpClient.cs | 21 +- .../ExternalBridge/ExternalBridgeUsbClient.cs | 5 + .../ExternalBridge/IExternalBridgeClient.cs | 5 + .../ExternalBridge/IExternalBridgeService.cs | 5 + .../ExternalBridge/Web/MachineInfo.cs | 1 + .../Tango.PMR/Diagnostics/DiagnosticsMonitors.cs | 48 +- .../Tango.PMR/Insights/InsightsMonitors.cs | 46 +- .../ExternalBridgeUdpDiscoveryPacket.cs | 35 +- .../Converters/TimeSpanToDaysConverter.cs | 23 + .../Tango.SharedUI/Tango.SharedUI.csproj | 3 +- .../Adapters/SignalRTransportAdapter.cs | 9 +- .../Adapters/TcpTransportAdapter.cs | 11 + .../Tango.Transport/Compression/GZipHelper.cs | 42 + .../Tango.Transport/GenericMessageSerializer.cs | 64 +- .../Tango.Transport/ITransportAdapter.cs | 5 + .../Tango.Transport/Tango.Transport.csproj | 3 +- .../Tango.Transport/TransportAdapterBase.cs | 5 + .../Tango.WebRTC/WebRtcTransportAdapter.cs | 16 +- .../Properties/AssemblyInfo.cs | 2 +- 94 files changed, 62903 insertions(+), 162 deletions(-) create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Contracts/IInsightsView.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsChart.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsRubberBandXYZoomModifier.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsZoomPanModifier.cs create mode 100644 Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.BL/EntityFrameworkExtensionsHelper.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/IInsightsProvider.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandler.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandlerStatus.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyEvent.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyFrame.cs create mode 100644 Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Charting.DrawingTools.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Charting.DrawingTools.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Charting.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Charting.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Charting3D.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Charting3D.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Core.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Core.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Data.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Data.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Drawing.DirectX.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Drawing.DirectX.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Drawing.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Drawing.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Examples.ExternalDependencies.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SciChart.Examples.ExternalDependencies.xml create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SharpDX.D3DCompiler.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SharpDX.DXGI.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SharpDX.Direct3D11.Effects.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SharpDX.Direct3D11.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SharpDX.Direct3D9.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SharpDX.Mathematics.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/SharpDX.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/sharpdx_direct3d11_1_effects_x64.dll create mode 100644 Software/Visual_Studio/Referenced Assemblies/SciChart/sharpdx_direct3d11_1_effects_x86.dll create mode 100644 Software/Visual_Studio/Tango.Insights/InsightsEvent.cs create mode 100644 Software/Visual_Studio/Tango.SharedUI/Converters/TimeSpanToDaysConverter.cs create mode 100644 Software/Visual_Studio/Tango.Transport/Compression/GZipHelper.cs (limited to 'Software/Visual_Studio') diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Contracts/IInsightsView.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Contracts/IInsightsView.cs new file mode 100644 index 000000000..7ca881f9a --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Contracts/IInsightsView.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.FSE.Common; + +namespace Tango.FSE.Insights.Contracts +{ + public interface IInsightsView : IFSEView + { + void ZoomExtents(); + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsChart.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsChart.cs new file mode 100644 index 000000000..c51015e66 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsChart.cs @@ -0,0 +1,68 @@ +using SciChart.Charting.Model.ChartSeries; +using SciChart.Charting.Model.DataSeries; +using SciChart.Charting.Visuals.Annotations; +using SciChart.Charting.Visuals.RenderableSeries; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using Tango.Core; + +namespace Tango.FSE.Insights.SciChart +{ + public class InsightsChart : ExtendedObject + { + public event EventHandler IsVisibleChanged; + + private ObservableCollection ChartsCollection { get; set; } + public String Name { get; set; } + public String Description { get; set; } + public PropertyInfo InsightsMonitorsProperty { get; set; } + public IRenderableSeriesViewModel RenderableSeries { get; set; } + public XyDataSeries DataSeries { get; set; } + public AnnotationCollection Annotations { get; set; } + + private bool _isVisible; + public bool IsVisible + { + get { return _isVisible; } + set + { + if (_isVisible != value) + { + _isVisible = value; + RaisePropertyChangedAuto(); + IsVisibleChanged?.Invoke(this, new EventArgs()); + } + } + } + + public bool IsLast + { + get + { + return ChartsCollection.Last() == this; + } + } + + public InsightsChart(ObservableCollection chartsCollection) + { + ChartsCollection = chartsCollection; + ChartsCollection.CollectionChanged += ChartsCollection_CollectionChanged; + RenderableSeries = new LineRenderableSeriesViewModel() { DrawNaNAs = LineDrawMode.Gaps }; + RenderableSeries.Stroke = Colors.DodgerBlue; + DataSeries = new XyDataSeries(); + RenderableSeries.DataSeries = DataSeries; + Annotations = new AnnotationCollection(); + } + + private void ChartsCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + RaisePropertyChanged(nameof(IsLast)); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsRubberBandXYZoomModifier.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsRubberBandXYZoomModifier.cs new file mode 100644 index 000000000..21f7ecc8f --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsRubberBandXYZoomModifier.cs @@ -0,0 +1,24 @@ +using SciChart.Charting.ChartModifiers; +using SciChart.Core.Utility.Mouse; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Tango.FSE.Insights.SciChart +{ + public class InsightsRubberBandXYZoomModifier : RubberBandXyZoomModifier + { + public override void OnModifierMouseDown(ModifierMouseArgs e) + { + //IsXAxisOnly = !e.IsMaster; + + if (Keyboard.Modifiers == ModifierKeys.Control) + { + base.OnModifierMouseDown(e); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsZoomPanModifier.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsZoomPanModifier.cs new file mode 100644 index 000000000..00bb7beea --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/SciChart/InsightsZoomPanModifier.cs @@ -0,0 +1,22 @@ +using SciChart.Charting.ChartModifiers; +using SciChart.Core.Utility.Mouse; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace Tango.FSE.Insights.SciChart +{ + public class InsightsZoomPanModifier : ZoomPanModifier + { + public override void OnModifierMouseDown(ModifierMouseArgs e) + { + if (!(Keyboard.Modifiers == ModifierKeys.Control)) + { + base.OnModifierMouseDown(e); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj index 83cb8cdef..623783f98 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Tango.FSE.Insights.csproj @@ -58,6 +58,34 @@ ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + False + ..\..\..\Referenced Assemblies\SciChart\SciChart.Charting.dll + + + False + ..\..\..\Referenced Assemblies\SciChart\SciChart.Charting.DrawingTools.dll + + + False + ..\..\..\Referenced Assemblies\SciChart\SciChart.Charting3D.dll + + + False + ..\..\..\Referenced Assemblies\SciChart\SciChart.Core.dll + + + False + ..\..\..\Referenced Assemblies\SciChart\SciChart.Data.dll + + + False + ..\..\..\Referenced Assemblies\SciChart\SciChart.Drawing.dll + + + False + ..\..\..\Referenced Assemblies\SciChart\SciChart.Drawing.DirectX.dll + @@ -78,6 +106,10 @@ + + + + @@ -127,6 +159,10 @@ {a34ee0f0-649d-41c8-8489-b6f1cc6924ee} Tango.Core + + {4a55c185-3f8d-41b0-8815-c15f6213a14a} + Tango.Insights + {4206ac58-3b57-4699-8835-90bf6db01a61} Tango.Integration @@ -165,6 +201,10 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + Designer MSBuild:Compile diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml new file mode 100644 index 000000000..4c8731fa1 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Themes/Generic.xaml @@ -0,0 +1,60 @@ + + + + + + + + + # + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs index 40b29c643..e5d09c282 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/ViewModels/InsightsViewVM.cs @@ -1,13 +1,479 @@ -using System; +using SciChart.Charting.Model.ChartSeries; +using SciChart.Charting.Visuals.Annotations; +using SciChart.Charting.Visuals.RenderableSeries; +using SciChart.Data.Model; +using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; using System.Linq; +using System.Reflection; using System.Text; +using System.Threading; using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Media; +using Tango.BL.Entities; +using Tango.BL.Enumerations; +using Tango.Core.Commands; using Tango.FSE.Common; +using Tango.FSE.Common.Insights; +using Tango.FSE.Insights.Contracts; +using Tango.FSE.Insights.SciChart; +using Tango.Logging; +using Tango.PMR.Insights; namespace Tango.FSE.Insights.ViewModels { - public class InsightsViewVM : FSEViewModel + public class InsightsViewVM : FSEViewModel { + private bool _chartsLoaded; + private ICollectionView _monitorsView; + + public RelayCommand GetInsightsCommand { get; set; } + + public ObservableCollection Charts { get; set; } + + public ObservableCollection VisibleCharts { get; set; } + + private DateTime _minDate; + public DateTime MinDate + { + get { return _minDate; } + set { _minDate = value; RaisePropertyChangedAuto(); } + } + + private DateTime _maxDate; + public DateTime MaxDate + { + get { return _maxDate; } + set { _maxDate = value; RaisePropertyChangedAuto(); } + } + + private DateTime? _startDate; + public DateTime? StartDate + { + get { return _startDate; } + set { _startDate = value; RaisePropertyChangedAuto(); } + } + + private DateTime? _startTime; + public DateTime? StartTime + { + get { return _startTime; } + set { _startTime = value; RaisePropertyChangedAuto(); } + } + + private DateTime? _endDate; + public DateTime? EndDate + { + get { return _endDate; } + set { _endDate = value; RaisePropertyChangedAuto(); } + } + + private DateTime? _endTime; + public DateTime? EndTime + { + get { return _endTime; } + set { _endTime = value; RaisePropertyChangedAuto(); } + } + + private InsightsHandler _handler; + public InsightsHandler Handler + { + get { return _handler; } + set { _handler = value; RaisePropertyChangedAuto(); } + } + + private IRange _visibleChartsRange; + public IRange VisibleChartsRange + { + get { return _visibleChartsRange; } + set { _visibleChartsRange = value; RaisePropertyChangedAuto(); } + } + + private String _monitorsFilter; + public String MonitorsFilter + { + get { return _monitorsFilter; } + set { _monitorsFilter = value; RaisePropertyChangedAuto(); OnMonitorsFilterChanged(); } + } + + private InsightsPackage _insightsPackage; + public InsightsPackage InsightsPackage + { + get { return _insightsPackage; } + set { _insightsPackage = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(InsightsPackageAvailable)); } + } + + public bool InsightsPackageAvailable + { + get { return InsightsPackage != null; } + } + + private bool _displayAnnotations; + public bool DisplayAnnotations + { + get { return _displayAnnotations; } + set { _displayAnnotations = value; RaisePropertyChangedAuto(); } + } + + private bool _isSearchBarOpened; + public bool IsSearchBarOpened + { + get { return _isSearchBarOpened; } + set { _isSearchBarOpened = value; RaisePropertyChangedAuto(); } + } + + public AnnotationCollection Annotations { get; set; } + + public InsightsViewVM() + { + IsSearchBarOpened = true; + Charts = new ObservableCollection(); + VisibleCharts = new ObservableCollection(); + Annotations = new AnnotationCollection(); + GetInsightsCommand = new RelayCommand(GetInsights, () => IsFree); + } + + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); + StartDate = DateTime.Now.AddDays(-7); + StartTime = new DateTime(1, 1, 1, 0, 0, 0); + EndDate = null; + EndTime = null; + } + + public async override void OnApplicationReady() + { + base.OnApplicationReady(); + + if (!_chartsLoaded) + { + try + { + var monitors = (await Services.TechComponentsService.Monitors.FindAll()).OrderBy(x => x.Description).ToList(); + + foreach (var monitor in monitors.Where(x => !x.MultiChannel).ToList()) + { + InsightsChart chart = new InsightsChart(VisibleCharts); + chart.Name = monitor.Name; + chart.Description = monitor.Description; + chart.InsightsMonitorsProperty = typeof(InsightsMonitors).GetProperty(((TechMonitors)monitor.Code).ToString(), BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + chart.IsVisibleChanged += Chart_IsVisibleChanged; + chart.DataSeries.Append(GetDemoDates(), GetDemoValues()); + Charts.Add(chart); + } + + foreach (var chart in Charts.ToList().Where(x => x.InsightsMonitorsProperty == null)) + { + Charts.Remove(chart); + LogManager.Log($"Error loading insights chart '{chart.Name}'. Could not find property on InsightsMonitors.", LogCategory.Error); + } + + _monitorsView = CollectionViewSource.GetDefaultView(Charts); + _monitorsView.Filter = (x) => + { + if (!MonitorsFilter.IsNotNullOrEmpty()) return true; + + InsightsChart chart = x as InsightsChart; + if (chart != null) + { + return chart.Description.ToLower().Contains(MonitorsFilter.ToLower()); + } + + return false; + }; + + _chartsLoaded = true; + } + catch (Exception ex) + { + //TODO: Report Insights module error with BugReporting Snackbar... + } + } + } + + public override void OnNavigatedTo() + { + base.OnNavigatedTo(); + MinDate = DateTime.Now.AddDays(-30); + MaxDate = DateTime.Now; + } + + private async void GetInsights() + { + if (StartDate == null) + { + await NotificationProvider.ShowError("Please specify start date before trying to get insights."); + return; + } + + DateTime? start = null; + + if (StartTime != null) + { + start = + new DateTime( + StartDate.Value.Year, + StartDate.Value.Month, + StartDate.Value.Day, + StartTime.Value.Hour, + StartTime.Value.Minute, + StartTime.Value.Second); + } + else + { + start = StartDate.Value.Date; + } + + DateTime? end = null; + + if (EndDate != null) + { + if (EndTime != null) + { + end = + new DateTime( + EndDate.Value.Year, + EndDate.Value.Month, + EndDate.Value.Day, + EndTime.Value.Hour, + EndTime.Value.Minute, + EndTime.Value.Second); + } + else + { + end = EndDate.Value.Date.AddDays(1); + } + } + else + { + end = DateTime.Now.AddDays(1); + } + + LogManager.Log($"Getting insights from '{start.Value}' to '{end.Value}'"); + + try + { + IsSearchBarOpened = false; + + using (var task = NotificationProvider.PushTaskItem("Getting insights from the remote machine...", false, () => + { + try + { + Handler?.Abort(); + } + catch (Exception ex) + { + throw; + } + })) + { + IsFree = false; + Handler = await InsightsProvider.GetInsights(start.Value.ToUniversalTime(), end.Value.ToUniversalTime()); + Handler.ProgressChanged += (x, e) => + { + task.UpdateProgress(e.Progress.Message, e.Progress.Value, e.Progress.Maximum, e.Progress.IsIndeterminate); + }; + + task.CanCancel = true; + + var package = await Handler.WaitForCompletion(); + + task.CanCancel = false; + + await LoadInsightsPackage(package); + } + } + catch (ThreadAbortException) + { + IsSearchBarOpened = true; + //Operation canceled by cancel button.. + } + catch (OperationCanceledException) + { + IsSearchBarOpened = true; + //Aborted by user... + } + catch (Exception ex) + { + IsSearchBarOpened = true; + LogManager.Log(ex, "Error getting insights."); + await NotificationProvider.ShowError($"Error occurred while trying to get insights.\n{ex.FlattenMessage()}"); + } + finally + { + IsFree = true; + } + } + + private async Task LoadInsightsPackage(InsightsPackage package) + { + LogManager.Log($"Insights received with {package.Frames.Count} frames."); + + await Task.Factory.StartNew(() => + { + foreach (var chart in Charts) + { + chart.DataSeries.Clear(); + + List dates = new List(); + List values = new List(); + + foreach (var frame in package.Frames) + { + var value = chart.InsightsMonitorsProperty.GetValue(frame.Monitors); + + dates.Add(frame.Frame.Time.ToLocalTime()); + + if (value != null) + { + values.Add((double)value); + } + else + { + values.Add(double.NaN); + } + } + + chart.DataSeries.Append(dates, values); + } + + + InvokeUI(() => + { + Annotations.Clear(); + + //Load annotations + bool disconnected = false; + int positiveFrameCounter = 0; + + foreach (var frame in package.Frames) + { + if (frame.Frame.IsEmpty) + { + if (!disconnected && positiveFrameCounter > 1) + { + disconnected = true; + AddMachineConnectedDisconnectedAnnotation(frame.Frame.Time.ToLocalTime(), false); + } + + positiveFrameCounter = 0; + } + else + { + positiveFrameCounter++; + + if (disconnected) + { + disconnected = false; + AddMachineConnectedDisconnectedAnnotation(frame.Frame.Time.ToLocalTime(), true); + } + } + } + + PlotInsightsEvents(package); + InsightsPackage = package; + View.ZoomExtents(); + }); + }); + } + + public void AddMachineConnectedDisconnectedAnnotation(DateTime date, bool connected) + { + VerticalLineAnnotation line = new VerticalLineAnnotation(); + line.StrokeThickness = 2; + line.Stroke = connected ? Brushes.Green : Brushes.Red; + line.X1 = date; + line.X2 = date; + line.ShowLabel = false; + line.AnnotationLabels.Add(new AnnotationLabel() + { + LabelPlacement = LabelPlacement.TopRight, + Text = connected ? "machine connected" : "machine disconnected" + }); + Annotations.Add(line); + } + + private void PlotInsightsEvents(InsightsPackage package) + { + double y = 0.05; + + foreach (var ev in package.Events) + { + CustomAnnotation eventBox = new CustomAnnotation(); + eventBox.X1 = ev.Time.ToLocalTime(); + eventBox.Y1 = y; + eventBox.CoordinateMode = AnnotationCoordinateMode.RelativeY; + eventBox.Content = ev.EventType; + eventBox.ContentTemplate = Application.Current.Resources["InsightEventTemplate"] as DataTemplate; + Annotations.Add(eventBox); + + y += 0.05; + + if (y > 0.95) + { + y = 0.05; + } + } + } + + private void Chart_IsVisibleChanged(object sender, EventArgs e) + { + InsightsChart chart = sender as InsightsChart; + + if (chart.IsVisible) + { + VisibleCharts.Add(chart); + } + else + { + VisibleCharts.Remove(chart); + } + } + + private void OnMonitorsFilterChanged() + { + _monitorsView?.Refresh(); + } + + private List GetDemoDates() + { + List dates = new List(); + + for (int i = 0; i < 30; i++) + { + dates.Add(DateTime.Now.AddDays(-30).AddDays(i)); + } + + return dates; + } + + private List GetDemoValues() + { + List values = new List(); + + int counter2 = 0; + + for (int i = 0; i < 30; i++) + { + if (counter2 == 2) + { + values.Add(double.NaN); + counter2 = 0; + } + else + { + values.Add(i); + counter2++; + } + } + + return values; + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml index be3211e78..c70656c00 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml @@ -7,55 +7,234 @@ xmlns:vm="clr-namespace:Tango.FSE.Insights.ViewModels" xmlns:local="clr-namespace:Tango.FSE.Insights.Views" xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:insights="clr-namespace:Tango.FSE.Insights.SciChart" + xmlns:s="http://schemas.abtsoftware.co.uk/scichart" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" mc:Ignorable="d" d:DesignHeight="1080" d:DesignWidth="1920" d:DataContext="{d:DesignInstance Type=vm:InsightsViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.InsightsViewVM}"> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml.cs index 3d17caa97..e9107e100 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Insights/Views/InsightsView.xaml.cs @@ -1,4 +1,5 @@ -using System; +using SciChart.Charting.Visuals; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -12,17 +13,42 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using Tango.FSE.Insights.Contracts; namespace Tango.FSE.Insights.Views { /// /// Interaction logic for InsightsView.xaml /// - public partial class InsightsView : UserControl + public partial class InsightsView : UserControl, IInsightsView { public InsightsView() { InitializeComponent(); + this.Register(); + } + + private void SciChartSurface_Loaded(object sender, RoutedEventArgs e) + { + Grid grid = sender as Grid; + + if (grid != null) + { + SciChartSurface chart = grid.FindChild(); + + if (chart != null) + { + chart.ZoomExtents(); + } + } + } + + public void ZoomExtents() + { + foreach (var chart in chartsItemsControl.FindVisualChildren()) + { + chart.ZoomExtents(); + } } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityFrameworkExtensionsHelper.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityFrameworkExtensionsHelper.cs new file mode 100644 index 000000000..0f5ce3cf1 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityFrameworkExtensionsHelper.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.BL +{ + public static class EntityFrameworkExtensionsHelper + { + public static void SetupLicense(String licenseName, String licenseKey) + { + Z.EntityFramework.Extensions.LicenseManager.AddLicense(licenseName, licenseKey); + + string licenseErrorMessage; + if (!Z.EntityFramework.Extensions.LicenseManager.ValidateLicense(out licenseErrorMessage)) + { + throw new Exception(licenseErrorMessage); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj b/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj index b1b0b300e..b28f8b45a 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Tango.FSE.BL.csproj @@ -83,6 +83,7 @@ + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs index 07d2a7a5b..efe9e877a 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs @@ -44,6 +44,7 @@ using Tango.FSE.Common.RemoteJob; using Tango.FSE.Common.WindowsManager; using Tango.FSE.Common.DemoMode; using Tango.FSE.Common.FileAssociation; +using Tango.FSE.Common.Insights; namespace Tango.FSE.Common { @@ -235,6 +236,12 @@ namespace Tango.FSE.Common [TangoInject] public IFileAssociationProvider FileAssociationProvider { get; set; } + /// + /// Gets or sets the insights provider. + /// + [TangoInject] + public IInsightsProvider InsightsProvider { get; set; } + /// /// Gets or sets the FSE service. /// diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs index a97a44f81..32c795ffc 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FileSystem/IFileSystemProvider.cs @@ -49,9 +49,19 @@ namespace Tango.FSE.Common.FileSystem /// /// The file or folder. /// The local target folder or file. - /// Indicates whether the localTargetFolder is a file. + /// Indicates whether the localTargetFolder is a file. /// - Task Download(FileSystemItem item, String localTargetFolderOrFile, bool isSingleFile = false); + Task Download(FileSystemItem item, String localTargetFolderOrFile, bool isLocaTargetFile = false); + + /// + /// Downloads the specified file or folder item. + /// + /// The remote file or folder. + /// Indicates whether the remote path is a file. + /// The local target folder or file. + /// Indicates whether the localTargetFolder is a file. + /// + Task Download(String remotePath, bool isRemotePathFile, String localTargetFolderOrFile, bool isLocalTargetFile = false); /// /// Uploads the specified local file or folder. diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/IInsightsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/IInsightsProvider.cs new file mode 100644 index 000000000..f90e398fd --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/IInsightsProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.Insights +{ + public interface IInsightsProvider + { + Task GetInsights(DateTime startDateUTC, DateTime endTimeUTC); + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandler.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandler.cs new file mode 100644 index 000000000..a263a50bb --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandler.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.FSE.Common.Insights +{ + public class InsightsHandler : ExtendedObject + { + private Action _abortAction; + private TaskCompletionSource _completionSource; + private bool _completed; + + public event EventHandler StatusChanged; + public event EventHandler> ProgressChanged; + public event EventHandler Completed; + + + private InsightsHandlerStatus _status; + public InsightsHandlerStatus Status + { + get { return _status; } + set + { + if (_status != value) + { + _status = value; + RaisePropertyChangedAuto(); + StatusChanged?.Invoke(this, _status); + } + } + } + + private TangoProgress _progress; + public TangoProgress Progress + { + get { return _progress; } + set + { + _progress = value; RaisePropertyChangedAuto(); + + if (_progress != null) + { + ProgressChanged?.Invoke(this, new TangoProgressChangedEventArgs(_progress)); + } + } + } + + private Exception _failedException; + public Exception FailedException + { + get { return _failedException; } + set { _failedException = value; RaisePropertyChangedAuto(); } + } + + public InsightsHandler(Action abortAction) + { + _completionSource = new TaskCompletionSource(); + _abortAction = abortAction; + Progress = new TangoProgress("Initializing..."); + } + + public void Abort() + { + if (!_completed) + { + _completed = true; + _abortAction?.Invoke(); + Status = InsightsHandlerStatus.Aborted; + _completionSource.SetException(new OperationCanceledException()); + } + } + + public void RaiseFailed(Exception ex) + { + if (!_completed) + { + _completed = true; + FailedException = ex; + Status = InsightsHandlerStatus.Failed; + _completionSource.SetException(ex); + } + } + + public void RaiseCompleted(InsightsPackage package) + { + if (!_completed) + { + _completed = true; + Status = InsightsHandlerStatus.Completed; + Completed?.Invoke(this, package); + _completionSource.SetResult(package); + } + } + + public Task WaitForCompletion() + { + return _completionSource.Task; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandlerStatus.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandlerStatus.cs new file mode 100644 index 000000000..ec911b836 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsHandlerStatus.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.Common.Insights +{ + public enum InsightsHandlerStatus + { + Initializing, + Downloading, + Composing, + Completed, + Failed, + Aborted, + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs new file mode 100644 index 000000000..96718f6bf --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsPackage.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Insights; + +namespace Tango.FSE.Common.Insights +{ + public class InsightsPackage + { + public List Frames { get; set; } + public List Events { get; set; } + + public InsightsPackage() + { + Frames = new List(); + Events = new List(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyEvent.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyEvent.cs new file mode 100644 index 000000000..0378e6a5a --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyEvent.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; + +namespace Tango.FSE.Common.Insights +{ + public class InsightsReadyEvent + { + public DateTime Time { get; set; } + public EventType EventType { get; set; } + + public override string ToString() + { + return $"{Time}: {EventType.Name}"; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyFrame.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyFrame.cs new file mode 100644 index 000000000..b4ad8ec50 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Insights/InsightsReadyFrame.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Insights; +using Tango.PMR.Insights; + +namespace Tango.FSE.Common.Insights +{ + public class InsightsReadyFrame + { + public InsightsFrame Frame { get; private set; } + public InsightsMonitors Monitors { get; private set; } + + public InsightsReadyFrame(InsightsFrame frame) + { + Frame = frame; + Monitors = frame.ToInsightsMonitors(); + } + + public override string ToString() + { + return $"{Frame.Time}: {Monitors.ToString()}"; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/INotificationProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/INotificationProvider.cs index 5fff158fd..1a5026e8e 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/INotificationProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/INotificationProvider.cs @@ -257,8 +257,10 @@ namespace Tango.FSE.Common.Notifications /// Pushes the task item with the specified message. /// /// The message. + /// Indicates whether the cancel button will be enabled. + /// Specify the action to execute when cancel button is pressed. /// - TaskItem PushTaskItem(String message); + TaskItem PushTaskItem(String message, bool canCancel = false, Action cancelAction = null); /// /// Pops the task item. diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/TaskItem.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/TaskItem.cs index 048374727..9492433f6 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/TaskItem.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Notifications/TaskItem.cs @@ -22,10 +22,10 @@ namespace Tango.FSE.Common.Notifications } private bool _hasCancel; - public bool HasCancel + public bool CanCancel { get { return _hasCancel; } - set { _hasCancel = value; RaisePropertyChangedAuto(); } + set { _hasCancel = value; RaisePropertyChangedAuto(); CancelCommand?.RaiseCanExecuteChanged(); } } public RelayCommand CancelCommand { get; set; } @@ -43,7 +43,12 @@ namespace Tango.FSE.Common.Notifications public TaskItem(String message, Action cancelAction) : this(message) { _cancelAction = cancelAction; - HasCancel = true; + CancelCommand = new RelayCommand(() => + { + CanCancel = false; + cancelAction?.Invoke(); + }, () => CanCancel); + CanCancel = true; } public void UpdateProgress(String message, double value = 0, double maximum = 100, bool isIndeterminate = true) diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml index dce8bea15..922790d5e 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml @@ -44,4 +44,5 @@ + \ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj index 0584d2e0b..d2208615b 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Tango.FSE.Common.csproj @@ -85,6 +85,34 @@ ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Charting.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Charting.DrawingTools.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Charting3D.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Core.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Data.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Drawing.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Drawing.DirectX.dll + @@ -198,6 +226,12 @@ + + + + + + @@ -470,6 +504,10 @@ {c6ebbbbe-2123-44dc-aef7-a0d47d736ac0} Tango.FileSystem + + {4A55C185-3F8D-41B0-8815-C15F6213A14A} + Tango.Insights + {4206ac58-3b57-4699-8835-90bf6db01a61} Tango.Integration @@ -569,6 +607,7 @@ + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml index 73680103b..fc6f427c1 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:dragablz="clr-namespace:Dragablz;assembly=Dragablz" + xmlns:s="http://schemas.abtsoftware.co.uk/scichart" xmlns:local="clr-namespace:Tango.FSE.UI" StartupUri="MainWindow.xaml"> @@ -92,12 +93,24 @@ + + + + + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs index de0594703..047df9f50 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using SciChart.Charting.Visuals; using System; using System.Collections.Generic; using System.Configuration; @@ -13,6 +14,7 @@ using System.Windows; using System.Windows.Markup; using Tango.Core.DI; using Tango.Core.Helpers; +using Tango.FSE.BL; using Tango.FSE.Common; using Tango.FSE.Common.BugReporting; using Tango.FSE.Common.FileAssociation; @@ -131,6 +133,24 @@ namespace Tango.FSE.UI WebRequest.DefaultWebProxy = null; + try + { + EntityFrameworkExtensionsHelper.SetupLicense("4578;101-twine-s.com", "9d23b66f-1101-b253-7f8a-59ae011b2ee8"); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error performing EF extensions license setup."); + } + + try + { + SciChartSurface.SetRuntimeLicenseKey("27FuI+bWcfmLHSBlM4B8nUs23aeeXvft2+7Pxj0fOrcnruWXyOm/swjI2PpoBPOKS9dNVtw60E4Xdpq4Ts8UgMWQHU8qcJtPoAyNQqbVMQNOr/sv1QpSD2mRjogERcrGty+tvlCHMGhkw/TOiL5DPnw5rOPqGfymyRuJRNFTTYB/hCIAiCt7VIlyHhO+uo0DOfxIC+gNVKoWyGd0xdQ3xSUmfdNvUigW7ZkUKDkAIBpRcmOLx5wV4y77I/4MghTl3FAZlhhFoBdAUKLZWpbISU8xfAUkI1s/md0mAztMTbqzkRT94AsSI1/KPnH7fuuH82ABJcp0UnKWh8aIlkbjD2vVCKXn9omMBEBRmTx68IuHoP4iT5mTyd6R3OfnEM6Vc6AZ9SLytjoP7Iu2hPKR7uqGJW/2KZ0jIZ4Hn+bJfl23fBexgJl4jK33aeIIkw/Og67w/CRK4MgiHtSLp7x1I3Fsmw8EYbQ2nZe3lA4SH1DU"); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error settings SciChart runtime license."); + } + base.OnStartup(e); exceptionTrapper = new WpfGlobalExceptionTrapper(); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs index 6e1ec93a6..55866361b 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Connection/DefaultMachineProvider.cs @@ -162,7 +162,7 @@ namespace Tango.FSE.UI.Connection { _machineEventsStateProvider = new FSEMachineEventsStateProvider(); - MachineOperator = new ExternalBridgeTcpClient("N/A", "N/A"); + MachineOperator = new ExternalBridgeTcpClient("N/A", "N/A", false); MachineOperator.MachineEventsStateProvider = _machineEventsStateProvider; MachineOperator.StateChanged += MachineOperator_StateChanged; MachineOperator.As().SessionClosed += DefaultMachineProvider_SessionClosed; @@ -185,7 +185,7 @@ namespace Tango.FSE.UI.Connection { try { - LogManager.Log($"Connecting to machine '{machine.GetType().Name}' => '{machine.SerialNumber}' => '{machine.Adapter?.Address}'..."); + LogManager.Log($"Connecting to machine '{machine.GetType().Name}' => '{machine.SerialNumber}' => '{machine.Adapter?.Address}' => {(machine.CompressionEnabled ? "Compression Enabled" : "Compression Disabled")}..."); IsBusy = true; diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Controls/NotificationsControl.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Controls/NotificationsControl.xaml index a0715a96f..4e6ada6b5 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Controls/NotificationsControl.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Controls/NotificationsControl.xaml @@ -267,7 +267,7 @@ - + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs index 6673a5ae3..e7f9772ff 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/FileSystem/DefaultFileSystemProvider.cs @@ -167,7 +167,10 @@ namespace Tango.FSE.UI.FileSystem Priority = QueuePriority.Low }); - _webRtcTransporter = new BasicTransporter(new WebRtcTransportAdapter(_machineProvider.MachineOperator, WebRtcTransportAdapterMode.Active, WEB_RTC_CHANNEL_NAME)); + _webRtcTransporter = new BasicTransporter(new WebRtcTransportAdapter(_machineProvider.MachineOperator, WebRtcTransportAdapterMode.Active, WEB_RTC_CHANNEL_NAME) + { + EnableCompression = _machineProvider.MachineOperator.CompressionEnabled, + }); _webRtcTransporter.UseKeepAlive = false; _webRtcTransporter.ComponentName = "File System Active WebRTC Transporter"; await _webRtcTransporter.Connect(); @@ -272,11 +275,12 @@ namespace Tango.FSE.UI.FileSystem /// /// Downloads the specified file or folder item. /// - /// The file or folder. + /// The remote file or folder. + /// Indicates whether the remote path is a file. /// The local target folder or file. - /// Indicates whether the localTargetFolder is a file. + /// Indicates whether the localTargetFolder is a file. /// - public Task Download(FileSystemItem item, String localTargetFolderOrFile, bool isSingleFile = false) + public Task Download(FileSystemItem item, String localTargetFolderOrFile, bool isLocalTargetFile = false) { AuthenticationProvider.ThrowIfNoPermission(Permissions.FSE_PPCFileSystemRead); @@ -289,7 +293,7 @@ namespace Tango.FSE.UI.FileSystem FileSystemHandler handler = null; - if (isSingleFile) + if (isLocalTargetFile) { destination = localTargetFolderOrFile; } @@ -536,6 +540,32 @@ namespace Tango.FSE.UI.FileSystem return Task.FromResult(handler); } + /// + /// Downloads the specified file or folder item. + /// + /// The remote file or folder. + /// Indicates whether the remote path is a file. + /// The local target folder or file. + /// Indicates whether the localTargetFolder is a file. + /// + public Task Download(String remotePath, bool isRemotePathFile, String localTargetFolderOrFile, bool isLocalTargetFile = false) + { + FileSystemItem item = null; + + if (isRemotePathFile) + { + item = new FileItem(); + } + else + { + item = new FolderItem(); + } + + item.Path = remotePath; + + return Download(item, localTargetFolderOrFile, isLocalTargetFile); + } + /// /// Uploads the specified local file or folder. /// diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs new file mode 100644 index 000000000..1e9996bd2 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Insights/DefaultInsightsProvider.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Entities; +using Tango.Core; +using Tango.Core.DI; +using Tango.FSE.BL; +using Tango.FSE.Common.Connection; +using Tango.FSE.Common.FileSystem; +using Tango.FSE.Common.Insights; +using Tango.Insights; +using Tango.PPC.Shared.Insights; + +namespace Tango.FSE.UI.Insights +{ + public class DefaultInsightsProvider : ExtendedObject, IInsightsProvider + { + [TangoInject] + private IMachineProvider MachineProvider { get; set; } + + [TangoInject] + private IFileSystemProvider FileSystemProvider { get; set; } + + [TangoInject] + private FSEServicesContainer Services { get; set; } + + public async Task GetInsights(DateTime startDateUTC, DateTime endTimeUTC) + { + InsightsHandler handler = null; + + var response = await MachineProvider.MachineOperator.SendGenericRequest(new InsightsRequest() + { + StartDateUTC = startDateUTC, + EndDateUTC = endTimeUTC + }, new Transport.TransportRequestConfig() + { + Timeout = TimeSpan.FromMinutes(1), + }); + + var insightsFilePath = TemporaryManager.CreateImaginaryFile(".insights"); + var fileSystemHandler = await FileSystemProvider.Download(response.InisightsFilePath, true, insightsFilePath, true); + + handler = new InsightsHandler(() => + { + fileSystemHandler.Abort(); + }); + + fileSystemHandler.StatusChanged += (x, status) => + { + if (status == FileSystemHandlerStatus.Downloading) + { + handler.Status = InsightsHandlerStatus.Downloading; + } + else if (status == FileSystemHandlerStatus.Completed) + { + Task.Factory.StartNew(() => + { + try + { + handler.Progress = new TangoProgress("Composing insights..."); + + handler.Status = InsightsHandlerStatus.Composing; + + var package = new InsightsPackage(); + + var insightsFile = InsightsFile.FromFile(insightsFilePath); + + int progress = 0; + + foreach (var frame in insightsFile.Frames.OrderBy(xx => xx.Time)) + { + if (handler.Status == InsightsHandlerStatus.Aborted) + { + return; + } + + package.Frames.Add(new InsightsReadyFrame(frame)); + progress++; + handler.Progress = new TangoProgress("Composing insights...", false, progress, insightsFile.Frames.Count); + } + + handler.Progress = new TangoProgress("Composing insights..."); + + progress = 0; + + var eventTypes = Services.MachineEventsService.GetAllEventTypes().Result; + Dictionary eventsDictionary = new Dictionary(); + foreach (var eventType in eventTypes) + { + eventsDictionary.Add(eventType.Code, eventType); + } + + foreach (var ev in insightsFile.Events.OrderBy(xx => xx.Time)) + { + if (handler.Status == InsightsHandlerStatus.Aborted) + { + return; + } + + EventType eventType = eventsDictionary[ev.EventCode]; + package.Events.Add(new InsightsReadyEvent() + { + Time = ev.Time, + EventType = eventType, + }); + + progress++; + handler.Progress = new TangoProgress("Composing insights...", false, progress, insightsFile.Events.Count); + } + + handler.RaiseCompleted(package); + } + catch (Exception ex) + { + handler.RaiseFailed(ex); + } + }); + } + else if (status == FileSystemHandlerStatus.Failed) + { + handler.RaiseFailed(fileSystemHandler.FailedException); + } + }; + + fileSystemHandler.ProgressChanged += (x, e) => + { + e.Progress.Message = "Getting insights from the remote machine..."; + handler.Progress = e.Progress; + }; + + return handler; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs index 368752120..0ebf457eb 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Notifications/DefaultNotificationProvider.cs @@ -667,13 +667,22 @@ namespace Tango.FSE.UI.Notifications } /// - /// Pushes the task item. + /// Pushes the task item with the specified message. /// - /// + /// The message. + /// Indicates whether the cancel button will be enabled. + /// Specify the action to execute when cancel button is pressed. /// - public TaskItem PushTaskItem(String message) + public TaskItem PushTaskItem(String message, bool canCancel = false, Action cancelAction = null) { - return PushTaskItem(new TaskItem(message)); + if (canCancel || cancelAction != null) + { + return PushTaskItem(new TaskItem(message, cancelAction)); + } + else + { + return PushTaskItem(new TaskItem(message)); + } } /// diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml index e5791f23c..db2559a9d 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Panes/ConnectedMachinePane.xaml @@ -79,6 +79,8 @@ + + diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj index ee1b0bd29..24cbfd55f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj @@ -98,6 +98,34 @@ ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Charting.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Charting.DrawingTools.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Charting3D.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Core.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Data.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Drawing.dll + + + False + ..\..\Referenced Assemblies\SciChart\SciChart.Drawing.DirectX.dll + ..\..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll @@ -277,6 +305,7 @@ + @@ -613,6 +642,10 @@ {c6ebbbbe-2123-44dc-aef7-a0d47d736ac0} Tango.FileSystem + + {4A55C185-3F8D-41B0-8815-C15F6213A14A} + Tango.Insights + {4206AC58-3B57-4699-8835-90BF6DB01A61} Tango.Integration diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs index 25d0b45c9..5da32809f 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModelLocator.cs @@ -66,6 +66,8 @@ using Tango.FSE.Common.SQL; using Tango.FSE.UI.SQL; using Tango.FSE.Common.FileAssociation; using Tango.FSE.UI.FileAssociation; +using Tango.FSE.Common.Insights; +using Tango.FSE.UI.Insights; namespace Tango.FSE.UI { @@ -104,6 +106,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Unregister(); TangoIOC.Default.Unregister(); TangoIOC.Default.Unregister(); + TangoIOC.Default.Unregister(); //TangoIOC.Default.Unregister(); //TangoIOC.Default.Unregister(); //TangoIOC.Default.Unregister(); @@ -142,6 +145,7 @@ namespace Tango.FSE.UI TangoIOC.Default.Register(); TangoIOC.Default.Register(); TangoIOC.Default.Register(); + TangoIOC.Default.Register(); TangoIOC.Default.Register(); diff --git a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml index 4f7385513..d436c58b7 100644 --- a/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml +++ b/Software/Visual_Studio/PPC/Modules/Tango.PPC.MachineSettings/Views/MainView.xaml @@ -296,12 +296,17 @@ + + External Bridge Transport Compression + + + Enable External Bridge SignalR - + External Bridge SignalR Hub @@ -328,6 +333,26 @@ + + Enable Insights + + + + + Insights Sampling Interval (sec) + + + + + Insights Storage Cleanup Interval (min) + + + + + Insights Max Storage Duration (days) + + + diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs index 6eaeb58a0..236c066e3 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/ExternalBridge/PPCExternalBridgeService.cs @@ -53,6 +53,7 @@ namespace Tango.PPC.Common.ExternalBridge applicationManager.ApplicationReady += (_, __) => { var settings = SettingsManager.Default.GetOrCreate(); + EnableTransportCompression = settings.EnableExternalBridgeTransportCompression; MachineOperator = machineProvider.MachineOperator; Machine = machineProvider.Machine; SignalRConfiguration.Enabled = settings.EnableExternalBridgeSignalR; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs index 86506abcf..958c1aa12 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/FileSystem/DefaultFileSystemService.cs @@ -15,6 +15,7 @@ using Tango.Integration.Operation; using Tango.Logging; using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Shared.Logs; +using Tango.Settings; using Tango.Transport; using Tango.Transport.Transporters; using Tango.WebRTC; @@ -33,6 +34,7 @@ namespace Tango.PPC.Common.FileSystem private FileSystemManager _manager; private Dictionary _operations; private Dictionary _webRtcClients; + private bool _enableCompression; public bool Enabled { get; set; } = true; public bool EnableWebRTC { get; set; } = true; @@ -43,6 +45,7 @@ namespace Tango.PPC.Common.FileSystem _manager = new FileSystemManager(); _operations = new Dictionary(); externalBridge.RegisterRequestHandler(this); + _enableCompression = SettingsManager.Default.GetOrCreate().EnableExternalBridgeTransportCompression; } [ExternalBridgeRequestHandlerMethod(typeof(InitWebRtcRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] @@ -66,7 +69,10 @@ namespace Tango.PPC.Common.FileSystem } LogManager.Log("Initializing WebRTC transport adapter on 'Passive' mode."); - var webRtcAdapter = new WebRtcTransportAdapter(receiver, WebRtcTransportAdapterMode.Passive, request.DataChannelName); + var webRtcAdapter = new WebRtcTransportAdapter(receiver, WebRtcTransportAdapterMode.Passive, request.DataChannelName) + { + EnableCompression = _enableCompression + }; webRtcAdapter.Ready += (x, e) => { LogManager.Log("The file system service WebRTC channel is ready."); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs index bfbf7114f..24852d853 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Insights/DefaultInsightsService.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.BL; using Tango.Core; using Tango.Core.DI; using Tango.Insights; @@ -74,6 +75,8 @@ namespace Tango.PPC.Common.Insights { var frames = InsightsManager.Default.GetFrames(request.StartDateUTC, request.EndDateUTC); insightsFile.Frames = frames; + insightsFile.Events = InsightsManager.Default.GetEvents(request.StartDateUTC, request.EndDateUTC); + insightsFile.ToFile(filePath); }); diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs index 9afbb52b6..bd21b3bb0 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/PPCSettings.cs @@ -60,6 +60,11 @@ namespace Tango.PPC.Common /// public String ExternalBridgePassword { get; set; } + /// + /// Gets or sets a value indicating whether to enable transport compression for external bridge clients. + /// + public bool EnableExternalBridgeTransportCompression { get; set; } + /// /// Gets or sets a value indicating whether [enable hot spot]. /// @@ -296,6 +301,7 @@ namespace Tango.PPC.Common EmbeddedComPort = "COM10"; EmbeddedDeviceHint = "Tango USB Serial Port"; ExternalBridgePassword = "Aa123456"; + EnableExternalBridgeTransportCompression = true; HotSpotPassword = "Aa123456"; LockScreenTimeout = TimeSpan.FromMinutes(10); LockScreenPassword = "1111"; diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml index 955a584c2..806a94bb0 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Resources/Merged.xaml @@ -54,6 +54,7 @@ +