From 10b307ba4b3e33eb8891f1808be6436d33bd9f61 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sun, 6 Sep 2020 16:46:50 +0200
Subject: [PATCH 01/17] Fix "How many bytes do I have left to send before the
 gate closes?" mechanism + add processing delay to scheduler.

---
 .../ViewModels/LinkViewModel.cs               | 46 ++++++++++++-------
 .../Implementation/RandomSchedulingService.cs |  5 +-
 2 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
index d2902db..36a4752 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
@@ -148,6 +148,11 @@ 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.
@@ -157,10 +162,11 @@ namespace CBSVisualizer.Modules.Link.ViewModels
                         {
                             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,37 +187,43 @@ 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)
+
+                    try
                     {
-                        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}.");
-                    }
+                        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}.");
+                        }
 
-                    if (transmittedBytes >= packetInTransit.Size)
+                    } catch (TaskCanceledException) { }
+                    finally
                     {
                         await 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)
+            {
+                log.Info($"Packet Size: {packet.Size}, remaining bytes until next GateCloseEvent: {remainingBytes}. {remainingBytes - packet.Size} bytes left.");
+                remainingBytes -= packet.Size;
+                return true;
+            }
+
+            return false;
         }
 
         private void CloseInactiveGates(ISet<int> openedGates)
diff --git a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs
index 8bee7e8..ddccc65 100644
--- a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs
+++ b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs
@@ -12,6 +12,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;
@@ -40,7 +41,7 @@ namespace CBSVisualizer.Services.SchedulingService.Implementation
                 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();
@@ -50,7 +51,7 @@ namespace CBSVisualizer.Services.SchedulingService.Implementation
                 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);
             }
         }
 
-- 
GitLab


From 4bff075cb5f72682979023c276776a5a3b6b7192 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sun, 6 Sep 2020 18:12:01 +0200
Subject: [PATCH 02/17] Add WPF Live Charts. Needs some love :-)

---
 .../ViewModels/LinkViewModel.cs               |  1 -
 .../Views/QueueGroup.xaml                     |  1 +
 .../CBSVisualizer.Modules.Queue.csproj        |  2 ++
 .../ViewModels/QueueViewModel.cs              | 28 ++++++++++++++++++-
 .../Views/Queue.xaml                          | 18 +++++++++---
 5 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
index 36a4752..1b96afe 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
@@ -200,7 +200,6 @@ namespace CBSVisualizer.Modules.Link.ViewModels
                             transmittedBytes += REFRESH_TIME_MS * (bitrate / 1000);
                             log.Info($"Transmitted {transmittedBytes} of {packetInTransit.Size} bytes of packet {packetInTransit}.");
                         }
-
                     } catch (TaskCanceledException) { }
                     finally
                     {
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml
index 4f47ea4..7dab185 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml
@@ -25,6 +25,7 @@
             <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"/>
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
index 5fbb50f..98b739a 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
@@ -5,6 +5,8 @@
     <AssemblyName>CBSVisualizer.Modules.Queue</AssemblyName>
   </PropertyGroup>
   <ItemGroup>
+    <PackageReference Include="LiveCharts" Version="0.9.7" />
+    <PackageReference Include="LiveCharts.Wpf" Version="0.9.7" />
     <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" />
   </ItemGroup>
   <ItemGroup>
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 1b2a34e..2339590 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -1,6 +1,9 @@
 using CBSVisualizer.Core.Mvvm;
 using CBSVisualizer.Messaging;
 using CBSVisualizer.Messaging.Events;
+using LiveCharts;
+using LiveCharts.Defaults;
+using LiveCharts.Wpf;
 using Prism.Events;
 using Prism.Regions;
 using System;
@@ -75,9 +78,13 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
         /// </summary>
         public int IdleSlope { get; set; } = 100;
 
+        public SeriesCollection Series { get; set; }
+
         public QueueViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, int prio) :
             base(regionManager)
         {
+            InitCharts();
+
             this.eventAggregator = eventAggregator;
             Priority = prio;
 
@@ -86,10 +93,25 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             RegisterSimulationStartStopHandler();
 
             PropertyChanged += HandleCreditBehaviourChanged;
-
             eventAggregator.GetEvent<RegisterLinkCallbackEvent>().Publish(GetLinkCallback());
         }
 
+        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"))
@@ -191,7 +213,11 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 {
                     lock (queueLock)
                     {
+                        // Add packet.
                         Queue.Add(packet);
+
+                        // Update chart value.
+                        Series[1].Values.Add(new DateTimePoint(DateTime.Now, Queue.Count));
                     }
                 }
             });
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
index 4897b5c..5c77652 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
@@ -2,6 +2,7 @@
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              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" 
@@ -10,14 +11,23 @@
              prism:ViewModelLocator.AutoWireViewModel="False" >
     <Grid>
         <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="*"/>
-            <ColumnDefinition Width="*"/>
-            <ColumnDefinition Width="*"/>
-            <ColumnDefinition Width="*"/>
+            <ColumnDefinition Width="0.5*"/>
+            <ColumnDefinition Width="0.5*"/>
+            <ColumnDefinition Width="0.5*"/>
+            <ColumnDefinition Width="0.5*"/>
+            <ColumnDefinition Width="2*"/>
         </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"/>
+        <lvc:CartesianChart Series="{Binding Series}" LegendLocation="Right" Grid.Column="4">
+            <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>
-- 
GitLab


From cc268283c31e1f890fc1d2d342a9cddda5a82173 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Mon, 7 Sep 2020 21:55:54 +0200
Subject: [PATCH 03/17] Switch to Material Design :-)

---
 .../CBSVisualizer.Common.csproj               |  1 +
 .../CBSVisualizer.Core.csproj                 |  2 +-
 .../CBSVisualizer.Messaging.csproj            |  1 +
 .../CBSVisualizer.Modules.Link.csproj         |  3 ++
 .../CBSVisualizer.Modules.MenuBar.csproj      |  3 ++
 .../CBSVisualizer.Modules.QueueGroup.csproj   |  3 ++
 .../Views/QueueGroup.xaml                     | 12 ------
 .../Views/QueueGroup.xaml.cs                  |  7 ++--
 .../CBSVisualizer.Modules.Queue.csproj        |  3 ++
 .../ViewModels/QueueViewModel.cs              | 40 +++++++++++++++----
 .../Views/Queue.xaml                          | 36 ++++++++++++-----
 ...BSVisualizer.Modules.SettingsDialog.csproj |  3 ++
 ...sualizer.Services.SchedulingService.csproj |  2 +-
 ...SVisualizer.Services.SettingService.csproj |  1 +
 CBSVisualizer/CBSVisualizer/App.xaml          |  7 ++++
 .../CBSVisualizer/CBSVisualizer.csproj        |  4 +-
 .../CBSVisualizer/Views/MainWindow.xaml       |  9 ++++-
 17 files changed, 100 insertions(+), 37 deletions(-)

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.Modules.Link/CBSVisualizer.Modules.Link.csproj b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
index b2c95d5..58eb0a9 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
@@ -5,8 +5,11 @@
     <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" />
+    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Common\CBSVisualizer.Common.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
index 39e0363..7ea0227 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
@@ -5,7 +5,10 @@
     <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" />
+    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
index 9a03652..45b7765 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
@@ -5,7 +5,10 @@
     <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" />
+    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml
index 7dab185..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,16 +19,5 @@
             <RowDefinition Height="*"/>
             <RowDefinition Height="*"/>
         </Grid.RowDefinitions>
-        <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="*"/>
-            <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..c23cc56 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs
@@ -27,11 +27,10 @@ namespace CBSVisualizer.Modules.Queue.QueueGroup.Views
         {
             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));
+                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 98b739a..18306af 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
@@ -7,7 +7,10 @@
   <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" />
+    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 2339590..21f45d7 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -8,6 +8,7 @@ using Prism.Events;
 using Prism.Regions;
 using System;
 using System.Collections.ObjectModel;
+using System.Collections.Specialized;
 using System.Diagnostics;
 using System.Threading;
 using System.Threading.Tasks;
@@ -24,10 +25,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private const double CREDIT_REFRESH_RATE_S = 0.1;
 
-        private double currentCredit = 0;
-
         private Task creditUpdateTask;
 
+        private double currentCredit = 0;
         public double CurrentCredit
         {
             get
@@ -71,6 +71,12 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         public int Priority { get; private set; }
 
+        public string PrioLabel { get; private set; }
+
+        public string PacketLabel { get; private set; }
+
+
+
         public ObservableCollection<PriorityPacket> Queue { get; private set; } = new ObservableCollection<PriorityPacket>();
 
         /// <summary>
@@ -83,17 +89,38 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
         public QueueViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, int prio) :
             base(regionManager)
         {
-            InitCharts();
-
             this.eventAggregator = eventAggregator;
             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)
+        {
+            Series[1].Values.Add(new DateTimePoint(DateTime.Now, Queue.Count));
         }
 
         private void InitCharts()
@@ -203,6 +230,8 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
         private void AtomicUpdateCredit(double increment, double limit)
         {
             Interlocked.Exchange(ref currentCredit, Math.Min(currentCredit + increment, limit));
+
+            Series[0].Values.Add(new DateTimePoint(DateTime.Now, currentCredit));
         }
 
         private void RegisterPacketHandler()
@@ -215,9 +244,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     {
                         // Add packet.
                         Queue.Add(packet);
-
-                        // Update chart value.
-                        Series[1].Values.Add(new DateTimePoint(DateTime.Now, Queue.Count));
                     }
                 }
             });
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
index 5c77652..1437a81 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
@@ -1,6 +1,7 @@
 <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" 
@@ -10,18 +11,33 @@
              xmlns:prism="http://prismlibrary.com/"
              prism:ViewModelLocator.AutoWireViewModel="False" >
     <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto"/>
+            <RowDefinition Height="*"/>
+        </Grid.RowDefinitions>
         <Grid.ColumnDefinitions>
-            <ColumnDefinition Width="0.5*"/>
-            <ColumnDefinition Width="0.5*"/>
-            <ColumnDefinition Width="0.5*"/>
-            <ColumnDefinition Width="0.5*"/>
-            <ColumnDefinition Width="2*"/>
+            <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"/>
-        <lvc:CartesianChart Series="{Binding Series}" LegendLocation="Right" Grid.Column="4">
+        <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"/>
+
+        <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>
diff --git a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
index e681e4a..3cd4a74 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
@@ -5,7 +5,10 @@
     <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" />
+    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
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.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/App.xaml b/CBSVisualizer/CBSVisualizer/App.xaml
index 80fe455..55a77f6 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="Light" PrimaryColor="Cyan" 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/CBSVisualizer.csproj b/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
index 5e2cc6e..2252ea0 100644
--- a/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
+++ b/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
@@ -7,8 +7,10 @@
     <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" />
+    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Modules.Link\CBSVisualizer.Modules.Link.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml b/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml
index 4be8a18..dccc3d8 100644
--- a/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml
+++ b/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml
@@ -4,7 +4,14 @@
         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"/>
-- 
GitLab


From a85c65b3decafb71ed3d334f953ae473a0f0d087 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Mon, 7 Sep 2020 23:14:28 +0200
Subject: [PATCH 04/17] Apply some visual changes.

---
 .../CBSVisualizer.Modules.Link.csproj         |   1 -
 .../Views/Link.xaml                           | 122 ++++++++++++++----
 .../CBSVisualizer.Modules.MenuBar.csproj      |   1 -
 .../CBSVisualizer.Modules.QueueGroup.csproj   |   1 -
 .../CBSVisualizer.Modules.Queue.csproj        |   1 -
 ...BSVisualizer.Modules.SettingsDialog.csproj |   1 -
 .../Views/SettingsDialog.xaml                 |   8 +-
 CBSVisualizer/CBSVisualizer/App.xaml          |   2 +-
 .../CBSVisualizer/CBSVisualizer.csproj        |   1 -
 .../CBSVisualizer/Views/MainWindow.xaml       |   6 +-
 10 files changed, 110 insertions(+), 34 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
index 58eb0a9..0dc7e0a 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
@@ -9,7 +9,6 @@
     <PackageReference Include="MaterialDesignThemes" Version="3.1.3" />
     <PackageReference Include="ParallelExtensionsExtras" Version="1.2.0" />
     <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" />
-    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Common\CBSVisualizer.Common.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml b/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml
index 055371c..04d16ec 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml
@@ -2,36 +2,112 @@
              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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
              xmlns:externals="clr-namespace:CBSVisualizer.Modules.Link.Externals"
-             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             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"/>
+            <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" />
+        <!--
+        <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}}" />
+        -->
+
+        <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 7ea0227..d71e29b 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
@@ -8,7 +8,6 @@
     <PackageReference Include="log4net" Version="2.0.9" />
     <PackageReference Include="MaterialDesignThemes" Version="3.1.3" />
     <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" />
-    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
index 45b7765..5dd618b 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
@@ -8,7 +8,6 @@
     <PackageReference Include="log4net" Version="2.0.9" />
     <PackageReference Include="MaterialDesignThemes" Version="3.1.3" />
     <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" />
-    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
index 18306af..754e306 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
@@ -10,7 +10,6 @@
     <PackageReference Include="log4net" Version="2.0.9" />
     <PackageReference Include="MaterialDesignThemes" Version="3.1.3" />
     <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" />
-    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
index 3cd4a74..40a784e 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
@@ -8,7 +8,6 @@
     <PackageReference Include="log4net" Version="2.0.9" />
     <PackageReference Include="MaterialDesignThemes" Version="3.1.3" />
     <PackageReference Include="Prism.Wpf" Version="7.2.0.1422" />
-    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
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/App.xaml b/CBSVisualizer/CBSVisualizer/App.xaml
index 55a77f6..bc2cf44 100644
--- a/CBSVisualizer/CBSVisualizer/App.xaml
+++ b/CBSVisualizer/CBSVisualizer/App.xaml
@@ -7,7 +7,7 @@
     <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
-                <materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Cyan" SecondaryColor="LightBlue" />
+                <materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Amber" SecondaryColor="LightBlue" />
                 <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
diff --git a/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj b/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
index 2252ea0..0ecc3d1 100644
--- a/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
+++ b/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
@@ -10,7 +10,6 @@
     <PackageReference Include="log4net" Version="2.0.9" />
     <PackageReference Include="MaterialDesignThemes" Version="3.1.3" />
     <PackageReference Include="Prism.DryIoc" Version="7.2.0.1422" />
-    <PackageReference Include="ShowMeTheXAML.MSBuild" Version="1.0.12" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\CBSVisualizer.Modules.Link\CBSVisualizer.Modules.Link.csproj" />
diff --git a/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml b/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml
index dccc3d8..1d12452 100644
--- a/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml
+++ b/CBSVisualizer/CBSVisualizer/Views/MainWindow.xaml
@@ -18,11 +18,11 @@
             <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


From e5c6a85cdc8e8726fe789d2b35ab66b256e9011c Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Thu, 10 Sep 2020 18:56:22 +0200
Subject: [PATCH 05/17] Remove some blank lines.

---
 .../CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs   | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 21f45d7..cd9ef0d 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -40,7 +40,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 SetProperty(ref currentCredit, value);
             }
         }
-
         public enum CreditBehaviour
         {
             // This is selected when there should be no credit-based shaper for this queue.
@@ -75,8 +74,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         public string PacketLabel { get; private set; }
 
-
-
         public ObservableCollection<PriorityPacket> Queue { get; private set; } = new ObservableCollection<PriorityPacket>();
 
         /// <summary>
-- 
GitLab


From 1b858813df7bbc348b46c073c490276e55c140fb Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Thu, 10 Sep 2020 19:21:14 +0200
Subject: [PATCH 06/17] Add UniqueId to the PriorityPacket.

---
 .../Models/PriorityPacket.cs                  | 42 +++++++++++--------
 1 file changed, 24 insertions(+), 18 deletions(-)

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}";
         }
     }
 }
-- 
GitLab


From c94b97b0a82682b1e0f9fb64c9d92704c3fc7272 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Thu, 10 Sep 2020 21:45:53 +0200
Subject: [PATCH 07/17] Refactor a bit, move some interfaces + introduce
 packetService.

---
 .../CBSVisualizer.Modules.Link.csproj         |  13 --
 .../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               |  12 +-
 .../Views/Link.xaml                           |  14 --
 .../CBSVisualizer.Modules.MenuBar.csproj      |   1 +
 .../MenuBarViewModel.LoadGeneration.cs        |  16 +--
 .../ViewModels/MenuBarViewModel.cs            |  15 +--
 .../Views/QueueGroup.xaml.cs                  |   6 +-
 .../CBSVisualizer.Modules.Queue.csproj        |   1 +
 .../QueueViewModel.LinkCallbacks.cs           |  26 +++-
 .../ViewModels/QueueViewModel.cs              |  71 +++++-----
 .../Views/Queue.xaml                          |   6 +-
 .../Views/Queue.xaml.cs                       |  14 +-
 .../ViewModels/SettingsDialogViewModel.cs     |   8 +-
 ...BSVisualizer.Services.PacketService.csproj |  11 ++
 .../Implementation/RandomPacketService.cs     |  37 +++++
 .../Interface/IPacketService.cs               |  22 +++
 .../Implementation/RandomSchedulingService.cs |   3 +-
 .../Interface/ISchedulingService.cs           |   8 +-
 .../SettingService.cs                         |   2 +-
 CBSVisualizer/CBSVisualizer.sln               |   7 +
 CBSVisualizer/CBSVisualizer/App.xaml.cs       |   7 +-
 .../CBSVisualizer/CBSVisualizer.csproj        |   1 +
 27 files changed, 185 insertions(+), 356 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.Modules.Link/CBSVisualizer.Modules.Link.csproj b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
index 0dc7e0a..88a26a2 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/CBSVisualizer.Modules.Link.csproj
@@ -16,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 1b96afe..52ff6b8 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
@@ -2,8 +2,8 @@
 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;
@@ -72,6 +72,14 @@ namespace CBSVisualizer.Modules.Link.ViewModels
                     return;
                 }
 
+                // Call Initialize() on each ILinkCallback.
+                log.Info("Initializing all links");
+                foreach (var callback in linkCallbacks.Values)
+                {
+                    callback.Initialize();
+                }
+
+                // Start scheduling.
                 scheduler.StartScheduling();
 
                 log.Info("Simulation started.");
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml b/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml
index 04d16ec..1c59871 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/Views/Link.xaml
@@ -3,7 +3,6 @@
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:CBSVisualizer.Modules.Link.Views"
              xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
-             xmlns:externals="clr-namespace:CBSVisualizer.Modules.Link.Externals"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              mc:Ignorable="d"
@@ -11,9 +10,6 @@
              xmlns:prism="http://prismlibrary.com/"
              prism:ViewModelLocator.AutoWireViewModel="True">
     <Grid>
-        <Grid.Resources>
-            <externals:BoolToImageConverter x:Key="BoolToImageConv" />
-        </Grid.Resources>
         <Grid.RowDefinitions>
             <RowDefinition Height="Auto" />
             <RowDefinition Height="*" />
@@ -26,16 +22,6 @@
             <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}}" />
-        -->
 
         <ToggleButton Style="{StaticResource MaterialDesignActionToggleButton}" ToolTip="Gate Status" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"
                       IsChecked="{Binding GateStatusDictionary[7].Value, Mode=OneWay}">
diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
index d71e29b..bd70497 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
@@ -12,6 +12,7 @@
   <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>
diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs
index 8e09473..4fb601d 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,14 +29,8 @@ 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;
@@ -75,11 +65,7 @@ namespace CBSVisualizer.Modules.MenuBar.ViewModels
 
         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;
         }
diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs
index eb68171..0187f30 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,12 +36,15 @@ 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);
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/Views/QueueGroup.xaml.cs
index c23cc56..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,13 +25,13 @@ 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 = 7; prio >= 0; prio--)
             {
-                Queue.Views.Queue newQueue = new Queue.Views.Queue(new QueueViewModel(regionManager, eventAggregator, prio));
+                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 754e306..2398fc6 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
@@ -14,6 +14,7 @@
   <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\CBSVisualizer.Core\CBSVisualizer.Core.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..37c7375 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
@@ -198,17 +198,35 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override async Task Initialize()
             {
-                await parent.StartCreditThread(parent.IdleSlope);
+                log.Info("Initialize");
+                var shouldStartThread = false;
+                
+                lock (parent.queueLock)
+                {
+                    shouldStartThread = parent.CurrentCredit < 0 || parent.Queue.Count > 0;
+                }
+
+                if (shouldStartThread)
+                {
+                    await parent.StartCreditThread(parent.IdleSlope);
+                }
+
             }
 
             public override async Task GateClosed()
             {
+                log.Info("GateClosed");
+
                 // Stop the credit growth thread.
                 await parent.StopCreditThread();
+
             }
 
             public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
+                log.Info("GateOpened");
+
+
                 // Start the credit 
                 lock (parent.queueLock)
                 {
@@ -231,6 +249,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
             {
+
+                log.Info("PacketPreempted");
+
                 lock (parent.queueLock)
                 {
                     parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes));
@@ -241,12 +262,15 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override async Task TransmissionCompleted()
             {
+                log.Info("TransmissionCompleted");
+
                 await parent.StopCreditThread();
                 await parent.StartCreditThread(parent.IdleSlope);
             }
 
             public override async Task TransmissionStarted(double bytesPerSecondRate)
             {
+                log.Info("TransmissionStarted");
                 await parent.StopCreditThread();
                 await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index cd9ef0d..932e9d9 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -1,9 +1,12 @@
 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;
@@ -17,8 +20,12 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 {
     public partial class QueueViewModel : RegionViewModelBase
     {
+        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 CancellationTokenSource creditGrowthCancellationSource;
@@ -83,10 +90,13 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         public SeriesCollection Series { get; set; }
 
-        public QueueViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, int prio) :
+        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();
 
@@ -166,15 +176,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private void RegisterSimulationStartStopHandler()
         {
-            eventAggregator.GetEvent<SimulationStartedEvent>().Subscribe(() =>
-            {
-                if (SelectedCreditBehaviour != CreditBehaviour.NoCBS && Queue.Count >= 1)
-                {
-                    creditUpdateTask = StartCreditThread(IdleSlope);
-                }
-            }
-            );
-
             eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(async () =>
             {
                 if (SelectedCreditBehaviour != CreditBehaviour.NoCBS)
@@ -187,6 +188,25 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             });
         }
 
+        private async Task StartCreditThread(double bytesPerSecondSlope, double limit = double.PositiveInfinity)
+        {
+            log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope.");
+            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);
+
+                    Debug.WriteLine($"Queue {Priority}: Credit {CurrentCredit}");
+                }
+            }, creditGrowthCancellationSource.Token);
+        }
+
         private async Task StopCreditThread()
         {
             creditGrowthCancellationSource?.Cancel();
@@ -199,31 +219,14 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             } catch (TaskCanceledException)
             {
-                // Do nothing.
+                log.Info($"Queue {Priority}: Credit Thread was cancelled.");
             }
+
+            log.Info($"Queue {Priority}: Credit Thread was stopped successfully.");
             creditUpdateTask = null;
             creditGrowthCancellationSource = null;
         }
 
-        private async Task StartCreditThread(double bytesPerSecondSlope, double limit = double.PositiveInfinity)
-        {
-            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);
-
-                        Debug.WriteLine($"Queue {Priority}: Credit {CurrentCredit}");
-                    }
-                }
-            , creditGrowthCancellationSource.Token);
-        }
-
         private void AtomicUpdateCredit(double increment, double limit)
         {
             Interlocked.Exchange(ref currentCredit, Math.Min(currentCredit + increment, limit));
@@ -244,6 +247,14 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     }
                 }
             });
+
+            GeneratePacketOnClick = new DelegateCommand(() =>
+            {
+                lock (queueLock)
+                {
+                    Queue.Add(packetService.GeneratePacket(Priority));
+                }
+            });
         }
     }
 }
\ No newline at end of file
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
index 1437a81..13428af 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml
@@ -26,7 +26,11 @@
         <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 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}"
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs
index 7b92184..cbf853e 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
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.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/Implementation/RandomSchedulingService.cs b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs
index ddccc65..0f89150 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;
diff --git a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs
index 2fd639a..4896d20 100644
--- a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs
+++ b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs
@@ -1,10 +1,6 @@
-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
     {
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.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 0ecc3d1..3a731bf 100644
--- a/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
+++ b/CBSVisualizer/CBSVisualizer/CBSVisualizer.csproj
@@ -16,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>
-- 
GitLab


From 1cf18089e46724dac97d8f81d3d6623183241b54 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Thu, 10 Sep 2020 21:57:09 +0200
Subject: [PATCH 08/17] Remove some of the logs.

---
 .../ViewModels/QueueViewModel.LinkCallbacks.cs           | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
index 37c7375..e48021e 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
@@ -215,8 +215,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override async Task GateClosed()
             {
-                log.Info("GateClosed");
-
                 // Stop the credit growth thread.
                 await parent.StopCreditThread();
 
@@ -224,9 +222,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
-                log.Info("GateOpened");
-
-
                 // Start the credit 
                 lock (parent.queueLock)
                 {
@@ -249,9 +244,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
             {
-
-                log.Info("PacketPreempted");
-
                 lock (parent.queueLock)
                 {
                     parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes));
@@ -263,7 +255,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             public override async Task TransmissionCompleted()
             {
                 log.Info("TransmissionCompleted");
-
                 await parent.StopCreditThread();
                 await parent.StartCreditThread(parent.IdleSlope);
             }
-- 
GitLab


From 317910365f3aaad48b8ce2dd16fabda1f5171731 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sat, 12 Sep 2020 15:50:24 +0200
Subject: [PATCH 09/17] Remove wrapping Task.Run(...) from StartCreditThread.

---
 .../ViewModels/QueueViewModel.cs                 | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 932e9d9..03b2add 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -192,19 +192,15 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
         {
             log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope.");
             creditGrowthCancellationSource = new CancellationTokenSource();
-            await Task.Run(async () =>
+            while (!creditGrowthCancellationSource.Token.IsCancellationRequested && CurrentCredit < limit && Queue.Count > 0)
             {
-                // 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);
+                // 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);
+                AtomicUpdateCredit(CREDIT_REFRESH_RATE_S * bytesPerSecondSlope, limit);
 
-                    Debug.WriteLine($"Queue {Priority}: Credit {CurrentCredit}");
-                }
-            }, creditGrowthCancellationSource.Token);
+                log.Info($"Queue {Priority}: Credit {CurrentCredit}");
+            }
         }
 
         private async Task StopCreditThread()
-- 
GitLab


From 54737ca784fc93e0d27a8643349df8a75b16c418 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sat, 12 Sep 2020 15:57:24 +0200
Subject: [PATCH 10/17] Remove some wrong references.

---
 .../CBSVisualizer.Modules.MenuBar.csproj                         | 1 -
 .../CBSVisualizer.Modules.QueueGroup.csproj                      | 1 -
 .../CBSVisualizer.Modules.Queue.csproj                           | 1 -
 .../CBSVisualizer.Modules.SettingsDialog.csproj                  | 1 -
 4 files changed, 4 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
index bd70497..390006b 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/CBSVisualizer.Modules.MenuBar.csproj
@@ -14,6 +14,5 @@
     <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.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
index 5dd618b..4028604 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue.QueueGroup/CBSVisualizer.Modules.QueueGroup.csproj
@@ -12,6 +12,5 @@
   <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/CBSVisualizer.Modules.Queue.csproj b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
index 2398fc6..7a155ee 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/CBSVisualizer.Modules.Queue.csproj
@@ -15,6 +15,5 @@
     <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\CBSVisualizer.Core\CBSVisualizer.Core.csproj" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
index 40a784e..f9da61e 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
+++ b/CBSVisualizer/CBSVisualizer.Modules.SettingsDialog/CBSVisualizer.Modules.SettingsDialog.csproj
@@ -12,6 +12,5 @@
   <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
-- 
GitLab


From d1f6e26e19fc61577808ebda44c33cf6295060e6 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sat, 12 Sep 2020 16:06:56 +0200
Subject: [PATCH 11/17] Remove wrapping await Task.Run(...) in
 MenuBarViewModel.LoadGeneration.cs. Remove one CanExecute method, because it
 can be expressed by inverting the other one.

---
 .../MenuBarViewModel.LoadGeneration.cs        | 33 +++++++------------
 .../ViewModels/MenuBarViewModel.cs            |  2 +-
 2 files changed, 12 insertions(+), 23 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs
index 4fb601d..c94c3c8 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.LoadGeneration.cs
@@ -36,9 +36,11 @@ namespace CBSVisualizer.Modules.MenuBar.ViewModels
             return !LoadGenerationInProgress;
         }
 
-        private bool CanStopLoadGeneration()
+        private async Task StartLoadThread()
         {
-            return LoadGenerationInProgress;
+            tokenSource = new CancellationTokenSource();
+            LoadGenerationInProgress = true;
+            await GenerateLoad();
         }
 
         private void StopLoadThread()
@@ -49,18 +51,14 @@ 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()
@@ -69,14 +67,5 @@ namespace CBSVisualizer.Modules.MenuBar.ViewModels
             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 0187f30..ee49c0f 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.MenuBar/ViewModels/MenuBarViewModel.cs
@@ -51,7 +51,7 @@ namespace CBSVisualizer.Modules.MenuBar.ViewModels
             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()
         {
-- 
GitLab


From bb356efbd459ef7021435a86d616735bf057d7aa Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sat, 12 Sep 2020 16:25:08 +0200
Subject: [PATCH 12/17] Remove some more stuff.

---
 .../ViewModels/LinkViewModel.cs               | 21 +----------
 .../QueueViewModel.LinkCallbacks.cs           | 35 +++++++++++--------
 .../ViewModels/QueueViewModel.cs              | 26 +++-----------
 3 files changed, 26 insertions(+), 56 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
index 52ff6b8..e558a51 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
@@ -31,8 +31,6 @@ namespace CBSVisualizer.Modules.Link.ViewModels
 
         private CancellationTokenSource tokenSource;
 
-        private Task packetTransmissionTask;
-
         /// <summary>
         /// The queue that is currently sending.
         /// </summary>
@@ -92,14 +90,6 @@ namespace CBSVisualizer.Modules.Link.ViewModels
 
                 // Stop packet sending.
                 tokenSource?.Cancel();
-                if (packetTransmissionTask != null)
-                {
-                    try
-                    {
-                        await packetTransmissionTask;
-                    } catch (TaskCanceledException) { }
-
-                }
 
                 // Reset all gate status lamps.
                 SetStatusLamps(new HashSet<int>());
@@ -126,15 +116,6 @@ namespace CBSVisualizer.Modules.Link.ViewModels
         {
             // Cancel old sending task.
             tokenSource?.Cancel();
-            if (packetTransmissionTask != null)
-            {
-                try
-                {
-                    await packetTransmissionTask;
-                }
-                catch (TaskCanceledException) { }
-
-            }
 
             packetInTransit = PriorityPacket.NoPacket;
 
@@ -146,7 +127,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels
 
             // Handle transmission.
             tokenSource = new CancellationTokenSource();
-            packetTransmissionTask = TransmitPackets(infoTuple);
+            await TransmitPackets(infoTuple);
         }
 
         /// <summary>
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
index e48021e..7a5da57 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
@@ -154,7 +154,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                         // If my packet was denied due to pre-closing, freeze my credit.
                     } else if (submitResult == PacketSubmitResult.DeniedPreClosing)
                     {
-                        _ = parent.StopCreditThread();
+                        parent.StopCreditThread();
                     }
                 }
 
@@ -176,14 +176,14 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             public override async Task TransmissionCompleted()
             {
                 // Stop and restart the credit thread.
-                await parent.StopCreditThread();
+                parent.StopCreditThread();
                 await parent.StartCreditThread(parent.IdleSlope);
             }
 
             public override async Task TransmissionStarted(double bytesPerSecondRate)
             {
                 // Decrease the credit by the idle slope.
-                await parent.StopCreditThread();
+                parent.StopCreditThread();
                 await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
         }
@@ -213,11 +213,11 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             }
 
-            public override async Task GateClosed()
+            public override Task GateClosed()
             {
                 // Stop the credit growth thread.
-                await parent.StopCreditThread();
-
+                parent.StopCreditThread();
+                return Task.CompletedTask;
             }
 
             public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
@@ -255,14 +255,14 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             public override async Task TransmissionCompleted()
             {
                 log.Info("TransmissionCompleted");
-                await parent.StopCreditThread();
+                parent.StopCreditThread();
                 await parent.StartCreditThread(parent.IdleSlope);
             }
 
             public override async Task TransmissionStarted(double bytesPerSecondRate)
             {
                 log.Info("TransmissionStarted");
-                await parent.StopCreditThread();
+                parent.StopCreditThread();
                 await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
         }
@@ -285,14 +285,15 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 return Task.CompletedTask;
             }
 
-            public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
+            public override async Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
+                var sentSuccessfully = false;
                 lock (parent.queueLock)
                 {
                     // Again, check if we can submit anything.
                     if (!CanSend())
                     {
-                        return Task.CompletedTask;
+                        return;
                     }
 
                     var firstPacket = parent.Queue.First();
@@ -301,14 +302,18 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     if (submitResult == PacketSubmitResult.Accepted)
                     {
                         parent.Queue.Remove(firstPacket);
+                        sentSuccessfully = true;
                     } 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();
+                        sentSuccessfully = false;
                     }
                 }
 
-                return Task.CompletedTask;
+                if (sentSuccessfully)
+                {
+                    await parent.StartCreditThread(parent.IdleSlope, 0);
+                }
             }
 
             public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
@@ -323,13 +328,13 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override async Task TransmissionCompleted()
             {
-                await parent.StopCreditThread();
+                parent.StopCreditThread();
                 await parent.StartCreditThread(parent.IdleSlope);
             }
 
             public override async Task TransmissionStarted(double bytesPerSecondRate)
             {
-                await parent.StopCreditThread();
+                parent.StopCreditThread();
                 await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
         }
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 03b2add..37cb0ae 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -20,6 +20,8 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 {
     public partial class QueueViewModel : RegionViewModelBase
     {
+        private const double CREDIT_REFRESH_RATE_S = 0.1;
+
         private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
 
         private readonly IEventAggregator eventAggregator;
@@ -30,10 +32,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private CancellationTokenSource creditGrowthCancellationSource;
 
-        private const double CREDIT_REFRESH_RATE_S = 0.1;
-
-        private Task creditUpdateTask;
-
         private double currentCredit = 0;
         public double CurrentCredit
         {
@@ -176,11 +174,11 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private void RegisterSimulationStartStopHandler()
         {
-            eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(async () =>
+            eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(() =>
             {
                 if (SelectedCreditBehaviour != CreditBehaviour.NoCBS)
                 {
-                    await StopCreditThread();
+                    StopCreditThread();
 
                     // Reset credit.
                     currentCredit = 0;
@@ -203,24 +201,10 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             }
         }
 
-        private async Task StopCreditThread()
+        private void StopCreditThread()
         {
             creditGrowthCancellationSource?.Cancel();
-            try
-            {
-                if (creditUpdateTask != null)
-                {
-                    await creditUpdateTask;
-                }
-
-            } catch (TaskCanceledException)
-            {
-                log.Info($"Queue {Priority}: Credit Thread was cancelled.");
-            }
-
             log.Info($"Queue {Priority}: Credit Thread was stopped successfully.");
-            creditUpdateTask = null;
-            creditGrowthCancellationSource = null;
         }
 
         private void AtomicUpdateCredit(double increment, double limit)
-- 
GitLab


From e7cc913f28e235c190cbb69c1c1cb6b21030c9fd Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sat, 12 Sep 2020 16:59:50 +0200
Subject: [PATCH 13/17] Correct the RandomSchedulingService to have an async
 start and a void stop method. I've come to the conclusion that async/await is
 not applicable for the Credit Update Scenario. I'll switch to a traditional
 thread there.

---
 .../ViewModels/LinkViewModel.cs               | 17 ++++++++++----
 .../ViewModels/QueueViewModel.cs              | 19 +++++++++------
 .../Implementation/RandomSchedulingService.cs | 23 +++++--------------
 .../Interface/ISchedulingService.cs           |  4 ++--
 4 files changed, 32 insertions(+), 31 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
index e558a51..1f4a2ff 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
@@ -7,6 +7,7 @@ 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;
@@ -62,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,21 +73,27 @@ namespace CBSVisualizer.Modules.Link.ViewModels
 
                 // Call Initialize() on each ILinkCallback.
                 log.Info("Initializing all links");
+                var initTasks = new List<Task>();
                 foreach (var callback in linkCallbacks.Values)
                 {
-                    callback.Initialize();
+                   initTasks.Add(callback.Initialize());
                 }
 
                 // Start scheduling.
-                scheduler.StartScheduling();
+                try
+                {
+                    await Task.WhenAll(initTasks);
+                    await scheduler.StartScheduling();
+                } catch (TaskCanceledException) { 
+                }
 
                 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();
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 37cb0ae..2247c06 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -188,17 +188,22 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private async Task StartCreditThread(double bytesPerSecondSlope, double limit = double.PositiveInfinity)
         {
-            log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope.");
+            // Init new cancellation token.
             creditGrowthCancellationSource = new CancellationTokenSource();
-            while (!creditGrowthCancellationSource.Token.IsCancellationRequested && CurrentCredit < limit && Queue.Count > 0)
+
+            await Task.Run(async () =>
             {
-                // Wait for the specified amount of time.
-                await Task.Delay(TimeSpan.FromSeconds(CREDIT_REFRESH_RATE_S), creditGrowthCancellationSource.Token);
+                log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope.");
+                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);
+                    AtomicUpdateCredit(CREDIT_REFRESH_RATE_S * bytesPerSecondSlope, limit);
 
-                log.Info($"Queue {Priority}: Credit {CurrentCredit}");
-            }
+                    log.Info($"Queue {Priority}: Credit {CurrentCredit}");
+                }
+            }, creditGrowthCancellationSource.Token);
         }
 
         private void StopCreditThread()
diff --git a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs
index 0f89150..9eb15cd 100644
--- a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs
+++ b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Implementation/RandomSchedulingService.cs
@@ -38,8 +38,8 @@ 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 + PROCESSING_DELAY_MS, tokenSource.Token);
@@ -48,8 +48,8 @@ namespace CBSVisualizer.Services.SchedulingService.Implementation
                 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 + PROCESSING_DELAY_MS, tokenSource.Token);
@@ -61,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 4896d20..e5bb1a1 100644
--- a/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs
+++ b/CBSVisualizer/CBSVisualizer.Services.SchedulingService/Interface/ISchedulingService.cs
@@ -4,8 +4,8 @@ namespace CBSVisualizer.Services.SchedulingService.Interface
 {
     public interface ISchedulingService
     {
-        public void StartScheduling();
+        public Task StartScheduling();
 
-        public Task StopScheduling();
+        public void StopScheduling();
     }
 }
-- 
GitLab


From d944c95b6aca17604007c66ea32af4ba01711cbc Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sat, 12 Sep 2020 17:56:52 +0200
Subject: [PATCH 14/17] Change link callback interface a bit and introduce
 "normal" thread for credit update.

---
 .../Events/RegisterLinkCallbackEvent.cs       |  12 +-
 .../ViewModels/LinkViewModel.cs               |  13 +-
 .../QueueViewModel.LinkCallbacks.cs           | 146 ++++++++----------
 .../ViewModels/QueueViewModel.cs              | 124 +++++++--------
 .../Views/Queue.xaml.cs                       |   4 +-
 5 files changed, 135 insertions(+), 164 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs
index d564aef..8503b93 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(double bytesPerSecondRate);
 
         /// <summary>
         /// Called when the transmission of the last packet has been completed.
         /// </summary>
-        Task TransmissionCompleted();
+        void TransmissionCompleted();
     }
     
     /// <summary>
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
index 1f4a2ff..db692ca 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
@@ -73,18 +73,17 @@ namespace CBSVisualizer.Modules.Link.ViewModels
 
                 // Call Initialize() on each ILinkCallback.
                 log.Info("Initializing all links");
-                var initTasks = new List<Task>();
                 foreach (var callback in linkCallbacks.Values)
                 {
-                   initTasks.Add(callback.Initialize());
+                   callback.Initialize();
                 }
 
                 // Start scheduling.
                 try
                 {
-                    await Task.WhenAll(initTasks);
                     await scheduler.StartScheduling();
-                } catch (TaskCanceledException) { 
+                } catch (TaskCanceledException) {
+                    log.Info("Scheduling was cancelled by button press.");
                 }
 
                 log.Info("Simulation started.");
@@ -154,7 +153,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels
                     // 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)
                             {
@@ -186,7 +185,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels
                     // Once a packet was selected for transmission, we send it.
                     transmittedBytes = 0;
 
-                    await linkCallbacks[activeQueue].TransmissionStarted(bitrate);
+                    linkCallbacks[activeQueue].TransmissionStarted(bitrate);
 
                     try
                     {
@@ -199,7 +198,7 @@ namespace CBSVisualizer.Modules.Link.ViewModels
                     } catch (TaskCanceledException) { }
                     finally
                     {
-                        await linkCallbacks[activeQueue].TransmissionCompleted();
+                        linkCallbacks[activeQueue].TransmissionCompleted();
                         log.Info($"{packetInTransit} of queue {activeQueue} has been sent successfully.");
 
                         // Reset the "Packet in transit" pointer.
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
index 7a5da57..ddc31d8 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
@@ -9,11 +9,26 @@ 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 LinkCallbackBase(QueueViewModel parentViewModel)
             {
                 parent = parentViewModel;
             }
@@ -28,10 +43,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 return parent.Priority;
             }
 
-            public virtual Task Initialize()
+            public virtual void Initialize()
             {
                 // Do nothing by default.
-                return Task.CompletedTask;
             }
 
             protected bool CanSend()
@@ -42,31 +56,30 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 }
             }
 
-            public abstract Task GateClosed();
+            public abstract void GateClosed();
 
-            public abstract Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket);
+            public abstract void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket);
 
-            public abstract Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes);
+            public abstract void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes);
 
-            public abstract Task TransmissionCompleted();
+            public abstract void TransmissionCompleted();
 
-            public abstract Task TransmissionStarted(double bytesPerSecondRate);
+            public abstract void TransmissionStarted(double bytesPerSecondRate);
         }
 
-        private class NoCBSLinkCallback : LinkCallbackBase
+        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)
@@ -74,7 +87,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     // If the queue is empty, return.
                     if (!CanSend())
                     {
-                        return Task.CompletedTask;
+                        return;
                     }
 
                     // If the packet was accepted, remove it from the queue.
@@ -87,29 +100,25 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
                     // 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)
                 {
                     parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes));
-                    return Task.CompletedTask;
                 }
             }
 
-            public override Task TransmissionCompleted()
+            public override void TransmissionCompleted()
             {
-                return Task.CompletedTask;
             }
 
-            public override Task TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(double bytesPerSecondRate)
             {
                 // Just write some log.
                 Debug.WriteLine($"Packet of Queue {parent.Priority} has started transmission with {bytesPerSecondRate} bytes/s.");
-                return Task.CompletedTask;
             }
         }
 
@@ -121,18 +130,17 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             {
             }
 
-            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;
             }
 
-            public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
+            public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
                 // Try to submit first packet.
                 lock (parent.queueLock)
@@ -140,7 +148,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
                     if (!CanSend())
                     {
-                        return Task.CompletedTask;
+                        return;
                     }
 
                     var firstPacket = parent.Queue.First();
@@ -159,32 +167,29 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 }
 
                 // Otherwise, just let the credit grow for now.
-                return Task.CompletedTask;
             }
 
-            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)
                 {
                     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.
                 parent.StopCreditThread();
-                await parent.StartCreditThread(parent.IdleSlope);
+                parent.StartCreditThread(parent.IdleSlope);
             }
 
-            public override async Task TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(double bytesPerSecondRate)
             {
                 // Decrease the credit by the idle slope.
                 parent.StopCreditThread();
-                await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
+                parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
         }
 
@@ -196,31 +201,18 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             {
             }
 
-            public override async Task Initialize()
+            public override void Initialize()
             {
-                log.Info("Initialize");
-                var shouldStartThread = false;
-                
-                lock (parent.queueLock)
-                {
-                    shouldStartThread = parent.CurrentCredit < 0 || parent.Queue.Count > 0;
-                }
-
-                if (shouldStartThread)
-                {
-                    await parent.StartCreditThread(parent.IdleSlope);
-                }
-
+                parent.StartCreditThread(parent.IdleSlope);
             }
 
-            public override Task GateClosed()
+            public override void GateClosed()
             {
                 // Stop the credit growth thread.
                 parent.StopCreditThread();
-                return Task.CompletedTask;
             }
 
-            public override Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
+            public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
                 // Start the credit 
                 lock (parent.queueLock)
@@ -228,7 +220,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     // Don't do anything when there are no packets.
                     if (!CanSend())
                     {
-                        return Task.CompletedTask;
+                        return;
                     }
 
                     // Otherwise, once again try to send the first packet.
@@ -238,32 +230,28 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                         parent.Queue.Remove(firstPacket);
                     }
                 }
-
-                return Task.CompletedTask;
             }
 
-            public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
+            public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
             {
                 lock (parent.queueLock)
                 {
                     parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes));
                 }
-
-                return Task.CompletedTask;
             }
 
-            public override async Task TransmissionCompleted()
+            public override void TransmissionCompleted()
             {
-                log.Info("TransmissionCompleted");
+                Log.Info("TransmissionCompleted");
                 parent.StopCreditThread();
-                await parent.StartCreditThread(parent.IdleSlope);
+                parent.StartCreditThread(parent.IdleSlope);
             }
 
-            public override async Task TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(double bytesPerSecondRate)
             {
-                log.Info("TransmissionStarted");
+                Log.Info("TransmissionStarted");
                 parent.StopCreditThread();
-                await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
+                parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
         }
 
@@ -274,20 +262,18 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             {
             }
 
-            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 async Task GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
+            public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
-                var sentSuccessfully = false;
                 lock (parent.queueLock)
                 {
                     // Again, check if we can submit anything.
@@ -302,40 +288,32 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     if (submitResult == PacketSubmitResult.Accepted)
                     {
                         parent.Queue.Remove(firstPacket);
-                        sentSuccessfully = true;
                     } else if (submitResult == PacketSubmitResult.DeniedPreClosing) // In the pre-closing case, we signal the thread to increase our credit to zero.
                     {
                         parent.StopCreditThread();
-                        sentSuccessfully = false;
+                        parent.StartCreditThread(parent.IdleSlope, 0);
                     }
                 }
-
-                if (sentSuccessfully)
-                {
-                    await parent.StartCreditThread(parent.IdleSlope, 0);
-                }
             }
 
-            public override Task PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
+            public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
             {
                 lock (parent.queueLock)
                 {
                     parent.Queue.Insert(0, new PriorityPacket(GetPriority(), leftoverBytes));
                 }
-
-                return Task.CompletedTask;
             }
 
-            public override async Task TransmissionCompleted()
+            public override void TransmissionCompleted()
             {
                 parent.StopCreditThread();
-                await parent.StartCreditThread(parent.IdleSlope);
+                parent.StartCreditThread(parent.IdleSlope, 0);
             }
 
-            public override async Task TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(double bytesPerSecondRate)
             {
                 parent.StopCreditThread();
-                await parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
+                parent.StartCreditThread(GetSendSlope(bytesPerSecondRate), 0);
             }
         }
     }
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 2247c06..ddb6843 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -12,7 +12,6 @@ using Prism.Regions;
 using System;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
-using System.Diagnostics;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -20,9 +19,11 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 {
     public partial class QueueViewModel : RegionViewModelBase
     {
-        private const double CREDIT_REFRESH_RATE_S = 0.1;
+        private const int ThreadJoinTimeoutS = 1;
 
-        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+        private const double CreditRefreshRateS = 0.1;
+
+        private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType);
 
         private readonly IEventAggregator eventAggregator;
 
@@ -32,54 +33,33 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private CancellationTokenSource creditGrowthCancellationSource;
 
-        private double currentCredit = 0;
-        public double CurrentCredit
+        private CreditBehaviour selectedCreditBehaviour;
+
+        public CreditBehaviour SelectedCreditBehaviour
         {
-            get
-            {
-                return currentCredit;
-            }
+            get => selectedCreditBehaviour;
 
-            private set
-            {
-                SetProperty(ref currentCredit, value);
-            }
+            set => SetProperty(ref selectedCreditBehaviour, value);
         }
-        public enum CreditBehaviour
-        {
-            // This is selected when there should be no credit-based shaper for this queue.
-            NoCBS,
 
-            // Frozen credit behaviour
-            Frozen,
+        private double currentCredit = 0;
 
-            // The standard credit behaviour
-            Standard,
+        public double CurrentCredit
+        {
+            get => currentCredit;
 
-            // Return to zero.
-            ReturnToZero
+            private set => SetProperty(ref currentCredit, value);
         }
 
-        private CreditBehaviour selectedCreditBehaviour;
-        public CreditBehaviour SelectedCreditBehaviour { 
-            get 
-            {
-                return selectedCreditBehaviour;
-            }
-
-            set
-            {
-                SetProperty(ref selectedCreditBehaviour, value);
-            }
-        }
+        private Thread creditUpdateThread;
 
-        public int Priority { get; private set; }
+        public int Priority { get; }
 
         public string PrioLabel { 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).
@@ -116,7 +96,8 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             {
                 PrioLabel = "Priority";
                 PacketLabel = "Packet Count";
-            } else
+            }
+            else
             {
                 PrioLabel = "";
                 PacketLabel = "";
@@ -146,7 +127,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         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());
             }
@@ -166,9 +147,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 case CreditBehaviour.Standard:
                     return new StandardLinkCallback(this);
 
-                case CreditBehaviour.NoCBS:
+                case CreditBehaviour.NoCbs:
                 default:
-                    return new NoCBSLinkCallback(this);
+                    return new NoCbsLinkCallback(this);
             }
         }
 
@@ -176,40 +157,48 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
         {
             eventAggregator.GetEvent<SimulationStoppedEvent>().Subscribe(() =>
             {
-                if (SelectedCreditBehaviour != CreditBehaviour.NoCBS)
+                if (SelectedCreditBehaviour == CreditBehaviour.NoCbs)
                 {
-                    StopCreditThread();
-
-                    // Reset credit.
-                    currentCredit = 0;
+                    return;
                 }
+
+                StopCreditThread();
+
+                // Reset credit.
+                currentCredit = 0;
             });
         }
 
-        private async Task StartCreditThread(double bytesPerSecondSlope, double limit = double.PositiveInfinity)
+        private void StartCreditThread(double bytesPerSecondSlope, double limit = double.PositiveInfinity)
         {
             // Init new cancellation token.
             creditGrowthCancellationSource = new CancellationTokenSource();
 
-            await Task.Run(async () =>
+            creditUpdateThread = new Thread(() =>
             {
-                log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope.");
-                while (!creditGrowthCancellationSource.Token.IsCancellationRequested && CurrentCredit < limit && Queue.Count > 0)
+                Log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope.");
+                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);
+                    Thread.Sleep(TimeSpan.FromSeconds(CreditRefreshRateS));
 
-                    AtomicUpdateCredit(CREDIT_REFRESH_RATE_S * bytesPerSecondSlope, limit);
+                    AtomicUpdateCredit(CreditRefreshRateS * bytesPerSecondSlope, limit);
 
-                    log.Info($"Queue {Priority}: Credit {CurrentCredit}");
+                    Log.Info($"Queue {Priority}: Credit {CurrentCredit}");
                 }
-            }, creditGrowthCancellationSource.Token);
+            });
+
+            creditUpdateThread.Start();
         }
 
         private void StopCreditThread()
         {
             creditGrowthCancellationSource?.Cancel();
-            log.Info($"Queue {Priority}: Credit Thread was stopped successfully.");
+
+            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)
@@ -223,23 +212,28 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
         {
             eventAggregator.GetEvent<PacketArrivedEvent>().Subscribe(packet =>
             {
-                if (packet.Priority == Priority)
+                if (packet.Priority != Priority)
                 {
-                    lock (queueLock)
-                    {
-                        // Add packet.
-                        Queue.Add(packet);
-                    }
+                    return;
                 }
-            });
 
-            GeneratePacketOnClick = new DelegateCommand(() =>
-            {
                 lock (queueLock)
                 {
-                    Queue.Add(packetService.GeneratePacket(Priority));
+                    // Add packet.
+                    Queue.Add(packet);
                 }
             });
+
+            GeneratePacketOnClick = new DelegateCommand(async () =>
+            {
+                await Task.Run(() =>
+                {
+                    lock (queueLock)
+                    {
+                        Queue.Add(packetService.GeneratePacket(Priority));
+                    }
+                });
+            });
         }
     }
 }
\ No newline at end of file
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs
index cbf853e..e20fa11 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/Views/Queue.xaml.cs
@@ -27,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
@@ -39,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);
-- 
GitLab


From c60cc618c4198bf28c235cae3652e9e0dee6fe3e Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Sat, 12 Sep 2020 18:40:07 +0200
Subject: [PATCH 15/17] Change some stuff. Maybe works better now.

---
 .../CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs  | 4 ++--
 CBSVisualizer/CBSVisualizer/App.xaml                          | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index ddb6843..2e2dc0f 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -19,9 +19,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 {
     public partial class QueueViewModel : RegionViewModelBase
     {
-        private const int ThreadJoinTimeoutS = 1;
+        private const int ThreadJoinTimeoutS = 5;
 
-        private const double CreditRefreshRateS = 0.1;
+        private const double CreditRefreshRateS = 1;
 
         private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType);
 
diff --git a/CBSVisualizer/CBSVisualizer/App.xaml b/CBSVisualizer/CBSVisualizer/App.xaml
index bc2cf44..220ab7b 100644
--- a/CBSVisualizer/CBSVisualizer/App.xaml
+++ b/CBSVisualizer/CBSVisualizer/App.xaml
@@ -7,7 +7,7 @@
     <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
-                <materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="Amber" SecondaryColor="LightBlue" />
+                <materialDesign:BundledTheme BaseTheme="Dark" PrimaryColor="Amber" SecondaryColor="LightBlue" />
                 <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
-- 
GitLab


From 3ff173ec666df97d1d08bfac5c398488161674a0 Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Mon, 14 Sep 2020 20:04:38 +0200
Subject: [PATCH 16/17] Replace a lot of double variables by long for
 performance reasons + introduce second lock for credit.

---
 .../Events/RegisterLinkCallbackEvent.cs       |   2 +-
 .../ViewModels/LinkViewModel.cs               |  24 ++--
 .../QueueViewModel.LinkCallbacks.cs           | 104 +++++++++---------
 .../ViewModels/QueueViewModel.cs              |  52 ++++++---
 4 files changed, 101 insertions(+), 81 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs
index 8503b93..21304fe 100644
--- a/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs
+++ b/CBSVisualizer/CBSVisualizer.MessagingCore/Events/RegisterLinkCallbackEvent.cs
@@ -59,7 +59,7 @@ namespace CBSVisualizer.Messaging.Events
         /// Called by the link when the transmission has started.
         /// </summary>
         /// <param name="bytesPerSecondRate"> the rate in bytes per second. </param>
-        void TransmissionStarted(double bytesPerSecondRate);
+        void TransmissionStarted(long bytesPerSecondRate);
 
         /// <summary>
         /// Called when the transmission of the last packet has been completed.
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
index db692ca..995c0f5 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Link/ViewModels/LinkViewModel.cs
@@ -210,17 +210,18 @@ namespace CBSVisualizer.Modules.Link.ViewModels
 
         private bool CanSendInTime(ref int remainingBytes, PriorityPacket packet)
         {
-            if (packet.Size <= remainingBytes)
+            if (packet.Size > remainingBytes)
             {
-                log.Info($"Packet Size: {packet.Size}, remaining bytes until next GateCloseEvent: {remainingBytes}. {remainingBytes - packet.Size} bytes left.");
-                remainingBytes -= packet.Size;
-                return true;
+                return false;
             }
 
-            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);
@@ -236,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.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
index ddc31d8..611f353 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
@@ -26,21 +26,21 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private abstract class LinkCallbackBase : ILinkCallback
         {
-            protected readonly QueueViewModel parent;
+            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 void Initialize()
@@ -50,9 +50,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             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;
                 }
             }
 
@@ -64,7 +64,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public abstract void TransmissionCompleted();
 
-            public abstract void TransmissionStarted(double bytesPerSecondRate);
+            public abstract void TransmissionStarted(long bytesPerSecondRate);
         }
 
         private class NoCbsLinkCallback : LinkCallbackBase
@@ -82,7 +82,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             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())
@@ -91,11 +91,11 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     }
 
                     // 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 :-)
@@ -105,9 +105,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             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));
+                    Parent.Queue.Insert(0, new PriorityPacket(Parent.Priority, leftoverBytes));
                 }
             }
 
@@ -115,10 +115,10 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             {
             }
 
-            public override void TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(long bytesPerSecondRate)
             {
                 // Just write some log.
-                Debug.WriteLine($"Packet of Queue {parent.Priority} has started transmission with {bytesPerSecondRate} bytes/s.");
+                Debug.WriteLine($"Packet of Queue {Parent.Priority} has started transmission with {bytesPerSecondRate} bytes/s.");
             }
         }
 
@@ -132,7 +132,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void Initialize()
             {
-                parent.StartCreditThread(parent.IdleSlope);
+                Parent.StartCreditThread(Parent.IdleSlope);
             }
 
             public override void GateClosed()
@@ -143,7 +143,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
                 // Try to submit first packet.
-                lock (parent.queueLock)
+                lock (Parent.queueLock)
                 {
 
                     if (!CanSend())
@@ -151,18 +151,18 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                         return;
                     }
 
-                    var firstPacket = parent.Queue.First();
+                    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);
+                        Parent.Queue.Remove(firstPacket);
 
                         // If my packet was denied due to pre-closing, freeze my credit.
                     } else if (submitResult == PacketSubmitResult.DeniedPreClosing)
                     {
-                        parent.StopCreditThread();
+                        Parent.StopCreditThread();
                     }
                 }
 
@@ -172,24 +172,24 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             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));
                 }
             }
 
             public override void TransmissionCompleted()
             {
                 // Stop and restart the credit thread.
-                parent.StopCreditThread();
-                parent.StartCreditThread(parent.IdleSlope);
+                Parent.StopCreditThread();
+                Parent.StartCreditThread(Parent.IdleSlope);
             }
 
-            public override void TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(long bytesPerSecondRate)
             {
                 // Decrease the credit by the idle slope.
-                parent.StopCreditThread();
-                parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
+                Parent.StopCreditThread();
+                Parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
         }
 
@@ -203,19 +203,19 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void Initialize()
             {
-                parent.StartCreditThread(parent.IdleSlope);
+                Parent.StartCreditThread(Parent.IdleSlope);
             }
 
             public override void GateClosed()
             {
                 // Stop the credit growth thread.
-                parent.StopCreditThread();
+                Parent.StopCreditThread();
             }
 
             public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
                 // Start the credit 
-                lock (parent.queueLock)
+                lock (Parent.queueLock)
                 {
                     // Don't do anything when there are no packets.
                     if (!CanSend())
@@ -224,34 +224,34 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     }
 
                     // Otherwise, once again try to send the first packet.
-                    var firstPacket = parent.Queue.First();
+                    var firstPacket = Parent.Queue.First();
                     if (trySubmitFirstPacket.Invoke(firstPacket) == PacketSubmitResult.Accepted)
                     {
-                        parent.Queue.Remove(firstPacket);
+                        Parent.Queue.Remove(firstPacket);
                     }
                 }
             }
 
             public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
             {
-                lock (parent.queueLock)
+                lock (Parent.queueLock)
                 {
-                    parent.Queue.Insert(0, new PriorityPacket(parent.Priority, leftoverBytes));
+                    Parent.Queue.Insert(0, new PriorityPacket(Parent.Priority, leftoverBytes));
                 }
             }
 
             public override void TransmissionCompleted()
             {
                 Log.Info("TransmissionCompleted");
-                parent.StopCreditThread();
-                parent.StartCreditThread(parent.IdleSlope);
+                Parent.StopCreditThread();
+                Parent.StartCreditThread(Parent.IdleSlope);
             }
 
-            public override void TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(long bytesPerSecondRate)
             {
                 Log.Info("TransmissionStarted");
-                parent.StopCreditThread();
-                parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
+                Parent.StopCreditThread();
+                Parent.StartCreditThread(GetSendSlope(bytesPerSecondRate));
             }
         }
 
@@ -264,7 +264,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void Initialize()
             {
-                parent.StartCreditThread(parent.IdleSlope);
+                Parent.StartCreditThread(Parent.IdleSlope);
             }
 
             public override void GateClosed()
@@ -274,7 +274,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
-                lock (parent.queueLock)
+                lock (Parent.queueLock)
                 {
                     // Again, check if we can submit anything.
                     if (!CanSend())
@@ -282,38 +282,38 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                         return;
                     }
 
-                    var firstPacket = parent.Queue.First();
+                    var firstPacket = Parent.Queue.First();
                     var submitResult = trySubmitFirstPacket.Invoke(firstPacket);
 
                     if (submitResult == PacketSubmitResult.Accepted)
                     {
-                        parent.Queue.Remove(firstPacket);
+                        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);
                     }
                 }
             }
 
             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));
                 }
             }
 
             public override void TransmissionCompleted()
             {
-                parent.StopCreditThread();
-                parent.StartCreditThread(parent.IdleSlope, 0);
+                Parent.StopCreditThread();
+                Parent.StartCreditThread(Parent.IdleSlope, 0);
             }
 
-            public override void TransmissionStarted(double bytesPerSecondRate)
+            public override void TransmissionStarted(long bytesPerSecondRate)
             {
-                parent.StopCreditThread();
-                parent.StartCreditThread(GetSendSlope(bytesPerSecondRate), 0);
+                Parent.StopCreditThread();
+                Parent.StartCreditThread(GetSendSlope(bytesPerSecondRate), 0);
             }
         }
     }
diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
index 2e2dc0f..b33fa8a 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -21,7 +21,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
     {
         private const int ThreadJoinTimeoutS = 5;
 
-        private const double CreditRefreshRateS = 1;
+        private const long CreditRefreshRateS = 1;
 
         private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType);
 
@@ -31,6 +31,8 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         private readonly object queueLock = new object();
 
+        private readonly object creditLock = new object();
+
         private CancellationTokenSource creditGrowthCancellationSource;
 
         private CreditBehaviour selectedCreditBehaviour;
@@ -42,13 +44,25 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             set => SetProperty(ref selectedCreditBehaviour, value);
         }
 
-        private double currentCredit = 0;
+        private long currentCredit;
 
-        public double CurrentCredit
+        public long CurrentCredit
         {
-            get => currentCredit;
+            get
+            {
+                lock (creditLock)
+                {
+                    return currentCredit;
+                }
+            }
 
-            private set => SetProperty(ref currentCredit, value);
+            private set
+            {
+                lock (creditLock)
+                {
+                    SetProperty(ref currentCredit, value);
+                }
+            }
         }
 
         private Thread creditUpdateThread;
@@ -146,7 +160,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
                 case CreditBehaviour.Standard:
                     return new StandardLinkCallback(this);
-
+                // Default is no CBS.
                 case CreditBehaviour.NoCbs:
                 default:
                     return new NoCbsLinkCallback(this);
@@ -165,11 +179,11 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 StopCreditThread();
 
                 // Reset credit.
-                currentCredit = 0;
+                CurrentCredit = 0;
             });
         }
 
-        private void StartCreditThread(double bytesPerSecondSlope, double limit = double.PositiveInfinity)
+        private void StartCreditThread(long bytesPerSecondSlope, long limit = long.MaxValue)
         {
             // Init new cancellation token.
             creditGrowthCancellationSource = new CancellationTokenSource();
@@ -177,9 +191,19 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             creditUpdateThread = new Thread(() =>
             {
                 Log.Info($"Queue {Priority}: Credit Thread was started with {bytesPerSecondSlope} bytes/s slope.");
-                while (!creditGrowthCancellationSource.Token.IsCancellationRequested && CurrentCredit < limit &&
-                       Queue.Count > 0)
+                while (!creditGrowthCancellationSource.Token.IsCancellationRequested)
                 {
+                    lock (queueLock)
+                    {
+                        lock (creditLock)
+                        {
+                            if (CurrentCredit > limit || Queue.Count <= 0)
+                            {
+                                return;
+                            }
+                        }
+                    }
+
                     // Wait for the specified amount of time.
                     Thread.Sleep(TimeSpan.FromSeconds(CreditRefreshRateS));
 
@@ -201,11 +225,13 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 : $"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);
 
-            Series[0].Values.Add(new DateTimePoint(DateTime.Now, currentCredit));
+            // Add the new value to the series.
+            Series[0].Values.Add(new DateTimePoint(DateTime.Now, CurrentCredit));
         }
 
         private void RegisterPacketHandler()
-- 
GitLab


From d0ba462ab3671041e842bf9e6af015e7aaa739ab Mon Sep 17 00:00:00 2001
From: Dmitrii Cetvericov <d.cetvericov@live.de>
Date: Mon, 14 Sep 2020 21:13:47 +0200
Subject: [PATCH 17/17] Standard Credit Behaviour seems to do something nice
 :-) I guess this is a good moment to merge to master.

---
 .../QueueViewModel.LinkCallbacks.cs           | 136 +++++++++++-------
 .../ViewModels/QueueViewModel.cs              |  21 +--
 2 files changed, 96 insertions(+), 61 deletions(-)

diff --git a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
index 611f353..5053171 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.LinkCallbacks.cs
@@ -3,7 +3,6 @@ using CBSVisualizer.Messaging.Events;
 using System;
 using System.Diagnostics;
 using System.Linq;
-using System.Threading.Tasks;
 
 namespace CBSVisualizer.Modules.Queue.ViewModels
 {
@@ -56,6 +55,40 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 }
             }
 
+
+            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 void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket);
@@ -67,6 +100,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
             public abstract void TransmissionStarted(long bytesPerSecondRate);
         }
 
+        #region NoCbsLinkCallback
         private class NoCbsLinkCallback : LinkCallbackBase
         {
             public NoCbsLinkCallback(QueueViewModel parent)
@@ -85,7 +119,7 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 lock (Parent.queueLock)
                 {
                     // If the queue is empty, return.
-                    if (!CanSend())
+                    if (Parent.Queue.Count <= 0)
                     {
                         return;
                     }
@@ -111,22 +145,24 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 }
             }
 
-            public override void TransmissionCompleted()
-            {
-            }
-
             public override void TransmissionStarted(long bytesPerSecondRate)
             {
                 // Just write some log.
                 Debug.WriteLine($"Packet of Queue {Parent.Priority} has started transmission with {bytesPerSecondRate} bytes/s.");
             }
+            
+            public override void TransmissionCompleted()
+            {
+                // 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)
             {
             }
 
@@ -137,41 +173,21 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void GateClosed()
             {
-                // Nothing special happens here. The credit handling is done in the GateOpened method.
+                // Stop the credit thread.
+                Parent.StopCreditThread();
             }
 
             public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
-                // Try to submit first packet.
-                lock (Parent.queueLock)
-                {
-
-                    if (!CanSend())
-                    {
-                        return;
-                    }
-
-                    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.
+                // Try to send the packet if we can.
+                TrySendPacket(trySubmitFirstPacket, null, null, null);
             }
 
             public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
             {
-                // Put the leftovers of the packet back into the queue.
                 lock (Parent.queueLock)
                 {
                     Parent.Queue.Insert(0, new PriorityPacket(Parent.Priority, leftoverBytes));
@@ -180,24 +196,25 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void TransmissionCompleted()
             {
-                // Stop and restart the credit thread.
+                Log.Info("Transmission Completed");
                 Parent.StopCreditThread();
                 Parent.StartCreditThread(Parent.IdleSlope);
             }
 
             public override void TransmissionStarted(long bytesPerSecondRate)
             {
-                // Decrease the credit by the idle slope.
+                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)
             {
             }
 
@@ -208,32 +225,41 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void GateClosed()
             {
-                // Stop the credit growth thread.
-                Parent.StopCreditThread();
+                // Nothing special happens here. The credit handling is done in the GateOpened method.
             }
 
             public override void GateOpened(Func<PriorityPacket, PacketSubmitResult> trySubmitFirstPacket)
             {
-                // Start the credit 
+                // Try to submit first packet.
                 lock (Parent.queueLock)
                 {
-                    // Don't do anything when there are no packets.
                     if (!CanSend())
                     {
                         return;
                     }
 
-                    // Otherwise, once again try to send the first packet.
                     var firstPacket = Parent.Queue.First();
-                    if (trySubmitFirstPacket.Invoke(firstPacket) == PacketSubmitResult.Accepted)
+                    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();
                     }
                 }
+
+                // Otherwise, just let the credit grow for now.
             }
 
             public override void PacketPreempted(PriorityPacket preemptedPacket, int leftoverBytes)
             {
+                // Put the leftovers of the packet back into the queue.
                 lock (Parent.queueLock)
                 {
                     Parent.Queue.Insert(0, new PriorityPacket(Parent.Priority, leftoverBytes));
@@ -242,23 +268,25 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
             public override void TransmissionCompleted()
             {
-                Log.Info("TransmissionCompleted");
+                // Stop and restart the credit thread.
                 Parent.StopCreditThread();
                 Parent.StartCreditThread(Parent.IdleSlope);
             }
 
             public override void TransmissionStarted(long bytesPerSecondRate)
             {
-                Log.Info("TransmissionStarted");
+                // 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)
             {
             }
 
@@ -288,7 +316,8 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                     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.
+                    }
+                    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);
@@ -316,5 +345,6 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
                 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 b33fa8a..e3b9186 100644
--- a/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
+++ b/CBSVisualizer/CBSVisualizer.Modules.Queue/ViewModels/QueueViewModel.cs
@@ -19,9 +19,9 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 {
     public partial class QueueViewModel : RegionViewModelBase
     {
-        private const int ThreadJoinTimeoutS = 5;
+        private const int ThreadJoinTimeoutS = 1;
 
-        private const long CreditRefreshRateS = 1;
+        private const long CreditRefreshRateS = 5;
 
         private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType);
 
@@ -120,6 +120,11 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
 
         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));
         }
 
@@ -220,18 +225,18 @@ namespace CBSVisualizer.Modules.Queue.ViewModels
         {
             creditGrowthCancellationSource?.Cancel();
 
-            Log.Info(creditUpdateThread.Join(TimeSpan.FromSeconds(ThreadJoinTimeoutS))
-                ? $"Queue {Priority}: Unable to stop credit thread."
-                : $"Queue {Priority}: Credit Thread was stopped successfully.");
+            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(long increment, long limit)
         {
             // Update the credit.
             CurrentCredit = Math.Min(CurrentCredit + increment, limit);
-
-            // Add the new value to the series.
-            Series[0].Values.Add(new DateTimePoint(DateTime.Now, CurrentCredit));
         }
 
         private void RegisterPacketHandler()
-- 
GitLab