diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-17 06:12:39 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-17 06:12:39 +0300 |
| commit | f41d7e0a4457c0e894f53f5c9c866b8588f67eab (patch) | |
| tree | 678fa2f1c21a0d6418eeb2cc0270066dce971f32 /Software | |
| parent | d6b5c18d94c70679f92fd54d95de1d39f355c0b7 (diff) | |
| download | Tango-f41d7e0a4457c0e894f53f5c9c866b8588f67eab.tar.gz Tango-f41d7e0a4457c0e894f53f5c9c866b8588f67eab.zip | |
Beit Hakodesh !
Diffstat (limited to 'Software')
43 files changed, 1586 insertions, 70 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGrid.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGrid.cs new file mode 100644 index 000000000..45b6d9a36 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Controls/DiagnosticsGrid.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using Tango.FSE.Diagnostics.Project; + +namespace Tango.FSE.Diagnostics.Controls +{ + public class DiagnosticsGrid : Grid + { + public List<DiagnosticsProjectTabColumnDefinition> Columns + { + get { return (List<DiagnosticsProjectTabColumnDefinition>)GetValue(ColumnsProperty); } + set { SetValue(ColumnsProperty, value); } + } + public static readonly DependencyProperty ColumnsProperty = + DependencyProperty.Register("Columns", typeof(List<DiagnosticsProjectTabColumnDefinition>), typeof(DiagnosticsGrid), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGrid).LoadDefinitions())); + + public List<DiagnosticsProjectTabRowDefinition> Rows + { + get { return (List<DiagnosticsProjectTabRowDefinition>)GetValue(RowsProperty); } + set { SetValue(RowsProperty, value); } + } + public static readonly DependencyProperty RowsProperty = + DependencyProperty.Register("Rows", typeof(List<DiagnosticsProjectTabRowDefinition>), typeof(DiagnosticsGrid), new PropertyMetadata(null, (d, e) => (d as DiagnosticsGrid).LoadDefinitions())); + + private void LoadDefinitions() + { + if (Rows != null && Columns != null) + { + ColumnDefinitions.Clear(); + RowDefinitions.Clear(); + + foreach (var column in Columns) + { + ColumnDefinitions.Add(new ColumnDefinition() { Width = column.Width }); + } + + foreach (var row in Rows) + { + RowDefinitions.Add(new RowDefinition() { Height = row.Height }); + } + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToViewConverter.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToViewConverter.cs new file mode 100644 index 000000000..439b1a17a --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Converters/DiagnosticsWidgetToViewConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using Tango.FSE.Diagnostics.Project; + +namespace Tango.FSE.Diagnostics.Converters +{ + public class DiagnosticsWidgetToViewConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + DiagnosticsWidget widget = value as DiagnosticsWidget; + + if (widget != null) + { + return widget.GetView(); + } + + return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsPackage.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsPackage.cs new file mode 100644 index 000000000..48fe8c186 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/DiagnosticsPackage.cs @@ -0,0 +1,81 @@ +using Google.Protobuf.Collections; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.BL.Enumerations; +using Tango.FSE.Common.Diagnostics; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics +{ + public class DiagnosticsPackage + { + /// <summary> + /// Gets or sets the frame. + /// </summary> + public DiagnosticsFrame Frame { get; set; } + + /// <summary> + /// Gets or sets the monitors properties. + /// </summary> + public Dictionary<String, PropertyInfo> MonitorsProperties { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="DiagnosticsPackage"/> class. + /// </summary> + public DiagnosticsPackage() + { + MonitorsProperties = new Dictionary<string, PropertyInfo>(); + } + + /// <summary> + /// Gets the monitor value by the specified monitor using reflections. + /// </summary> + /// <param name="monitor">The monitor.</param> + /// <returns></returns> + public object GetMonitorObject(TechMonitors monitor) + { + return MonitorsProperties[monitor.ToString()].GetValue(Frame.Data.Monitors); + } + + /// <summary> + /// Gets the last data point from a protobuf repeated field. + /// </summary> + /// <param name="monitor">The monitor.</param> + /// <param name="value">The value.</param> + /// <returns></returns> + public double GetMonitorLastValue(TechMonitors monitor) + { + var value = GetMonitorObject(monitor); + RepeatedField<double> arr = value as RepeatedField<double>; + return arr.LastOrDefault(); + } + + /// <summary> + /// Gets the data array from a protobuf repeated field. + /// </summary> + /// <param name="monitor">The monitor.</param> + /// <param name="value">The value.</param> + /// <returns></returns> + public List<double> GetMonitorArray(TechMonitors monitor) + { + var value = GetMonitorObject(monitor); + return (value as RepeatedField<double>).ToList(); + } + + /// <summary> + /// Gets the data matrix from a protobuf repeated field of <see cref="DoubleArray"/>. + /// </summary> + /// <param name="monitor">The monitor.</param> + /// <returns></returns> + public List<List<double>> GetMonitorMatrix(TechMonitors monitor) + { + var value = GetMonitorObject(monitor); + DoubleArray[] arrayOfDoubles = Enumerable.ToArray(value as IEnumerable<DoubleArray>); + return arrayOfDoubles.Select(x => x.Data.ToList()).ToList(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProject.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProject.cs new file mode 100644 index 000000000..bc93f4101 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProject.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsProject : ExtendedObject + { + private static JsonSerializerSettings _settings; + + public String Name { get; set; } + public ObservableCollection<DiagnosticsProjectTab> Tabs { get; set; } + + static DiagnosticsProject() + { + _settings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.Auto, + Formatting = Formatting.Indented + }; + } + + public DiagnosticsProject() + { + Name = "Diagnostics Project"; + Tabs = new ObservableCollection<DiagnosticsProjectTab>(); + } + + public String ToJson() + { + return JsonConvert.SerializeObject(this, _settings); + } + + public static DiagnosticsProject FromJson(String json) + { + return JsonConvert.DeserializeObject<DiagnosticsProject>(json, _settings); + } + + public void ToFile(String fileName) + { + File.WriteAllText(fileName, ToJson()); + } + + public static DiagnosticsProject FromFile(String fileName) + { + return FromJson(File.ReadAllText(fileName)); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTab.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTab.cs new file mode 100644 index 000000000..d50a6aa0d --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTab.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.Core; +using Tango.FSE.Diagnostics.Project.Widgets; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsProjectTab : ExtendedObject + { + public String Name { get; set; } + public List<DiagnosticsProjectTabColumnDefinition> Columns { get; set; } + public List<DiagnosticsProjectTabRowDefinition> Rows { get; set; } + public ObservableCollection<DiagnosticsWidget> Widgets { get; set; } + + public DiagnosticsProjectTab() + { + Columns = new List<DiagnosticsProjectTabColumnDefinition>(); + Rows = new List<DiagnosticsProjectTabRowDefinition>(); + Widgets = new ObservableCollection<DiagnosticsWidget>(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabColumnDefinition.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabColumnDefinition.cs new file mode 100644 index 000000000..3f10fa793 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabColumnDefinition.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsProjectTabColumnDefinition + { + public GridLength Width { get; set; } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabRowDefinition.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabRowDefinition.cs new file mode 100644 index 000000000..0797d89ac --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsProjectTabRowDefinition.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Tango.FSE.Diagnostics.Project +{ + public class DiagnosticsProjectTabRowDefinition + { + public GridLength Height { get; set; } + } +} 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 new file mode 100644 index 000000000..4689af541 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/DiagnosticsWidget.cs @@ -0,0 +1,63 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using Tango.Core; +using Tango.Core.DI; +using Tango.FSE.BL; +using Tango.FSE.Common.Authentication; +using Tango.FSE.Common.Connection; +using Tango.FSE.Common.Notifications; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.Project +{ + public abstract class DiagnosticsWidget : ExtendedObject + { + [JsonIgnore] + [TangoInject(TangoInjectMode.WhenAvailable)] + protected IAuthenticationProvider AuthenticationProvider { get; set; } + + [JsonIgnore] + [TangoInject(TangoInjectMode.WhenAvailable)] + protected IMachineProvider MachineProvider { get; set; } + + [JsonIgnore] + [TangoInject(TangoInjectMode.WhenAvailable)] + protected INotificationProvider NotificationProvider { get; set; } + + private FSEServicesContainer _services; + [JsonIgnore] + [TangoInject(TangoInjectMode.WhenAvailable)] + public FSEServicesContainer Services + { + get { return _services; } + set { _services = value; OnServicesAvailable(); } + } + + public int Column { get; set; } + public int Row { get; set; } + public int ColumnSpan { get; set; } + public int RowSpan { get; set; } + + public DiagnosticsWidget() + { + TangoIOC.Default.Inject(this); + } + + protected virtual void OnServicesAvailable() + { + + } + + public virtual void OnDiagnosticsData(DiagnosticsPackage package) + { + //Called when diagnostics data is available + } + + public abstract FrameworkElement GetView(); + } +} 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 new file mode 100644 index 000000000..bc7b38a1c --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidget.cs @@ -0,0 +1,66 @@ +using Newtonsoft.Json; +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; +using Tango.BL.Enumerations; + +namespace Tango.FSE.Diagnostics.Project.Widgets +{ + public class RealTimeGraphWidget : DiagnosticsWidget + { + public TechMonitors Monitor { get; set; } = TechMonitors.Dancer2Angle; + + [JsonIgnore] + public WpfGraphController<TimeSpanDataPoint, DoubleDataPoint> Controller { get; set; } + + public RealTimeGraphWidget() + { + Controller = new WpfGraphController<TimeSpanDataPoint, DoubleDataPoint>(); + Controller.Range.AutoY = true; + Controller.Range.MaximumX = TimeSpan.FromSeconds(60); + Controller.RefreshRate = TimeSpan.FromMilliseconds(100); + + Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() + { + Stroke = Colors.DodgerBlue + }); + } + + public override FrameworkElement GetView() + { + return new RealTimeGraphWidgetView() { DataContext = this }; + } + + public override void OnDiagnosticsData(DiagnosticsPackage package) + { + base.OnDiagnosticsData(package); + var points = package.GetMonitorArray(Monitor); + + if (points.Count > 0) + { + List<TimeSpanDataPoint> dates = new List<TimeSpanDataPoint>(); + var dPoints = points.Select(x => new DoubleDataPoint(x)).ToList(); + + 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 < points.Count; i++) + { + dates.Add( + offset + .Add(TimeSpan.FromMilliseconds(-package.Frame.Delta.TotalMilliseconds)) + .Add(TimeSpan.FromMilliseconds(package.Frame.Delta.TotalMilliseconds * (i / (double)points.Count)))); + } + + Controller.PushData(dates, dPoints); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml new file mode 100644 index 000000000..7c6eb92d3 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml @@ -0,0 +1,13 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Project.Widgets.RealTimeGraphWidgetView" + 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:RealTimeGraphWidget,IsDesignTimeCreatable=False}"> + <Grid> + <graphs:RealTimeGraph Controller="{Binding Controller}" /> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.xaml.cs new file mode 100644 index 000000000..546a55f74 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Project/Widgets/RealTimeGraphWidgetView.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 RealTimeGraphWidgetView : UserControl + { + public RealTimeGraphWidgetView() + { + InitializeComponent(); + } + } +} 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 26b419103..371cdc6b5 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 @@ -24,6 +24,7 @@ <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> + <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> @@ -78,9 +79,29 @@ <Reference Include="PresentationFramework" /> </ItemGroup> <ItemGroup> + <Compile Include="Controls\DiagnosticsGrid.cs" /> + <Compile Include="Converters\DiagnosticsWidgetToViewConverter.cs" /> + <Compile Include="DiagnosticsPackage.cs" /> + <Compile Include="Project\DiagnosticsProject.cs" /> + <Compile Include="Project\DiagnosticsProjectTab.cs" /> + <Compile Include="Project\DiagnosticsProjectTabColumnDefinition.cs" /> + <Compile Include="Project\DiagnosticsProjectTabRowDefinition.cs" /> + <Compile Include="Project\DiagnosticsWidget.cs" /> + <Compile Include="Project\Widgets\RealTimeGraphWidget.cs" /> + <Compile Include="Project\Widgets\RealTimeGraphWidgetView.xaml.cs"> + <DependentUpon>RealTimeGraphWidgetView.xaml</DependentUpon> + </Compile> <Compile Include="ViewModelLocator.cs" /> <Compile Include="DiagnosticsModule.cs" /> + <Compile Include="ViewModels\DiagnosticsTabViewVM.cs" /> + <Compile Include="ViewModels\DiagnosticsViewVM.cs" /> <Compile Include="ViewModels\MainViewVM.cs" /> + <Compile Include="Views\DiagnosticsTabView.xaml.cs"> + <DependentUpon>DiagnosticsTabView.xaml</DependentUpon> + </Compile> + <Compile Include="Views\DiagnosticsView.xaml.cs"> + <DependentUpon>DiagnosticsView.xaml</DependentUpon> + </Compile> <Compile Include="Views\MainView.xaml.cs"> <DependentUpon>MainView.xaml</DependentUpon> </Compile> @@ -103,7 +124,9 @@ <Generator>ResXFileCodeGenerator</Generator> <LastGenOutput>Resources.Designer.cs</LastGenOutput> </EmbeddedResource> - <None Include="app.config" /> + <None Include="app.config"> + <SubType>Designer</SubType> + </None> <None Include="packages.config" /> <None Include="Properties\Settings.settings"> <Generator>SettingsSingleFileGenerator</Generator> @@ -111,6 +134,14 @@ </None> </ItemGroup> <ItemGroup> + <ProjectReference Include="..\..\..\SideChains\RealTimeGraphX-master\RealTimeGraphX.WPF\RealTimeGraphX.WPF.csproj"> + <Project>{6b9774f7-960d-438e-ad81-c6b9be328d50}</Project> + <Name>RealTimeGraphX.WPF</Name> + </ProjectReference> + <ProjectReference Include="..\..\..\SideChains\RealTimeGraphX-master\RealTimeGraphX\RealTimeGraphX.csproj"> + <Project>{f13a489c-80ee-4cd0-bdd4-92d959215646}</Project> + <Name>RealTimeGraphX</Name> + </ProjectReference> <ProjectReference Include="..\..\..\SideChains\Tango.AutoComplete\Tango.AutoComplete.csproj"> <Project>{bb2abb74-ba58-4812-83aa-ec8171f42df4}</Project> <Name>Tango.AutoComplete</Name> @@ -161,6 +192,18 @@ <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> </Page> + <Page Include="Project\Widgets\RealTimeGraphWidgetView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\DiagnosticsTabView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Views\DiagnosticsView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="Views\MainView.xaml"> <SubType>Designer</SubType> <Generator>MSBuild:Compile</Generator> @@ -169,6 +212,7 @@ <ItemGroup> <Resource Include="Images\diagnostics.png" /> </ItemGroup> + <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\..\..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModelLocator.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModelLocator.cs index 6cb3edceb..6048474ef 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModelLocator.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModelLocator.cs @@ -13,6 +13,7 @@ namespace Tango.FSE.Diagnostics static ViewModelLocator() { TangoIOC.Default.Register<MainViewVM>(); + TangoIOC.Default.Register<DiagnosticsViewVM>(); } public static MainViewVM MainViewVM @@ -22,5 +23,13 @@ namespace Tango.FSE.Diagnostics return TangoIOC.Default.GetInstance<MainViewVM>(); } } + + public static DiagnosticsViewVM DiagnosticsViewVM + { + get + { + return TangoIOC.Default.GetInstance<DiagnosticsViewVM>(); + } + } } } 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 new file mode 100644 index 000000000..e3566fd40 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsTabViewVM.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.FSE.Common; +using Tango.FSE.Diagnostics.Project; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.ViewModels +{ + public class DiagnosticsTabViewVM : FSEViewModel + { + private DiagnosticsProjectTab _tab; + public DiagnosticsProjectTab Tab + { + get { return _tab; } + set { _tab = value; RaisePropertyChangedAuto(); } + } + + public void PopulateDiagnosticsData(DiagnosticsPackage package) + { + foreach (var widget in Tab.Widgets.ToList()) + { + widget.OnDiagnosticsData(package); + } + } + } +} 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 new file mode 100644 index 000000000..f49b9bb15 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/ViewModels/DiagnosticsViewVM.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.FSE.Common; +using Tango.FSE.Common.Diagnostics; +using Tango.FSE.Diagnostics.Project; +using Tango.PMR.Diagnostics; + +namespace Tango.FSE.Diagnostics.ViewModels +{ + public class DiagnosticsViewVM : FSEViewModel + { + private Dictionary<String, PropertyInfo> _monitorsProperties; + + private DiagnosticsProject _project; + public DiagnosticsProject Project + { + get { return _project; } + set { _project = value; RaisePropertyChangedAuto(); } + } + + private ObservableCollection<DiagnosticsTabViewVM> _tabs; + + public ObservableCollection<DiagnosticsTabViewVM> Tabs + { + get { return _tabs; } + set { _tabs = value; RaisePropertyChangedAuto(); } + } + + public DiagnosticsViewVM() + { + _monitorsProperties = new Dictionary<string, PropertyInfo>(); + + foreach (var prop in typeof(DiagnosticsMonitors).GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList()) + { + _monitorsProperties.Add(prop.Name, prop); + } + + Tabs = new ObservableCollection<DiagnosticsTabViewVM>(); + Project = new DiagnosticsProject(); + } + + public override void OnApplicationStarted() + { + base.OnApplicationStarted(); + DiagnosticsProvider.FrameReceived += DiagnosticsProvider_FrameReceived; + } + + private void DiagnosticsProvider_FrameReceived(object sender, DiagnosticsFrameReceivedEventArgs e) + { + PopulateDiagnosticsData(e.Frame); + } + + public override void OnApplicationReady() + { + base.OnApplicationReady(); + LoadProject(); + } + + private void LoadProject() + { + //TODO: Load project... + try + { + Project = DiagnosticsProject.FromFile(Path.Combine(ApplicationManager.StartPath, "diagnostics.json")); + } + catch (Exception ex) + { + Project = new DiagnosticsProject(); + Project.Tabs = new ObservableCollection<DiagnosticsProjectTab>() + { + new DiagnosticsProjectTab() { Name = "Tab 1" }, + new DiagnosticsProjectTab() { Name = "Tab 2" }, + }; + Project.ToFile(Path.Combine(ApplicationManager.StartPath, "diagnostics.json")); + } + + Tabs = new ObservableCollection<DiagnosticsTabViewVM>(); + foreach (var tab in Project.Tabs) + { + Tabs.Add(new DiagnosticsTabViewVM() { Tab = tab }); + } + } + + private void PopulateDiagnosticsData(DiagnosticsFrame frame) + { + foreach (var tab in Tabs.ToList()) + { + 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 new file mode 100644 index 000000000..52b8a619e --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml @@ -0,0 +1,40 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Views.DiagnosticsTabView" + 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:global="clr-namespace:Tango.FSE.Diagnostics" + xmlns:vm="clr-namespace:Tango.FSE.Diagnostics.ViewModels" + xmlns:controls="clr-namespace:Tango.FSE.Diagnostics.Controls" + xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Views" + xmlns:converters="clr-namespace:Tango.FSE.Diagnostics.Converters" + mc:Ignorable="d" + d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:DiagnosticsTabViewVM, IsDesignTimeCreatable=False}" Background="{StaticResource FSE_PrimaryBackgroundBrush}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> + + <UserControl.Resources> + <converters:DiagnosticsWidgetToViewConverter x:Key="DiagnosticsWidgetToViewConverter" /> + </UserControl.Resources> + + <Grid> + <ItemsControl ItemsSource="{Binding Tab.Widgets}"> + <ItemsControl.ItemsPanel> + <ItemsPanelTemplate> + <controls:DiagnosticsGrid IsItemsHost="True" ShowGridLines="True" Columns="{Binding Tab.Columns}" Rows="{Binding Tab.Rows}"/> + </ItemsPanelTemplate> + </ItemsControl.ItemsPanel> + <ItemsControl.ItemContainerStyle> + <Style TargetType="FrameworkElement"> + <Setter Property="Grid.Column" Value="{Binding Column}"></Setter> + <Setter Property="Grid.Row" Value="{Binding Row}"></Setter> + <Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}"></Setter> + <Setter Property="Grid.RowSpan" Value="{Binding RowSpan}"></Setter> + </Style> + </ItemsControl.ItemContainerStyle> + <ItemsControl.ItemTemplate> + <DataTemplate> + <ContentPresenter Content="{Binding Converter={StaticResource DiagnosticsWidgetToViewConverter}}"/> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.xaml.cs new file mode 100644 index 000000000..e3814dd79 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsTabView.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.Views +{ + /// <summary> + /// Interaction logic for DiagnosticsTabView.xaml + /// </summary> + public partial class DiagnosticsTabView : UserControl + { + public DiagnosticsTabView() + { + InitializeComponent(); + } + } +} 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 new file mode 100644 index 000000000..2ae3b9ea7 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml @@ -0,0 +1,108 @@ +<UserControl x:Class="Tango.FSE.Diagnostics.Views.DiagnosticsView" + 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:global="clr-namespace:Tango.FSE.Diagnostics" + xmlns:vm="clr-namespace:Tango.FSE.Diagnostics.ViewModels" + 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}"> + <Grid Margin="20"> + <DockPanel> + <Grid DockPanel.Dock="Top" Height="50"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="1*" /> + <ColumnDefinition Width="Auto" /> + <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.Style> + <Style TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}"> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"></Setter> + <Setter Property="ItemsPanel"> + <Setter.Value> + <ItemsPanelTemplate> + <UniformGrid Margin="15 0 0 0" Columns="{Binding RelativeSource={RelativeSource AncestorType=ListBox},Path=Items.Count}" IsItemsHost="True"></UniformGrid> + </ItemsPanelTemplate> + </Setter.Value> + </Setter> + <Setter Property="ItemContainerStyle"> + <Setter.Value> + <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}"> + <Setter Property="HorizontalContentAlignment" Value="Center"></Setter> + <Setter Property="VerticalContentAlignment" Value="Center"></Setter> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryBackgroundBrush}"></Setter> + <Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_GrayBrush}"></Setter> + <Setter Property="Width" Value="200"></Setter> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="ListBoxItem"> + <Grid x:Name="grid" Margin="-15 0 0 0" Background="Transparent"> + <Viewbox Stretch="Fill"> + <Grid> + <Polygon Fill="{TemplateBinding Background}" Stretch="Fill" Points="0,30 15,0 85,0 100,30"></Polygon> + <Polygon Fill="White" Stretch="Fill" Points="0,30 15,0 85,0 100,30" IsHitTestVisible="False" Opacity="0.1"> + <Polygon.Style> + <Style TargetType="Polygon"> + <Setter Property="Visibility" Value="Hidden"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsMouseOver}" Value="True"> + <Setter Property="Visibility" Value="Visible"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </Polygon.Style> + </Polygon> + <Polyline Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" StrokeThickness="1" Stretch="Fill" Points="0,30 15,0 85,0 100,30" /> + <Rectangle VerticalAlignment="Bottom" Stroke="{StaticResource FSE_PrimaryAccentDarkBrush}" StrokeThickness="1" /> + </Grid> + </Viewbox> + <ContentPresenter Content="{Binding Tab.Name}" TextElement.Foreground="{TemplateBinding Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" /> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsSelected" Value="True"> + + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + <Style.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Background" Value="{StaticResource FSE_PrimaryAccentDarkBrush}"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_PrimaryForegroundBrush}"></Setter> + <Setter Property="FontWeight" Value="SemiBold"></Setter> + <Setter Property="Panel.ZIndex" Value="200"></Setter> + </Trigger> + <Trigger Property="IsSelected" Value="False"> + <Setter Property="Panel.ZIndex" Value="-1"></Setter> + </Trigger> + </Style.Triggers> + </Style> + </Setter.Value> + </Setter> + </Style> + </ListBox.Style> + </ListBox> + <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> + </Style> + </TabControl.ItemContainerStyle> + <TabControl.ContentTemplate> + <DataTemplate> + <local:DiagnosticsTabView /> + </DataTemplate> + </TabControl.ContentTemplate> + </TabControl> + </DockPanel> + </Grid> +</UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.xaml.cs new file mode 100644 index 000000000..553183f96 --- /dev/null +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/DiagnosticsView.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.Views +{ + /// <summary> + /// Interaction logic for DiagnosticsView.xaml + /// </summary> + public partial class DiagnosticsView : UserControl + { + public DiagnosticsView() + { + InitializeComponent(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/MainView.xaml index e04aaeb98..7733198b4 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Diagnostics/Views/MainView.xaml @@ -7,8 +7,8 @@ xmlns:vm="clr-namespace:Tango.FSE.Diagnostics.ViewModels" xmlns:local="clr-namespace:Tango.FSE.Diagnostics.Views" mc:Ignorable="d" - d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> + d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> <Grid> - <TextBlock FontSize="60" HorizontalAlignment="Center" VerticalAlignment="Center">Diagnostics View</TextBlock> + <local:DiagnosticsView/> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Tango.FSE.Firmware.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Tango.FSE.Firmware.csproj index 6df43ccce..18b8e81b4 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Tango.FSE.Firmware.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Firmware/Tango.FSE.Firmware.csproj @@ -24,6 +24,7 @@ <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> + <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj index 287273015..3c740f103 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj @@ -24,6 +24,7 @@ <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> + <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj index a3acc4b19..afc7344f5 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Upgrade/Tango.FSE.Upgrade.csproj @@ -24,6 +24,7 @@ <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> + <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/CacheManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/CacheManager.cs deleted file mode 100644 index 389e17808..000000000 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/CacheManager.cs +++ /dev/null @@ -1,40 +0,0 @@ -using LiteDB; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.FSE.BL -{ - public class CacheManager - { - public String DatabasePath { get; private set; } - - private static CacheManager _default; - public static CacheManager Default - { - get - { - if (_default == null) - { - _default = new CacheManager(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Cache", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName) + ".cache")); - } - - return _default; - } - } - - public CacheManager(String databasePath) - { - DatabasePath = databasePath; - } - - public LiteDatabase CreateContext() - { - Directory.CreateDirectory(Path.GetDirectoryName(DatabasePath)); - return new LiteDatabase(DatabasePath); - } - } -} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/DiskCacheManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/DiskCacheManager.cs new file mode 100644 index 000000000..15f67c59a --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/DiskCacheManager.cs @@ -0,0 +1,57 @@ +using LiteDB; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.BL +{ + /// <summary> + /// Represents a disk cache manager. + /// </summary> + public class DiskCacheManager + { + /// <summary> + /// Gets the database file path. + /// </summary> + public String DatabasePath { get; private set; } + + private static DiskCacheManager _default; + /// <summary> + /// Gets the default instance. + /// </summary> + public static DiskCacheManager Default + { + get + { + if (_default == null) + { + _default = new DiskCacheManager(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Cache", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName) + ".cache")); + } + + return _default; + } + } + + /// <summary> + /// Initializes a new instance of the <see cref="DiskCacheManager"/> class. + /// </summary> + /// <param name="databasePath">The database path.</param> + public DiskCacheManager(String databasePath) + { + DatabasePath = databasePath; + } + + /// <summary> + /// Creates a new disk cache context. + /// </summary> + /// <returns></returns> + public LiteDatabase CreateContext() + { + Directory.CreateDirectory(Path.GetDirectoryName(DatabasePath)); + return new LiteDatabase(DatabasePath); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs new file mode 100644 index 000000000..2ce9b68f1 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/EntityRepositoryBase.cs @@ -0,0 +1,137 @@ +using ExpressionTreeToString; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Tango.BL; + +namespace Tango.FSE.BL +{ + public abstract class EntityRepositoryBase<TEntity, TCachedEntity> : FSEServiceBase where TEntity : ObservableEntity<TEntity> where TCachedEntity : ObservableEntityDTO<TCachedEntity, TEntity> + { + private MemoryCacheDictionary<String, TCachedEntity> _memoryCache; + + public EntityRepositoryBase() + { + _memoryCache = MemoryCache.GetOrCreateCache<String, TCachedEntity>(typeof(TEntity).Name); + } + + protected Task<List<TEntity>> FindAll(Expression<Func<TEntity, bool>> expression, params DataResolverNode[] nodes) + { + return DataResolver<List<TEntity>>.Builder.New() + .ConfigureCascade(nodes) + .InMemoryCache((context) => + { + return _memoryCache + .ToList(true) + .Where(GetCacheExpression(expression).Compile()) + .ToList() + .Select(x => ConvertToEntity(x)) + .ToList(); + }) + .Online((context) => + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var entities = db.Set<TEntity>().WhereDynamic(expression.ToString()).ToList(); + + using (var cache = DiskCache.CreateContext()) + { + var collection = cache.GetCollection<TCachedEntity>(); + + foreach (var entity in entities) + { + var cachedEntity = ConvertToCached(entity); + _memoryCache.Put(entity.Guid, cachedEntity); + collection.Upsert(cachedEntity); + } + } + + return entities; + } + }) + .DiskCache((context) => + { + using (var cache = DiskCache.CreateContext()) + { + List<TEntity> entities = new List<TEntity>(); + + var cachedEntities = cache.GetCollection<TCachedEntity>().Find(GetCacheExpression(expression)).ToList(); + + foreach (var cachedEntity in cachedEntities) + { + _memoryCache.Put(cachedEntity.Guid, cachedEntity); + entities.Add(ConvertToEntity(cachedEntity)); + } + + return entities; + } + }) + .BuildExecuteAsync(); + } + + protected Task<TEntity> FindOne(Expression<Func<TEntity, bool>> expression, params DataResolverNode[] nodes) + { + return DataResolver<TEntity>.Builder.New() + .ConfigureCascade(nodes) + .InMemoryCache((context) => + { + return ConvertToEntity(_memoryCache + .ToList(true) + .First(GetCacheExpression(expression).Compile())); + }) + .Online((context) => + { + using (ObservablesContext db = ObservablesContext.CreateDefault()) + { + var entity = db.Set<TEntity>().First(expression); + + using (var cache = DiskCache.CreateContext()) + { + var collection = cache.GetCollection<TCachedEntity>(); + var cachedEntity = ConvertToCached(entity); + _memoryCache.Put(entity.Guid, cachedEntity); + collection.Upsert(cachedEntity); + } + + return entity; + } + }) + .DiskCache((context) => + { + using (var cache = DiskCache.CreateContext()) + { + var cachedEntity = cache.GetCollection<TCachedEntity>().FindOne(GetCacheExpression(expression)); + + _memoryCache.Put(cachedEntity.Guid, cachedEntity); + + return ConvertToEntity(cachedEntity); + } + }) + .BuildExecuteAsync(); + } + + protected virtual Expression<Func<TCachedEntity, bool>> GetCacheExpression(Expression<Func<TEntity, bool>> expression) + { + String str = expression.ToString("C#"); + int startIndex = str.IndexOf("=>"); + str = str.Substring(startIndex + 2, str.Length - (startIndex + 2)); + str = Regex.Replace(str, @"\((.*?)\)", ""); + + var xparam = Expression.Parameter(typeof(TCachedEntity), expression.Parameters[0].Name); + Expression<Func<TCachedEntity, bool>> expr = (Expression<Func<TCachedEntity, bool>>)System.Linq.Dynamic.DynamicExpression + .ParseLambda( + new[] { xparam }, + typeof(bool), + str); + + return expr; + } + + protected abstract TCachedEntity ConvertToCached(TEntity entity); + protected abstract TEntity ConvertToEntity(TCachedEntity cachedEntity); + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServiceBase.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServiceBase.cs index f2eb0dbe1..1f22134d2 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServiceBase.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServiceBase.cs @@ -30,12 +30,20 @@ namespace Tango.FSE.BL get { return Authentication.CurrentUser; } } - public CacheManager DiskCache { get; set; } + protected DiskCacheManager DiskCache + { + get { return DiskCacheManager.Default; } + } + + protected MemoryCacheManager MemoryCache + { + get { return MemoryCacheManager.Default; } + } public FSEServiceBase() { TangoIOC.Default.Inject(this); - DiskCache = CacheManager.Default; + TangoIOC.Default.GetInstanceWhenAvailable<FSEServicesContainer>((x) => { Services = x; diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs index 60d0fb372..1c2d5901a 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/FSEServicesContainer.cs @@ -43,6 +43,11 @@ namespace Tango.FSE.BL public TangoVersionsService TangoVersionsService { get; set; } /// <summary> + /// Gets or sets the tango versions service. + /// </summary> + public TechComponentsService TechComponentsService { get; set; } + + /// <summary> /// Initializes a new instance of the <see cref="FSEServicesContainer"/> class. /// </summary> /// <param name="authentication">The authentication.</param> @@ -54,6 +59,7 @@ namespace Tango.FSE.BL AuthenticationService = new AuthenticationService(); BugReportingService = new BugReportingService(); TangoVersionsService = new TangoVersionsService(); + TechComponentsService = new TechComponentsService(); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/IMemoryCacheDictionary.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/IMemoryCacheDictionary.cs new file mode 100644 index 000000000..3b64b4676 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/IMemoryCacheDictionary.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.BL +{ + /// <summary> + /// Represents an in-memory cache dictionary. + /// </summary> + public interface IMemoryCacheDictionary + { + /// <summary> + /// Gets the cache name. + /// </summary> + String Name { get; } + + /// <summary> + /// Gets the count of items. + /// </summary> + int Count { get; } + + /// <summary> + /// Clears this all items from cache. + /// </summary> + void Clear(); + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/MemoryCacheDictionary.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/MemoryCacheDictionary.cs new file mode 100644 index 000000000..8d7a563ff --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/MemoryCacheDictionary.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.BL +{ + /// <summary> + /// Represents an in-memory cache dictionary of type T. + /// </summary> + /// <typeparam name="TValue"></typeparam> + /// <seealso cref="Tango.FSE.BL.IMemoryCacheDictionary" /> + public class MemoryCacheDictionary<TKey, TValue> : IMemoryCacheDictionary where TValue : class + { + private ConcurrentDictionary<TKey, TValue> _dictionary; + + /// <summary> + /// Gets the cache name. + /// </summary> + public String Name { get; private set; } + + /// <summary> + /// Gets the count of items. + /// </summary> + public int Count + { + get { return _dictionary.Count; } + } + + /// <summary> + /// Initializes a new instance of the <see cref="MemoryCacheDictionary{T}"/> class. + /// </summary> + /// <param name="name">The name of the cache.</param> + public MemoryCacheDictionary(String name) + { + Name = name; + _dictionary = new ConcurrentDictionary<TKey, TValue>(); + } + + /// <summary> + /// Determines whether this cache contains an element with the specified key. + /// </summary> + /// <param name="key">The key.</param> + public bool ContainsKey(TKey key) + { + return _dictionary.ContainsKey(key); + } + + /// <summary> + /// Gets a cached item by the specified key. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="throwIfNotFound">if set to <c>true</c> throws exception when item not found otherwise returns null.</param> + /// <exception cref="KeyNotFoundException"></exception> + public TValue Get(TKey key, bool throwIfNotFound = true) + { + TValue value = null; + + if (_dictionary.TryGetValue(key, out value)) + { + return value; + } + else + { + if (throwIfNotFound) + { + throw new KeyNotFoundException($"Could not locate key '{key}' on cache '{Name}'."); + } + else + { + return null; + } + } + } + + /// <summary> + /// Puts a new cached item or overrides an existing one. + /// </summary> + /// <param name="key">The key.</param> + /// <param name="value">The value.</param> + public void Put(TKey key, TValue value) + { + _dictionary[key] = value; + } + + /// <summary> + /// Get all cached items as a list. + /// </summary> + /// <returns></returns> + public List<TValue> ToList(bool throwOnEmpty = false) + { + var list = _dictionary.Select(x => x.Value).ToList(); + + if (throwOnEmpty && list.Count == 0) + { + throw new KeyNotFoundException("The memory cache does not contain any items."); + } + + return list; + } + + /// <summary> + /// Clears this all items from cache. + /// </summary> + public void Clear() + { + _dictionary.Clear(); + } + } + + /// <summary> + /// Represents an in-memory cache dictionary of type T. + /// </summary> + /// <typeparam name="TValue"></typeparam> + /// <seealso cref="Tango.FSE.BL.IMemoryCacheDictionary" /> + public class MemoryCacheDoubleKeyDictionary<TKey1, TKey2, TValue> : IMemoryCacheDictionary where TValue : class + { + private ConcurrentDictionary<String, TValue> _dictionary; + + /// <summary> + /// Gets the cache name. + /// </summary> + public String Name { get; private set; } + + /// <summary> + /// Gets the count of items. + /// </summary> + public int Count + { + get { return _dictionary.Count; } + } + + /// <summary> + /// Initializes a new instance of the <see cref="MemoryCacheDictionary{T}"/> class. + /// </summary> + /// <param name="name">The name of the cache.</param> + public MemoryCacheDoubleKeyDictionary(String name) + { + Name = name; + _dictionary = new ConcurrentDictionary<String, TValue>(); + } + + /// <summary> + /// Determines whether this cache contains an element with the specified keys. + /// </summary> + /// <param name="key1">The first key.</param> + /// <param name="key2">The second key.</param> + public bool ContainsKey(TKey1 key1, TKey2 key2) + { + return _dictionary.ContainsKey(key1.ToString() + key2.ToString()); + } + + /// <summary> + /// Gets a cached item by the specified keys. + /// </summary> + /// <param name="key1">The first key.</param> + /// <param name="key2">The second key.</param> + /// <param name="throwIfNotFound">if set to <c>true</c> throws exception when item not found otherwise returns null.</param> + /// <exception cref="KeyNotFoundException"></exception> + public TValue Get(TKey1 key1, TKey2 key2, bool throwIfNotFound = true) + { + TValue value = null; + + if (_dictionary.TryGetValue(key1.ToString() + key2.ToString(), out value)) + { + return value; + } + else + { + if (throwIfNotFound) + { + throw new KeyNotFoundException($"Could not locate key '{key1 + " " + key2}' on cache '{Name}'."); + } + else + { + return null; + } + } + } + + /// <summary> + /// Puts a new cached item or overrides an existing one. + /// </summary> + /// <param name="key1">The first key.</param> + /// <param name="key2">The second key.</param> + /// <param name="value">The value.</param> + public void Put(TKey1 key1, TKey2 key2, TValue value) + { + _dictionary[key1.ToString() + key2.ToString()] = value; + } + + /// <summary> + /// Get all cached items as a list. + /// </summary> + /// <returns></returns> + public List<TValue> ToList(bool throwOnEmpty = false) + { + var list = _dictionary.Select(x => x.Value).ToList(); + + if (throwOnEmpty && list.Count == 0) + { + throw new KeyNotFoundException("The memory cache does not contain any items."); + } + + return list; + } + + /// <summary> + /// Clears this all items from cache. + /// </summary> + public void Clear() + { + _dictionary.Clear(); + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/MemoryCacheManager.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/MemoryCacheManager.cs new file mode 100644 index 000000000..6a53e302f --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/MemoryCacheManager.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.FSE.BL +{ + /// <summary> + /// Represents an in-memory global cache manager. + /// </summary> + public class MemoryCacheManager + { + private Dictionary<String, IMemoryCacheDictionary> _cacheDictionaries; + + private static MemoryCacheManager _instance; + /// <summary> + /// Gets the default singleton instance. + /// </summary> + public static MemoryCacheManager Default + { + get + { + if (_instance == null) + { + _instance = new MemoryCacheManager(); + } + + return _instance; + } + } + + /// <summary> + /// Initializes a new instance of the <see cref="MemoryCacheManager"/> class. + /// </summary> + public MemoryCacheManager() + { + _cacheDictionaries = new Dictionary<String, IMemoryCacheDictionary>(); + } + + /// <summary> + /// Gets the specified <see cref="MemoryCacheDictionary{T}"/> or creates and return a new one. + /// </summary> + /// <typeparam name="TValue"></typeparam> + /// <param name="name">The name.</param> + /// <returns></returns> + public MemoryCacheDictionary<TKey, TValue> GetOrCreateCache<TKey, TValue>(String name) where TValue : class + { + if (_cacheDictionaries.ContainsKey(name)) + { + return _cacheDictionaries[name] as MemoryCacheDictionary<TKey, TValue>; + } + else + { + var cacheDictionary = new MemoryCacheDictionary<TKey, TValue>(name); + _cacheDictionaries[name] = cacheDictionary; + return cacheDictionary; + } + } + + /// <summary> + /// Gets the specified <see cref="MemoryCacheDoubleKeyDictionary{T}"/> or creates and return a new one. + /// </summary> + /// <typeparam name="TValue"></typeparam> + /// <param name="name">The name.</param> + /// <returns></returns> + public MemoryCacheDoubleKeyDictionary<TKey1, TKey2, TValue> GetOrCreateCache<TKey1, TKey2, TValue>(String name) where TValue : class + { + if (_cacheDictionaries.ContainsKey(name)) + { + return _cacheDictionaries[name] as MemoryCacheDoubleKeyDictionary<TKey1, TKey2, TValue>; + } + else + { + var cacheDictionary = new MemoryCacheDoubleKeyDictionary<TKey1, TKey2, TValue>(name); + _cacheDictionaries[name] = cacheDictionary; + return cacheDictionary; + } + } + + /// <summary> + /// Clears all <see cref="IMemoryCacheDictionary"/> stored by this manager. + /// </summary> + public void ClearAll() + { + foreach (var cacheDictionary in _cacheDictionaries) + { + cacheDictionary.Value.Clear(); + } + } + } +} diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/ReadOnlyEntityRepository.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/ReadOnlyEntityRepository.cs new file mode 100644 index 000000000..45fb65e10 --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/ReadOnlyEntityRepository.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Tango.BL; + +namespace Tango.FSE.BL +{ + public class ReadOnlyEntityRepository<TEntity, TCachedEntity> : EntityRepositoryBase<TEntity, TCachedEntity> where TEntity : ObservableEntity<TEntity> where TCachedEntity : ObservableEntityDTO<TCachedEntity, TEntity> + { + private Func<TCachedEntity, TEntity> _convertToEntity; + private Func<TEntity, TCachedEntity> _convertToCached; + private DataResolverNode[] _nodes; + + public ReadOnlyEntityRepository(Func<TCachedEntity, TEntity> convertToEntity, Func<TEntity, TCachedEntity> convertToCached, params DataResolverNode[] nodes) + { + _convertToEntity = convertToEntity; + _convertToCached = convertToCached; + _nodes = nodes; + } + + protected override TCachedEntity ConvertToCached(TEntity entity) + { + return _convertToCached.Invoke(entity); + } + + protected override TEntity ConvertToEntity(TCachedEntity cachedEntity) + { + return _convertToEntity(cachedEntity); + } + + public Task<List<TEntity>> FindAll(Expression<Func<TEntity, bool>> expression) + { + return FindAll(expression, _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/MachinesService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/MachinesService.cs index 03d17e5ed..34aaf86b6 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/MachinesService.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/MachinesService.cs @@ -26,16 +26,16 @@ namespace Tango.FSE.BL.Services private const string FULL_MACHINES_COLLECTION = "Machines_Full"; private bool _fullMachinesCachePerformed; - private ConcurrentDictionary<String, CachedMachine> _machinesCache; - private ConcurrentDictionary<String, CachedMachine> _machinesCacheFull; + private MemoryCacheDictionary<String, CachedMachine> _machinesCache; + private MemoryCacheDictionary<String, CachedMachine> _machinesCacheFull; /// <summary> /// Initializes a new instance of the <see cref="MachinesService"/> class. /// </summary> public MachinesService() { - _machinesCache = new ConcurrentDictionary<string, CachedMachine>(); - _machinesCacheFull = new ConcurrentDictionary<string, CachedMachine>(); + _machinesCache = MemoryCache.GetOrCreateCache<String, CachedMachine>(MACHINES_COLLECTION); + _machinesCacheFull = MemoryCache.GetOrCreateCache<String, CachedMachine>(FULL_MACHINES_COLLECTION); } /// <summary> @@ -53,7 +53,7 @@ namespace Tango.FSE.BL.Services .ConfigureCascade(DataResolverNode.InMemoryCache, DataResolverNode.Online, DataResolverNode.DiskCache) .InMemoryCache((context) => { - return _machinesCache[serialNumber].ToObservable(); + return _machinesCache.Get(serialNumber).ToObservable(); }) .Online((context) => { @@ -72,7 +72,7 @@ namespace Tango.FSE.BL.Services var m = cachedMachine.ToObservable(); //Store in memory cache. - _machinesCache[serialNumber] = cachedMachine; + _machinesCache.Put(serialNumber, cachedMachine); //Store disk cache. try @@ -98,6 +98,10 @@ namespace Tango.FSE.BL.Services using (var cache = DiskCache.CreateContext()) { var cachedMachine = cache.GetCollection<CachedMachine>(MACHINES_COLLECTION).FindOne(x => x.SerialNumber == serialNumber && x.OrganizationGuid == CurrentUser.OrganizationGuid); + + //Store in memory cache. + _machinesCache.Put(serialNumber, cachedMachine); + return cachedMachine.ToObservable(); } }) @@ -126,7 +130,7 @@ namespace Tango.FSE.BL.Services .ConfigureCascade(DataResolverNode.InMemoryCache, DataResolverNode.Online, DataResolverNode.DiskCache) .InMemoryCache((context) => { - return _machinesCacheFull[serialNumber].ToObservable(); + return _machinesCacheFull.Get(serialNumber).ToObservable(); }) .Online((context) => { @@ -147,7 +151,7 @@ namespace Tango.FSE.BL.Services var cachedMachine = CachedMachine.FromObservable<CachedMachine>(machine); //Store in memory cache. - _machinesCacheFull[serialNumber] = cachedMachine; + _machinesCacheFull.Put(serialNumber, cachedMachine); //Store disk cache. try @@ -208,6 +212,10 @@ namespace Tango.FSE.BL.Services using (var cache = DiskCache.CreateContext()) { var cachedMachine = cache.GetCollection<CachedMachine>(FULL_MACHINES_COLLECTION).FindOne(x => x.SerialNumber == serialNumber && x.OrganizationGuid == CurrentUser.OrganizationGuid); + + //Store in memory cache. + _machinesCacheFull.Put(serialNumber, cachedMachine); + return cachedMachine.ToObservable(); } }) @@ -228,7 +236,6 @@ namespace Tango.FSE.BL.Services { var machines = _machinesCache .ToList() - .Select(x => x.Value) .Where(x => x.OrganizationGuid == CurrentUser.OrganizationGuid) .Select(x => x.ToObservable()) .ToList(); @@ -256,7 +263,7 @@ namespace Tango.FSE.BL.Services { var cachedMachine = CachedMachine.FromObservable<CachedMachine>(machine); - _machinesCache[machine.SerialNumber] = cachedMachine; + _machinesCache.Put(machine.SerialNumber, cachedMachine); collection.Upsert(cachedMachine); } @@ -282,7 +289,7 @@ namespace Tango.FSE.BL.Services foreach (var cachedMachine in cachedMachines) { - _machinesCache[cachedMachine.SerialNumber] = cachedMachine; + _machinesCache.Put(cachedMachine.SerialNumber, cachedMachine); } return cachedMachines.Select(x => x.ToObservable()).ToList(); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs index 2c44cac74..94387004d 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TangoVersionsService.cs @@ -15,11 +15,11 @@ namespace Tango.FSE.BL.Services public class TangoVersionsService : FSEServiceBase { private const string TANGO_VERSIONS_COLLECTION = "TangoVersions"; - private ConcurrentDictionary<String, CachedTangoVersion> _tangoVersionsCache; + private MemoryCacheDoubleKeyDictionary<String, String, CachedTangoVersion> _tangoVersionsCache; public TangoVersionsService() { - _tangoVersionsCache = new ConcurrentDictionary<string, CachedTangoVersion>(); + _tangoVersionsCache = MemoryCache.GetOrCreateCache<String, String, CachedTangoVersion>(TANGO_VERSIONS_COLLECTION); } /// <summary> @@ -34,7 +34,6 @@ namespace Tango.FSE.BL.Services { var tangoVersions = _tangoVersionsCache .ToList() - .Select(x => x.Value) .Where(x => x.EnvironmentID == Authentication.CurrentEnvironment.ID) .Select(x => x.TangoVersion.ToObservable()) .OrderByDescending(x => Version.Parse(x.Version)) @@ -66,7 +65,7 @@ namespace Tango.FSE.BL.Services cachedTangoVersion.EnvironmentID = Authentication.CurrentEnvironment.ID; cachedTangoVersion.TangoVersion = tangoVersionDTO; - _tangoVersionsCache[tangoVersion.Version + " " + Authentication.CurrentEnvironment.ID] = cachedTangoVersion; + _tangoVersionsCache.Put(tangoVersion.Version, Authentication.CurrentEnvironment.ID, cachedTangoVersion); collection.Upsert(cachedTangoVersion); } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs new file mode 100644 index 000000000..f0f72be7a --- /dev/null +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/Services/TechComponentsService.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Tango.BL; +using Tango.BL.DTO; +using Tango.BL.Entities; + +namespace Tango.FSE.BL.Services +{ + public class TechComponentsService : FSEServiceBase + { + 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 TechComponentsService() + { + Monitors = new ReadOnlyEntityRepository<TechMonitor, TechMonitorDTO>( + x => x.ToObservable(), + x => TechMonitorDTO.FromObservable(x), + DataResolverNode.InMemoryCache, + DataResolverNode.Online, + DataResolverNode.DiskCache); + + IOs = new ReadOnlyEntityRepository<TechIo, TechIoDTO>( + x => x.ToObservable(), + x => TechIoDTO.FromObservable(x), + DataResolverNode.InMemoryCache, + DataResolverNode.Online, + DataResolverNode.DiskCache); + + Dispensers = new ReadOnlyEntityRepository<TechDispenser, TechDispenserDTO>( + x => x.ToObservable(), + x => TechDispenserDTO.FromObservable(x), + DataResolverNode.InMemoryCache, + DataResolverNode.Online, + DataResolverNode.DiskCache); + } + } +} 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 ad514c09c..f0097c2f6 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 @@ -38,6 +38,9 @@ <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <HintPath>..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath> </Reference> + <Reference Include="ExpressionTreeToString, Version=2.0.20.0, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\packages\ExpressionTreeToString.2.0.20\lib\netstandard2.0\ExpressionTreeToString.dll</HintPath> + </Reference> <Reference Include="LiteDB, Version=5.0.4.0, Culture=neutral, PublicKeyToken=4ee40123013c9f27, processorArchitecture=MSIL"> <HintPath>..\..\packages\LiteDB.5.0.4\lib\net45\LiteDB.dll</HintPath> </Reference> @@ -50,6 +53,9 @@ <Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.Configuration" /> <Reference Include="System.Core" /> + <Reference Include="System.Linq.Dynamic, Version=1.0.6132.35681, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\packages\System.Linq.Dynamic.1.0.7\lib\net40\System.Linq.Dynamic.dll</HintPath> + </Reference> <Reference Include="System.Runtime" /> <Reference Include="System.Runtime.Serialization" /> <Reference Include="System.Xaml" /> @@ -69,15 +75,20 @@ <Reference Include="Z.Expressions.Eval, Version=3.1.8.0, Culture=neutral, PublicKeyToken=59b66d028979105b, processorArchitecture=MSIL"> <HintPath>..\..\packages\Z.Expressions.Eval.3.1.8\lib\net45\Z.Expressions.Eval.dll</HintPath> </Reference> + <Reference Include="ZSpitz.Util, Version=0.0.6.0, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\packages\ZSpitz.Util.0.0.6\lib\netstandard2.0\ZSpitz.Util.dll</HintPath> + </Reference> </ItemGroup> <ItemGroup> + <Compile Include="EntityRepositoryBase.cs" /> + <Compile Include="MemoryCacheDictionary.cs" /> <Compile Include="CacheEntities\CachedBugInfoResponse.cs" /> <Compile Include="CacheEntities\CachedConfiguration.cs" /> <Compile Include="CacheEntities\CachedLoginResponse.cs" /> <Compile Include="CacheEntities\CachedMachine.cs" /> <Compile Include="CacheEntities\CachedTangoVersion.cs" /> <Compile Include="CacheEntities\CachedUser.cs" /> - <Compile Include="CacheManager.cs" /> + <Compile Include="DiskCacheManager.cs" /> <Compile Include="Connectivity\DefaultConnectivityProvider.cs" /> <Compile Include="Connectivity\IConnectivityProvider.cs" /> <Compile Include="DataResolver.cs" /> @@ -86,13 +97,17 @@ <Compile Include="FSEServiceBase.cs" /> <Compile Include="Gateway\GatewayClient.cs" /> <Compile Include="IAuthenticationService.cs" /> + <Compile Include="IMemoryCacheDictionary.cs" /> <Compile Include="InternetConnectionException.cs" /> + <Compile Include="MemoryCacheManager.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="ReadOnlyEntityRepository.cs" /> <Compile Include="Services\AuthenticationService.cs" /> <Compile Include="Services\BugReportingService.cs" /> <Compile Include="Services\GatewayService.cs" /> <Compile Include="Services\MachinesService.cs" /> <Compile Include="Services\TangoVersionsService.cs" /> + <Compile Include="Services\TechComponentsService.cs" /> <Compile Include="Services\UsersService.cs" /> <Compile Include="Web\FSEWebClient.cs" /> <Compile Include="Web\FSEWebClientBase.cs" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.BL/packages.config b/Software/Visual_Studio/FSE/Tango.FSE.BL/packages.config index 9e8400eb2..ea481ad19 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.BL/packages.config +++ b/Software/Visual_Studio/FSE/Tango.FSE.BL/packages.config @@ -1,9 +1,13 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> + <package id="ExpressionTreeToString" version="2.0.20" targetFramework="net461" /> <package id="LiteDB" version="5.0.4" targetFramework="net461" /> + <package id="Microsoft.CSharp" version="4.7.0" targetFramework="net461" /> <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> + <package id="System.Linq.Dynamic" version="1.0.7" targetFramework="net461" /> <package id="Z.EntityFramework.Extensions" version="4.0.58" targetFramework="net461" /> <package id="Z.EntityFramework.Plus.EF6" version="1.12.19" targetFramework="net461" /> <package id="Z.Expressions.Eval" version="3.1.8" targetFramework="net461" /> + <package id="ZSpitz.Util" version="0.0.6" targetFramework="net461" /> </packages>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Diagnostics/DiagnosticsFrame.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/Diagnostics/DiagnosticsFrame.cs index ff2364e0a..88139d628 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Diagnostics/DiagnosticsFrame.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Diagnostics/DiagnosticsFrame.cs @@ -9,6 +9,24 @@ namespace Tango.FSE.Common.Diagnostics { public class DiagnosticsFrame { - public StartDiagnosticsResponse Diagnostics { get; set; } + /// <summary> + /// Diagnostics frame data. + /// </summary> + public StartDiagnosticsResponse Data { get; set; } + + /// <summary> + /// The calculated local date and time by the first diagnostics response and elapsed Milli. + /// </summary> + public DateTime DiagnosticsTime { get; set; } + + /// <summary> + /// The reported elapsed time from the previous diagnostics frame (reported by the embedded device). + /// </summary> + public TimeSpan Delta { get; set; } + + /// <summary> + /// The average interval of diagnostics frame rate reported by the embedded device. + /// </summary> + public uint Interval { get; set; } } } 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 eba89b198..cf49286a4 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Diagnostics/DefaultDiagnosticsProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Diagnostics/DefaultDiagnosticsProvider.cs @@ -22,6 +22,7 @@ namespace Tango.FSE.UI.Diagnostics { private ProducerConsumerQueue<StartDiagnosticsResponse> _diagnosticsQueue; private Thread _queueThread; + private IMachineProvider _machineProvider; #region Events @@ -59,6 +60,7 @@ namespace Tango.FSE.UI.Diagnostics /// <param name="machineProvider">The machine provider.</param> public DefaultDiagnosticsProvider(IMachineProvider machineProvider) { + _machineProvider = machineProvider; _diagnosticsQueue = new ProducerConsumerQueue<StartDiagnosticsResponse>(); ThrottlingMode = SettingsManager.Default.GetOrCreate<FSESettings>().DiagnosticsThrottlingMode; machineProvider.MachineOperator.DiagnosticsDataAvailable += MachineOperator_DiagnosticsDataAvailable; @@ -95,15 +97,24 @@ namespace Tango.FSE.UI.Diagnostics } } - private void PostDiagnostics(StartDiagnosticsResponse diagnostics) + private void PostDiagnostics(StartDiagnosticsResponse data) { - FrameRate = (int)diagnostics.ElapsedMilli; + if (data.Monitors == null || _machineProvider.MachineOperator.DeviceInformation == null) return; + + FrameRate = (int)data.ElapsedMilli; + + uint interval = _machineProvider.MachineOperator.DeviceInformation.DiagnosticsInterval; + DateTime diagnosticsTime = DateTime.ParseExact(data.DateTime, "MM/dd/yyyy HH:mm:ss.fff", null); + TimeSpan delta = TimeSpan.FromMilliseconds(data.ElapsedMilli); FrameReceived?.Invoke(this, new DiagnosticsFrameReceivedEventArgs() { Frame = new DiagnosticsFrame() { - Diagnostics = diagnostics, + Data = data, + DiagnosticsTime = diagnosticsTime, + Delta = delta, + Interval = interval }, }); } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LoginViewVM.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LoginViewVM.cs index 15ae3af50..a9a677368 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LoginViewVM.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/ViewModels/LoginViewVM.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.BL; +using Tango.BL.DTO; +using Tango.BL.Entities; using Tango.Core.Commands; using Tango.Core.Cryptography; using Tango.FSE.Common; diff --git a/Software/Visual_Studio/Tango.Scripting/ExpressionGenerator.cs b/Software/Visual_Studio/Tango.Scripting/ExpressionGenerator.cs new file mode 100644 index 000000000..8db917a10 --- /dev/null +++ b/Software/Visual_Studio/Tango.Scripting/ExpressionGenerator.cs @@ -0,0 +1,22 @@ +using Microsoft.CodeAnalysis.CSharp.Scripting; +using Microsoft.CodeAnalysis.Scripting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Scripting +{ + public static class ExpressionGenerator + { + public static Func<T, bool> GenerateExpression<T>(String body, params Assembly[] assemblies) + { + var options = ScriptOptions.Default.AddReferences(assemblies); + Func<T, bool> func = CSharpScript.EvaluateAsync<Func<T, bool>>(body, options).Result; + return func; + } + } +} diff --git a/Software/Visual_Studio/Tango.Scripting/Tango.Scripting.csproj b/Software/Visual_Studio/Tango.Scripting/Tango.Scripting.csproj index f8dbc66c0..718bd96ce 100644 --- a/Software/Visual_Studio/Tango.Scripting/Tango.Scripting.csproj +++ b/Software/Visual_Studio/Tango.Scripting/Tango.Scripting.csproj @@ -141,6 +141,7 @@ <Link>GlobalVersionInfo.cs</Link> </Compile> <Compile Include="CompilerError.cs" /> + <Compile Include="ExpressionGenerator.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="ScriptEngine.cs" /> <Compile Include="OnExecuteParameters.cs" /> @@ -175,7 +176,7 @@ <Import Project="..\packages\Costura.Fody.1.6.2\build\dotnet\Costura.Fody.targets" Condition="Exists('..\packages\Costura.Fody.1.6.2\build\dotnet\Costura.Fody.targets')" /> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> + <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs index d0bfc886d..69d9fb6ae 100644 --- a/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs +++ b/Software/Visual_Studio/Tango.WebRTC/WebRtcTransportAdapter.cs @@ -143,19 +143,31 @@ namespace Tango.WebRTC else { LogManager.Log("Waiting for offer..."); - completed = true; State = TransportComponentState.Connected; - completionSource.SetResult(true); + + if (!completed) + { + completed = true; + completionSource.SetResult(true); + } } } catch (Exception ex) { - completionSource.SetException(ex); + if (!completed) + { + completed = true; + completionSource.SetException(ex); + } } } else { - completionSource.SetResult(true); + if (!completed) + { + completed = true; + completionSource.SetResult(true); + } } }); |
