From e258ef14ddcf9e60cf6a018b4a5dd87e49a8723f Mon Sep 17 00:00:00 2001 From: Dmitrii Cetvericov <dmitrii.cetvericov@fau.de> Date: Mon, 14 Sep 2020 21:14:09 +0200 Subject: [PATCH] Fix "How many bytes do I have left to send before the gate closes?" mechanism + add processing delay to scheduler. --- .../CBSVisualizer.Common.csproj | 1 + .../CBSVisualizer.Core.csproj | 2 +- .../CBSVisualizer.Messaging.csproj | 1 + .../Events/RegisterLinkCallbackEvent.cs | 12 +- .../Models/PriorityPacket.cs | 42 ++- .../CBSVisualizer.Modules.Link.csproj | 15 +- .../Externals/BoolToImageConverter.cs | 30 -- .../Properties/Resources.Designer.cs | 83 ----- .../Properties/Resources.resx | 127 ------- .../Resources/greendot.png | Bin 896 -> 0 bytes .../Resources/reddot.png | Bin 1074 -> 0 bytes .../ViewModels/LinkViewModel.cs | 114 +++---- .../Views/Link.xaml | 114 +++++-- .../CBSVisualizer.Modules.MenuBar.csproj | 4 +- .../MenuBarViewModel.LoadGeneration.cs | 49 +-- .../ViewModels/MenuBarViewModel.cs | 17 +- .../CBSVisualizer.Modules.QueueGroup.csproj | 3 +- .../Views/QueueGroup.xaml | 11 - .../Views/QueueGroup.xaml.cs | 11 +- .../CBSVisualizer.Modules.Queue.csproj | 6 +- .../QueueViewModel.LinkCallbacks.cs | 316 ++++++++++-------- .../ViewModels/QueueViewModel.cs | 236 ++++++++----- .../Views/Queue.xaml | 38 ++- .../Views/Queue.xaml.cs | 18 +- ...BSVisualizer.Modules.SettingsDialog.csproj | 3 +- .../ViewModels/SettingsDialogViewModel.cs | 8 +- .../Views/SettingsDialog.xaml | 8 +- ...BSVisualizer.Services.PacketService.csproj | 11 + .../Implementation/RandomPacketService.cs | 37 ++ .../Interface/IPacketService.cs | 22 ++ ...sualizer.Services.SchedulingService.csproj | 2 +- .../Implementation/RandomSchedulingService.cs | 31 +- .../Interface/ISchedulingService.cs | 12 +- ...SVisualizer.Services.SettingService.csproj | 1 + .../SettingService.cs | 2 +- CBSVisualizer/CBSVisualizer.sln | 7 + CBSVisualizer/CBSVisualizer/App.xaml | 7 + CBSVisualizer/CBSVisualizer/App.xaml.cs | 7 +- .../CBSVisualizer/CBSVisualizer.csproj | 4 +- .../CBSVisualizer/Views/MainWindow.xaml | 15 +- 40 files changed, 709 insertions(+), 718 deletions(-) delete mode 100644 CBSVisualizer/CBSVisualizer.Modules.Link/Externals/BoolToImageConverter.cs delete mode 100644 CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.Designer.cs delete mode 100644 CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.resx delete mode 100644 CBSVisualizer/CBSVisualizer.Modules.Link/Resources/greendot.png delete mode 100644 CBSVisualizer/CBSVisualizer.Modules.Link/Resources/reddot.png create mode 100644 CBSVisualizer/CBSVisualizer.Services.PacketService/CBSVisualizer.Services.PacketService.csproj create mode 100644 CBSVisualizer/CBSVisualizer.Services.PacketService/Implementation/RandomPacketService.cs create mode 100644 CBSVisualizer/CBSVisualizer.Services.PacketService/Interface/IPacketService.cs rename CBSVisualizer/CBSVisualizer.Services.SettingsService/{Service => Implementation}/SettingService.cs (96%) diff --git a/CBSVisualizer/CBSVisualizer.Common/CBSVisualizer.Common.csproj b/CBSVisualizer/CBSVisualizer.Common/CBSVisualizer.Common.csproj index 0a54f5c..6a7fe1b 100644 --- a/CBSVisualizer/CBSVisualizer.Common/CBSVisualizer.Common.csproj +++ b/CBSVisualizer/CBSVisualizer.Common/CBSVisualizer.Common.csproj @@ -5,6 +5,7 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="log4net" Version="2.0.9" /> <PackageReference Include="Prism.Core" Version="7.2.0.1422" /> </ItemGroup> diff --git a/CBSVisualizer/CBSVisualizer.Core/CBSVisualizer.Core.csproj b/CBSVisualizer/CBSVisualizer.Core/CBSVisualizer.Core.csproj index 16f7d6c..f6367cc 100644 --- a/CBSVisualizer/CBSVisualizer.Core/CBSVisualizer.Core.csproj +++ b/CBSVisualizer/CBSVisualizer.Core/CBSVisualizer.Core.csproj @@ -5,7 +5,7 @@ <AssemblyName>CBSVisualizer.Core</AssemblyName> </PropertyGroup> <ItemGroup> - <PackageReference Include="log4net" Version="2.0.8" /> + <PackageReference Include="log4net" Version="2.0.9" /> <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.MessagingCore/CBSVisualizer.Messaging.csproj b/CBSVisualizer/CBSVisualizer.MessagingCore/CBSVisualizer.Messaging.csproj index a1193fe..73d623a 100644 --- a/CBSVisualizer/CBSVisualizer.MessagingCore/CBSVisualizer.Messaging.csproj +++ b/CBSVisualizer/CBSVisualizer.MessagingCore/CBSVisualizer.Messaging.csproj @@ -5,6 +5,7 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="log4net" Version="2.0.9" /> <PackageReference Include="Prism.Core" Version="7.2.0.1422" /> </ItemGroup> diff --git a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs index d564aef..21304fe 100644 --- a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs +++ b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs @@ -35,36 +35,36 @@ namespace CBSVisualizer.Messaging.Events /// Allows to perform necessary initialization operations. /// </summary> /// <returns></returns> - Task Initialize(); + void Initialize(); /// <summary> /// Called by the link when the gate of this queue has been opened. /// </summary> /// <param name="trySubmitFirstPacket">Called with the packet that should be sent. Returns the result of the attempt (Accepted or Denied because of whatever reason). </param> - Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket); + void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket); /// <summary> /// Called by the link if the gate of the queue has been closed. /// </summary> - Task GateClosed(); + void GateClosed(); /// <summary> /// Called by the gate if the transmission of the given packet has been preempted. /// </summary> /// <param name="preemptedPacket"> the preempted packet.</param> /// <param name="leftoverBytes"> the bytes that are left to sent.</param> - Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes); + void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes); /// <summary> /// Called by the link when the transmission has started. /// </summary> /// <param name="bytesPerSecondRate"> the rate in bytes per second. </param> - Task TransmissionStarted(double bytesPerSecondRate); + void TransmissionStarted(long bytesPerSecondRate); /// <summary> /// Called when the transmission of the last packet has been completed. /// </summary> - Task TransmissionCompleted(); + void TransmissionCompleted(); } /// <summary> diff --git a/CBSVisualizer/CBSVisualizer.MessagingCore/Models/PriorityPacket.cs b/CBSVisualizer/CBSVisualizer.MessagingCore/Models/PriorityPacket.cs index 00be892..475ab8d 100644 --- a/CBSVisualizer/CBSVisualizer.MessagingCore/Models/PriorityPacket.cs +++ b/CBSVisualizer/CBSVisualizer.MessagingCore/Models/PriorityPacket.cs @@ -13,25 +13,31 @@ namespace CBSVisualizer.Messaging private static readonly int PREEMPTION_TRAILER_SIZE_BYTES = 12; - public static PriorityPacket NoPacket { get; } = new PriorityPacket(0, 0); - /** - * The priority of the packet. - */ + public static PriorityPacket NoPacket { get; } = new PriorityPacket(0, 0) { UniqueId = -1 }; + + /// <summary> + /// The unique ID of the packet. + /// </summary> + public long UniqueId { get; private set; } + + /// <summary> + /// The priority of the packet. + /// </summary> public int Priority { get; private set; } - /** - * The header size of the packet. - */ + /// <summary> + /// The header size of the packet. + /// </summary> public int HeaderBytes { get; private set; } - /* - * The amount of payload bytes. - */ + /// <summary> + /// The amount of payload bytes. + /// </summary> public int PayloadBytes { get; private set; } - /** - * The amount of trailer bytes. - */ + /// <summary> + /// The amount of trailer bytes. + /// </summary> public int TrailerBytes { get; private set; } public int Size @@ -42,6 +48,8 @@ namespace CBSVisualizer.Messaging } } + private static long currentId = 0; + /// <summary> /// Constructs a new PriorityPacket. /// </summary> @@ -51,6 +59,7 @@ namespace CBSVisualizer.Messaging /// <param name="trailerBytes"></param> public PriorityPacket(int prio, int headerBytes, int payloadBytes, int trailerBytes) { + UniqueId = currentId++; Priority = prio; HeaderBytes = headerBytes; PayloadBytes = payloadBytes; @@ -63,16 +72,13 @@ namespace CBSVisualizer.Messaging /// <param name="prio"></param> /// <param name="payloadBytes"></param> public PriorityPacket(int prio, int payloadBytes) + : this(prio, payloadBytes, PREEMPTION_HEADER_SIZE_BYTES, PREEMPTION_TRAILER_SIZE_BYTES) { - Priority = prio; - PayloadBytes = payloadBytes; - HeaderBytes = PREEMPTION_HEADER_SIZE_BYTES; - TrailerBytes = PREEMPTION_TRAILER_SIZE_BYTES; } public override string ToString() { - return $"Priority: {Priority}, Header Size: {HeaderBytes}, Payload Bytes: {PayloadBytes}, Trailer Bytes: {TrailerBytes}"; + return $"ID: {UniqueId} Priority: {Priority}, Header Size: {HeaderBytes}, Payload Bytes: {PayloadBytes}, Trailer Bytes: {TrailerBytes}"; } } } diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj index b2c95d5..88a26a2 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj +++ b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj @@ -5,6 +5,8 @@ <AssemblyName>CBSVisualizer.Modules.Link</AssemblyName> </PropertyGroup> <ItemGroup> + <PackageReference Include="log4net" Version="2.0.9" /> + <PackageReference Include="MaterialDesignThemes" Version="3.1.3" /> <PackageReference Include="ParallelExtensionsExtras" Version="1.2.0" /> <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" /> </ItemGroup> @@ -14,17 +16,4 @@ <ProjectReference Include="..\CBSVisualizer.MessagingCore\CBSVisualizer.Messaging.csproj" /> <ProjectReference Include="..\CBSVisualizer.Services.SchedulingService\CBSVisualizer.Services.SchedulingService.csproj" /> </ItemGroup> - <ItemGroup> - <Compile Update="Properties\Resources.Designer.cs"> - <DesignTime>True</DesignTime> - <AutoGen>True</AutoGen> - <DependentUpon>Resources.resx</DependentUpon> - </Compile> - </ItemGroup> - <ItemGroup> - <EmbeddedResource Update="Properties\Resources.resx"> - <Generator>ResXFileCodeGenerator</Generator> - <LastGenOutput>Resources.Designer.cs</LastGenOutput> - </EmbeddedResource> - </ItemGroup> </Project> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Externals/BoolToImageConverter.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/Externals/BoolToImageConverter.cs deleted file mode 100644 index 0e34bdd..0000000 --- a/CBSVisualizer/CBSVisualizer.Modules.Link/Externals/BoolToImageConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Resources; -using System.Text; -using System.Windows.Data; -using System.Windows.Media.Imaging; - -namespace CBSVisualizer.Modules.Link.Externals -{ - public class BoolToImageConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - bool val = (bool)value; - if (val) - { - return Properties.Resources.GreenDot; - } else - { - return Properties.Resources.RedDot; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } -} diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.Designer.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.Designer.cs deleted file mode 100644 index 7ca5c05..0000000 --- a/CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.Designer.cs +++ /dev/null @@ -1,83 +0,0 @@ -//------------------------------------------------------------------------------ -// <auto-generated> -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// </auto-generated> -//------------------------------------------------------------------------------ - -namespace CBSVisualizer.Modules.Link.Properties { - using System; - - - /// <summary> - /// A strongly-typed resource class, for looking up localized strings, etc. - /// </summary> - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// <summary> - /// Returns the cached ResourceManager instance used by this class. - /// </summary> - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CBSVisualizer.Modules.Link.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// <summary> - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// </summary> - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// <summary> - /// Looks up a localized resource of type System.Byte[]. - /// </summary> - internal static byte[] GreenDot { - get { - object obj = ResourceManager.GetObject("GreenDot", resourceCulture); - return ((byte[])(obj)); - } - } - - /// <summary> - /// Looks up a localized resource of type System.Byte[]. - /// </summary> - internal static byte[] RedDot { - get { - object obj = ResourceManager.GetObject("RedDot", resourceCulture); - return ((byte[])(obj)); - } - } - } -} diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.resx b/CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.resx deleted file mode 100644 index 49e1ad3..0000000 --- a/CBSVisualizer/CBSVisualizer.Modules.Link/Properties/Resources.resx +++ /dev/null @@ -1,127 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<root> - <!-- - Microsoft ResX Schema - - Version 2.0 - - The primary goals of this format is to allow a simple XML format - that is mostly human readable. The generation and parsing of the - various data types are done through the TypeConverter classes - associated with the data types. - - Example: - - ... ado.net/XML headers & schema ... - <resheader name="resmimetype">text/microsoft-resx</resheader> - <resheader name="version">2.0</resheader> - <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> - <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> - <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> - <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> - <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> - <value>[base64 mime encoded serialized .NET Framework object]</value> - </data> - <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> - <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> - <comment>This is a comment</comment> - </data> - - There are any number of "resheader" rows that contain simple - name/value pairs. - - Each data row contains a name, and value. The row also contains a - type or mimetype. Type corresponds to a .NET class that support - text/value conversion through the TypeConverter architecture. - Classes that don't support this are serialized and stored with the - mimetype set. - - The mimetype is used for serialized objects, and tells the - ResXResourceReader how to depersist the object. This is currently not - extensible. For a given mimetype the value must be set accordingly: - - Note - application/x-microsoft.net.object.binary.base64 is the format - that the ResXResourceWriter will generate, however the reader can - read any of the formats listed below. - - mimetype: application/x-microsoft.net.object.binary.base64 - value : The object must be serialized with - : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter - : and then encoded with base64 encoding. - - mimetype: application/x-microsoft.net.object.soap.base64 - value : The object must be serialized with - : System.Runtime.Serialization.Formatters.Soap.SoapFormatter - : and then encoded with base64 encoding. - - mimetype: application/x-microsoft.net.object.bytearray.base64 - value : The object must be serialized into a byte array - : using a System.ComponentModel.TypeConverter - : and then encoded with base64 encoding. - --> - <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> - <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> - <xsd:element name="root" msdata:IsDataSet="true"> - <xsd:complexType> - <xsd:choice maxOccurs="unbounded"> - <xsd:element name="metadata"> - <xsd:complexType> - <xsd:sequence> - <xsd:element name="value" type="xsd:string" minOccurs="0" /> - </xsd:sequence> - <xsd:attribute name="name" use="required" type="xsd:string" /> - <xsd:attribute name="type" type="xsd:string" /> - <xsd:attribute name="mimetype" type="xsd:string" /> - <xsd:attribute ref="xml:space" /> - </xsd:complexType> - </xsd:element> - <xsd:element name="assembly"> - <xsd:complexType> - <xsd:attribute name="alias" type="xsd:string" /> - <xsd:attribute name="name" type="xsd:string" /> - </xsd:complexType> - </xsd:element> - <xsd:element name="data"> - <xsd:complexType> - <xsd:sequence> - <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> - <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> - </xsd:sequence> - <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> - <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> - <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> - <xsd:attribute ref="xml:space" /> - </xsd:complexType> - </xsd:element> - <xsd:element name="resheader"> - <xsd:complexType> - <xsd:sequence> - <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> - </xsd:sequence> - <xsd:attribute name="name" type="xsd:string" use="required" /> - </xsd:complexType> - </xsd:element> - </xsd:choice> - </xsd:complexType> - </xsd:element> - </xsd:schema> - <resheader name="resmimetype"> - <value>text/microsoft-resx</value> - </resheader> - <resheader name="version"> - <value>2.0</value> - </resheader> - <resheader name="reader"> - <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> - </resheader> - <resheader name="writer"> - <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> - </resheader> - <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> - <data name="GreenDot" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\greendot.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> - </data> - <data name="RedDot" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\reddot.png;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> - </data> -</root> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Resources/greendot.png b/CBSVisualizer/CBSVisualizer.Modules.Link/Resources/greendot.png deleted file mode 100644 index 507dccf03172b0f3c7615fcd5cc7f5a69237bb53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 896 zcmeAS@N?(olHy`uVBq!ia0y~yVCZLHV3@|i#K6Fial>ai0|NtNage(c!@6@aFBupZ zSkfJR9T^xl_H+M9WMyDr;4JWnEM{QfI}E~%$MaXDFfcHSdb&7<RK&f#6PS0~frsJZ zlJJ+6w+?T6{xULzF<YXkmt~tvk>#Z`{(n~9RbR)V{Nec~9eK8w$KS3O4C<Z|wd9J@ zQZdb~9xGkFbc3=c5)j(>-}&wH`SIKR?|*y${r+wB3YE3uxpADYuE%Nzyjbl}RJ)aH z&Njs}w=zYQZLiN<JMmh{@?6`qQ5jo{Ze2T@vneckd2a2QWtoa|wv`&p{v6BJm$mk= zss9C~px$Nim0vwiEWKs+I%LgdtM<!#H4|LbAD&!sZP}U?POoc17XK<;nmu=FR>+=R zF>8y1d$q35SW(KlD)6S)<}K@-O;<(ccU`->!i{xx-}PN;S2e2N9*hcKCbjgP!=vc7 zR`Hcj6M8>=Q}pp(mFv0tp{IwI+v$T<dddEC)*d-@kZFs|noV=o-bu=Tx;Tn2EcIMi zRipVAMP2sQ7U|tr>U7y(e_izL)J>(OVk_rH$u++h+mw6`9Au%_KOQdVpT@s7(lQzr zj(gWW)jl?n@7=u3cmnjw?WntT5;LwIyj#2t7V@_iKkYuYX3pAOefOV&;^B&)u6!)q zuD91e8Px1uvA1ZOhwP=IJzd4yE^+T!epRV7<n-YWzmvWnzo{g;;Aur|=#O(p&P+=< zpZca#U2&y>?(yvCOL;EmrX?)iQ~N<hMRd*6ily%y{^Z0;>QukgRDWoCkSlEN*E_qU zBF<I`-#1#v9JcL}%i680eIv@|pWbxGZdvK0`E6SJWQ)_YORjOQjt_6WcI)SXWouS= zWWV)E*nBPM<DDvwzY?>n&tE-z&Gy{{-~FFBqq1E#@LjigsB)*xLiG2Y=*e5%a?kFX z%c#4>ZS9$=c~^V4xLrPLWgmPyvv=8y(lRO2tGmJvT$6tpSH3p4u}EQIuFBf>dxx4o t*|1#Ol~BCz^oCmE5+_{M<>SZe3m!2tt#Z7<&cMLH;OXk;vd$@?2>?0uups~d diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Resources/reddot.png b/CBSVisualizer/CBSVisualizer.Modules.Link/Resources/reddot.png deleted file mode 100644 index 885ff703a6a15f21a203b56b3969027e813427a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1074 zcmeAS@N?(olHy`uVBq!ia0y~yVCZLHV3@|i#K6Fial>ai0|NtNage(c!@6@aFBupZ zSkfJR9T^xl_H+M9WMyDr;4JWnEM{QfI}E~%$MaXDFfcG5_jGX#sfc?!(J@cPk%#&7 z1ewqO=Rf83V|Hd?6V|_$<*9paLx6kr@}s{#CYBWFs>XP8UJp97bqeXsw^94+|5dsF z*=pytb;ZHHAFig$t}mLZePp`GjOcE&wPNve&+dpaN!nj=+=K1vqO0e+%z2YtbfdER zD(*}0U0+n1*0r7QL4<Bp%D#&4f#<F)QVcor`h4L6G2aEMc@{3^x>j)^GMD}0b*&;| zW3GA!>so!4d$i5XD(m9Jav|}uz_{*nyXWuN+<Ggj<VNh#tzSj1Et>pJH&1WbDlys5 zEQOV-s#{<5Jn#5@`owxyb{pR{0nSCbRlkgnim~np+jnD8!<ncrFVwqTH+imhJ-_va zs_6AqLc5nt3htK6(%<MOw=Pth%}Z&a*xvJXV$!M)qn;)$<0;F&c>2x$q?J4|tDSqc zo(<Ejn*7)6&DP%R(vH2`I<GHczj-}rt8L6`&o$fHvrRj%e&e{dX!(uuBW2P%!sg$| zW4``M_;&7tsI^J^G$uxUVfwu<!k{aAYZvR{9bv0cn5VX9Uwr<y{AizI%<AYj5{I_# zBA>Z0HrsLj_V?YGwm|H5$<lox_|4ZaUIgmA+N9mQF{}M^wmWXP)-*3EzWeI8g0*TJ zZ^^B@suFfvIWF6ge^Y$t-fe|z`8HlRi{2{sMdx?C;We{$p?cF!9oTy6XprQaYf%>- zze(R1D6}qA+ssR8;kBlD8K6+L+$#1ZpgT6GaIMxxZ>`L&VqflnqTuA3tqa`kgL48K zvY&SAa(S%Vx?s6ID8}m6vdVstDXf=N-6~dcO!&ytsUcURE*O3nGZznz$aYk}8yXYs zpSzY-w#>UQ%l7G3v69<!kF>^?T#33c@w>ow(@P=Qj>}hdudaHzdh3Gb(xbL-w_Mw` z;PlobyzLeN*^a_1I<C)u?6a1Y*D!w1Z;j(wu@{t#k4Cc>?6}6d*4TYdK96!%?1iB8 zqqEx#S6pLVdrkkI;iST?dKm}hKE6H3v-YdF)E1{2&&HQq?VPpWcf^M{uM~4+jO+d{ n=)U6`b0N8zOV-ZrAH#yZV$*}>{5NJ`U|{fc^>bP0l+XkKzBuiw diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs index d2902db..995c0f5 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs @@ -2,11 +2,12 @@ using CBSVisualizer.Core.Mvvm; using CBSVisualizer.Messaging; using CBSVisualizer.Messaging.Events; -using CBSVisualizer.Services.SchedulingService; -using CBSVisualizer.Services.SettingsService.Service; +using CBSVisualizer.Services.SchedulingService.Interface; +using CBSVisualizer.Services.SettingsService.Implementation; using log4net; using Prism.Events; using Prism.Regions; +using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -31,8 +32,6 @@ namespace CBSVisualizer.Modules.Link.ViewModels private CancellationTokenSource tokenSource; - private Task packetTransmissionTask; - /// <summary> /// The queue that is currently sending. /// </summary> @@ -64,7 +63,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels linkCallbacks[callback.GetPriority()] = callback; }); - eventAggregator.GetEvent<SimulationStartedEvent>().Subscribe(() => + eventAggregator.GetEvent<SimulationStartedEvent>().Subscribe(async () => { if (linkCallbacks.Count != 8) { @@ -72,26 +71,31 @@ namespace CBSVisualizer.Modules.Link.ViewModels return; } - scheduler.StartScheduling(); + // Call Initialize() on each ILinkCallback. + log.Info("Initializing all links"); + foreach (var callback in linkCallbacks.Values) + { + callback.Initialize(); + } + + // Start scheduling. + try + { + await scheduler.StartScheduling(); + } catch (TaskCanceledException) { + log.Info("Scheduling was cancelled by button press."); + } log.Info("Simulation started."); }); - eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(async () => + eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(() => { // Stop the scheduler - await scheduler.StopScheduling(); + scheduler.StopScheduling(); // Stop packet sending. tokenSource?.Cancel(); - if (packetTransmissionTask != null) - { - try - { - await packetTransmissionTask; - } catch (TaskCanceledException) { } - - } // Reset all gate status lamps. SetStatusLamps(new HashSet<int>()); @@ -118,15 +122,6 @@ namespace CBSVisualizer.Modules.Link.ViewModels { // Cancel old sending task. tokenSource?.Cancel(); - if (packetTransmissionTask != null) - { - try - { - await packetTransmissionTask; - } - catch (TaskCanceledException) { } - - } packetInTransit = PriorityPacket.NoPacket; @@ -138,7 +133,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels // Handle transmission. tokenSource = new CancellationTokenSource(); - packetTransmissionTask = TransmitPackets(infoTuple); + await TransmitPackets(infoTuple); } /// <summary> @@ -148,19 +143,25 @@ namespace CBSVisualizer.Modules.Link.ViewModels { await Task.Run(async () => { + var bitrate = settingService.GetSettingValue<int>("bitrate"); + var remainingBytes = infoTuple.OpenedTime * (bitrate / 1000); + + log.Info($"The link can send {remainingBytes} until the next GateCloseEvent."); + while (!tokenSource.IsCancellationRequested) { // Scan the callbacks for the highest-prio queue that wants to send a packet. foreach (var queue in infoTuple.OpenedGates.OrderByDescending(gate => gate)) { - await linkCallbacks[queue].GateOpened(packet => + linkCallbacks[queue].GateOpened(packet => { if (packetInTransit == PriorityPacket.NoPacket) { - if (CanSendInTime(infoTuple.OpenedTime, packet)) + if (CanSendInTime(ref remainingBytes, packet)) { activeQueue = queue; packetInTransit = packet; + log.Info($"Packet {packetInTransit} of queue {activeQueue} has been scheduled for transit."); return PacketSubmitResult.Accepted; } else @@ -181,40 +182,46 @@ namespace CBSVisualizer.Modules.Link.ViewModels continue; } - log.Info($"Packet {packetInTransit} of queue {activeQueue} has been scheduled for transit."); - // Once a packet was selected for transmission, we send it. transmittedBytes = 0; - var bitrate = settingService.GetSettingValue<int>("bitrate"); - await linkCallbacks[activeQueue].TransmissionStarted(bitrate); - while (!tokenSource.IsCancellationRequested && transmittedBytes < packetInTransit.Size) - { - await Task.Delay(REFRESH_TIME_MS, tokenSource.Token); - transmittedBytes += REFRESH_TIME_MS * (bitrate / 1000); - log.Info($"Transmitted {transmittedBytes} of {packetInTransit.Size} bytes of packet {packetInTransit}."); - } + linkCallbacks[activeQueue].TransmissionStarted(bitrate); - if (transmittedBytes >= packetInTransit.Size) + try { - await linkCallbacks[activeQueue].TransmissionCompleted(); + while (!tokenSource.IsCancellationRequested && transmittedBytes < packetInTransit.Size) + { + await Task.Delay(REFRESH_TIME_MS, tokenSource.Token); + transmittedBytes += REFRESH_TIME_MS * (bitrate / 1000); + log.Info($"Transmitted {transmittedBytes} of {packetInTransit.Size} bytes of packet {packetInTransit}."); + } + } catch (TaskCanceledException) { } + finally + { + linkCallbacks[activeQueue].TransmissionCompleted(); log.Info($"{packetInTransit} of queue {activeQueue} has been sent successfully."); - } - // Reset the "Packet in transit" pointer. - packetInTransit = PriorityPacket.NoPacket; + // Reset the "Packet in transit" pointer. + packetInTransit = PriorityPacket.NoPacket; + } } }, tokenSource.Token); } - private bool CanSendInTime(int openedTime, PriorityPacket packet) + private bool CanSendInTime(ref int remainingBytes, PriorityPacket packet) { - // Bitrate * time = bits we can send in that time. - // if the packet is larger than that, we have to deny it due to pre-closing. - return packet.Size <= openedTime * (settingService.GetSettingValue<int>("bitrate") / 1000); + if (packet.Size > remainingBytes) + { + return false; + } + + log.Info($"Packet Size: {packet.Size}, remaining bytes until next GateCloseEvent: {remainingBytes}. {remainingBytes - packet.Size} bytes left."); + remainingBytes -= packet.Size; + return true; + } - private void CloseInactiveGates(ISet<int> openedGates) + private void CloseInactiveGates(IEnumerable<int> openedGates) { ISet<int> gatesToClose = new HashSet<int>(linkCallbacks.Keys); gatesToClose.ExceptWith(openedGates); @@ -230,18 +237,11 @@ namespace CBSVisualizer.Modules.Link.ViewModels /// Sets the status lamps according to the set. /// </summary> /// <param name="openedGates">the set containing the opened gates</param> - private void SetStatusLamps(ISet<int> openedGates) + private void SetStatusLamps(ICollection<int> openedGates) { foreach (var key in GateStatusDictionary.Keys) { - if (openedGates.Contains(key)) - { - GateStatusDictionary[key].Value = true; - } - else - { - GateStatusDictionary[key].Value = false; - } + GateStatusDictionary[key].Value = openedGates.Contains(key); } } diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml b/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml index 055371c..1c59871 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml +++ b/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml @@ -2,36 +2,98 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CBSVisualizer.Modules.Link.Views" - xmlns:externals="clr-namespace:CBSVisualizer.Modules.Link.Externals" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - mc:Ignorable="d" + mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" xmlns:prism="http://prismlibrary.com/" - prism:ViewModelLocator.AutoWireViewModel="True" > + prism:ViewModelLocator.AutoWireViewModel="True"> <Grid> - <Grid.Resources> - <externals:BoolToImageConverter x:Key="BoolToImageConv"/> - </Grid.Resources> <Grid.RowDefinitions> - <RowDefinition Height="Auto"/> - <RowDefinition Height="*"/> - <RowDefinition Height="*"/> - <RowDefinition Height="*"/> - <RowDefinition Height="*"/> - <RowDefinition Height="*"/> - <RowDefinition Height="*"/> - <RowDefinition Height="*"/> - <RowDefinition Height="*"/> + <RowDefinition Height="Auto" /> + <RowDefinition Height="*" /> + <RowDefinition Height="*" /> + <RowDefinition Height="*" /> + <RowDefinition Height="*" /> + <RowDefinition Height="*" /> + <RowDefinition Height="*" /> + <RowDefinition Height="*" /> + <RowDefinition Height="*" /> </Grid.RowDefinitions> - <TextBlock Text="Gate Status" Grid.Row="0" TextAlignment="Center"/> - <Image Grid.Row="1" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[7].Value, Converter={StaticResource BoolToImageConv}}"/> - <Image Grid.Row="2" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[6].Value, Converter={StaticResource BoolToImageConv}}"/> - <Image Grid.Row="3" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[5].Value, Converter={StaticResource BoolToImageConv}}"/> - <Image Grid.Row="4" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[4].Value, Converter={StaticResource BoolToImageConv}}"/> - <Image Grid.Row="5" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[3].Value, Converter={StaticResource BoolToImageConv}}"/> - <Image Grid.Row="6" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[2].Value, Converter={StaticResource BoolToImageConv}}"/> - <Image Grid.Row="7" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[1].Value, Converter={StaticResource BoolToImageConv}}"/> - <Image Grid.Row="8" HorizontalAlignment="Center" Source="{Binding GateStatusDictionary[0].Value, Converter={StaticResource BoolToImageConv}}"/> + <TextBlock Text="Gate Status" Grid.Row="0" TextAlignment="Center" /> + + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="Gate Status" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[7].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="MaterialDesignActionLightToggleButton" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[6].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="MaterialDesignActionLightToggleButton" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[5].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="MaterialDesignActionLightToggleButton" Grid.Row="4" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[4].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="MaterialDesignActionLightToggleButton" Grid.Row="5" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[3].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="MaterialDesignActionLightToggleButton" Grid.Row="6" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[2].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="MaterialDesignActionLightToggleButton" Grid.Row="7" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[1].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> + <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="MaterialDesignActionLightToggleButton" Grid.Row="8" HorizontalAlignment="Center" VerticalAlignment="Center" + IsChecked="{Binding GateStatusDictionary[0].Value, Mode=OneWay}"> + <ToggleButton.Content> + <materialDesign:PackIcon Kind="Gate" Foreground="Red"/> + </ToggleButton.Content> + <materialDesign:ToggleButtonAssist.OnContent> + <materialDesign:PackIcon Kind="GateOpen" Foreground="Green"/> + </materialDesign:ToggleButtonAssist.OnContent> + </ToggleButton> </Grid> -</UserControl> +</UserControl> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj index 39e0363..390006b 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj +++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj @@ -5,12 +5,14 @@ <AssemblyName>CBSVisualizer.Modules.MenuBar</AssemblyName> </PropertyGroup> <ItemGroup> + <PackageReference Include="log4net" Version="2.0.9" /> + <PackageReference Include="MaterialDesignThemes" Version="3.1.3" /> <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> <ProjectReference Include="..\CBSVisualizer.MessagingCore\CBSVisualizer.Messaging.csproj" /> + <ProjectReference Include="..\CBSVisualizer.Services.PacketService\CBSVisualizer.Services.PacketService.csproj" /> <ProjectReference Include="..\CBSVisualizer.Services.SettingsService\CBSVisualizer.Services.SettingService.csproj" /> - <ProjectReference Include="..\CBSVisualizer\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs index 8e09473..c94c3c8 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs @@ -2,10 +2,6 @@ using CBSVisualizer.Messaging.Events; using log4net; using Prism.Commands; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -33,22 +29,18 @@ namespace CBSVisualizer.Modules.MenuBar.ViewModels } } - private const int HEADER_BYTES = 100; - - private const int TRAILER_BYTES = 100; - private CancellationTokenSource tokenSource = new CancellationTokenSource(); - private readonly Random random = new Random(); - private bool CanStartLoadGeneration() { return !LoadGenerationInProgress; } - private bool CanStopLoadGeneration() + private async Task StartLoadThread() { - return LoadGenerationInProgress; + tokenSource = new CancellationTokenSource(); + LoadGenerationInProgress = true; + await GenerateLoad(); } private void StopLoadThread() @@ -59,38 +51,21 @@ namespace CBSVisualizer.Modules.MenuBar.ViewModels private async Task GenerateLoad() { - await Task.Run(async () => - { - int packetCount = 0; + int packetCount = 0; - while (!tokenSource.IsCancellationRequested) - { - eventAggregator.GetEvent<PacketArrivedEvent>().Publish(GenerateRandomPacket()); - await Task.Delay(settings.GetSettingValue<int>("interarrival_time")); - log.Info($"I've generated {++packetCount} packets"); - } - - }, tokenSource.Token); + while (!tokenSource.IsCancellationRequested) + { + eventAggregator.GetEvent<PacketArrivedEvent>().Publish(GenerateRandomPacket()); + await Task.Delay(settings.GetSettingValue<int>("interarrival_time")); + log.Info($"I've generated {++packetCount} packets"); + } } private PriorityPacket GenerateRandomPacket() { - PriorityPacket ret = new PriorityPacket( - random.Next(0, 8), // Priority between 0 and 7 - HEADER_BYTES, - random.Next(2000), // Random value between 0 and 1999. - TRAILER_BYTES); + PriorityPacket ret = packetService.GeneratePacket(); log.Info(ret); return ret; } - - - private async Task StartLoadThread() - { - tokenSource = new CancellationTokenSource(); - LoadGenerationInProgress = true; - - await GenerateLoad(); - } } } diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs index eb68171..ee49c0f 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs @@ -1,16 +1,12 @@ using CBSVisualizer.Core.Mvvm; using CBSVisualizer.Messaging.Events; -using CBSVisualizer.Services.SettingsService.Service; +using CBSVisualizer.Services.PacketService.Interface; +using CBSVisualizer.Services.SettingsService.Implementation; using Prism.Commands; using Prism.Events; -using Prism.Mvvm; using Prism.Regions; using Prism.Services.Dialogs; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + namespace CBSVisualizer.Modules.MenuBar.ViewModels { @@ -40,19 +36,22 @@ namespace CBSVisualizer.Modules.MenuBar.ViewModels private readonly SettingService settings; + private readonly IPacketService packetService; + - public MenuBarViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, IDialogService dialogService, SettingService settingService) + public MenuBarViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, IDialogService dialogService, SettingService settingService, IPacketService packetServ) : base(regionManager) { this.eventAggregator = eventAggregator; settings = settingService; + packetService = packetServ; StartSimulationCommand = new DelegateCommand(SignalSimulationStart, () => !SimulationRunning).ObservesProperty(() => SimulationRunning); StopSimulationCommand = new DelegateCommand(SignalSimulationStop).ObservesCanExecute(() => SimulationRunning); OpenSettingsCommand = new DelegateCommand(() => dialogService.Show("SettingsDialog", new DialogParameters(), result => { })); StartLoadGeneration = new DelegateCommand(async () => await StartLoadThread(), CanStartLoadGeneration).ObservesProperty(() => LoadGenerationInProgress); - StopLoadGeneration = new DelegateCommand(StopLoadThread, CanStopLoadGeneration).ObservesProperty(() => LoadGenerationInProgress); + StopLoadGeneration = new DelegateCommand(StopLoadThread, () => !CanStartLoadGeneration()).ObservesProperty(() => LoadGenerationInProgress); } private void SignalSimulationStart() { diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj index 9a03652..4028604 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj @@ -5,11 +5,12 @@ <AssemblyName>CBSVisualizer.Modules.Queue.QueueGroup</AssemblyName> </PropertyGroup> <ItemGroup> + <PackageReference Include="log4net" Version="2.0.9" /> + <PackageReference Include="MaterialDesignThemes" Version="3.1.3" /> <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> <ProjectReference Include="..\CBSVisualizer.Modules.Queue\CBSVisualizer.Modules.Queue.csproj" /> - <ProjectReference Include="..\CBSVisualizer\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml index 4f47ea4..091e5a5 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml @@ -10,7 +10,6 @@ prism:ViewModelLocator.AutoWireViewModel="True" > <Grid x:Name="Grid"> <Grid.RowDefinitions> - <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <RowDefinition Height="*"/> <RowDefinition Height="*"/> @@ -20,15 +19,5 @@ <RowDefinition Height="*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="*"/> - </Grid.ColumnDefinitions> - <TextBlock Text="Priority" Grid.Row="0" Grid.Column="0" TextAlignment="Center"/> - <TextBlock Text="Packet Count" Grid.Row="0" Grid.Column="1" TextAlignment="Center"/> - <TextBlock Text="Idle Slope [b/s]" Grid.Row="0" Grid.Column="2" TextAlignment="Center"/> - <TextBlock Text="Credit Behaviour" Grid.Row="0" Grid.Column="3" TextAlignment="Center"/> </Grid> </UserControl> diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs index 3100399..f917451 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs @@ -1,5 +1,7 @@ using CBSVisualizer.Modules.Queue.ViewModels; +using CBSVisualizer.Services.PacketService.Interface; using Prism.Events; +using Prism.Ioc; using Prism.Regions; using System; using System.Collections.Generic; @@ -23,15 +25,14 @@ namespace CBSVisualizer.Modules.Queue.QueueGroup.Views /// </summary> public partial class QueueGroup : UserControl { - public QueueGroup(IRegionManager regionManager, IEventAggregator eventAggregator) + public QueueGroup(IRegionManager regionManager, IEventAggregator eventAggregator, IPacketService packetService) { InitializeComponent(); - for (int prio = 1; prio < 9; prio++) + for (int prio = 7; prio >= 0; prio--) { - Queue.Views.Queue newQueue = new Queue.Views.Queue(new QueueViewModel(regionManager, eventAggregator, prio - 1)); - Grid.SetRow(newQueue, 9 - prio); - Grid.SetColumnSpan(newQueue, 4); + Queue.Views.Queue newQueue = new Queue.Views.Queue(new QueueViewModel(regionManager, eventAggregator, prio, packetService)); + Grid.SetRow(newQueue, 7 - prio); Grid.Children.Add(newQueue); } } diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj index 5fbb50f..7a155ee 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj @@ -5,11 +5,15 @@ <AssemblyName>CBSVisualizer.Modules.Queue</AssemblyName> </PropertyGroup> <ItemGroup> + <PackageReference Include="LiveCharts" Version="0.9.7" /> + <PackageReference Include="LiveCharts.Wpf" Version="0.9.7" /> + <PackageReference Include="log4net" Version="2.0.9" /> + <PackageReference Include="MaterialDesignThemes" Version="3.1.3" /> <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> <ProjectReference Include="..\CBSVisualizer.MessagingCore\CBSVisualizer.Messaging.csproj" /> - <ProjectReference Include="..\CBSVisualizer\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> + <ProjectReference Include="..\CBSVisualizer.Services.PacketService\CBSVisualizer.Services.PacketService.csproj" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs index 5658c4b..5053171 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs @@ -3,320 +3,348 @@ using CBSVisualizer.Messaging.Events; using System; using System.Diagnostics; using System.Linq; -using System.Threading.Tasks; namespace CBSVisualizer.Modules.Queue.ViewModels { public partial class QueueViewModel { + public enum CreditBehaviour + { + // This is selected when there should be no credit-based shaper for this queue. + NoCbs, + + // Frozen credit behaviour + Frozen, + + // The standard credit behaviour + Standard, + + // Return to zero. + ReturnToZero + } private abstract class LinkCallbackBase : ILinkCallback { - protected readonly QueueViewModel parent; - public LinkCallbackBase(QueueViewModel parentViewModel) + protected readonly QueueViewModel Parent; + + protected LinkCallbackBase(QueueViewModel parentViewModel) { - parent = parentViewModel; + Parent = parentViewModel; } - protected double GetSendSlope(double rate) + protected long GetSendSlope(long rate) { - return parent.IdleSlope - rate; + return Parent.IdleSlope - rate; } public int GetPriority() { - return parent.Priority; + return Parent.Priority; } - public virtual Task Initialize() + public virtual void Initialize() { // Do nothing by default. - return Task.CompletedTask; } protected bool CanSend() { - lock (parent.queueLock) + lock (Parent.queueLock) { - return parent.Queue.Count > 0 && parent.CurrentCredit >= 0; + return Parent.Queue.Count > 0 && Parent.CurrentCredit >= 0; } } - public abstract Task GateClosed(); - public abstract Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket); + protected void TrySendPacket(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket, Action<PriorityPacket> additionalAcceptedAction, + Action<PriorityPacket> deniedPreClosingAction, Action<PriorityPacket> deniedHigherPrioAction) + { + lock (Parent.queueLock) + { + lock (Parent.creditLock) + { + if (Parent.Queue.Count <= 0 || Parent.CurrentCredit < 0) + { + return; + } + + var firstPacket = Parent.Queue.First(); + + switch (trySubmitFirstPacket.Invoke(firstPacket)) + { + case PacketSubmitResult.Accepted: + Parent.Queue.Remove(firstPacket); + additionalAcceptedAction?.Invoke(firstPacket); + break; + + case PacketSubmitResult.DeniedHigherPrio: + deniedHigherPrioAction?.Invoke(firstPacket); + break; + + case PacketSubmitResult.DeniedPreClosing: + deniedPreClosingAction?.Invoke(firstPacket); + break; + } + } + } + } + + public abstract void GateClosed(); - public abstract Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes); + public abstract void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket); - public abstract Task TransmissionCompleted(); + public abstract void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes); - public abstract Task TransmissionStarted(double bytesPerSecondRate); + public abstract void TransmissionCompleted(); + + public abstract void TransmissionStarted(long bytesPerSecondRate); } - private class NoCBSLinkCallback : LinkCallbackBase + #region NoCbsLinkCallback + private class NoCbsLinkCallback : LinkCallbackBase { - public NoCBSLinkCallback(QueueViewModel parent) + public NoCbsLinkCallback(QueueViewModel parent) : base(parent) { } - public override Task GateClosed() + public override void GateClosed() { // Nothing to be done. - return Task.CompletedTask; } - public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) + public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) { // Try to submit the "oldest" packet. - lock (parent.queueLock) + lock (Parent.queueLock) { // If the queue is empty, return. - if (!CanSend()) + if (Parent.Queue.Count <= 0) { - return Task.CompletedTask; + return; } // If the packet was accepted, remove it from the queue. - var firstPacket = parent.Queue.First(); + var firstPacket = Parent.Queue.First(); if (trySubmitFirstPacket.Invoke(firstPacket) == PacketSubmitResult.Accepted) { - parent.Queue.Remove(firstPacket); + Parent.Queue.Remove(firstPacket); } // Otherwise, just don't do anything :-) } - return Task.CompletedTask; } - public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) + public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) { // Build a new packet that just contains the leftover bytes and put it into the queue. - lock (parent.queueLock) + lock (Parent.queueLock) { - parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes)); - return Task.CompletedTask; + Parent.Queue.Insert(0, new PriorityPacket(Parent.Priority, leftoverBytes)); } } - public override Task TransmissionCompleted() + public override void TransmissionStarted(long bytesPerSecondRate) { - return Task.CompletedTask; + // Just write some log. + Debug.WriteLine($"Packet of Queue {Parent.Priority} has started transmission with {bytesPerSecondRate} bytes/s."); } - - public override Task TransmissionStarted(double bytesPerSecondRate) + + public override void TransmissionCompleted() { - // Just write some log. - Debug.WriteLine($"Packet of Queue {parent.Priority} has started transmission with {bytesPerSecondRate} bytes/s."); - return Task.CompletedTask; + // Nothing to be done. } } + #endregion - private class FrozenLinkCallback : LinkCallbackBase + #region StandardLinkCallback + private class StandardLinkCallback : LinkCallbackBase { - - public FrozenLinkCallback(QueueViewModel parent) - : base(parent) + public StandardLinkCallback(QueueViewModel parentViewModel) + : base(parentViewModel) { } - public override async Task Initialize() + public override void Initialize() { - await parent.StartCreditThread(parent.IdleSlope); + Parent.StartCreditThread(Parent.IdleSlope); } - public override Task GateClosed() + public override void GateClosed() { - // Nothing special happens here. The credit handling is done in the GateOpened method. - return Task.CompletedTask; + // Stop the credit thread. + Parent.StopCreditThread(); } - public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) + public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) { - // Try to submit first packet. - lock (parent.queueLock) - { - - if (!CanSend()) - { - return Task.CompletedTask; - } - - var firstPacket = parent.Queue.First(); - var submitResult = trySubmitFirstPacket.Invoke(firstPacket); - - // If the packet was accepted, remove it from the queue. - if (submitResult == PacketSubmitResult.Accepted) - { - parent.Queue.Remove(firstPacket); - - // If my packet was denied due to pre-closing, freeze my credit. - } else if (submitResult == PacketSubmitResult.DeniedPreClosing) - { - _ = parent.StopCreditThread(); - } - } + // Start the credit thread + Parent.StartCreditThread(Parent.IdleSlope); - // Otherwise, just let the credit grow for now. - return Task.CompletedTask; + // Try to send the packet if we can. + TrySendPacket(trySubmitFirstPacket, null, null, null); } - public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) + public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) { - // Put the leftovers of the packet back into the queue. - lock (parent.queueLock) + lock (Parent.queueLock) { - parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes)); + Parent.Queue.Insert(0, new PriorityPacket(Parent.Priority, leftoverBytes)); } - - return Task.CompletedTask; } - public override async Task TransmissionCompleted() + public override void TransmissionCompleted() { - // Stop and restart the credit thread. - await parent.StopCreditThread(); - await parent.StartCreditThread(parent.IdleSlope); + Log.Info("Transmission Completed"); + Parent.StopCreditThread(); + Parent.StartCreditThread(Parent.IdleSlope); } - public override async Task TransmissionStarted(double bytesPerSecondRate) + public override void TransmissionStarted(long bytesPerSecondRate) { - // Decrease the credit by the idle slope. - await parent.StopCreditThread(); - await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate)); + Log.Info("TransmissionStarted"); + Parent.StopCreditThread(); + Parent.StartCreditThread(GetSendSlope(bytesPerSecondRate)); } } + #endregion - private class StandardLinkCallback : LinkCallbackBase + #region FrozenLinkCallback + private class FrozenLinkCallback : LinkCallbackBase { - - public StandardLinkCallback(QueueViewModel parentViewModel) - : base(parentViewModel) + public FrozenLinkCallback(QueueViewModel parent) + : base(parent) { } - public override async Task Initialize() + public override void Initialize() { - await parent.StartCreditThread(parent.IdleSlope); + Parent.StartCreditThread(Parent.IdleSlope); } - public override async Task GateClosed() + public override void GateClosed() { - // Stop the credit growth thread. - await parent.StopCreditThread(); + // Nothing special happens here. The credit handling is done in the GateOpened method. } - public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) + public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) { - // Start the credit - lock (parent.queueLock) + // Try to submit first packet. + lock (Parent.queueLock) { - // Don't do anything when there are no packets. if (!CanSend()) { - return Task.CompletedTask; + return; } - // Otherwise, once again try to send the first packet. - var firstPacket = parent.Queue.First(); - if (trySubmitFirstPacket.Invoke(firstPacket) == PacketSubmitResult.Accepted) + var firstPacket = Parent.Queue.First(); + var submitResult = trySubmitFirstPacket.Invoke(firstPacket); + + // If the packet was accepted, remove it from the queue. + if (submitResult == PacketSubmitResult.Accepted) + { + Parent.Queue.Remove(firstPacket); + + // If my packet was denied due to pre-closing, freeze my credit. + } + else if (submitResult == PacketSubmitResult.DeniedPreClosing) { - parent.Queue.Remove(firstPacket); + Parent.StopCreditThread(); } } - return Task.CompletedTask; + // Otherwise, just let the credit grow for now. } - public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) + public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) { - lock (parent.queueLock) + // Put the leftovers of the packet back into the queue. + lock (Parent.queueLock) { - parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes)); + Parent.Queue.Insert(0, new PriorityPacket(Parent.Priority, leftoverBytes)); } - - return Task.CompletedTask; } - public override async Task TransmissionCompleted() + public override void TransmissionCompleted() { - await parent.StopCreditThread(); - await parent.StartCreditThread(parent.IdleSlope); + // Stop and restart the credit thread. + Parent.StopCreditThread(); + Parent.StartCreditThread(Parent.IdleSlope); } - public override async Task TransmissionStarted(double bytesPerSecondRate) + public override void TransmissionStarted(long bytesPerSecondRate) { - await parent.StopCreditThread(); - await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate)); + // Decrease the credit by the idle slope. + Parent.StopCreditThread(); + Parent.StartCreditThread(GetSendSlope(bytesPerSecondRate)); } } + #endregion + #region ReturnToZeroLinkCallback private class ReturnToZeroLinkCallback : LinkCallbackBase { public ReturnToZeroLinkCallback(QueueViewModel parentViewModel) - :base(parentViewModel) + : base(parentViewModel) { } - public override async Task Initialize() + public override void Initialize() { - await parent.StartCreditThread(parent.IdleSlope); + Parent.StartCreditThread(Parent.IdleSlope); } - public override Task GateClosed() + public override void GateClosed() { // Nothing special to be done here. - return Task.CompletedTask; } - public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) + public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket) { - lock (parent.queueLock) + lock (Parent.queueLock) { // Again, check if we can submit anything. if (!CanSend()) { - return Task.CompletedTask; + return; } - var firstPacket = parent.Queue.First(); + var firstPacket = Parent.Queue.First(); var submitResult = trySubmitFirstPacket.Invoke(firstPacket); if (submitResult == PacketSubmitResult.Accepted) { - parent.Queue.Remove(firstPacket); - } else if (submitResult == PacketSubmitResult.DeniedPreClosing) // In the pre-closing case, we signal the thread to increase our credit to zero. + Parent.Queue.Remove(firstPacket); + } + else if (submitResult == PacketSubmitResult.DeniedPreClosing) // In the pre-closing case, we signal the thread to increase our credit to zero. { - _ = parent.StopCreditThread(); - _ = parent.StartCreditThread(parent.IdleSlope, 0); + Parent.StopCreditThread(); + Parent.StartCreditThread(Parent.IdleSlope, 0); } } - - return Task.CompletedTask; } - public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) + public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes) { - lock (parent.queueLock) + lock (Parent.queueLock) { - parent.Queue.Insert(0, new PriorityPacket(GetPriority(), leftoverBytes)); + Parent.Queue.Insert(0, new PriorityPacket(GetPriority(), leftoverBytes)); } - - return Task.CompletedTask; } - public override async Task TransmissionCompleted() + public override void TransmissionCompleted() { - await parent.StopCreditThread(); - await parent.StartCreditThread(parent.IdleSlope); + Parent.StopCreditThread(); + Parent.StartCreditThread(Parent.IdleSlope, 0); } - public override async Task TransmissionStarted(double bytesPerSecondRate) + public override void TransmissionStarted(long bytesPerSecondRate) { - await parent.StopCreditThread(); - await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate)); + Parent.StopCreditThread(); + Parent.StartCreditThread(GetSendSlope(bytesPerSecondRate), 0); } } + #endregion } -} +} \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs index 1b2a34e..e3b9186 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs @@ -1,11 +1,17 @@ using CBSVisualizer.Core.Mvvm; using CBSVisualizer.Messaging; using CBSVisualizer.Messaging.Events; +using CBSVisualizer.Services.PacketService.Interface; +using LiveCharts; +using LiveCharts.Defaults; +using LiveCharts.Wpf; +using log4net; +using Prism.Commands; using Prism.Events; using Prism.Regions; using System; using System.Collections.ObjectModel; -using System.Diagnostics; +using System.Collections.Specialized; using System.Threading; using System.Threading.Tasks; @@ -13,86 +19,134 @@ namespace CBSVisualizer.Modules.Queue.ViewModels { public partial class QueueViewModel : RegionViewModelBase { + private const int ThreadJoinTimeoutS = 1; + + private const long CreditRefreshRateS = 5; + + private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType); + private readonly IEventAggregator eventAggregator; + private readonly IPacketService packetService; + private readonly object queueLock = new object(); + private readonly object creditLock = new object(); + private CancellationTokenSource creditGrowthCancellationSource; - private const double CREDIT_REFRESH_RATE_S = 0.1; + private CreditBehaviour selectedCreditBehaviour; - private double currentCredit = 0; + public CreditBehaviour SelectedCreditBehaviour + { + get => selectedCreditBehaviour; - private Task creditUpdateTask; + set => SetProperty(ref selectedCreditBehaviour, value); + } - public double CurrentCredit + private long currentCredit; + + public long CurrentCredit { get { - return currentCredit; + lock (creditLock) + { + return currentCredit; + } } private set { - SetProperty(ref currentCredit, value); + lock (creditLock) + { + SetProperty(ref currentCredit, value); + } } } - public enum CreditBehaviour - { - // This is selected when there should be no credit-based shaper for this queue. - NoCBS, - - // Frozen credit behaviour - Frozen, + private Thread creditUpdateThread; - // The standard credit behaviour - Standard, - - // Return to zero. - ReturnToZero - } - - private CreditBehaviour selectedCreditBehaviour; - public CreditBehaviour SelectedCreditBehaviour { - get - { - return selectedCreditBehaviour; - } + public int Priority { get; } - set - { - SetProperty(ref selectedCreditBehaviour, value); - } - } + public string PrioLabel { get; private set; } - public int Priority { get; private set; } + public string PacketLabel { get; private set; } - public ObservableCollection<PriorityPacket> Queue { get; private set; } = new ObservableCollection<PriorityPacket>(); + public ObservableCollection<PriorityPacket> Queue { get; } = new ObservableCollection<PriorityPacket>(); /// <summary> /// Idle Slope ( given in byte / s). /// </summary> public int IdleSlope { get; set; } = 100; - public QueueViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, int prio) : + public SeriesCollection Series { get; set; } + + public DelegateCommand GeneratePacketOnClick { get; private set; } + + public QueueViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, int prio, IPacketService packetProvider) : base(regionManager) { this.eventAggregator = eventAggregator; + packetService = packetProvider; Priority = prio; + HandleLabels(); // Register handlers for the different events. RegisterPacketHandler(); RegisterSimulationStartStopHandler(); PropertyChanged += HandleCreditBehaviourChanged; + Queue.CollectionChanged += QueueChangedHandler; eventAggregator.GetEvent<RegisterLinkCallbackEvent>().Publish(GetLinkCallback()); + + InitCharts(); + } + + private void HandleLabels() + { + if (Priority == 7) + { + PrioLabel = "Priority"; + PacketLabel = "Packet Count"; + } + else + { + PrioLabel = ""; + PacketLabel = ""; + } + } + + private void QueueChangedHandler(object sender, NotifyCollectionChangedEventArgs e) + { + // Add the new value to the series. + if (selectedCreditBehaviour != CreditBehaviour.NoCbs) + { + Series[0].Values.Add(new DateTimePoint(DateTime.Now, CurrentCredit)); + } + Series[1].Values.Add(new DateTimePoint(DateTime.Now, Queue.Count)); + } + + private void InitCharts() + { + Series = new SeriesCollection + { + new LineSeries { + Title = "Credit Values", + Values = new ChartValues<DateTimePoint>() { new DateTimePoint(DateTime.Now, 0) } + }, + + new LineSeries { + Title = "Packet Count", + Values = new ChartValues<DateTimePoint>() { new DateTimePoint(DateTime.Now, 0) } + } + }; } private void HandleCreditBehaviourChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { - if (e.PropertyName.Equals("SelectedCreditBehaviour")) + if (e.PropertyName != null && e.PropertyName.Equals("SelectedCreditBehaviour")) { eventAggregator.GetEvent<RegisterLinkCallbackEvent>().Publish(GetLinkCallback()); } @@ -111,89 +165,105 @@ namespace CBSVisualizer.Modules.Queue.ViewModels case CreditBehaviour.Standard: return new StandardLinkCallback(this); - - case CreditBehaviour.NoCBS: + // Default is no CBS. + case CreditBehaviour.NoCbs: default: - return new NoCBSLinkCallback(this); + return new NoCbsLinkCallback(this); } } private void RegisterSimulationStartStopHandler() { - eventAggregator.GetEvent<SimulationStartedEvent>().Subscribe(() => + eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(() => { - if (SelectedCreditBehaviour != CreditBehaviour.NoCBS && Queue.Count >= 1) + if (SelectedCreditBehaviour == CreditBehaviour.NoCbs) { - creditUpdateTask = StartCreditThread(IdleSlope); + return; } - } - ); - eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(async () => - { - if (SelectedCreditBehaviour != CreditBehaviour.NoCBS) - { - await StopCreditThread(); + StopCreditThread(); - // Reset credit. - currentCredit = 0; - } + // Reset credit. + CurrentCredit = 0; }); } - private async Task StopCreditThread() + private void StartCreditThread(long bytesPerSecondSlope, long limit = long.MaxValue) { - creditGrowthCancellationSource?.Cancel(); - try + // Init new cancellation token. + creditGrowthCancellationSource = new CancellationTokenSource(); + + creditUpdateThread = new Thread(() => { - if (creditUpdateTask != null) + Log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope."); + while (!creditGrowthCancellationSource.Token.IsCancellationRequested) { - await creditUpdateTask; + lock (queueLock) + { + lock (creditLock) + { + if (CurrentCredit > limit || Queue.Count <= 0) + { + return; + } + } + } + + // Wait for the specified amount of time. + Thread.Sleep(TimeSpan.FromSeconds(CreditRefreshRateS)); + + AtomicUpdateCredit(CreditRefreshRateS * bytesPerSecondSlope, limit); + + Log.Info($"Queue {Priority}: Credit {CurrentCredit}"); } + }); - } catch (TaskCanceledException) - { - // Do nothing. - } - creditUpdateTask = null; - creditGrowthCancellationSource = null; + creditUpdateThread.Start(); } - private async Task StartCreditThread(double bytesPerSecondSlope, double limit = double.PositiveInfinity) + private void StopCreditThread() { - creditGrowthCancellationSource = new CancellationTokenSource(); - await Task.Run(async () => - { - // Refresh the credit. - while (!creditGrowthCancellationSource.Token.IsCancellationRequested && CurrentCredit < limit && Queue.Count > 0) - { - // Wait for the specified amount of time. - await Task.Delay(TimeSpan.FromSeconds(CREDIT_REFRESH_RATE_S), creditGrowthCancellationSource.Token); - - AtomicUpdateCredit(CREDIT_REFRESH_RATE_S * bytesPerSecondSlope, limit); + creditGrowthCancellationSource?.Cancel(); - Debug.WriteLine($"Queue {Priority}: Credit {CurrentCredit}"); - } - } - , creditGrowthCancellationSource.Token); + if (creditUpdateThread != null) + { + Log.Info(creditUpdateThread.Join(TimeSpan.FromSeconds(ThreadJoinTimeoutS)) + ? $"Queue {Priority}: Unable to stop credit thread." + : $"Queue {Priority}: Credit Thread was stopped successfully."); + } } - private void AtomicUpdateCredit(double increment, double limit) + private void AtomicUpdateCredit(long increment, long limit) { - Interlocked.Exchange(ref currentCredit, Math.Min(currentCredit + increment, limit)); + // Update the credit. + CurrentCredit = Math.Min(CurrentCredit + increment, limit); } private void RegisterPacketHandler() { eventAggregator.GetEvent<PacketArrivedEvent>().Subscribe(packet => { - if (packet.Priority == Priority) + if (packet.Priority != Priority) + { + return; + } + + lock (queueLock) + { + // Add packet. + Queue.Add(packet); + } + }); + + GeneratePacketOnClick = new DelegateCommand(async () => + { + await Task.Run(() => { lock (queueLock) { - Queue.Add(packet); + Queue.Add(packetService.GeneratePacket(Priority)); } - } + }); }); } } diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml index 4897b5c..13428af 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml @@ -1,7 +1,9 @@ <UserControl x:Class="CBSVisualizer.Modules.Queue.Views.Queue" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:local="clr-namespace:CBSVisualizer.Modules.Queue.Views" + xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" @@ -9,15 +11,43 @@ xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="False" > <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="*"/> + </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> + <ColumnDefinition Width="3*"/> </Grid.ColumnDefinitions> - <TextBlock Text="{Binding Priority}" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/> - <TextBlock Text="{Binding Queue.Count}" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center"/> - <TextBox x:Name="CreditRateTextBox" Text="{Binding IdleSlope}" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center"/> - <ComboBox x:Name="CreditBehaviourBox" SelectedItem="{Binding SelectedCreditBehaviour}" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center"/> + <TextBlock Text="{Binding PrioLabel}" Grid.Column="0" Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Center"/> + <TextBlock Text="{Binding Priority}" Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center"/> + + <TextBlock Text="{Binding PacketLabel}" Grid.Column="1" Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Center"/> + <TextBlock Text="{Binding Queue.Count}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center"> + <TextBlock.InputBindings> + <MouseBinding MouseAction="RightClick" Command="{Binding GeneratePacketOnClick}"/> + </TextBlock.InputBindings> + </TextBlock> + + <TextBox materialDesign:HintAssist.Hint="Idle Slope [byte/s]" + Style="{StaticResource MaterialDesignFloatingHintTextBox}" + x:Name="CreditRateTextBox" Text="{Binding IdleSlope}" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Grid.RowSpan="2"/> + + <ComboBox Style="{StaticResource MaterialDesignFloatingHintComboBox}" + materialDesign:TextFieldAssist.UnderlineBrush="{DynamicResource SecondaryAccentBrush}" + materialDesign:HintAssist.Hint="Credit Behaviour" + x:Name="CreditBehaviourBox" SelectedItem="{Binding SelectedCreditBehaviour}" Grid.Column="3" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center"/> + + <lvc:CartesianChart Series="{Binding Series}" LegendLocation="Right" Grid.Column="4" Grid.RowSpan="2"> + <lvc:CartesianChart.AxisX> + <lvc:Axis Title="Time" LabelFormatter="{Binding XFormatter}" /> + </lvc:CartesianChart.AxisX> + <lvc:CartesianChart.AxisY> + <lvc:Axis Title="Credit"/> + </lvc:CartesianChart.AxisY> + </lvc:CartesianChart> </Grid> </UserControl> diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs index 7b92184..e20fa11 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs @@ -1,19 +1,7 @@ using CBSVisualizer.Modules.Queue.ViewModels; -using System; -using System.Collections.Generic; using System.Collections.ObjectModel; -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; + using static CBSVisualizer.Modules.Queue.ViewModels.QueueViewModel; namespace CBSVisualizer.Modules.Queue.Views @@ -39,7 +27,7 @@ namespace CBSVisualizer.Modules.Queue.Views private void CreditBehaviourBoxSelectionChanged(object sender, SelectionChangedEventArgs e) { - if (CreditBehaviourBox.SelectedItem.Equals(CreditBehaviour.NoCBS)) + if (CreditBehaviourBox.SelectedItem.Equals(CreditBehaviour.NoCbs)) { CreditRateTextBox.IsEnabled = false; } else @@ -51,7 +39,7 @@ namespace CBSVisualizer.Modules.Queue.Views private static ObservableCollection<CreditBehaviour> InitList() { ObservableCollection<CreditBehaviour> ret = new ObservableCollection<CreditBehaviour>(); - ret.Add(CreditBehaviour.NoCBS); + ret.Add(CreditBehaviour.NoCbs); ret.Add(CreditBehaviour.Frozen); ret.Add(CreditBehaviour.Standard); ret.Add(CreditBehaviour.ReturnToZero); diff --git a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj index e681e4a..f9da61e 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj +++ b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj @@ -5,11 +5,12 @@ <AssemblyName>CBSVisualizer.Modules.SettingsDialog</AssemblyName> </PropertyGroup> <ItemGroup> + <PackageReference Include="log4net" Version="2.0.9" /> + <PackageReference Include="MaterialDesignThemes" Version="3.1.3" /> <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> <ProjectReference Include="..\CBSVisualizer.Services.SettingsService\CBSVisualizer.Services.SettingService.csproj" /> - <ProjectReference Include="..\CBSVisualizer\CBSVisualizer.Core\CBSVisualizer.Core.csproj" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/ViewModels/SettingsDialogViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/ViewModels/SettingsDialogViewModel.cs index 48b3dc5..ad966f2 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/ViewModels/SettingsDialogViewModel.cs +++ b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/ViewModels/SettingsDialogViewModel.cs @@ -1,14 +1,8 @@ using CBSVisualizer.Core.Mvvm; -using CBSVisualizer.Services.SettingsService.Service; -using Prism.Commands; -using Prism.Mvvm; +using CBSVisualizer.Services.SettingsService.Implementation; using Prism.Regions; using Prism.Services.Dialogs; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace CBSVisualizer.Modules.SettingsDialog.ViewModels { diff --git a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/Views/SettingsDialog.xaml b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/Views/SettingsDialog.xaml index 6a5d5cc..6488678 100644 --- a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/Views/SettingsDialog.xaml +++ b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/Views/SettingsDialog.xaml @@ -8,7 +8,13 @@ mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" xmlns:prism="http://prismlibrary.com/" - prism:ViewModelLocator.AutoWireViewModel="True" > + prism:ViewModelLocator.AutoWireViewModel="True" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + TextElement.Foreground="{DynamicResource MaterialDesignBody}" + Background="{DynamicResource MaterialDesignPaper}" + TextElement.FontWeight="Medium" + TextElement.FontSize="14" + FontFamily="{materialDesign:MaterialDesignFont}"> <prism:Dialog.WindowStyle> <Style TargetType="Window"> diff --git a/CBSVisualizer/CBSVisualizer.Services.PacketService/CBSVisualizer.Services.PacketService.csproj b/CBSVisualizer/CBSVisualizer.Services.PacketService/CBSVisualizer.Services.PacketService.csproj new file mode 100644 index 0000000..2d123f6 --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Services.PacketService/CBSVisualizer.Services.PacketService.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net5.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <ProjectReference Include="..\CBSVisualizer.MessagingCore\CBSVisualizer.Messaging.csproj" /> + </ItemGroup> + +</Project> diff --git a/CBSVisualizer/CBSVisualizer.Services.PacketService/Implementation/RandomPacketService.cs b/CBSVisualizer/CBSVisualizer.Services.PacketService/Implementation/RandomPacketService.cs new file mode 100644 index 0000000..be5b66a --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Services.PacketService/Implementation/RandomPacketService.cs @@ -0,0 +1,37 @@ +using CBSVisualizer.Messaging; +using CBSVisualizer.Services.PacketService.Interface; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CBSVisualizer.Services.PacketService.Implementation +{ + public class RandomPacketService : IPacketService + { + private const int HEADER_BYTES = 100; + + private const int TRAILER_BYTES = 100; + + private readonly Random random = new Random(); + + public PriorityPacket GeneratePacket(int priority) + { + return new PriorityPacket( + priority, // Priority between 0 and 7 + HEADER_BYTES, + random.Next(2000), // Random value between 0 and 1999. + TRAILER_BYTES); + } + + public PriorityPacket GeneratePacket() + { + return new PriorityPacket( + random.Next(0, 8), // Priority between 0 and 7 + HEADER_BYTES, + random.Next(2000), // Random value between 0 and 1999. + TRAILER_BYTES); + } + } +} diff --git a/CBSVisualizer/CBSVisualizer.Services.PacketService/Interface/IPacketService.cs b/CBSVisualizer/CBSVisualizer.Services.PacketService/Interface/IPacketService.cs new file mode 100644 index 0000000..0b7ca4c --- /dev/null +++ b/CBSVisualizer/CBSVisualizer.Services.PacketService/Interface/IPacketService.cs @@ -0,0 +1,22 @@ +using CBSVisualizer.Messaging; +using System; +using System.Net.Mail; + +namespace CBSVisualizer.Services.PacketService.Interface +{ + public interface IPacketService + { + /// <summary> + /// Generates a packet with the specified priority. + /// </summary> + /// <param name="priority"></param> + /// <returns></returns> + PriorityPacket GeneratePacket(int priority); + + /// <summary> + /// Generates a packet with a random priority. + /// </summary> + /// <returns></returns> + PriorityPacket GeneratePacket(); + } +} diff --git a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/CBSVisualizer.Services.SchedulingService.csproj b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/CBSVisualizer.Services.SchedulingService.csproj index ae5e714..20f292c 100644 --- a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/CBSVisualizer.Services.SchedulingService.csproj +++ b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/CBSVisualizer.Services.SchedulingService.csproj @@ -5,7 +5,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="log4net" Version="2.0.8" /> + <PackageReference Include="log4net" Version="2.0.9" /> <PackageReference Include="Prism.Core" Version="7.2.0.1422" /> </ItemGroup> diff --git a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs index 8bee7e8..9eb15cd 100644 --- a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs +++ b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs @@ -1,5 +1,6 @@ using CBSVisualizer.Messaging.Events; -using CBSVisualizer.Services.SettingsService.Service; +using CBSVisualizer.Services.SchedulingService.Interface; +using CBSVisualizer.Services.SettingsService.Implementation; using log4net; using Prism.Events; using System; @@ -12,6 +13,7 @@ namespace CBSVisualizer.Services.SchedulingService.Implementation public class RandomSchedulingService : ISchedulingService { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private const int PROCESSING_DELAY_MS = 1500; private const string MIN_DELAY_SETTING_KEY = "random_scheduler_min_delay"; private const string MAX_DELAY_SETTING_KEY = "random_scheduler_max_delay"; private CancellationTokenSource tokenSource; @@ -36,21 +38,21 @@ namespace CBSVisualizer.Services.SchedulingService.Implementation int highPrioOpenedTime = GetRandomWaitingTime(); // Publish GateOpenedEvent for the high prio queue. + log.Info("Publishing GateOpenedEvent [High Prio]"); eventAggregator.GetEvent<GateOpenedEvent>().Publish((OpenedTime: highPrioOpenedTime, OpenedGates: new HashSet<int> { 7 })); - log.Info("Published GateOpenedEvent [High Prio]"); // Wait for the specified time. - await Task.Delay(highPrioOpenedTime, tokenSource.Token); + await Task.Delay(highPrioOpenedTime + PROCESSING_DELAY_MS, tokenSource.Token); // Get the opening time for the low prio. int lowPrioOpenedTime = GetRandomWaitingTime(); // Publish another GateOpenedEvent for the other queues. + log.Info("Publishing GateOpenedEvent [Lower Prio]"); eventAggregator.GetEvent<GateOpenedEvent>().Publish((OpenedTime: lowPrioOpenedTime, OpenedGates: new HashSet<int> { 0, 1, 2, 3, 4, 5, 6 })); - log.Info("Published GateOpenedEvent [Lower Prio]"); // Wait for the specified time again. - await Task.Delay(lowPrioOpenedTime, tokenSource.Token); + await Task.Delay(lowPrioOpenedTime + PROCESSING_DELAY_MS, tokenSource.Token); } } @@ -59,26 +61,15 @@ namespace CBSVisualizer.Services.SchedulingService.Implementation return random.Next(settings.GetSettingValue<int>(MIN_DELAY_SETTING_KEY), settings.GetSettingValue<int>(MAX_DELAY_SETTING_KEY)); } - public void StartScheduling() + public async Task StartScheduling() { tokenSource = new CancellationTokenSource(); - schedulerTask = StartScheduler(); + await StartScheduler(); } - public async Task StopScheduling() + public void StopScheduling() { - try - { - tokenSource?.Cancel(); - if (schedulerTask != null) - { - await schedulerTask; - } - } catch (TaskCanceledException) - { - // Don't do anything. - } - + tokenSource?.Cancel(); } } } \ No newline at end of file diff --git a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs index 2fd639a..e5bb1a1 100644 --- a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs +++ b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs @@ -1,15 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Threading.Tasks; -namespace CBSVisualizer.Services.SchedulingService +namespace CBSVisualizer.Services.SchedulingService.Interface { public interface ISchedulingService { - public void StartScheduling(); + public Task StartScheduling(); - public Task StopScheduling(); + public void StopScheduling(); } } diff --git a/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj b/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj index e90b892..6ba72c0 100644 --- a/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj +++ b/CBSVisualizer/CBSVisualizer.Services.SettingsService/CBSVisualizer.Services.SettingService.csproj @@ -7,6 +7,7 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="log4net" Version="2.0.9" /> <PackageReference Include="Ookii.Dialogs.Wpf" Version="1.1.0" /> <PackageReference Include="Prism.Core" Version="7.2.0.1422" /> </ItemGroup> diff --git a/CBSVisualizer/CBSVisualizer.Services.SettingsService/Service/SettingService.cs b/CBSVisualizer/CBSVisualizer.Services.SettingsService/Implementation/SettingService.cs similarity index 96% rename from CBSVisualizer/CBSVisualizer.Services.SettingsService/Service/SettingService.cs rename to CBSVisualizer/CBSVisualizer.Services.SettingsService/Implementation/SettingService.cs index 72e9458..3be0dff 100644 --- a/CBSVisualizer/CBSVisualizer.Services.SettingsService/Service/SettingService.cs +++ b/CBSVisualizer/CBSVisualizer.Services.SettingsService/Implementation/SettingService.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace CBSVisualizer.Services.SettingsService.Service +namespace CBSVisualizer.Services.SettingsService.Implementation { public class SettingService { diff --git a/CBSVisualizer/CBSVisualizer.sln b/CBSVisualizer/CBSVisualizer.sln index bc17186..ccf16e1 100644 --- a/CBSVisualizer/CBSVisualizer.sln +++ b/CBSVisualizer/CBSVisualizer.sln @@ -36,6 +36,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CBSVisualizer.Core", "CBSVi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CBSVisualizer.Common", "CBSVisualizer.Common\CBSVisualizer.Common.csproj", "{9B1B603C-601C-4F31-ADD9-D0962C0011AF}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CBSVisualizer.Services.PacketService", "CBSVisualizer.Services.PacketService\CBSVisualizer.Services.PacketService.csproj", "{274C0DC3-C59C-4C91-8130-6DEF2BDBD0A1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -86,6 +88,10 @@ Global {9B1B603C-601C-4F31-ADD9-D0962C0011AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {9B1B603C-601C-4F31-ADD9-D0962C0011AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {9B1B603C-601C-4F31-ADD9-D0962C0011AF}.Release|Any CPU.Build.0 = Release|Any CPU + {274C0DC3-C59C-4C91-8130-6DEF2BDBD0A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {274C0DC3-C59C-4C91-8130-6DEF2BDBD0A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {274C0DC3-C59C-4C91-8130-6DEF2BDBD0A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {274C0DC3-C59C-4C91-8130-6DEF2BDBD0A1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -99,6 +105,7 @@ Global {B2059A32-91EC-4CFF-AB5C-87FBC3B6686C} = {6D2194E0-E17B-44D6-AD8C-F3699549D259} {AB9EA79C-F11F-4B93-A08E-8C52A9716666} = {BFDCC6CE-CAA6-45AA-832F-0CBAB9A3C8BA} {61B7FF00-1B9D-4ABF-B3BF-667A1505415F} = {BFDCC6CE-CAA6-45AA-832F-0CBAB9A3C8BA} + {274C0DC3-C59C-4C91-8130-6DEF2BDBD0A1} = {BFDCC6CE-CAA6-45AA-832F-0CBAB9A3C8BA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {EE8EFE44-67AF-451F-9DFD-7B458AA3B3B3} diff --git a/CBSVisualizer/CBSVisualizer/App.xaml b/CBSVisualizer/CBSVisualizer/App.xaml index 80fe455..220ab7b 100644 --- a/CBSVisualizer/CBSVisualizer/App.xaml +++ b/CBSVisualizer/CBSVisualizer/App.xaml @@ -2,7 +2,14 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CBSVisualizer" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:prism="http://prismlibrary.com/" > <Application.Resources> + <ResourceDictionary> + <ResourceDictionary.MergedDictionaries> + <materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="Amber" SecondaryColor="LightBlue" /> + <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" /> + </ResourceDictionary.MergedDictionaries> + </ResourceDictionary> </Application.Resources> </prism:PrismApplication> diff --git a/CBSVisualizer/CBSVisualizer/App.xaml.cs b/CBSVisualizer/CBSVisualizer/App.xaml.cs index 8fd0e59..dfe06d6 100644 --- a/CBSVisualizer/CBSVisualizer/App.xaml.cs +++ b/CBSVisualizer/CBSVisualizer/App.xaml.cs @@ -2,7 +2,7 @@ using CBSVisualizer.Views; using System.Windows; using Prism.Modularity; -using CBSVisualizer.Services.SettingsService.Service; +using CBSVisualizer.Services.SettingsService.Implementation; using CBSVisualizer.Services.SchedulingService.Implementation; using CBSVisualizer.Modules.Queue.QueueGroup; using CBSVisualizer.Services.SchedulingService; @@ -10,7 +10,9 @@ using CBSVisualizer.Modules.Link; using CBSVisualizer.Modules.SettingsDialog; using CBSVisualizer.Modules.MenuBar; using System.IO; -using System.Configuration; +using CBSVisualizer.Services.PacketService.Implementation; +using CBSVisualizer.Services.PacketService.Interface; +using CBSVisualizer.Services.SchedulingService.Interface; namespace CBSVisualizer { @@ -29,6 +31,7 @@ namespace CBSVisualizer // containerRegistry.RegisterSingleton<IMessageService, MessageService>(); containerRegistry.RegisterSingleton<SettingService>(); containerRegistry.RegisterSingleton<ISchedulingService, RandomSchedulingService>(); + containerRegistry.RegisterSingleton<IPacketService, RandomPacketService>(); } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) diff --git a/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj b/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj index 5e2cc6e..3a731bf 100644 --- a/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj +++ b/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj @@ -7,7 +7,8 @@ <AssemblyName>CBSVisualizer</AssemblyName> </PropertyGroup> <ItemGroup> - <PackageReference Include="log4net" Version="2.0.8" /> + <PackageReference Include="log4net" Version="2.0.9" /> + <PackageReference Include="MaterialDesignThemes" Version="3.1.3" /> <PackageReference Include="Prism.DryIoc" Version="7.2.0.1422" /> </ItemGroup> <ItemGroup> @@ -15,6 +16,7 @@ <ProjectReference Include="..\CBSVisualizer.Modules.MenuBar\CBSVisualizer.Modules.MenuBar.csproj" /> <ProjectReference Include="..\CBSVisualizer.Modules.Queue.QueueGroup\CBSVisualizer.Modules.QueueGroup.csproj" /> <ProjectReference Include="..\CBSVisualizer.Modules.SettingsDialog\CBSVisualizer.Modules.SettingsDialog.csproj" /> + <ProjectReference Include="..\CBSVisualizer.Services.PacketService\CBSVisualizer.Services.PacketService.csproj" /> <ProjectReference Include="..\CBSVisualizer.Services.SchedulingService\CBSVisualizer.Services.SchedulingService.csproj" /> <ProjectReference Include="..\CBSVisualizer.Services.SettingsService\CBSVisualizer.Services.SettingService.csproj" /> </ItemGroup> diff --git a/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml b/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml index 4be8a18..1d12452 100644 --- a/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml +++ b/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml @@ -4,18 +4,25 @@ xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" xmlns:core="clr-namespace:CBSVisualizer.Core;assembly=CBSVisualizer.Core" - Title="{Binding Title}" MinHeight="433" Height="433" MinWidth="867" Width="867" > + Title="{Binding Title}" MinHeight="433" Height="433" MinWidth="867" Width="867" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + TextElement.Foreground="{DynamicResource MaterialDesignBody}" + Background="{DynamicResource MaterialDesignPaper}" + TextElement.FontWeight="Medium" + TextElement.FontSize="14" + FontFamily="{materialDesign:MaterialDesignFont}" + > <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> - <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.MenuBarRegion}" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2"/> - <ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.QueueGroupRegion}" Grid.Column="0" Grid.Row="1"/> - <ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.LinkRegion}" Grid.Column="1" Grid.Row="1" Margin="0, 0, 5, 0"/> + <ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.QueueGroupRegion}" Grid.Column="1" Grid.Row="1"/> + <ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.LinkRegion}" Grid.Column="0" Grid.Row="1" Margin="30, 0, 0, 0"/> </Grid> </Window> -- GitLab