diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-18 05:54:15 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-18 05:54:15 +0300 |
| commit | 6e172dd3bc3e2388e532fd43381896f15abaed70 (patch) | |
| tree | 37dfa0969c9a329ffc503034eda22be4e4168a6c /Software | |
| parent | 477b07b197242605f3fbfc65838dac3995736e13 (diff) | |
| download | Tango-6e172dd3bc3e2388e532fd43381896f15abaed70.tar.gz Tango-6e172dd3bc3e2388e532fd43381896f15abaed70.zip | |
Working on diagnostics.
Diffstat (limited to 'Software')
20 files changed, 770 insertions, 45 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs index 7b0b47893..b91da83c2 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs @@ -43,6 +43,21 @@ namespace Tango.FSE.Diagnostics.Project public int ColumnSpan { get; set; } public int RowSpan { get; set; } + private bool _isVisible; + public bool IsVisible + { + get { return _isVisible; } + set + { + if (_isVisible != value) + { + _isVisible = value; + OnVisibleChanged(_isVisible); + RaisePropertyChangedAuto(); + } + } + } + public DiagnosticsWidget() { TangoIOC.Default.Inject(this); @@ -53,9 +68,11 @@ namespace Tango.FSE.Diagnostics.Project } - public virtual void OnDiagnosticsData(DiagnosticsPackage package) + public abstract void OnDiagnosticsData(DiagnosticsPackage package); + + protected virtual void OnVisibleChanged(bool isVisible) { - //Called when diagnostics data is available + //Called when the widget visibility changed. } public abstract FrameworkElement GetView(); diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidget.cs new file mode 100644 index 000000000..25425a683 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidget.cs @@ -0,0 +1,113 @@ +using RealTimeGraphX.DataPoints; +using RealTimeGraphX.WPF; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; + +namespace Tango.FSE.Diagnostics.Project.Widgets +{ + public class RealTimeGraphMultiChannelWidget : RealTimeGraphWidget + { + public async override Task Init() + { + await base.Init(); + + if (!TechMonitor.MultiChannel) + { + throw new InvalidOperationException($"Cannot initialize a real-time graph multi channel widget using the single channel monitor '{Monitor}'."); + } + + Controller.DataSeriesCollection.Clear(); + + for (int i = 0; i < TechMonitor.ChannelCount; i++) + { + Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() + { + Name = $"{TechMonitor.Name.First()}{i + 1}", + Stroke = Colors.DodgerBlue, + }); + } + + MachineProvider.MachineConnected -= MachineProvider_MachineConnected; + MachineProvider.MachineConnected += MachineProvider_MachineConnected; + } + + public override FrameworkElement GetView() + { + return new RealTimeGraphMultiChannelWidgetView() { DataContext = this }; + } + + private void MachineProvider_MachineConnected(object sender, Common.Connection.MachineConnectedEventArgs e) + { + try + { + foreach (var pack in MachineProvider.Machine.Configuration.NoneEmptyIdsPacks.OrderBy(x => x.PackIndex).ToList()) + { + Color color = Colors.DodgerBlue; + + if (pack.LiquidType.LiquidTypeColor == Colors.Black) + { + color = Colors.Gray; + } + else if (pack.LiquidType.LiquidTypeColor == Colors.Transparent) + { + color = Colors.White; + } + else + { + color = pack.LiquidType.LiquidTypeColor; + } + + Controller.DataSeriesCollection[pack.PackIndex].Name = pack.LiquidType.Name; + Controller.DataSeriesCollection[pack.PackIndex].Stroke = color; + } + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error initializing colors for real-time multi channel graph data series collection '{Monitor}'."); + } + } + + public override void OnDiagnosticsData(DiagnosticsPackage package) + { + var matrix = package.GetMonitorMatrix(Monitor); + + if (matrix.Count > 0) + { + var firstPoints = matrix.First(); + + if (matrix.Any(x => x.Count > 0)) + { + List<TimeSpanDataPoint> dates = new List<TimeSpanDataPoint>(); + + DateTime dayStart = new DateTime(package.Frame.DiagnosticsTime.Year, package.Frame.DiagnosticsTime.Month, package.Frame.DiagnosticsTime.Day); + TimeSpan offset = package.Frame.DiagnosticsTime - dayStart; + + for (int i = 0; i < firstPoints.Count; i++) + { + dates.Add( + offset + .Add(TimeSpan.FromMilliseconds(-package.Frame.Delta.TotalMilliseconds)) + .Add(TimeSpan.FromMilliseconds(package.Frame.Delta.TotalMilliseconds * (i / (double)firstPoints.Count)))); + } + + List<List<TimeSpanDataPoint>> datesMatrix = new List<List<TimeSpanDataPoint>>(); + List<List<DoubleDataPoint>> pointsMatrix = new List<List<DoubleDataPoint>>(); + + foreach (var points in matrix) + { + datesMatrix.Add(dates); + pointsMatrix.Add(points.Select(x => new DoubleDataPoint(x)).ToList()); + } + + Controller.PushData(datesMatrix, pointsMatrix); + } + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml new file mode 100644 index 000000000..a248ac6e4 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml @@ -0,0 +1,53 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannelWidgetView" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Project.Widgets" + xmlns:graphs="clr-namespace:Tango.FSE.Common.Graphs;assembly=Tango.FSE.Common" + mc:Ignorable="d" + d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=local:RealTimeGraphMultiChannelWidget,IsDesignTimeCreatable=False}"> + <Grid> + <DockPanel> + <Border Margin="2 0 0 0" DockPanel.Dock="Right" HorizontalAlignment="Right" BorderThickness="1" BorderBrush="{StaticResource FSE_RealTimeGraph_OuterBorderBrush}" Background="{StaticResource FSE_RealTimeGraph_BackgroundBrush}" CornerRadius="5" TextElement.FontSize="{StaticResource FSE_SmallerFontSize}" Padding="5" MaxWidth="83"> + <ItemsControl ItemsSource="{Binding Controller.DataSeriesCollection}"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <ToggleButton IsChecked="{Binding IsVisible}" Cursor="Hand"> + <ToggleButton.Template> + <ControlTemplate> + <StackPanel Orientation="Horizontal" Margin="0 2" Background="Transparent"> + <Ellipse Width="10" Height="10"> + <Ellipse.Style> + <Style TargetType="Ellipse"> + <Setter Property="Fill" Value="Black"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsVisible}" Value="True"> + <Setter Property="Fill"> + <Setter.Value> + <SolidColorBrush Color="{Binding Stroke}" /> + </Setter.Value> + </Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Ellipse.Style> + </Ellipse> + <TextBlock Margin="5 0 0 0" Text="{Binding Name}"> + <TextBlock.Foreground> + <SolidColorBrush Color="{Binding Stroke}" /> + </TextBlock.Foreground> + </TextBlock> + </StackPanel> + </ControlTemplate> + </ToggleButton.Template> + </ToggleButton> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </Border> + + <graphs:RealTimeGraph Controller="{Binding Controller}" HorizontalTicks="7" VerticalTicks="5" /> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml.cs new file mode 100644 index 000000000..944f73dc3 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphMultiChannelWidgetView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Tango.FSE.Diagnostics.Project.Widgets +{ + /// <summary> + /// Interaction logic for RealTimeGraphWidgetView.xaml + /// </summary> + public partial class RealTimeGraphMultiChannelWidgetView : UserControl + { + public RealTimeGraphMultiChannelWidgetView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidget.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidget.cs index 21316b567..3f8a12182 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidget.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidget.cs @@ -16,7 +16,7 @@ namespace Tango.FSE.Diagnostics.Project.Widgets { public class RealTimeGraphWidget : DiagnosticsWidget { - public TechMonitors Monitor { get; set; } = TechMonitors.Dancer2Angle; + public TechMonitors Monitor { get; set; } [JsonIgnore] public TechMonitor TechMonitor { get; private set; } @@ -30,6 +30,7 @@ namespace Tango.FSE.Diagnostics.Project.Widgets Controller.Range.AutoY = true; Controller.Range.MaximumX = TimeSpan.FromSeconds(60); Controller.RefreshRate = TimeSpan.FromMilliseconds(100); + Controller.DisableRendering = true; Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() { @@ -48,9 +49,15 @@ namespace Tango.FSE.Diagnostics.Project.Widgets return new RealTimeGraphWidgetView() { DataContext = this }; } + protected override void OnVisibleChanged(bool isVisible) + { + base.OnVisibleChanged(isVisible); + + Controller.DisableRendering = !isVisible; + } + public override void OnDiagnosticsData(DiagnosticsPackage package) { - base.OnDiagnosticsData(package); var points = package.GetMonitorArray(Monitor); if (points.Count > 0) diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj index 2cd6cb8ba..b39213edf 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Tango.FSE.Diagnostics.csproj @@ -87,7 +87,11 @@ <Compile Include="Project\DiagnosticsProjectTabColumnDefinition.cs" /> <Compile Include="Project\DiagnosticsProjectTabRowDefinition.cs" /> <Compile Include="Project\DiagnosticsWidget.cs" /> + <Compile Include="Project\Widgets\RealTimeGraphMultiChannelWidget.cs" /> <Compile Include="Project\Widgets\RealTimeGraphWidget.cs" /> + <Compile Include="Project\Widgets\RealTimeGraphMultiChannelWidgetView.xaml.cs"> + <DependentUpon>RealTimeGraphMultiChannelWidgetView.xaml</DependentUpon> + </Compile> <Compile Include="Project\Widgets\RealTimeGraphWidgetView.xaml.cs"> <DependentUpon>RealTimeGraphWidgetView.xaml</DependentUpon> </Compile> @@ -195,6 +199,10 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> + <Page Include="Project\Widgets\RealTimeGraphMultiChannelWidgetView.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> <Page Include="Project\Widgets\RealTimeGraphWidgetView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs index e3566fd40..a439eeeee 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs @@ -18,6 +18,18 @@ namespace Tango.FSE.Diagnostics.ViewModels set { _tab = value; RaisePropertyChangedAuto(); } } + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set { _isSelected = value; RaisePropertyChangedAuto(); OnIsSelectedChanged(); } + } + + private void OnIsSelectedChanged() + { + Tab.Widgets.ToList().ForEach(x => x.IsVisible = IsSelected); + } + public void PopulateDiagnosticsData(DiagnosticsPackage package) { foreach (var widget in Tab.Widgets.ToList()) diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs index c14d2af16..9c5ebaa66 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs @@ -16,6 +16,7 @@ namespace Tango.FSE.Diagnostics.ViewModels public class DiagnosticsViewVM : FSEViewModel { private Dictionary<String, PropertyInfo> _monitorsProperties; + private bool _isLoaded; private DiagnosticsProject _project; public DiagnosticsProject Project @@ -25,13 +26,19 @@ namespace Tango.FSE.Diagnostics.ViewModels } private ObservableCollection<DiagnosticsTabViewVM> _tabs; - public ObservableCollection<DiagnosticsTabViewVM> Tabs { get { return _tabs; } set { _tabs = value; RaisePropertyChangedAuto(); } } + private DiagnosticsTabViewVM _selectedTab; + public DiagnosticsTabViewVM SelectedTab + { + get { return _selectedTab; } + set { _selectedTab = value; RaisePropertyChangedAuto(); OnSelectedTabChanged(); } + } + public DiagnosticsViewVM() { _monitorsProperties = new Dictionary<string, PropertyInfo>(); @@ -59,42 +66,72 @@ namespace Tango.FSE.Diagnostics.ViewModels public override void OnApplicationReady() { base.OnApplicationReady(); - LoadProject(); + + if (!_isLoaded) + { + LoadProject(); + } } private async void LoadProject() { - //TODO: Load project... + Project = DiagnosticsProject.FromFile(Path.Combine(ApplicationManager.StartPath, "diagnostics.json")); + try { - Project = DiagnosticsProject.FromFile(Path.Combine(ApplicationManager.StartPath, "diagnostics.json")); + await Services.TechComponentsService.Preload(); foreach (var widget in Project.Tabs.SelectMany(x => x.Widgets)) { - await widget.Init(); + try + { + await widget.Init(); + } + catch (Exception ex) + { + NotificationProvider.PushErrorReportingSnackbar(ex, "Diagnostics Module Error", "Error initializing diagnostics widget."); + } + } + + Tabs = new ObservableCollection<DiagnosticsTabViewVM>(); + foreach (var tab in Project.Tabs) + { + Tabs.Add(new DiagnosticsTabViewVM() { Tab = tab }); } + + SelectedTab = Tabs.FirstOrDefault(); + + _isLoaded = true; } catch (Exception ex) { - + NotificationProvider.PushErrorReportingSnackbar(ex, "Diagnostics Module Error", "Error initializing diagnostics module."); + return; } + } - Tabs = new ObservableCollection<DiagnosticsTabViewVM>(); - foreach (var tab in Project.Tabs) - { - Tabs.Add(new DiagnosticsTabViewVM() { Tab = tab }); - } + private void OnSelectedTabChanged() + { + //if (SelectedTab != null) + //{ + // Tabs.Where(x => x != SelectedTab).SelectMany(x => x.Tab.Widgets).ToList().ForEach(x => x.IsVisible = false); + + // SelectedTab.Tab.Widgets.ToList().ForEach(x => x.IsVisible = true); + //} } private void PopulateDiagnosticsData(DiagnosticsFrame frame) { - foreach (var tab in Tabs.ToList()) + if (_isLoaded) { - tab.PopulateDiagnosticsData(new DiagnosticsPackage() + foreach (var tab in Tabs.ToList()) { - Frame = frame, - MonitorsProperties = _monitorsProperties - }); + tab.PopulateDiagnosticsData(new DiagnosticsPackage() + { + Frame = frame, + MonitorsProperties = _monitorsProperties + }); + } } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml index 52b8a619e..c53998f4d 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml @@ -19,7 +19,7 @@ <ItemsControl ItemsSource="{Binding Tab.Widgets}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> - <controls:DiagnosticsGrid IsItemsHost="True" ShowGridLines="True" Columns="{Binding Tab.Columns}" Rows="{Binding Tab.Rows}"/> + <controls:DiagnosticsGrid IsItemsHost="True" ShowGridLines="False" Columns="{Binding Tab.Columns}" Rows="{Binding Tab.Rows}"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> @@ -28,6 +28,7 @@ <Setter Property="Grid.Row" Value="{Binding Row}"></Setter> <Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}"></Setter> <Setter Property="Grid.RowSpan" Value="{Binding RowSpan}"></Setter> + <Setter Property="Margin" Value="5"></Setter> </Style> </ItemsControl.ItemContainerStyle> <ItemsControl.ItemTemplate> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml index 2ae3b9ea7..5b01eaa1b 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.FSE.Diagnostics" xmlns:vm="clr-namespace:Tango.FSE.Diagnostics.ViewModels" + xmlns:controls="clr-namespace:Tango.FSE.Common.Controls;assembly=Tango.FSE.Common" xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Views" mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:DiagnosticsViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.DiagnosticsViewVM}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> @@ -17,7 +18,7 @@ <ColumnDefinition Width="1*" /> </Grid.ColumnDefinitions> <Rectangle Grid.Column="0" VerticalAlignment="Bottom" StrokeThickness="2" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" /> - <ListBox x:Name="listTabs" Grid.Column="1" DisplayMemberPath="Tag" ItemsSource="{Binding ElementName=tabControl,Path=Items}" SelectedItem="{Binding ElementName=tabControl,Path=SelectedItem,Mode=TwoWay}" SelectedIndex="0"> + <ListBox x:Name="listTabs" Grid.Column="1" DisplayMemberPath="Tag" ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}" SelectedIndex="0"> <ListBox.Style> <Style TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}"> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter> @@ -38,6 +39,7 @@ <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> <Setter Property="Width" Value="200"></Setter> + <Setter Property="IsSelected" Value="{Binding IsSelected,Mode=OneWayToSource}"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> @@ -91,18 +93,28 @@ <Rectangle Grid.Column="2" VerticalAlignment="Bottom" StrokeThickness="2" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" /> </Grid> - <TabControl x:Name="tabControl" Margin="0 -2 0 0" ItemsSource="{Binding Tabs}" BorderThickness="0" Background="Transparent"> - <TabControl.ItemContainerStyle> - <Style TargetType="TabItem"> - <Setter Property="Visibility" Value="Collapsed"></Setter> + <ItemsControl x:Name="tabControl" Margin="0 0 0 0" ItemsSource="{Binding Tabs}" BorderThickness="0" Background="Transparent"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <Grid/> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemContainerStyle> + <Style TargetType="FrameworkElement"> + <Setter Property="Visibility" Value="Hidden"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding IsSelected}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> </Style> - </TabControl.ItemContainerStyle> - <TabControl.ContentTemplate> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemTemplate> <DataTemplate> <local:DiagnosticsTabView /> </DataTemplate> - </TabControl.ContentTemplate> - </TabControl> + </ItemsControl.ItemTemplate> + </ItemsControl> </DockPanel> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json index 9de3ffcf4..056761391 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/diagnostics.json @@ -85,16 +85,131 @@ "Monitor": "Dancer2Angle", "Column": 0, "Row": 0, - "ColumnSpan": 6, - "RowSpan": 6 + "ColumnSpan": 3, + "RowSpan": 3 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "Monitor": "Dancer2Angle", + "Column": 3, + "Row": 0, + "ColumnSpan": 3, + "RowSpan": 3 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "Monitor": "Dancer2Angle", + "Column": 6, + "Row": 0, + "ColumnSpan": 3, + "RowSpan": 3 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "Monitor": "Dancer2Angle", + "Column": 9, + "Row": 0, + "ColumnSpan": 3, + "RowSpan": 3 + }, + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphMultiChannelWidget, Tango.FSE.Diagnostics", + "Monitor": "DispensersMotorsFrequency", + "Column": 0, + "Row": 3, + "ColumnSpan": 3, + "RowSpan": 3 } ] }, { "Name": "Tab 2", - "Columns": [], - "Rows": [], - "Widgets": [] + "Columns": [ + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + }, + { + "Width": "*" + } + ], + "Rows": [ + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + }, + { + "Height": "*" + } + ], + "Widgets": [ + { + "$type": "Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidget, Tango.FSE.Diagnostics", + "Monitor": "Dancer2Angle", + "Column": 2, + "Row": 2, + "ColumnSpan": 6, + "RowSpan": 6 + } + ] } ] }
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs index 1c624dcbb..984a2e8ea 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/DataResolver.cs @@ -312,6 +312,18 @@ namespace Tango.FSE.BL } /// <summary> + /// Specify a custom name for the calling service when logs are enabled. + /// </summary> + /// <param name="callingName">Name of the calling service.</param> + /// <returns></returns> + public Builder WithLogsCallingName(String callingName) + { + var method = new StackTrace().GetFrame(1).GetMethod(); + _resolver._callingName = $"'{callingName}.{method.Name}'"; + return this; + } + + /// <summary> /// Builds this <see cref="DataResolver{T}"/> instance. /// </summary> /// <returns></returns> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs index 1f9fc984f..668dec8da 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs @@ -30,6 +30,7 @@ namespace Tango.FSE.BL return DataResolver<List<TEntity>>.Builder.New() .ConfigureCascade(nodes) + .WithLogsCallingName(typeof(TEntity).Name.PluralizeMVC()) .InMemoryCache((context) => { return _memoryCache @@ -90,6 +91,7 @@ namespace Tango.FSE.BL return DataResolver<TEntity>.Builder.New() .ConfigureCascade(nodes) + .WithLogsCallingName(typeof(TEntity).Name.PluralizeMVC()) .InMemoryCache((context) => { return ConvertToEntity(_memoryCache diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/ReadOnlyEntityRepository.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/ReadOnlyEntityRepository.cs index 45fb65e10..f27548309 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/ReadOnlyEntityRepository.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/ReadOnlyEntityRepository.cs @@ -34,6 +34,11 @@ namespace Tango.FSE.BL return FindAll(expression, _nodes); } + public Task<List<TEntity>> FindAll() + { + return FindAll(x => true, _nodes); + } + public Task<TEntity> FindOne(Expression<Func<TEntity, bool>> expression) { return FindOne(expression, _nodes); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs index fa1a436e4..e24c5b876 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs @@ -16,6 +16,9 @@ namespace Tango.FSE.BL.Services public ReadOnlyEntityRepository<TechMonitor, TechMonitorDTO> Monitors { get; private set; } public ReadOnlyEntityRepository<TechIo, TechIoDTO> IOs { get; private set; } public ReadOnlyEntityRepository<TechDispenser, TechDispenserDTO> Dispensers { get; private set; } + public ReadOnlyEntityRepository<TechController, TechControllerDTO> Controllers { get; private set; } + public ReadOnlyEntityRepository<TechHeater, TechHeaterDTO> Heaters { get; private set; } + public ReadOnlyEntityRepository<TechValve, TechValveDTO> Valves { get; private set; } public TechComponentsService() { @@ -39,6 +42,37 @@ namespace Tango.FSE.BL.Services DataResolverNode.InMemoryCache, DataResolverNode.DiskCache, DataResolverNode.Online); + + Controllers = new ReadOnlyEntityRepository<TechController, TechControllerDTO>( + x => x.ToObservable(), + x => TechControllerDTO.FromObservable(x), + DataResolverNode.InMemoryCache, + DataResolverNode.DiskCache, + DataResolverNode.Online); + + Heaters = new ReadOnlyEntityRepository<TechHeater, TechHeaterDTO>( + x => x.ToObservable(), + x => TechHeaterDTO.FromObservable(x), + DataResolverNode.InMemoryCache, + DataResolverNode.DiskCache, + DataResolverNode.Online); + + Valves = new ReadOnlyEntityRepository<TechValve, TechValveDTO>( + x => x.ToObservable(), + x => TechValveDTO.FromObservable(x), + DataResolverNode.InMemoryCache, + DataResolverNode.DiskCache, + DataResolverNode.Online); + } + + public async Task Preload() + { + await Monitors.FindAll(); + await IOs.FindAll(); + await Dispensers.FindAll(); + await Controllers.FindAll(); + await Heaters.FindAll(); + await Valves.FindAll(); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/KeepAliveTabControl.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/KeepAliveTabControl.cs new file mode 100644 index 000000000..f71fbc9ce --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Controls/KeepAliveTabControl.cs @@ -0,0 +1,258 @@ +using System; +using System.Windows; +using System.Windows.Threading; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Collections.Specialized; + +namespace Tango.FSE.Common.Controls +{ + [TemplatePart(Name = "PART_ItemsHolder", Type = typeof(Panel))] + public class KeepAliveTabControl : TabControl + { + // Holds all items, but only marks the current tab's item as visible + private Panel _itemsHolder = null; + + // Temporarily holds deleted item in case this was a drag/drop operation + private object _deletedObject = null; + + public KeepAliveTabControl() + : base() + { + // this is necessary so that we get the initial databound selected item + this.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; + } + + /// <summary> + /// if containers are done, generate the selected item + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) + { + if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) + { + this.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged; + UpdateSelectedItem(); + } + } + + /// <summary> + /// get the ItemsHolder and generate any children + /// </summary> + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + _itemsHolder = GetTemplateChild("PART_ItemsHolder") as Panel; + UpdateSelectedItem(); + } + + /// <summary> + /// when the items change we remove any generated panel children and add any new ones as necessary + /// </summary> + /// <param name="e"></param> + protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) + { + base.OnItemsChanged(e); + + if (_itemsHolder == null) + { + return; + } + + switch (e.Action) + { + case NotifyCollectionChangedAction.Reset: + _itemsHolder.Children.Clear(); + + if (base.Items.Count > 0) + { + base.SelectedItem = base.Items[0]; + UpdateSelectedItem(); + } + + break; + + case NotifyCollectionChangedAction.Add: + case NotifyCollectionChangedAction.Remove: + + // Search for recently deleted items caused by a Drag/Drop operation + if (e.NewItems != null && _deletedObject != null) + { + foreach (var item in e.NewItems) + { + if (_deletedObject == item) + { + // If the new item is the same as the recently deleted one (i.e. a drag/drop event) + // then cancel the deletion and reuse the ContentPresenter so it doesn't have to be + // redrawn. We do need to link the presenter to the new item though (using the Tag) + ContentPresenter cp = FindChildContentPresenter(_deletedObject); + if (cp != null) + { + int index = _itemsHolder.Children.IndexOf(cp); + + (_itemsHolder.Children[index] as ContentPresenter).Tag = + (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item)); + } + _deletedObject = null; + } + } + } + + if (e.OldItems != null) + { + foreach (var item in e.OldItems) + { + + _deletedObject = item; + + // We want to run this at a slightly later priority in case this + // is a drag/drop operation so that we can reuse the template + this.Dispatcher.BeginInvoke(DispatcherPriority.DataBind, + new Action(delegate () + { + if (_deletedObject != null) + { + ContentPresenter cp = FindChildContentPresenter(_deletedObject); + if (cp != null) + { + this._itemsHolder.Children.Remove(cp); + } + } + } + )); + } + } + + UpdateSelectedItem(); + break; + + case NotifyCollectionChangedAction.Replace: + throw new NotImplementedException("Replace not implemented yet"); + } + } + + /// <summary> + /// update the visible child in the ItemsHolder + /// </summary> + /// <param name="e"></param> + protected override void OnSelectionChanged(SelectionChangedEventArgs e) + { + base.OnSelectionChanged(e); + UpdateSelectedItem(); + } + + /// <summary> + /// generate a ContentPresenter for the selected item + /// </summary> + void UpdateSelectedItem() + { + if (_itemsHolder == null) + { + return; + } + + // generate a ContentPresenter if necessary + TabItem item = GetSelectedTabItem(); + if (item != null) + { + CreateChildContentPresenter(item); + } + + // show the right child + foreach (ContentPresenter child in _itemsHolder.Children) + { + child.Visibility = ((child.Tag as TabItem).IsSelected) ? Visibility.Visible : Visibility.Collapsed; + } + } + + /// <summary> + /// create the child ContentPresenter for the given item (could be data or a TabItem) + /// </summary> + /// <param name="item"></param> + /// <returns></returns> + ContentPresenter CreateChildContentPresenter(object item) + { + if (item == null) + { + return null; + } + + ContentPresenter cp = FindChildContentPresenter(item); + + if (cp != null) + { + return cp; + } + + // the actual child to be added. cp.Tag is a reference to the TabItem + cp = new ContentPresenter(); + cp.Content = (item is TabItem) ? (item as TabItem).Content : item; + cp.ContentTemplate = this.SelectedContentTemplate; + cp.ContentTemplateSelector = this.SelectedContentTemplateSelector; + cp.ContentStringFormat = this.SelectedContentStringFormat; + cp.Visibility = Visibility.Collapsed; + cp.Tag = (item is TabItem) ? item : (this.ItemContainerGenerator.ContainerFromItem(item)); + _itemsHolder.Children.Add(cp); + return cp; + } + + /// <summary> + /// Find the CP for the given object. data could be a TabItem or a piece of data + /// </summary> + /// <param name="data"></param> + /// <returns></returns> + ContentPresenter FindChildContentPresenter(object data) + { + if (data is TabItem) + { + data = (data as TabItem).Content; + } + + if (data == null) + { + return null; + } + + if (_itemsHolder == null) + { + return null; + } + + foreach (ContentPresenter cp in _itemsHolder.Children) + { + if (cp.Content == data) + { + return cp; + } + } + + return null; + } + + /// <summary> + /// copied from TabControl; wish it were protected in that class instead of private + /// </summary> + /// <returns></returns> + protected TabItem GetSelectedTabItem() + { + object selectedItem = base.SelectedItem; + if (selectedItem == null) + { + return null; + } + + if (_deletedObject == selectedItem) + { + + } + + TabItem item = selectedItem as TabItem; + if (item == null) + { + item = base.ItemContainerGenerator.ContainerFromIndex(base.SelectedIndex) as TabItem; + } + return item; + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs index 4c58321e9..719fc36d1 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/FSEViewModel.cs @@ -41,7 +41,7 @@ using Tango.FSE.Common.Firmware; namespace Tango.FSE.Common { /// <summary> - /// Represents a PPC view model base class. + /// Represents a FSE view model base class. /// </summary> /// <seealso cref="Tango.SharedUI.ViewModel" /> public abstract class FSEViewModel : ViewModel, INavigationBlocker @@ -175,7 +175,7 @@ namespace Tango.FSE.Common private FSESettings _settings; /// <summary> - /// Gets the main PPC settings. + /// Gets the main FSE settings. /// </summary> public FSESettings Settings { @@ -193,7 +193,7 @@ namespace Tango.FSE.Common private bool _isVisible; /// <summary> - /// Gets or sets a value indicating whether this <see cref="PPCViewModel"/> view is visible. + /// Gets or sets a value indicating whether this <see cref="FSEViewModel"/> view is visible. /// </summary> public bool IsVisible { @@ -369,7 +369,7 @@ namespace Tango.FSE.Common } /// <summary> - /// Represents a PPC view model base class a View property as an instance of a <see cref="IPPCView"/> contract. + /// Represents a FSE view model base class a View property as an instance of a <see cref="IFSEView"/> contract. /// </summary> /// <typeparam name="T"></typeparam> /// <seealso cref="Tango.SharedUI.ViewModel" /> @@ -377,7 +377,7 @@ namespace Tango.FSE.Common { private T _view; /// <summary> - /// Gets the IPPCView instance. + /// Gets the IFSEView instance. /// </summary> [TangoInject(TangoInjectMode.WhenAvailable)] public T View @@ -393,7 +393,7 @@ namespace Tango.FSE.Common /// <summary> - /// Gets a value indicating whether the instance of IPPCView is available. + /// Gets a value indicating whether the instance of IFSEView is available. /// </summary> public bool ViewAttached { get; private set; } @@ -406,7 +406,7 @@ namespace Tango.FSE.Common } /// <summary> - /// Called when the instance of IPPCView is available. + /// Called when the instance of IFSEView is available. /// </summary> public virtual void OnViewAttached() { 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 5ca1ca85b..47bc2c36f 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 @@ -100,6 +100,7 @@ <Compile Include="Connection\MachineDisconnectedEventArgs.cs" /> <Compile Include="Connectivity\IConnectivityProvider.cs" /> <Compile Include="Console\IConsoleProvider.cs" /> + <Compile Include="Controls\KeepAliveTabControl.cs" /> <Compile Include="Controls\ConnectedMachineIcon.xaml.cs"> <DependentUpon>ConnectedMachineIcon.xaml</DependentUpon> </Compile> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Diagnostics/DefaultDiagnosticsProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/Diagnostics/DefaultDiagnosticsProvider.cs index cf49286a4..01bfb26b2 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Diagnostics/DefaultDiagnosticsProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Diagnostics/DefaultDiagnosticsProvider.cs @@ -62,7 +62,7 @@ namespace Tango.FSE.UI.Diagnostics { _machineProvider = machineProvider; _diagnosticsQueue = new ProducerConsumerQueue<StartDiagnosticsResponse>(); - ThrottlingMode = SettingsManager.Default.GetOrCreate<FSESettings>().DiagnosticsThrottlingMode; + ThrottlingMode = DiagnosticsThrottlingMode.Direct; //SettingsManager.Default.GetOrCreate<FSESettings>().DiagnosticsThrottlingMode; machineProvider.MachineOperator.DiagnosticsDataAvailable += MachineOperator_DiagnosticsDataAvailable; _queueThread = new Thread(QueueThreadMethod); diff --git a/Software/Visual_Studio/Tango.Transport/Web/WebTransportClient.cs b/Software/Visual_Studio/Tango.Transport/Web/WebTransportClient.cs index 14b9a7562..4d68dbf59 100644 --- a/Software/Visual_Studio/Tango.Transport/Web/WebTransportClient.cs +++ b/Software/Visual_Studio/Tango.Transport/Web/WebTransportClient.cs @@ -103,6 +103,8 @@ namespace Tango.Transport.Web } catch (HttpRequestException ex) { + bool handled = false; + try { String message = JObject.Parse(data).GetValue("Message").ToString(); @@ -134,11 +136,19 @@ namespace Tango.Transport.Web throw new HttpRequestException(ex.Message + " " + message); } + handled = true; throw exception; } - catch + catch (Exception handledException) { - throw ex; + if (handled) + { + throw handledException; + } + else + { + throw ex; + } } } |
