Kenneth van Ewijk 10 gadi atpakaļ
vecāks
revīzija
7e9c9c705e
69 mainītis faili ar 6975 papildinājumiem un 0 dzēšanām
  1. 63 0
      .gitattributes
  2. 6 0
      ErgometerIPR/ErgometerApplication/App.config
  3. 105 0
      ErgometerIPR/ErgometerApplication/ChartPanel.cs
  4. 187 0
      ErgometerIPR/ErgometerApplication/ClientApplicatie.Designer.cs
  5. 150 0
      ErgometerIPR/ErgometerApplication/ClientApplicatie.cs
  6. 126 0
      ErgometerIPR/ErgometerApplication/ClientApplicatie.resx
  7. 127 0
      ErgometerIPR/ErgometerApplication/ErgometerApplication.csproj
  8. 284 0
      ErgometerIPR/ErgometerApplication/MainClient.cs
  9. 202 0
      ErgometerIPR/ErgometerApplication/PanelClientChat.cs
  10. 35 0
      ErgometerIPR/ErgometerApplication/PanelClientContainer.cs
  11. 115 0
      ErgometerIPR/ErgometerApplication/PanelClientData.cs
  12. 71 0
      ErgometerIPR/ErgometerApplication/PanelClientDataView.cs
  13. 158 0
      ErgometerIPR/ErgometerApplication/PanelLogin.cs
  14. 23 0
      ErgometerIPR/ErgometerApplication/Program.cs
  15. 36 0
      ErgometerIPR/ErgometerApplication/Properties/AssemblyInfo.cs
  16. 73 0
      ErgometerIPR/ErgometerApplication/Properties/Resources.Designer.cs
  17. 124 0
      ErgometerIPR/ErgometerApplication/Properties/Resources.resx
  18. 30 0
      ErgometerIPR/ErgometerApplication/Properties/Settings.Designer.cs
  19. 7 0
      ErgometerIPR/ErgometerApplication/Properties/Settings.settings
  20. BIN
      ErgometerIPR/ErgometerApplication/Resources/flatbike.png
  21. 4 0
      ErgometerIPR/ErgometerApplication/packages.config
  22. 6 0
      ErgometerIPR/ErgometerDoctorApplication/App.config
  23. 105 0
      ErgometerIPR/ErgometerDoctorApplication/Client/ChartPanel.cs
  24. 78 0
      ErgometerIPR/ErgometerDoctorApplication/Client/ClientThread.cs
  25. 206 0
      ErgometerIPR/ErgometerDoctorApplication/Client/PanelClientChat.cs
  26. 115 0
      ErgometerIPR/ErgometerDoctorApplication/Client/PanelClientData.cs
  27. 287 0
      ErgometerIPR/ErgometerDoctorApplication/Client/PanelClientSetData.cs
  28. 71 0
      ErgometerIPR/ErgometerDoctorApplication/Client/PanelGraphView.cs
  29. 175 0
      ErgometerIPR/ErgometerDoctorApplication/Client/SessionWindow.Designer.cs
  30. 103 0
      ErgometerIPR/ErgometerDoctorApplication/Client/SessionWindow.cs
  31. 120 0
      ErgometerIPR/ErgometerDoctorApplication/Client/SessionWindow.resx
  32. 84 0
      ErgometerIPR/ErgometerDoctorApplication/ConActiveSessions.cs
  33. 72 0
      ErgometerIPR/ErgometerDoctorApplication/ConClientBroadcast.cs
  34. 150 0
      ErgometerIPR/ErgometerDoctorApplication/ConClientData.cs
  35. 116 0
      ErgometerIPR/ErgometerDoctorApplication/ConPanelLogin.cs
  36. 65 0
      ErgometerIPR/ErgometerDoctorApplication/ConSessionHistory.cs
  37. 144 0
      ErgometerIPR/ErgometerDoctorApplication/ErgometerDoctorApplication.csproj
  38. 276 0
      ErgometerIPR/ErgometerDoctorApplication/MainClient.cs
  39. 320 0
      ErgometerIPR/ErgometerDoctorApplication/MainWindow.Designer.cs
  40. 147 0
      ErgometerIPR/ErgometerDoctorApplication/MainWindow.cs
  41. 126 0
      ErgometerIPR/ErgometerDoctorApplication/MainWindow.resx
  42. 22 0
      ErgometerIPR/ErgometerDoctorApplication/Program.cs
  43. 36 0
      ErgometerIPR/ErgometerDoctorApplication/Properties/AssemblyInfo.cs
  44. 73 0
      ErgometerIPR/ErgometerDoctorApplication/Properties/Resources.Designer.cs
  45. 124 0
      ErgometerIPR/ErgometerDoctorApplication/Properties/Resources.resx
  46. 30 0
      ErgometerIPR/ErgometerDoctorApplication/Properties/Settings.Designer.cs
  47. 7 0
      ErgometerIPR/ErgometerDoctorApplication/Properties/Settings.settings
  48. BIN
      ErgometerIPR/ErgometerDoctorApplication/Resources/doctorImage.png
  49. 91 0
      ErgometerIPR/ErgometerDoctorApplication/SessionPanel.cs
  50. 22 0
      ErgometerIPR/ErgometerIPR.sln
  51. 162 0
      ErgometerIPR/ErgometerLibrary/AESEncrypt.cs
  52. 63 0
      ErgometerIPR/ErgometerLibrary/Chat/ChatItem.cs
  53. 23 0
      ErgometerIPR/ErgometerLibrary/ChatMessage.cs
  54. 77 0
      ErgometerIPR/ErgometerLibrary/ComPort.cs
  55. 72 0
      ErgometerIPR/ErgometerLibrary/ErgometerLibrary.csproj
  56. 32 0
      ErgometerIPR/ErgometerLibrary/Helper.cs
  57. 103 0
      ErgometerIPR/ErgometerLibrary/Meting.cs
  58. 424 0
      ErgometerIPR/ErgometerLibrary/NetCommand.cs
  59. 135 0
      ErgometerIPR/ErgometerLibrary/NetHelper.cs
  60. 36 0
      ErgometerIPR/ErgometerLibrary/Properties/AssemblyInfo.cs
  61. 4 0
      ErgometerIPR/ErgometerLibrary/packages.config
  62. 6 0
      ErgometerIPR/ErgometerServer/App.config
  63. 137 0
      ErgometerIPR/ErgometerServer/ClientThread.cs
  64. 121 0
      ErgometerIPR/ErgometerServer/DoctorThread.cs
  65. 72 0
      ErgometerIPR/ErgometerServer/ErgometerServer.csproj
  66. 204 0
      ErgometerIPR/ErgometerServer/FileHandler.cs
  67. 36 0
      ErgometerIPR/ErgometerServer/Properties/AssemblyInfo.cs
  68. 167 0
      ErgometerIPR/ErgometerServer/Server.cs
  69. 4 0
      ErgometerIPR/ErgometerServer/packages.config

+ 63 - 0
.gitattributes

@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs     diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following 
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln       merge=binary
+#*.csproj    merge=binary
+#*.vbproj    merge=binary
+#*.vcxproj   merge=binary
+#*.vcproj    merge=binary
+#*.dbproj    merge=binary
+#*.fsproj    merge=binary
+#*.lsproj    merge=binary
+#*.wixproj   merge=binary
+#*.modelproj merge=binary
+#*.sqlproj   merge=binary
+#*.wwaproj   merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg   binary
+#*.png   binary
+#*.gif   binary
+
+###############################################################################
+# diff behavior for common document formats
+# 
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the 
+# entries below.
+###############################################################################
+#*.doc   diff=astextplain
+#*.DOC   diff=astextplain
+#*.docx  diff=astextplain
+#*.DOCX  diff=astextplain
+#*.dot   diff=astextplain
+#*.DOT   diff=astextplain
+#*.pdf   diff=astextplain
+#*.PDF   diff=astextplain
+#*.rtf   diff=astextplain
+#*.RTF   diff=astextplain

+ 6 - 0
ErgometerIPR/ErgometerApplication/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
+    </startup>
+</configuration>

+ 105 - 0
ErgometerIPR/ErgometerApplication/ChartPanel.cs

@@ -0,0 +1,105 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+
+namespace ErgometerApplication
+{
+    public class ChartPanel : Panel
+    {
+        private Chart chart;
+        private MetingType type;
+        private ChartArea chartArea;
+        private Series series;
+        private SeriesChartType ChartType;
+
+        public ChartPanel(MetingType type, SeriesChartType charttype) : base()
+        {
+            this.type = type;
+            this.ChartType = charttype;
+
+            this.chart = new Chart();
+            this.chartArea = new ChartArea();
+            this.chart.Titles.Add(new Title(type.ToString()));
+
+            this.Location = new System.Drawing.Point(0, 0);
+
+            this.Size = new System.Drawing.Size(400, 250);
+            this.Controls.Add(chart);
+
+            this.series = createSerie();
+            this.chartArea.Name = "chartArea";
+
+            this.chart.Size = new System.Drawing.Size(400, 250);
+
+            this.chart.Dock = DockStyle.Fill;
+            this.chart.Series.Add(series);
+            this.chart.Text = "chart";
+
+
+            this.chart.ChartAreas.Add(chartArea);
+
+        }
+
+        public void updateChart(List<Meting> metingen)
+        {
+            chart.Series[0] = createSerie();
+            for (int i = 0; i < metingen.Count; i++)
+            {
+                chart.Series[0].Points.Add(getMetingType(metingen[i]));
+            }
+            chart.Update();
+        }
+
+        public Series createSerie()
+        {
+            Series serie = new Series();
+            serie.Name = "series";
+            serie.ChartType = ChartType;
+            serie.ChartArea = "chartArea";
+            serie.BorderWidth = 3;
+            return serie;
+        }
+
+        public int getMetingType(Meting meting)
+        {
+            switch (type)
+            {
+                case MetingType.HEARTBEAT:
+                    return meting.HeartBeat;
+                case MetingType.RPM:
+                    return meting.RPM;
+                case MetingType.SPEED:
+                    return (int)meting.Speed;
+                case MetingType.DISTANCE:
+                    return (int)meting.Distance;
+                case MetingType.POWER:
+                    return meting.Power;
+                case MetingType.ENERGY:
+                    return meting.Energy;
+                case MetingType.SECONDS:
+                    return meting.Seconds;
+                case MetingType.ACTUALPOWER:
+                    return meting.ActualPower;
+                default:
+                    return 0;
+            }
+        }
+
+        public enum MetingType
+        {
+            HEARTBEAT,
+            RPM,
+            SPEED,
+            DISTANCE,
+            POWER,
+            ENERGY,
+            SECONDS,
+            ACTUALPOWER
+        }
+    }
+}

+ 187 - 0
ErgometerIPR/ErgometerApplication/ClientApplicatie.Designer.cs

@@ -0,0 +1,187 @@
+using System.IO.Ports;
+using System.Windows.Forms;
+
+namespace ErgometerApplication
+{
+    partial class ClientApplicatie
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.components = new System.ComponentModel.Container();
+            this.updateTimer = new System.Windows.Forms.Timer(this.components);
+            this.panelClientContainer = new System.Windows.Forms.Panel();
+            this.panelDataViewLeft = new System.Windows.Forms.Panel();
+            this.panelGraphView = new ErgometerApplication.PanelGraphView();
+            this.panelClientChat = new ErgometerApplication.PanelClientChat();
+            this.panelLogin = new ErgometerApplication.PanelLogin(this);
+            this.panelTopBar = new System.Windows.Forms.Panel();
+            this.buttonLogOff = new System.Windows.Forms.Button();
+            this.labelUsername = new System.Windows.Forms.Label();
+            this.labelHallo = new System.Windows.Forms.Label();
+
+            this.heartBeat = new PanelClientData("Hartslag", 50, 220);
+            this.RPM = new PanelClientData("RPM", 0, 120);
+            this.speed = new PanelClientData("Snelheid", 0, 50);
+            this.distance = new PanelClientData("Afstand (km)", 0, 100);
+            this.power = new PanelClientData("Weerstand", 25, 400);
+            this.energy = new PanelClientData("Energie", 0, 200);
+            this.actualpower = new PanelClientData("Absolute Weerstand", 0, 400);
+            this.time = new PanelClientData("Tijd", 0, 400);
+
+            this.panelClientContainer.SuspendLayout();
+            this.panelTopBar.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // updateTimer
+            // 
+            this.updateTimer.Interval = 600;
+            this.updateTimer.Tick += new System.EventHandler(this.updateTimer_Tick);
+            // 
+            // panelClientContainer
+            // 
+            this.panelClientContainer.Controls.Add(this.panelGraphView);
+            this.panelClientContainer.Controls.Add(this.panelDataViewLeft);
+
+            this.panelClientContainer.Controls.Add(this.panelClientChat);
+            this.panelClientContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.panelClientContainer.Location = new System.Drawing.Point(0, 0);
+            this.panelClientContainer.Name = "panelClientContainer";
+            this.panelClientContainer.Size = new System.Drawing.Size(800, 600);
+            this.panelClientContainer.TabIndex = 0;
+            // 
+            // panelDataViewLeft
+            // 
+            this.panelDataViewLeft.Dock = System.Windows.Forms.DockStyle.Left;
+            this.panelDataViewLeft.Location = new System.Drawing.Point(0, 0);
+            this.panelDataViewLeft.Name = "panelDataViewLeft";
+            this.panelDataViewLeft.Size = new System.Drawing.Size(18, 600);
+            this.panelDataViewLeft.TabIndex = 3;
+            this.panelDataViewLeft.BackColor = System.Drawing.Color.Gray;
+            this.panelDataViewLeft.Controls.Add(heartBeat);
+            this.panelDataViewLeft.Controls.Add(RPM);
+            this.panelDataViewLeft.Controls.Add(speed);
+            this.panelDataViewLeft.Controls.Add(distance);
+            this.panelDataViewLeft.Controls.Add(power);
+            this.panelDataViewLeft.Controls.Add(energy);
+            this.panelDataViewLeft.Controls.Add(actualpower);
+            this.panelDataViewLeft.Controls.Add(time);
+
+            // 
+            // panelClientChat
+            // 
+            this.panelClientChat.BackColor = System.Drawing.SystemColors.ButtonHighlight;
+            this.panelClientChat.Dock = System.Windows.Forms.DockStyle.Right;
+            this.panelClientChat.Location = new System.Drawing.Point(400, 0);
+            this.panelClientChat.Name = "panelClientChat";
+            this.panelClientChat.Size = new System.Drawing.Size(400, 600);
+            this.panelClientChat.TabIndex = 2;
+            // 
+            // panelTopBar
+            // 
+            this.panelTopBar.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
+            this.panelTopBar.Controls.Add(this.buttonLogOff);
+            this.panelTopBar.Controls.Add(this.labelUsername);
+            this.panelTopBar.Controls.Add(this.labelHallo);
+            this.panelTopBar.Dock = System.Windows.Forms.DockStyle.Top;
+            this.panelTopBar.Location = new System.Drawing.Point(0, 0);
+            this.panelTopBar.Name = "panelTopBar";
+            this.panelTopBar.Size = new System.Drawing.Size(800, 30);
+            this.panelTopBar.TabIndex = 1;
+            this.panelTopBar.Visible = false;
+            // 
+            // buttonLogOff
+            // 
+            this.buttonLogOff.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.buttonLogOff.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+            this.buttonLogOff.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonLogOff.Font = new System.Drawing.Font("Segoe UI Light", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.buttonLogOff.Location = new System.Drawing.Point(722, 3);
+            this.buttonLogOff.Name = "buttonLogOff";
+            this.buttonLogOff.Size = new System.Drawing.Size(75, 23);
+            this.buttonLogOff.TabIndex = 1;
+            this.buttonLogOff.Text = "Afmelden";
+            this.buttonLogOff.UseVisualStyleBackColor = false;
+            this.buttonLogOff.Click += new System.EventHandler(this.buttonLogOff_Click);
+            // 
+            // labelUsername
+            // 
+            this.labelUsername.AutoSize = true;
+            this.labelUsername.Font = new System.Drawing.Font("Segoe UI Semilight", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelUsername.ForeColor = System.Drawing.Color.White;
+            this.labelUsername.Location = new System.Drawing.Point(49, 3);
+            this.labelUsername.Name = "labelUsername";
+            this.labelUsername.Size = new System.Drawing.Size(144, 21);
+            this.labelUsername.TabIndex = 0;
+            this.labelUsername.Text = "<Gebruikersnaam>";
+            // 
+            // labelHallo
+            // 
+            this.labelHallo.AutoSize = true;
+            this.labelHallo.Font = new System.Drawing.Font("Segoe UI Semilight", 12F);
+            this.labelHallo.ForeColor = System.Drawing.Color.White;
+            this.labelHallo.Location = new System.Drawing.Point(3, 3);
+            this.labelHallo.Name = "labelHallo";
+            this.labelHallo.Size = new System.Drawing.Size(54, 21);
+            this.labelHallo.TabIndex = 0;
+            this.labelHallo.Text = "Hallo, ";
+            // 
+            // ClientApplicatie
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(700, 500);
+            this.MinimumSize = new System.Drawing.Size(550, 550);
+            this.Controls.Add(this.panelTopBar);
+            this.Controls.Add(this.panelLogin);
+            this.Controls.Add(this.panelClientContainer);
+            this.Name = "ClientApplicatie";
+            this.Text = "Client Applicatie";
+            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
+            this.Resize += new System.EventHandler(this.ClientApplicatie_Resize);
+            this.panelClientContainer.ResumeLayout(false);
+            this.panelTopBar.ResumeLayout(false);
+            this.panelTopBar.PerformLayout();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+        private System.Windows.Forms.Timer updateTimer;
+        private System.Windows.Forms.Panel panelClientContainer;
+        private PanelClientChat panelClientChat;
+        private PanelGraphView panelGraphView;
+        private PanelLogin panelLogin;
+        private System.Windows.Forms.Panel panelDataViewLeft;
+        private System.Windows.Forms.Panel panelTopBar;
+        private System.Windows.Forms.Button buttonLogOff;
+        private System.Windows.Forms.Label labelUsername;
+        private System.Windows.Forms.Label labelHallo;
+        public PanelClientData heartBeat, RPM, speed, distance, power, energy, seconds, actualpower, time;
+    }
+
+    
+}

+ 150 - 0
ErgometerIPR/ErgometerApplication/ClientApplicatie.cs

@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.IO.Ports;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Newtonsoft.Json;
+using System.IO;
+using System.Net.Sockets;
+using System.Net;
+using System.Timers;
+using ErgometerLibrary;
+
+namespace ErgometerApplication
+{
+    public partial class ClientApplicatie : Form
+    {
+        public PanelClientChat chat;
+        private int count;
+
+        public ClientApplicatie()
+        {
+            InitializeComponent();
+            MainClient.Init(this);
+            count = 0;
+        }
+
+        private void updateTimer_Tick(object sender, EventArgs e)
+        {
+            if(MainClient.Doctor.Connected)
+            {
+                MainClient.ComPort.Write("ST");
+                string response = MainClient.ComPort.Read();
+                if (response != "err")
+                {
+                    Meting m = MainClient.SaveMeting(response);
+
+                    heartBeat.updateValue(m.HeartBeat);
+                    RPM.updateValue(m.RPM);
+                    speed.updateValue(m.Speed);
+                    distance.updateValue(m.Distance);
+                    power.updateValue(m.Power);
+                    energy.updateValue(m.Energy);
+                    actualpower.updateValue(m.ActualPower);
+                    time.updateValue(m.Seconds);
+
+                    if (count >= 10)
+                    {
+                        count = 0;
+                        panelGraphView.updateAllCharts(MainClient.Metingen);
+                    }
+
+                    count++;
+                }
+                else
+                {
+                    logout("De Ergometer is niet meer verbonden.", Color.Red);
+                }
+            }
+        }
+
+        public void validateLogin(string username, string password)
+        {
+            if (username.Length > 0)
+            {
+                if (password.Length == 0)
+                {
+                    panelLogin.lblVerification.Text = "Vul een wachtwoord in.";
+                    panelLogin.lblVerification.ForeColor = Color.Red;
+                    panelLogin.lblVerification.Visible = true;
+                }
+                if (password.Length > 0)
+                {
+                    string error = "";
+                    bool connect = MainClient.Connect(SerialPort.GetPortNames()[0], username, password, out error);
+
+                    if (connect)
+                    {
+                        panelClientContainer.BringToFront();
+                        chat = panelClientChat;
+                        this.labelUsername.Text = panelLogin.textBoxUsername.Text;
+                        panelTopBar.Visible = true;
+                        updateTimer.Start();
+                    }
+                    else
+                    {
+                        panelLogin.lblVerification.Text = error;
+                        panelLogin.lblVerification.ForeColor = Color.Red;
+                        panelLogin.lblVerification.Visible = true;
+                    }
+                        
+                }
+            }
+            else
+            {
+                panelLogin.lblVerification.Text = "Vul een gebruikersnaam in.";
+                panelLogin.lblVerification.ForeColor = Color.Red;
+                panelLogin.lblVerification.Visible = true;
+            }
+        }
+
+        private void ClientApplicatie_Resize(object sender, System.EventArgs e)
+        {
+            Control control = (Control)sender;
+            if (control.Size.Width < 980)
+            {
+                panelGraphView.Visible = false;
+                panelClientChat.Width = 400;
+                panelDataViewLeft.Dock = DockStyle.Fill;
+            }
+            if (control.Size.Width >= 980 && control.Size.Width < 1368)
+            {
+                panelGraphView.Visible = true;
+                panelDataViewLeft.Width = 250;
+                panelClientChat.Width = 400;
+                panelDataViewLeft.Dock = DockStyle.Left;
+            }
+            if (control.Size.Width >= 1368)
+            {
+                panelGraphView.Visible = true;
+                panelDataViewLeft.Width = 400;
+                panelDataViewLeft.Dock = DockStyle.Left;
+            }
+
+        }
+
+        private void buttonLogOff_Click(object sender, EventArgs e)
+        {
+            logout("U bent uitgelogd.", Color.Blue);
+        }
+
+        private void logout(string message, System.Drawing.Color cl)
+        {
+            panelLogin.BringToFront();
+            panelTopBar.Visible = false;
+            panelLogin.lblVerification.Text = message;
+            panelLogin.lblVerification.ForeColor = cl;
+            panelLogin.lblVerification.Visible = true;
+            panelLogin.textBoxUsername.Text = "";
+            panelLogin.textBoxPassword.Text = "";
+            MainClient.Disconnect();
+            updateTimer.Stop();
+        }
+    }
+}

+ 126 - 0
ErgometerIPR/ErgometerApplication/ClientApplicatie.resx

@@ -0,0 +1,126 @@
+<?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>
+  <metadata name="updateTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>25</value>
+  </metadata>
+</root>

+ 127 - 0
ErgometerIPR/ErgometerApplication/ErgometerApplication.csproj

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{1191E100-AA1B-4F41-85E2-EC2BE8ED39FD}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ErgometerApplication</RootNamespace>
+    <AssemblyName>ErgometerApplication</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ErgometerLibrary, Version=1.0.0.2, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\ErgometerLibrary\ErgometerLibrary\ErgometerLibrary\bin\Debug\ErgometerLibrary.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Windows.Forms.DataVisualization" />
+    <Reference Include="System.Windows.Forms.DataVisualization.Design" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ChartPanel.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="MainClient.cs" />
+    <Compile Include="PanelClientData.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="PanelClientChat.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="PanelClientContainer.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="PanelClientDataView.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="PanelLogin.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="ClientApplicatie.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="ClientApplicatie.Designer.cs">
+      <DependentUpon>ClientApplicatie.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="ClientApplicatie.resx">
+      <DependentUpon>ClientApplicatie.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+      <DesignTime>True</DesignTime>
+    </Compile>
+    <None Include="packages.config" />
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <WCFMetadata Include="Service References\" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\flatbike.png" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 284 - 0
ErgometerIPR/ErgometerApplication/MainClient.cs

@@ -0,0 +1,284 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ErgometerApplication
+{
+    class MainClient
+    {
+
+        public static ComPort ComPort { get; }
+        public static TcpClient Doctor { get; set; }
+        public static List<Meting> Metingen { get; }
+        public static List<ChatMessage> Chat { get; }
+
+        public static string Name;
+
+        public static int Session;
+        public static bool Loggedin;
+
+        private static Thread t;
+        private static bool running;
+
+        public static string HOST = "127.0.0.1";
+        public static int PORT = 8888;
+
+        public static ClientApplicatie Client;
+
+        static MainClient()
+        {
+            ComPort = new ComPort();
+            Doctor = new TcpClient();
+            Metingen = new List<Meting>();
+            Chat = new List<ChatMessage>();
+
+            Name = "Unknown";
+            Session = 0;
+            Loggedin = false;
+        }
+
+        public static void Init(ClientApplicatie client)
+        {
+            Client = client;
+        }
+
+        public static bool Connect(string comport, string name, string password, out string error)
+        {
+            error = "Succes";
+
+            if (!ComPort.IsOpen())
+            {
+                if (ComPort.Connect(comport))
+                {
+                    ComPort.Write("RS");
+                    string temp = ComPort.Read();
+                    if (temp == "err")
+                    {
+                        ComPort.Disconnect();
+                        error = "De Ergometer is niet verbonden";
+                        return false;
+                    }
+                    Thread.Sleep(200);
+                    ComPort.Write("CM");
+                    ComPort.Read();
+                    Thread.Sleep(200);
+
+                    ComPort.Write("ST");
+                    string response = ComPort.Read();
+
+                    SaveMeting(response);
+                }
+                else
+                {
+                    error = "De ergometer is niet verbonden";
+                    return false;
+                }
+            }
+
+            if (Doctor == null || !Doctor.Connected)
+            {
+                if (Doctor == null)
+                    Doctor = new TcpClient();
+
+                try
+                {
+                    Doctor.Connect(HOST, PORT);
+                }
+                catch (Exception e)
+                {
+                    error = "Server is niet online.";
+                    return false;
+                }
+
+                Name = name;
+
+                NetCommand net = NetHelper.ReadNetCommand(Doctor);
+                if (net.Type == NetCommand.CommandType.SESSION)
+                    Session = net.Session;
+                else
+                    throw new Exception("Session not assigned");
+
+                running = true;
+
+                t = new Thread(run);
+                t.IsBackground = true;
+                t.Start();
+            }
+
+            if(! Loggedin)
+            {
+                NetCommand command = new NetCommand(name, false, password, Session);
+                NetHelper.SendNetCommand(Doctor, command);
+
+                NetCommand response = NetHelper.ReadNetCommand(Doctor);
+                if (response.Type == NetCommand.CommandType.RESPONSE && response.Response == NetCommand.ResponseType.LOGINWRONG)
+                {
+                    Loggedin = false;
+                    error = "De inloggegevens zijn onjuist.";
+                    return false;
+                }
+
+                Loggedin = true;
+            }
+
+            return true;
+        }
+
+        public static void Disconnect()
+        {
+            if (ComPort.IsOpen())
+            {
+                if (ComPort.Disconnect())
+                {
+                    
+                }
+                else
+                    throw new Exception("Comport was unable to disconnect");
+            }
+
+            if (Doctor != null && Doctor.Connected)
+            {
+                NetHelper.SendNetCommand(Doctor, new NetCommand(NetCommand.CommandType.LOGOUT, Session));
+                Loggedin = false;
+                running = false;
+                Doctor.Close();
+                Doctor = null;
+            }
+        }
+
+        public static Meting SaveMeting(string meting)
+        {
+            Meting m = null;
+
+            try
+            {
+                 m = Meting.Parse(meting);
+            }
+            catch(Exception e)
+            {
+                return new Meting(0, 0, 0, 0, 0, 0, 0, 0, 0);
+            }
+            
+
+            Metingen.Add(m);
+            if (Doctor.Connected)
+            {
+                NetHelper.SendNetCommand(Doctor, new NetCommand(m, Session));
+            }
+
+            return m;
+        }
+
+        public static void run()
+        {
+            while(running)
+            {
+                if(Doctor.Connected && Doctor.Available > 0)
+                {
+                    NetCommand command = NetHelper.ReadNetCommand(Doctor);
+                    ParseCommand(command);
+                }
+            }
+
+            if(Doctor != null)
+                Doctor.Close();
+        }
+
+        private static void ParseCommand(NetCommand command)
+        {
+            switch(command.Type)
+            {
+                case NetCommand.CommandType.VALUESET:
+                    ParseValueSet(command);
+                    break;
+                case NetCommand.CommandType.CHAT:
+                    ChatMessage chat = new ChatMessage(command.DisplayName, command.ChatMessage, true);
+                    Chat.Add(chat);
+                    Client.chat.Invoke(Client.chat.passChatMessage, new Object[] { chat });
+                    break;
+                case NetCommand.CommandType.RESPONSE:
+                    Console.WriteLine(command.Response.ToString());
+                    break;
+                case NetCommand.CommandType.SESSION:
+                    Session = command.Session;
+                    break;
+                case NetCommand.CommandType.ERROR:
+                    Console.WriteLine("An error occured, ignoring");
+                    break;
+                default:
+                    throw new FormatException("Error in Netcommand: Received command not recognized");
+            }
+        }
+
+        public static void SendNetCommand(NetCommand command)
+        {
+            if(! NetHelper.SendNetCommand(Doctor, command))
+            {
+                Disconnect();
+            }
+        }
+
+        private static void ParseValueSet(NetCommand command)
+        {
+            switch(command.Value)
+            {
+                case NetCommand.ValueType.DISTANCE:
+                    ComPort.Write("RS");
+                    ComPort.Read();
+                    Thread.Sleep(200);
+                    ComPort.Write("CM");
+                    ComPort.Read();
+                    Thread.Sleep(700);
+                    ComPort.Write("PD " + command.SetValue.ToString());
+                    ComPort.Read();
+                    break;
+                case NetCommand.ValueType.ENERGY:
+                    ComPort.Write("RS");
+                    ComPort.Read();
+                    Thread.Sleep(200);
+                    ComPort.Write("CM");
+                    ComPort.Read();
+                    Thread.Sleep(700);
+                    ComPort.Write("PE " + command.SetValue.ToString());
+                    ComPort.Read();
+                    break;
+                case NetCommand.ValueType.POWER:
+                    ComPort.Write("CM");
+                    ComPort.Read();
+                    Thread.Sleep(200);
+                    ComPort.Write("PW " + command.SetValue.ToString());
+                    ComPort.Read();
+                    break;
+                case NetCommand.ValueType.TIME:
+                    ComPort.Write("RS");
+                    ComPort.Read();
+                    Thread.Sleep(200);
+                    ComPort.Write("CM");
+                    ComPort.Read();
+                    Thread.Sleep(700);
+                    string temp = (command.SetValue / 60) + "";
+                    if(temp.Length < 2)
+                    {
+                        temp = "0" + temp;
+                    }
+                    string temp2 = (command.SetValue % 60) + "";
+                    if (temp2.Length < 2)
+                    {
+                        temp2 = "0" + temp2;
+                    }
+
+                    string time = temp + temp2;
+                    ComPort.Write("PT " + time);
+                    ComPort.Read();
+                    break;
+                default:
+                    throw new FormatException("Error in NetCommand: ValueSet is not recognized");
+            }
+        }
+    }
+}

+ 202 - 0
ErgometerIPR/ErgometerApplication/PanelClientChat.cs

@@ -0,0 +1,202 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using ErgometerLibrary;
+using ErgometerLibrary.Chat;
+
+namespace ErgometerApplication
+{
+   public class PanelClientChat : Panel
+    {
+
+
+        private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
+        private System.Windows.Forms.Panel panel2;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Panel panel1;
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.RichTextBox richTextBox1;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.Panel panel3;
+        private System.Windows.Forms.Label connectionLabel;
+
+        public PanelClientChat() : base()
+        {
+            this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
+            this.panel2 = new System.Windows.Forms.Panel();
+            this.connectionLabel = new System.Windows.Forms.Label();
+            this.label2 = new System.Windows.Forms.Label();
+            this.label1 = new System.Windows.Forms.Label();
+            this.panel1 = new System.Windows.Forms.Panel();
+            this.button1 = new System.Windows.Forms.Button();
+            this.richTextBox1 = new System.Windows.Forms.RichTextBox();
+
+            this.panel3 = new System.Windows.Forms.Panel();
+            // 
+            // flowLayoutPanel1
+            // 
+            this.flowLayoutPanel1.AutoSize = true;
+            this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
+            this.flowLayoutPanel1.Controls.Add(this.panel2);
+            this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
+            this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
+            this.flowLayoutPanel1.Name = "flowLayoutPanel1";
+            this.flowLayoutPanel1.Padding = new System.Windows.Forms.Padding(3);
+            this.flowLayoutPanel1.Size = new System.Drawing.Size(390, 36);
+            this.flowLayoutPanel1.TabIndex = 0;
+            this.flowLayoutPanel1.WrapContents = false;
+            this.flowLayoutPanel1.SizeChanged += new System.EventHandler(this.FlowLayoutPanel1_SizeChanged);
+            // 
+            // panel2
+            // 
+            this.panel2.Controls.Add(this.connectionLabel);
+            this.panel2.Dock = System.Windows.Forms.DockStyle.Left;
+            this.panel2.Location = new System.Drawing.Point(6, 6);
+            this.panel2.Name = "panel2";
+            this.panel2.Size = new System.Drawing.Size(385, 24);
+            this.panel2.TabIndex = 0;
+            // 
+            // connectionLabel
+            // 
+            this.connectionLabel.AutoSize = true;
+            this.connectionLabel.Font = new System.Drawing.Font("Segoe UI Semibold", 8F, System.Drawing.FontStyle.Bold);
+            this.connectionLabel.Location = new System.Drawing.Point(4, 4);
+            this.connectionLabel.Name = "connectionLabel";
+            this.connectionLabel.Size = new System.Drawing.Size(112, 13);
+            this.connectionLabel.TabIndex = 0;
+            this.connectionLabel.Text = "Now connected with: Doctor";
+            // 
+            // label2
+            // 
+            this.label2.Location = new System.Drawing.Point(0, 0);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(100, 23);
+            this.label2.TabIndex = 0;
+            // 
+            // label1
+            // 
+            this.label1.Location = new System.Drawing.Point(0, 0);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(100, 23);
+            this.label1.TabIndex = 0;
+            // 
+            // panel1
+            // 
+            this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
+            this.panel1.Controls.Add(this.button1);
+            this.panel1.Controls.Add(this.richTextBox1);
+            this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.panel1.Name = "panel1";
+            this.panel1.Size = new System.Drawing.Size(400, 100);
+            this.panel1.TabIndex = 1;
+            // 
+            // button1
+            // 
+            this.button1.BackColor = System.Drawing.Color.White;
+            this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.button1.Location = new System.Drawing.Point(310, 4);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(85, 90);
+            this.button1.TabIndex = 1;
+            this.button1.Text = "Send";
+            this.button1.UseVisualStyleBackColor = false;
+            this.button1.Click += new System.EventHandler(this.button1_Click);
+            // 
+            // richTextBox1
+            // 
+            this.richTextBox1.BackColor = System.Drawing.Color.White;
+            this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+            this.richTextBox1.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.richTextBox1.Location = new System.Drawing.Point(4, 4);
+            this.richTextBox1.MaxLength = 250;
+            this.richTextBox1.Name = "richTextBox1";
+            this.richTextBox1.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
+            this.richTextBox1.Size = new System.Drawing.Size(300, 90);
+            this.richTextBox1.TabIndex = 0;
+            this.richTextBox1.Text = "";
+            this.richTextBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBox_KeyDown);
+            // 
+            // panel3
+            // 
+            this.panel3.AutoScroll = true;
+            this.panel3.HorizontalScroll.Enabled = false;
+            this.panel3.HorizontalScroll.Visible = false;
+            this.panel3.BackColor = System.Drawing.Color.White;
+            this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.panel3.Controls.Add(this.flowLayoutPanel1);
+            this.panel3.Location = new System.Drawing.Point(0, 0);
+
+            this.panel3.Name = "panel3";
+            this.panel3.TabIndex = 1;
+            // 
+            // container
+            // 
+            this.Controls.Add(this.panel3);
+            this.Controls.Add(this.panel1);
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "container";
+            this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel3_MouseWheel);
+
+            passChatMessage = new ChatDelegate(this.AddChatItem);
+        }
+
+        private void button1_Click(object sender, EventArgs e)
+        {
+            if (richTextBox1.TextLength > 1)
+            {
+                AddChatItem(new ChatMessage("Anon", richTextBox1.Text, false));
+                MainClient.SendNetCommand(new NetCommand(richTextBox1.Text, false, MainClient.Session));
+                richTextBox1.ResetText();
+            }
+        }
+
+       public void AddChatItem(ChatMessage chat)
+       {
+            flowLayoutPanel1.Controls.Add(new ChatItem(chat));
+        }
+
+        private void panel3_MouseWheel(object sender, MouseEventArgs e)
+        {
+            panel3.Focus();
+        }
+
+        private void FlowLayoutPanel1_SizeChanged(object sender, System.EventArgs e)
+        {
+            if (flowLayoutPanel1.Size.Height > panel3.Size.Height)
+            {
+                panel2.Width = 375;
+                flowLayoutPanel1.Width = 380;
+                panel3.VerticalScroll.Value = panel3.VerticalScroll.Maximum;
+            }
+        }
+
+        private bool textBoxIsEmpty()
+        {
+            string[] text = richTextBox1.Text.Split();
+            foreach(string s in text)
+            {
+                if(s != " ")
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private void TextBox_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.KeyCode == Keys.Enter)
+            {
+                button1_Click(this, new EventArgs());
+                e.Handled = true;
+            }
+        }
+
+        public delegate void ChatDelegate(ChatMessage chat);
+        public ChatDelegate passChatMessage;
+    }
+}

+ 35 - 0
ErgometerIPR/ErgometerApplication/PanelClientContainer.cs

@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerApplication
+{
+    public class PanelClientContainer:Panel
+    {
+
+        public PanelClientChat panelClientChat;
+        public PanelGraphView panelGraphView;
+
+        public PanelClientContainer() : base()
+        {
+            this.panelClientChat = new PanelClientChat();
+            this.panelGraphView = new PanelGraphView();
+
+            // 
+            // panelClientContainer
+            // 
+            this.Controls.Add(this.panelGraphView);
+            this.Controls.Add(this.panelClientChat);
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "panelClientContainer";
+            this.Size = new System.Drawing.Size(800, 600);
+            this.TabIndex = 0;
+
+        }
+
+    }
+}

+ 115 - 0
ErgometerIPR/ErgometerApplication/PanelClientData.cs

@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerApplication
+{
+    public class PanelClientData : Panel
+    {
+        public Label labelMetingCurrentValue;
+        public ProgressBar progressBarMeting;
+        public Label metingName;
+
+        private int min;
+        private int max;
+        private string name;
+
+        public PanelClientData(string name, int min, int max) : base()
+        {
+            this.min = min;
+            this.max = max;
+            this.name = name;
+
+            this.metingName = new System.Windows.Forms.Label();
+            this.progressBarMeting = new System.Windows.Forms.ProgressBar();
+            this.labelMetingCurrentValue = new System.Windows.Forms.Label();
+            // 
+            // initialize panel
+            // 
+            this.BackColor = System.Drawing.SystemColors.ControlLightLight;
+            this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+            this.Controls.Add(this.labelMetingCurrentValue);
+            if(name != "Tijd")
+                this.Controls.Add(this.progressBarMeting);
+            this.Controls.Add(this.metingName);
+            this.Dock = System.Windows.Forms.DockStyle.Top;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "panel1";
+            this.Size = new System.Drawing.Size(284, 80);
+            // 
+            // metingName
+            // 
+            this.metingName.AutoSize = true;
+            this.metingName.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.metingName.Location = new System.Drawing.Point(12, 9);
+            this.metingName.Name = "metingName";
+            this.metingName.Size = new System.Drawing.Size(105, 21);
+            this.metingName.TabIndex = 0;
+            this.metingName.Text = name;
+            // 
+            // progressBarMeting
+            // 
+            this.progressBarMeting.Location = new System.Drawing.Point(16, 39);
+            this.progressBarMeting.Name = "progressBarMeting";
+            this.progressBarMeting.Size = new System.Drawing.Size(183, 23);
+            this.progressBarMeting.TabIndex = 1;
+            this.progressBarMeting.Value = 0;
+            // 
+            // labelMetingCurrentValue
+            // 
+            this.labelMetingCurrentValue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.labelMetingCurrentValue.AutoSize = true;
+            this.labelMetingCurrentValue.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelMetingCurrentValue.Location = new System.Drawing.Point(215, 32);
+            this.labelMetingCurrentValue.Name = "labelMetingCurrentValue";
+            this.labelMetingCurrentValue.Size = new System.Drawing.Size(57, 32);
+            this.labelMetingCurrentValue.TabIndex = 2;
+            this.labelMetingCurrentValue.Text = "0";
+        }
+
+        public void setText(string text)
+        {
+            this.metingName.Text = text;
+        }
+
+        public void updateValue(int value)
+        {
+            if (name == "Tijd")
+            {
+                this.labelMetingCurrentValue.Text = (value / 60) + ":" + (value % 60);
+            }
+            else
+            {
+                this.labelMetingCurrentValue.Text = value.ToString();
+                this.progressBarMeting.Value = ValueToPercentage(value);
+            }
+            
+        }
+
+        public void updateValue(double value)
+        {
+            this.labelMetingCurrentValue.Text = value.ToString();
+            this.progressBarMeting.Value = ValueToPercentage((int)value);
+        }
+
+        public void updateValue(decimal value)
+        { 
+            this.labelMetingCurrentValue.Text = value.ToString();
+            this.progressBarMeting.Value = ValueToPercentage((int)value);
+        }
+
+        private int ValueToPercentage(int value)
+        {
+            if (value < min)
+                return 0;
+
+            if (value > max)
+                return 100;
+
+            return ((value - min) * 100) / (max - min);
+        }
+    }
+}

+ 71 - 0
ErgometerIPR/ErgometerApplication/PanelClientDataView.cs

@@ -0,0 +1,71 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+
+namespace ErgometerApplication
+{
+    public class PanelGraphView : Panel
+    {
+
+        private List<ChartPanel> charts;
+        private FlowLayoutPanel flowlayout;
+
+        public PanelGraphView() : base()
+        {
+            createCharts();
+
+            flowlayout = new FlowLayoutPanel();
+
+            flowlayout.Dock = DockStyle.Fill;
+            flowlayout.BackColor = System.Drawing.Color.DarkGray;
+            flowlayout.Location = new System.Drawing.Point(0, 0);
+            flowlayout.Name = "flowlayout";
+            flowlayout.Padding = new Padding(15);
+            flowlayout.AutoScroll = true;
+            foreach (ChartPanel chart in charts)
+            {
+                flowlayout.Controls.Add(chart);
+            }
+
+            List<Meting> metingen = new List<Meting>();
+            metingen.Add(new Meting(0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+            updateAllCharts(metingen);
+            // 
+            // panelGraphView
+            // 
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Controls.Add(flowlayout);
+
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "panelGraphView";
+            this.Size = new System.Drawing.Size(400, 600);
+            this.TabIndex = 1;
+        }
+
+        public void createCharts()
+        {
+            charts = new List<ChartPanel>();
+            charts.Add(new ChartPanel(ChartPanel.MetingType.HEARTBEAT, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.RPM, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.SPEED, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.DISTANCE, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.ENERGY, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.POWER, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.ACTUALPOWER, SeriesChartType.Line));
+        }
+
+        public void updateAllCharts(List<Meting> metingen)
+        {
+            foreach (ChartPanel chart in charts)
+            {
+                chart.updateChart(metingen);
+            }
+        }
+    }
+}

+ 158 - 0
ErgometerIPR/ErgometerApplication/PanelLogin.cs

@@ -0,0 +1,158 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerApplication
+{
+    public class PanelLogin:Panel
+    {
+        private System.Windows.Forms.Label lblUsername;
+        private System.Windows.Forms.Label lblPassword;
+        public System.Windows.Forms.Label lblVerification;
+        public System.Windows.Forms.TextBox textBoxPassword;
+        public System.Windows.Forms.TextBox textBoxUsername;
+        public System.Windows.Forms.Button buttonLogin;
+        private System.Windows.Forms.Label lblLoginTitle;
+        private System.Windows.Forms.PictureBox pictureBoxBike;
+        private ClientApplicatie app;
+
+        public PanelLogin(ClientApplicatie app):base()
+        {
+            this.app = app;
+            this.pictureBoxBike = new System.Windows.Forms.PictureBox();
+            this.buttonLogin = new System.Windows.Forms.Button();
+            this.textBoxPassword = new System.Windows.Forms.TextBox();
+            this.textBoxUsername = new System.Windows.Forms.TextBox();
+            this.lblLoginTitle = new System.Windows.Forms.Label();
+            this.lblUsername = new System.Windows.Forms.Label();
+            this.lblPassword = new System.Windows.Forms.Label();
+            this.lblVerification = new System.Windows.Forms.Label();
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBike)).BeginInit();
+            // 
+            // panelLogin
+            // 
+            this.Controls.Add(this.pictureBoxBike);
+            this.Controls.Add(this.buttonLogin);
+            this.Controls.Add(this.textBoxUsername);
+            this.Controls.Add(this.textBoxPassword);
+            this.Controls.Add(this.lblLoginTitle);
+            this.Controls.Add(this.lblUsername);
+            this.Controls.Add(this.lblPassword);
+            this.Controls.Add(this.lblVerification);
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "panelLogin";
+            this.Size = new System.Drawing.Size(800, 600);
+            this.TabIndex = 0;
+            // 
+            // pictureBoxBike
+            // 
+            this.pictureBoxBike.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.pictureBoxBike.Image = global::ErgometerApplication.Properties.Resources.flatbike;
+            this.pictureBoxBike.Location = new System.Drawing.Point(137, 131);
+            this.pictureBoxBike.Name = "pictureBoxBike";
+            this.pictureBoxBike.Size = new System.Drawing.Size(250, 250);
+            this.pictureBoxBike.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+            this.pictureBoxBike.TabIndex = 4;
+            this.pictureBoxBike.TabStop = false;
+            // 
+            // buttonLogin
+            // 
+            this.buttonLogin.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.buttonLogin.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonLogin.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.buttonLogin.Location = new System.Drawing.Point(468, 338);
+            this.buttonLogin.Name = "buttonLogin";
+            this.buttonLogin.Size = new System.Drawing.Size(168, 31);
+            this.buttonLogin.TabIndex = 3;
+            this.buttonLogin.Text = "Aanmelden";
+            this.buttonLogin.UseVisualStyleBackColor = true;
+            this.buttonLogin.Click += new System.EventHandler(this.buttonLogin_Click);
+            // 
+            // textBoxPassword
+            // 
+            this.textBoxPassword.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.textBoxPassword.Location = new System.Drawing.Point(467, 287);
+            this.textBoxPassword.MaxLength = 16;
+            this.textBoxPassword.Name = "textBoxPassword";
+            this.textBoxPassword.PasswordChar = '*';
+            this.textBoxPassword.Size = new System.Drawing.Size(167, 20);
+            this.textBoxPassword.TabIndex = 2;
+            this.textBoxPassword.KeyDown += TextBoxPassword_KeyDown;
+            // 
+            // textBoxUsername
+            // 
+            this.textBoxUsername.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.textBoxUsername.Location = new System.Drawing.Point(468, 231);
+            this.textBoxUsername.MaxLength = 16;
+            this.textBoxUsername.Name = "textBoxUsername";
+            this.textBoxUsername.Size = new System.Drawing.Size(167, 20);
+            this.textBoxUsername.TabIndex = 2;
+            this.textBoxUsername.KeyDown += TextBoxPassword_KeyDown;
+            // 
+            // lblLoginTitle
+            // 
+            this.lblLoginTitle.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.lblLoginTitle.AutoSize = true;
+            this.lblLoginTitle.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.lblLoginTitle.Location = new System.Drawing.Point(461, 141);
+            this.lblLoginTitle.Name = "lblLoginTitle";
+            this.lblLoginTitle.Size = new System.Drawing.Size(87, 32);
+            this.lblLoginTitle.TabIndex = 1;
+            this.lblLoginTitle.Text = "Log In";
+            // 
+            // lblVerification
+            // 
+            this.lblVerification.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.lblVerification.AutoSize = true;
+            this.lblVerification.Font = new System.Drawing.Font("Segoe UI Light", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.lblVerification.Location = new System.Drawing.Point(140, 415);
+            this.lblVerification.Name = "lvlVerification";
+            this.lblVerification.Size = new System.Drawing.Size(200, 21);
+            this.lblVerification.TabIndex = 1;
+            this.lblVerification.Text = "Verification label";
+            this.lblVerification.Visible = false;
+            // 
+            // lblUsername
+            // 
+            this.lblUsername.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.lblUsername.AutoSize = true;
+            this.lblUsername.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.lblUsername.Location = new System.Drawing.Point(464, 207);
+            this.lblUsername.Name = "lblUsername";
+            this.lblUsername.Size = new System.Drawing.Size(128, 21);
+            this.lblUsername.TabIndex = 1;
+            this.lblUsername.Text = "Gebruikersnaam";
+            // 
+            // lblPassword
+            // 
+            this.lblPassword.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.lblPassword.AutoSize = true;
+            this.lblPassword.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold);
+            this.lblPassword.Location = new System.Drawing.Point(464, 263);
+            this.lblPassword.Name = "lblPassword";
+            this.lblPassword.Size = new System.Drawing.Size(103, 21);
+            this.lblPassword.TabIndex = 0;
+            this.lblPassword.Text = "Wachtwoord";
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBoxBike)).EndInit();
+        }
+
+        private void TextBoxPassword_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.KeyCode == Keys.Enter)
+            {
+                buttonLogin_Click(this, new EventArgs());
+            }
+        }
+
+        public void buttonLogin_Click(object sender, EventArgs e)
+        {
+            string username = textBoxUsername.Text;
+            string password = textBoxPassword.Text;
+            this.app.validateLogin(username,password);
+        }
+    }
+}

+ 23 - 0
ErgometerIPR/ErgometerApplication/Program.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.IO.Ports;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerApplication
+{
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new ClientApplicatie());
+        }
+    }
+}

+ 36 - 0
ErgometerIPR/ErgometerApplication/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ErgometerApplication")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ErgometerApplication")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1191e100-aa1b-4f41-85e2-ec2be8ed39fd")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 73 - 0
ErgometerIPR/ErgometerApplication/Properties/Resources.Designer.cs

@@ -0,0 +1,73 @@
+//------------------------------------------------------------------------------
+// <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 ErgometerApplication.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", "4.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("ErgometerApplication.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.Drawing.Bitmap.
+        /// </summary>
+        internal static System.Drawing.Bitmap flatbike {
+            get {
+                object obj = ResourceManager.GetObject("flatbike", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+    }
+}

+ 124 - 0
ErgometerIPR/ErgometerApplication/Properties/Resources.resx

@@ -0,0 +1,124 @@
+<?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="flatbike" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\flatbike.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+</root>

+ 30 - 0
ErgometerIPR/ErgometerApplication/Properties/Settings.Designer.cs

@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <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 ErgometerApplication.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+    {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default
+        {
+            get
+            {
+                return defaultInstance;
+            }
+        }
+    }
+}

+ 7 - 0
ErgometerIPR/ErgometerApplication/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

BIN
ErgometerIPR/ErgometerApplication/Resources/flatbike.png


+ 4 - 0
ErgometerIPR/ErgometerApplication/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net452" />
+</packages>

+ 6 - 0
ErgometerIPR/ErgometerDoctorApplication/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
+    </startup>
+</configuration>

+ 105 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/ChartPanel.cs

@@ -0,0 +1,105 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+
+namespace ErgometerDoctorApplication
+{
+    public class ChartPanel : Panel
+    {
+        private Chart chart;
+        private MetingType type;
+        private ChartArea chartArea;
+        private Series series;
+        private SeriesChartType ChartType;
+
+        public ChartPanel(MetingType type, SeriesChartType charttype) : base()
+        {
+            this.type = type;
+            this.ChartType = charttype;
+
+            this.chart = new Chart();
+            this.chartArea = new ChartArea();
+            this.chart.Titles.Add(new Title(type.ToString()));
+
+            this.Location = new System.Drawing.Point(0, 0);
+
+            this.Size = new System.Drawing.Size(400, 250);
+            this.Controls.Add(chart);
+
+            this.series = createSerie();
+            this.chartArea.Name = "chartArea";
+
+            this.chart.Size = new System.Drawing.Size(400, 250);
+
+            this.chart.Dock = DockStyle.Fill;
+            this.chart.Series.Add(series);
+            this.chart.Text = "chart";
+
+
+            this.chart.ChartAreas.Add(chartArea);
+
+        }
+
+        public void updateChart(List<Meting> metingen)
+        {
+            chart.Series[0] = createSerie();
+            for (int i = 0; i < metingen.Count; i++)
+            {
+                chart.Series[0].Points.Add(getMetingType(metingen[i]));
+            }
+            chart.Update();
+        }
+
+        public Series createSerie()
+        {
+            Series serie = new Series();
+            serie.Name = "series";
+            serie.ChartType = ChartType;
+            serie.ChartArea = "chartArea";
+            serie.BorderWidth = 3;
+            return serie;
+        }
+
+        public int getMetingType(Meting meting)
+        {
+            switch (type)
+            {
+                case MetingType.HEARTBEAT:
+                    return meting.HeartBeat;
+                case MetingType.RPM:
+                    return meting.RPM;
+                case MetingType.SPEED:
+                    return (int)meting.Speed;
+                case MetingType.DISTANCE:
+                    return (int)meting.Distance;
+                case MetingType.POWER:
+                    return meting.Power;
+                case MetingType.ENERGY:
+                    return meting.Energy;
+                case MetingType.SECONDS:
+                    return meting.Seconds;
+                case MetingType.ACTUALPOWER:
+                    return meting.ActualPower;
+                default:
+                    return 0;
+            }
+        }
+
+        public enum MetingType
+        {
+            HEARTBEAT,
+            RPM,
+            SPEED,
+            DISTANCE,
+            POWER,
+            ENERGY,
+            SECONDS,
+            ACTUALPOWER
+        }
+    }
+}

+ 78 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/ClientThread.cs

@@ -0,0 +1,78 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public class ClientThread
+    {
+        public int Session { get; }
+        public string Name { get; }
+
+        public bool IsOldData { get; }
+
+        private SessionWindow window;
+
+        public List<Meting> Metingen { get; set; }
+        public List<ChatMessage> Chat { get; }
+
+        public ClientThread(string name, int session, bool old)
+        {
+            Name = name;
+            Session = session;
+            IsOldData = old;
+
+            window = new SessionWindow(Name, old, Session, this);
+            window.FormClosed += Window_FormClosed;
+
+            Metingen = new List<Meting>();
+            Chat = new List<ChatMessage>();
+        }
+
+        private void Window_FormClosed(object sender, FormClosedEventArgs e)
+        {
+            MainClient.RemoveActiveClient(this);
+        }
+
+        public void HandleCommand(NetCommand command)
+        {
+            switch (command.Type)
+            {
+                case NetCommand.CommandType.DATA:
+                    lock (Metingen)
+                    {
+                        Metingen.Add(command.Meting);
+                    }
+                    window.Invoke(window.updateMetingen, new Object[] { command.Meting });
+                    break;
+                case NetCommand.CommandType.CHAT:
+                    ChatMessage chat = new ChatMessage(command.DisplayName, command.ChatMessage, command.IsDoctor);
+                    Chat.Add(chat);
+                    window.panelClientChat.Invoke(window.panelClientChat.passChatMessage, new Object[] { chat });
+                    break;
+            }
+        }
+
+        public void run()
+        {
+            Application.Run(window);
+        }
+
+        public void stop()
+        {
+            window.Close();
+            MainClient.RemoveActiveClient(this);
+        }
+
+        private void sendCommand(NetCommand command)
+        {
+            if(! IsOldData)
+                MainClient.SendNetCommand(command);
+        }
+        
+    }
+}

+ 206 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/PanelClientChat.cs

@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using ErgometerLibrary;
+using ErgometerLibrary.Chat;
+
+namespace ErgometerDoctorApplication
+{
+    public class PanelClientChat : Panel
+    {
+
+
+        private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
+        private System.Windows.Forms.Panel panel2;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Panel panel1;
+        public System.Windows.Forms.Button button1;
+        public System.Windows.Forms.RichTextBox richTextBox1;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.Panel panel3;
+        private System.Windows.Forms.Label connectionLabel;
+
+        private int Session { get; }
+
+        public PanelClientChat(int session, string name) : base()
+        {
+            this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
+            this.panel2 = new System.Windows.Forms.Panel();
+            this.connectionLabel = new System.Windows.Forms.Label();
+            this.label2 = new System.Windows.Forms.Label();
+            this.label1 = new System.Windows.Forms.Label();
+            this.panel1 = new System.Windows.Forms.Panel();
+            this.button1 = new System.Windows.Forms.Button();
+            this.richTextBox1 = new System.Windows.Forms.RichTextBox();
+
+            Session = session;
+
+            this.panel3 = new System.Windows.Forms.Panel();
+            // 
+            // flowLayoutPanel1
+            // 
+            this.flowLayoutPanel1.AutoSize = true;
+            this.flowLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
+            this.flowLayoutPanel1.Controls.Add(this.panel2);
+            this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
+            this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
+            this.flowLayoutPanel1.Name = "flowLayoutPanel1";
+            this.flowLayoutPanel1.Padding = new System.Windows.Forms.Padding(3);
+            this.flowLayoutPanel1.Size = new System.Drawing.Size(390, 36);
+            this.flowLayoutPanel1.TabIndex = 0;
+            this.flowLayoutPanel1.WrapContents = false;
+            this.flowLayoutPanel1.SizeChanged += new System.EventHandler(this.FlowLayoutPanel1_SizeChanged);
+            // 
+            // panel2
+            // 
+            this.panel2.Controls.Add(this.connectionLabel);
+            this.panel2.Dock = System.Windows.Forms.DockStyle.Left;
+            this.panel2.Location = new System.Drawing.Point(6, 6);
+            this.panel2.Name = "panel2";
+            this.panel2.Size = new System.Drawing.Size(385, 24);
+            this.panel2.TabIndex = 0;
+            // 
+            // connectionLabel
+            // 
+            this.connectionLabel.AutoSize = true;
+            this.connectionLabel.Font = new System.Drawing.Font("Segoe UI Semibold", 8F, System.Drawing.FontStyle.Bold);
+            this.connectionLabel.Location = new System.Drawing.Point(4, 4);
+            this.connectionLabel.Name = "connectionLabel";
+            this.connectionLabel.Size = new System.Drawing.Size(112, 13);
+            this.connectionLabel.TabIndex = 0;
+            this.connectionLabel.Text = "Now connected with: " + name;
+            // 
+            // label2
+            // 
+            this.label2.Location = new System.Drawing.Point(0, 0);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(100, 23);
+            this.label2.TabIndex = 0;
+            // 
+            // label1
+            // 
+            this.label1.Location = new System.Drawing.Point(0, 0);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(100, 23);
+            this.label1.TabIndex = 0;
+            // 
+            // panel1
+            // 
+            this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
+            this.panel1.Controls.Add(this.button1);
+            this.panel1.Controls.Add(this.richTextBox1);
+            this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.panel1.Name = "panel1";
+            this.panel1.Size = new System.Drawing.Size(400, 100);
+            this.panel1.TabIndex = 1;
+            // 
+            // button1
+            // 
+            this.button1.BackColor = System.Drawing.Color.White;
+            this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.button1.Location = new System.Drawing.Point(310, 4);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(85, 90);
+            this.button1.TabIndex = 1;
+            this.button1.Text = "Send";
+            this.button1.UseVisualStyleBackColor = false;
+            this.button1.Click += new System.EventHandler(this.button1_Click);
+            // 
+            // richTextBox1
+            // 
+            this.richTextBox1.BackColor = System.Drawing.Color.White;
+            this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+            this.richTextBox1.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.richTextBox1.Location = new System.Drawing.Point(4, 4);
+            this.richTextBox1.MaxLength = 250;
+            this.richTextBox1.Name = "richTextBox1";
+            this.richTextBox1.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
+            this.richTextBox1.Size = new System.Drawing.Size(300, 90);
+            this.richTextBox1.TabIndex = 0;
+            this.richTextBox1.Text = "";
+            this.richTextBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBox_KeyDown);
+            // 
+            // panel3
+            // 
+            this.panel3.AutoScroll = true;
+            this.panel3.HorizontalScroll.Enabled = false;
+            this.panel3.HorizontalScroll.Visible = false;
+            this.panel3.BackColor = System.Drawing.Color.White;
+            this.panel3.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.panel3.Controls.Add(this.flowLayoutPanel1);
+            this.panel3.Location = new System.Drawing.Point(0, 0);
+
+            this.panel3.Name = "panel3";
+            this.panel3.TabIndex = 1;
+            // 
+            // container
+            // 
+            this.Controls.Add(this.panel3);
+            this.Controls.Add(this.panel1);
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "container";
+            this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel3_MouseWheel);
+
+            passChatMessage = new ChatDelegate(this.AddChatItem);
+        }
+
+        private void button1_Click(object sender, EventArgs e)
+        {
+            if (richTextBox1.TextLength > 1)
+            {
+                AddChatItem(new ChatMessage("Doctor", richTextBox1.Text, true));
+                MainClient.SendNetCommand(new NetCommand(richTextBox1.Text, true, Session));
+                richTextBox1.ResetText();
+            }
+        }
+
+        public void AddChatItem(ChatMessage chat)
+        {
+            flowLayoutPanel1.Controls.Add(new ChatItem(chat));
+        }
+
+        private void panel3_MouseWheel(object sender, MouseEventArgs e)
+        {
+            panel3.Focus();
+        }
+
+        private void FlowLayoutPanel1_SizeChanged(object sender, System.EventArgs e)
+        {
+            if (flowLayoutPanel1.Size.Height > panel3.Size.Height)
+            {
+                panel2.Width = 375;
+                flowLayoutPanel1.Width = 380;
+                panel3.VerticalScroll.Value = panel3.VerticalScroll.Maximum;
+            }
+        }
+
+        private bool textBoxIsEmpty()
+        {
+            string[] text = richTextBox1.Text.Split();
+            foreach (string s in text)
+            {
+                if (s != " ")
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private void TextBox_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.KeyCode == Keys.Enter)
+            {
+                button1_Click(this, new EventArgs());
+                e.Handled = true;
+            }
+        }
+
+        public delegate void ChatDelegate(ChatMessage chat);
+        public ChatDelegate passChatMessage;
+    }
+}

+ 115 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/PanelClientData.cs

@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public class PanelClientData : Panel
+    {
+        public Label labelMetingCurrentValue;
+        public ProgressBar progressBarMeting;
+        public Label metingName;
+
+        private int min;
+        private int max;
+        private string name;
+
+        public PanelClientData(string name, int min, int max) : base()
+        {
+            this.min = min;
+            this.max = max;
+            this.name = name;
+
+            this.metingName = new System.Windows.Forms.Label();
+            this.progressBarMeting = new System.Windows.Forms.ProgressBar();
+            this.labelMetingCurrentValue = new System.Windows.Forms.Label();
+            // 
+            // initialize panel
+            // 
+            this.BackColor = System.Drawing.SystemColors.ControlLightLight;
+            this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+            this.Controls.Add(this.labelMetingCurrentValue);
+            if (name != "Tijd")
+                this.Controls.Add(this.progressBarMeting);
+            this.Controls.Add(this.metingName);
+            this.Dock = System.Windows.Forms.DockStyle.Top;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "panel1";
+            this.Size = new System.Drawing.Size(284, 80);
+            // 
+            // metingName
+            // 
+            this.metingName.AutoSize = true;
+            this.metingName.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.metingName.Location = new System.Drawing.Point(12, 9);
+            this.metingName.Name = "metingName";
+            this.metingName.Size = new System.Drawing.Size(105, 21);
+            this.metingName.TabIndex = 0;
+            this.metingName.Text = name;
+            // 
+            // progressBarMeting
+            // 
+            this.progressBarMeting.Location = new System.Drawing.Point(16, 39);
+            this.progressBarMeting.Name = "progressBarMeting";
+            this.progressBarMeting.Size = new System.Drawing.Size(183, 23);
+            this.progressBarMeting.TabIndex = 1;
+            this.progressBarMeting.Value = 0;
+            // 
+            // labelMetingCurrentValue
+            // 
+            this.labelMetingCurrentValue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.labelMetingCurrentValue.AutoSize = true;
+            this.labelMetingCurrentValue.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelMetingCurrentValue.Location = new System.Drawing.Point(215, 32);
+            this.labelMetingCurrentValue.Name = "labelMetingCurrentValue";
+            this.labelMetingCurrentValue.Size = new System.Drawing.Size(57, 32);
+            this.labelMetingCurrentValue.TabIndex = 2;
+            this.labelMetingCurrentValue.Text = "0";
+        }
+
+        public void setText(string text)
+        {
+            this.metingName.Text = text;
+        }
+
+        public void updateValue(int value)
+        {
+            if (name == "Tijd")
+            {
+                this.labelMetingCurrentValue.Text = (value / 60) + ":" + (value % 60);
+            }
+            else
+            {
+                this.labelMetingCurrentValue.Text = value.ToString();
+                this.progressBarMeting.Value = ValueToPercentage(value);
+            }
+
+        }
+
+        public void updateValue(double value)
+        {
+            this.labelMetingCurrentValue.Text = value.ToString();
+            this.progressBarMeting.Value = ValueToPercentage((int)value);
+        }
+
+        public void updateValue(decimal value)
+        {
+            this.labelMetingCurrentValue.Text = value.ToString();
+            this.progressBarMeting.Value = ValueToPercentage((int)value);
+        }
+
+        private int ValueToPercentage(int value)
+        {
+            if (value < min)
+                return 0;
+
+            if (value > max)
+                return 100;
+
+            return ((value - min) * 100) / (max - min);
+        }
+    }
+}

+ 287 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/PanelClientSetData.cs

@@ -0,0 +1,287 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication.Client
+{
+    public class PanelClientSetData : Panel
+    {
+
+        private Panel panel6;
+        private Label label3;
+        private Panel panel5;
+        private Label label4;
+        private Panel panel3;
+        private Label label2;
+        private Panel panel2;
+        private Label label1;
+        private Button buttonTrapsnelheid;
+        private TrackBar trackBar1;
+        private Label label6;
+        private Button buttonAfstand;
+        private TextBox textBox2;
+        private Label label5;
+        private Button buttonTijd;
+        private MaskedTextBox textBox1;
+
+        private int Session;
+
+        public PanelClientSetData(int session) : base()
+        {
+            Session = session;
+            this.panel6 = new System.Windows.Forms.Panel();
+            this.label3 = new System.Windows.Forms.Label();
+            this.panel5 = new System.Windows.Forms.Panel();
+            this.label4 = new System.Windows.Forms.Label();
+            this.panel3 = new System.Windows.Forms.Panel();
+            this.label2 = new System.Windows.Forms.Label();
+            this.panel2 = new System.Windows.Forms.Panel();
+            this.label1 = new System.Windows.Forms.Label();
+            this.textBox1 = new System.Windows.Forms.MaskedTextBox();
+            this.textBox2 = new System.Windows.Forms.TextBox();
+            this.trackBar1 = new System.Windows.Forms.TrackBar();
+            this.buttonTijd = new System.Windows.Forms.Button();
+            this.buttonAfstand = new System.Windows.Forms.Button();
+            this.label5 = new System.Windows.Forms.Label();
+            this.label6 = new System.Windows.Forms.Label();
+            this.buttonTrapsnelheid = new System.Windows.Forms.Button();
+            this.panel6.SuspendLayout();
+            this.panel5.SuspendLayout();
+            this.panel3.SuspendLayout();
+            this.panel2.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // panel1
+            // 
+
+            // 
+            // panel6
+            // 
+            this.panel6.BackColor = System.Drawing.Color.White;
+            this.panel6.Controls.Add(this.buttonTrapsnelheid);
+            this.panel6.Controls.Add(this.trackBar1);
+            this.panel6.Controls.Add(this.label3);
+            this.panel6.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.panel6.Location = new System.Drawing.Point(0, 199);
+            this.panel6.Name = "panel6";
+            this.panel6.Size = new System.Drawing.Size(370, 112);
+            this.panel6.TabIndex = 4;
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Font = new System.Drawing.Font("Segoe UI Semibold", 10F, System.Drawing.FontStyle.Bold);
+            this.label3.Location = new System.Drawing.Point(4, 5);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(146, 19);
+            this.label3.TabIndex = 0;
+            this.label3.Text = "Trapsterkte aanpassen";
+            // 
+            // panel5
+            // 
+            this.panel5.BackColor = System.Drawing.Color.White;
+            this.panel5.Controls.Add(this.label6);
+            this.panel5.Controls.Add(this.buttonAfstand);
+            this.panel5.Controls.Add(this.textBox2);
+            this.panel5.Controls.Add(this.label4);
+            this.panel5.Dock = System.Windows.Forms.DockStyle.Top;
+            this.panel5.Location = new System.Drawing.Point(0, 124);
+            this.panel5.Name = "panel5";
+            this.panel5.Size = new System.Drawing.Size(370, 75);
+            this.panel5.TabIndex = 3;
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Font = new System.Drawing.Font("Segoe UI Semibold", 10F, System.Drawing.FontStyle.Bold);
+            this.label4.Location = new System.Drawing.Point(4, 26);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(114, 19);
+            this.label4.TabIndex = 0;
+            this.label4.Text = "Afstand instellen";
+            // 
+            // panel3
+            // 
+            this.panel3.BackColor = System.Drawing.Color.White;
+            this.panel3.Controls.Add(this.label5);
+            this.panel3.Controls.Add(this.buttonTijd);
+            this.panel3.Controls.Add(this.textBox1);
+            this.panel3.Controls.Add(this.label2);
+            this.panel3.Dock = System.Windows.Forms.DockStyle.Top;
+            this.panel3.Font = new System.Drawing.Font("Tunga", 8.25F);
+            this.panel3.Location = new System.Drawing.Point(0, 52);
+            this.panel3.Name = "panel3";
+            this.panel3.Size = new System.Drawing.Size(370, 72);
+            this.panel3.TabIndex = 1;
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Font = new System.Drawing.Font("Segoe UI Semibold", 10F, System.Drawing.FontStyle.Bold);
+            this.label2.Location = new System.Drawing.Point(3, 23);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(101, 19);
+            this.label2.TabIndex = 0;
+            this.label2.Text = "Tijd aanpassen";
+            // 
+            // panel2
+            // 
+            this.panel2.BackColor = System.Drawing.SystemColors.ControlDarkDark;
+            this.panel2.Controls.Add(this.label1);
+            this.panel2.Dock = System.Windows.Forms.DockStyle.Top;
+            this.panel2.Location = new System.Drawing.Point(0, 0);
+            this.panel2.Name = "panel2";
+            this.panel2.Size = new System.Drawing.Size(500, 52);
+            this.panel2.TabIndex = 0;
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label1.ForeColor = System.Drawing.Color.White;
+            this.label1.Location = new System.Drawing.Point(3, 9);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(247, 21);
+            this.label1.TabIndex = 0;
+            this.label1.Text = "Eigenschappen fiets aanpassen";
+            // 
+            // textBox1
+            // 
+            this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+            this.textBox1.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.textBox1.Location = new System.Drawing.Point(123, 21);
+            this.textBox1.Name = "textBox1";
+            this.textBox1.Size = new System.Drawing.Size(77, 25);
+            this.textBox1.TabIndex = 1;
+            this.textBox1.Mask = "00:00";
+            this.textBox1.KeyDown += TextBox1_KeyDown;
+            // 
+            // textBox2
+            // 
+            this.textBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+            this.textBox2.Font = new System.Drawing.Font("Segoe UI", 9.75F);
+            this.textBox2.Location = new System.Drawing.Point(124, 24);
+            this.textBox2.Name = "textBox2";
+            this.textBox2.Size = new System.Drawing.Size(77, 25);
+            this.textBox2.TabIndex = 1;
+            this.textBox2.KeyDown += TextBox2_KeyDown;
+            // 
+            // trackBar1
+            // 
+            this.trackBar1.Location = new System.Drawing.Point(29, 42);
+            this.trackBar1.Maximum = 400;
+            this.trackBar1.Minimum = 25;
+            this.trackBar1.Name = "trackBar1";
+            this.trackBar1.Size = new System.Drawing.Size(221, 45);
+            this.trackBar1.TabIndex = 1;
+            this.trackBar1.Value = 25;
+            // 
+            // button1
+            // 
+            this.buttonTijd.BackColor = System.Drawing.Color.WhiteSmoke;
+            this.buttonTijd.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonTijd.Font = new System.Drawing.Font("Segoe UI", 9.75F);
+            this.buttonTijd.Location = new System.Drawing.Point(282, 19);
+            this.buttonTijd.Name = "button1";
+            this.buttonTijd.Size = new System.Drawing.Size(75, 25);
+            this.buttonTijd.TabIndex = 2;
+            this.buttonTijd.Text = "Set";
+            this.buttonTijd.UseVisualStyleBackColor = false;
+            this.buttonTijd.Click += new System.EventHandler(this.buttonTijd_Click);
+            // 
+            // button2
+            // 
+            this.buttonAfstand.BackColor = System.Drawing.Color.WhiteSmoke;
+            this.buttonAfstand.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonAfstand.Font = new System.Drawing.Font("Segoe UI", 9.75F);
+            this.buttonAfstand.Location = new System.Drawing.Point(283, 24);
+            this.buttonAfstand.Name = "button2";
+            this.buttonAfstand.Size = new System.Drawing.Size(75, 25);
+            this.buttonAfstand.TabIndex = 2;
+            this.buttonAfstand.Text = "Set";
+            this.buttonAfstand.UseVisualStyleBackColor = false;
+            this.buttonAfstand.Click += new System.EventHandler(this.buttonAfstand_Click);
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label5.Location = new System.Drawing.Point(207, 26);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(23, 13);
+            this.label5.TabIndex = 3;
+            this.label5.Text = "sec";
+            // 
+            // label6
+            // 
+            this.label6.AutoSize = true;
+            this.label6.Location = new System.Drawing.Point(208, 30);
+            this.label6.Name = "label6";
+            this.label6.Size = new System.Drawing.Size(15, 13);
+            this.label6.TabIndex = 3;
+            this.label6.Text = "m";
+            // 
+            // button3
+            // 
+            this.buttonTrapsnelheid.BackColor = System.Drawing.Color.WhiteSmoke;
+            this.buttonTrapsnelheid.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonTrapsnelheid.Location = new System.Drawing.Point(283, 42);
+            this.buttonTrapsnelheid.Name = "button3";
+            this.buttonTrapsnelheid.Size = new System.Drawing.Size(75, 25);
+            this.buttonTrapsnelheid.TabIndex = 2;
+            this.buttonTrapsnelheid.Text = "Set";
+            this.buttonTrapsnelheid.UseVisualStyleBackColor = false;
+            this.buttonTrapsnelheid.Click += new System.EventHandler(this.buttonTrapsnelheid_Click);
+
+            Controls.Add(this.panel6);
+            Controls.Add(this.panel5);
+            Controls.Add(this.panel3);
+            Controls.Add(this.panel2);
+            Dock = System.Windows.Forms.DockStyle.Fill;
+            Location = new System.Drawing.Point(0, 0);
+            BackColor = System.Drawing.Color.White;
+            Name = "panel1";
+            Size = new System.Drawing.Size(370, 400);
+
+        }
+
+        private void TextBox2_KeyDown(object sender, KeyEventArgs e)
+        {
+            if(e.KeyCode == Keys.Enter)
+            {
+                buttonAfstand_Click(this, new EventArgs());
+            }
+        }
+
+        private void TextBox1_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.KeyCode == Keys.Enter)
+            {
+                buttonTijd_Click(this, new EventArgs());
+            }
+        }
+
+        private void buttonTrapsnelheid_Click(object sender, EventArgs e)
+        {
+            MainClient.SendNetCommand(new NetCommand(NetCommand.ValueType.POWER, trackBar1.Value, Session));
+        }
+
+        private void buttonAfstand_Click(object sender, EventArgs e)
+        {
+            MainClient.SendNetCommand(new NetCommand(NetCommand.ValueType.DISTANCE, int.Parse(textBox2.Text), Session));
+            textBox2.Text = "";
+        }
+
+        private void buttonTijd_Click(object sender, EventArgs e)
+        {
+            int seconds = (int.Parse(textBox1.Text.Split(':')[0]) * 60) + int.Parse(textBox1.Text.Split(':')[1]);
+            MainClient.SendNetCommand(new NetCommand(NetCommand.ValueType.TIME, seconds, Session));
+            textBox1.Text = "";
+        }
+    }
+}

+ 71 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/PanelGraphView.cs

@@ -0,0 +1,71 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+
+namespace ErgometerDoctorApplication
+{
+    public class PanelGraphView : Panel
+    {
+
+        private List<ChartPanel> charts;
+        private FlowLayoutPanel flowlayout;
+
+        public PanelGraphView() : base()
+        {
+            createCharts();
+
+            flowlayout = new FlowLayoutPanel();
+
+            flowlayout.Dock = DockStyle.Fill;
+            flowlayout.BackColor = System.Drawing.Color.DarkGray;
+            flowlayout.Location = new System.Drawing.Point(0, 0);
+            flowlayout.Name = "flowlayout";
+            flowlayout.Padding = new Padding(15);
+            flowlayout.AutoScroll = true;
+            foreach (ChartPanel chart in charts)
+            {
+                flowlayout.Controls.Add(chart);
+            }
+
+            List<Meting> metingen = new List<Meting>();
+            metingen.Add(new Meting(0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+            updateAllCharts(metingen);
+            // 
+            // panelGraphView
+            // 
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Controls.Add(flowlayout);
+
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "panelGraphView";
+            this.Size = new System.Drawing.Size(400, 600);
+            this.TabIndex = 1;
+        }
+
+        public void createCharts()
+        {
+            charts = new List<ChartPanel>();
+            charts.Add(new ChartPanel(ChartPanel.MetingType.HEARTBEAT, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.RPM, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.SPEED, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.DISTANCE, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.ENERGY, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.POWER, SeriesChartType.Line));
+            charts.Add(new ChartPanel(ChartPanel.MetingType.ACTUALPOWER, SeriesChartType.Line));
+        }
+
+        public void updateAllCharts(List<Meting> metingen)
+        {
+            foreach (ChartPanel chart in charts)
+            {
+                chart.updateChart(metingen);
+            }
+        }
+    }
+}

+ 175 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/SessionWindow.Designer.cs

@@ -0,0 +1,175 @@
+using ErgometerDoctorApplication.Client;
+using System;
+
+namespace ErgometerDoctorApplication
+{
+    partial class SessionWindow
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.SuspendLayout();
+            
+
+            this.components = new System.ComponentModel.Container();
+            this.panelClientContainer = new System.Windows.Forms.Panel();
+            this.panelDataViewLeft = new System.Windows.Forms.Panel();
+            this.panelClientSetData = new PanelClientSetData(Session);
+            this.panelGraphView = new ErgometerDoctorApplication.PanelGraphView();
+            this.panelClientChat = new ErgometerDoctorApplication.PanelClientChat(Session, ClientName);
+            this.panelTopBar = new System.Windows.Forms.Panel();
+            this.labelUsername = new System.Windows.Forms.Label();
+            this.labelHallo = new System.Windows.Forms.Label();
+
+            this.heartBeat = new PanelClientData("Hartslag", 50, 220);
+            this.RPM = new PanelClientData("RPM", 0, 120);
+            this.speed = new PanelClientData("Snelheid", 0, 50);
+            this.distance = new PanelClientData("Afstand (km)", 0, 100);
+            this.power = new PanelClientData("Weerstand", 25, 400);
+            this.energy = new PanelClientData("Energie", 0, 200);
+            this.actualpower = new PanelClientData("Absolute Weerstand", 0, 400);
+            this.time = new PanelClientData("Tijd", 0, 400);
+
+            this.panelClientContainer.SuspendLayout();
+            this.panelTopBar.SuspendLayout();
+            // 
+            // panelClientContainer
+            // 
+            this.panelClientContainer.Controls.Add(this.panelGraphView);
+            this.panelClientContainer.Controls.Add(this.panelDataViewLeft);
+
+            this.panelClientContainer.Controls.Add(this.panelClientChat);
+            this.panelClientContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.panelClientContainer.Location = new System.Drawing.Point(0, 0);
+            this.panelClientContainer.Name = "panelClientContainer";
+            this.panelClientContainer.Size = new System.Drawing.Size(800, 600);
+            this.panelClientContainer.TabIndex = 0;
+            // 
+            // panelDataViewLeft
+            // 
+            //this.panelDataViewLeft.Dock = System.Windows.Forms.DockStyle.Left;
+            this.panelDataViewLeft.Location = new System.Drawing.Point(0, 0);
+            this.panelDataViewLeft.Name = "panelDataViewLeft";
+            this.panelDataViewLeft.Size = new System.Drawing.Size(18, 600);
+            this.panelDataViewLeft.TabIndex = 3;
+            this.panelDataViewLeft.BackColor = System.Drawing.Color.Gray;
+            this.panelDataViewLeft.Controls.Add(panelClientSetData);
+            this.panelDataViewLeft.Controls.Add(heartBeat);
+            this.panelDataViewLeft.Controls.Add(RPM);
+            this.panelDataViewLeft.Controls.Add(speed);
+            this.panelDataViewLeft.Controls.Add(distance);
+            this.panelDataViewLeft.Controls.Add(power);
+            this.panelDataViewLeft.Controls.Add(energy);
+            this.panelDataViewLeft.Controls.Add(actualpower);
+            this.panelDataViewLeft.Controls.Add(time);
+
+
+            // 
+            // panelClientChat
+            // 
+            this.panelClientChat.BackColor = System.Drawing.SystemColors.ButtonHighlight;
+            this.panelClientChat.Dock = System.Windows.Forms.DockStyle.Right;
+            this.panelClientChat.Location = new System.Drawing.Point(400, 0);
+            this.panelClientChat.Name = "panelClientChat";
+            this.panelClientChat.Size = new System.Drawing.Size(400, 600);
+            this.panelClientChat.TabIndex = 2;
+            // 
+            // panelTopBar
+            // 
+            this.panelTopBar.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
+            this.panelTopBar.Controls.Add(this.labelUsername);
+            this.panelTopBar.Controls.Add(this.labelHallo);
+            this.panelTopBar.Dock = System.Windows.Forms.DockStyle.Top;
+            this.panelTopBar.Location = new System.Drawing.Point(0, 0);
+            this.panelTopBar.Name = "panelTopBar";
+            this.panelTopBar.Size = new System.Drawing.Size(800, 30);
+            this.panelTopBar.TabIndex = 1;
+            this.panelTopBar.Visible = false;
+            // 
+            // labelUsername
+            // 
+            this.labelUsername.AutoSize = true;
+            this.labelUsername.Font = new System.Drawing.Font("Segoe UI Semilight", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelUsername.ForeColor = System.Drawing.Color.White;
+            this.labelUsername.Location = new System.Drawing.Point(49, 3);
+            this.labelUsername.Name = "labelUsername";
+            this.labelUsername.Size = new System.Drawing.Size(144, 21);
+            this.labelUsername.TabIndex = 0;
+            this.labelUsername.Text = "<Gebruikersnaam>";
+            // 
+            // labelHallo
+            // 
+            this.labelHallo.AutoSize = true;
+            this.labelHallo.Font = new System.Drawing.Font("Segoe UI Semilight", 12F);
+            this.labelHallo.ForeColor = System.Drawing.Color.White;
+            this.labelHallo.Location = new System.Drawing.Point(3, 3);
+            this.labelHallo.Name = "labelHallo";
+            this.labelHallo.Size = new System.Drawing.Size(54, 21);
+            this.labelHallo.TabIndex = 0;
+            this.labelHallo.Text = "Hallo, ";
+            // 
+            // SessionWindow
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(800, 600);
+            this.Controls.Add(this.panelTopBar);
+            this.Controls.Add(this.panelClientContainer);
+            this.Name = "SessionWindow";
+            this.Text = "Sessie: " + ClientName;
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Resize += new System.EventHandler(this.ClientApplicatie_Resize);
+            this.panelClientContainer.ResumeLayout(false);
+            this.panelTopBar.ResumeLayout(false);
+            this.panelTopBar.PerformLayout();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+        private System.Windows.Forms.Panel panelClientContainer;
+        public PanelClientChat panelClientChat;
+        public PanelGraphView panelGraphView;
+        private System.Windows.Forms.Panel panelDataViewLeft;
+        private System.Windows.Forms.Panel panelTopBar;
+        private System.Windows.Forms.Label labelUsername;
+        private System.Windows.Forms.Label labelHallo;
+        public PanelClientData heartBeat, RPM, speed, distance, power, energy, seconds, actualpower, time;
+        public PanelClientSetData panelClientSetData;
+
+        private void createTitle()
+        {
+            if (ActiveSession)
+            {
+                this.Text = "Actieve Sessie: " + ClientName;
+            }
+            else
+            {
+                this.Text = "Afgelopen Sessie: " + ClientName;
+            }
+        }
+    }
+}

+ 103 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/SessionWindow.cs

@@ -0,0 +1,103 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public partial class SessionWindow : Form
+    {
+
+        private bool ActiveSession { get; }
+        private string ClientName { get; set; }
+        public int Session { get; }
+
+        private ClientThread client;
+
+        private int count;
+
+        public delegate void UpdateMetingen(Meting m);
+        public UpdateMetingen updateMetingen;
+
+        public delegate void UpdateGraph();
+        public UpdateGraph updateGraph;
+
+        public SessionWindow(string ClientName, bool old, int session, ClientThread parentthread)
+        {
+            this.ActiveSession = !old;
+            this.ClientName = ClientName;
+            this.client = parentthread;
+            Session = session;
+
+            count = 0;
+
+            updateMetingen = new UpdateMetingen(this.SaveMeting);
+            updateGraph = new UpdateGraph(this.LoadGraph);
+
+            InitializeComponent();
+
+            if(! ActiveSession)
+            {
+                panelClientChat.richTextBox1.Enabled = false;
+                panelClientChat.button1.Enabled = false;
+                panelDataViewLeft.Visible = false;
+            }
+        }
+
+        public void ClientApplicatie_Resize(object sender, EventArgs e)
+        {
+            Control control = (Control)sender;
+            if (control.Size.Width < 980)
+            {
+                panelGraphView.Visible = false;
+                panelClientChat.Width = 400;
+                panelDataViewLeft.Dock = DockStyle.Fill;
+            }
+            if (control.Size.Width >= 980 && control.Size.Width < 1368)
+            {
+                panelGraphView.Visible = true;
+                panelDataViewLeft.Width = 250;
+                panelClientChat.Width = 400;
+                panelDataViewLeft.Dock = DockStyle.Left;
+            }
+            if (control.Size.Width >= 1368)
+            {
+                panelGraphView.Visible = true;
+                panelDataViewLeft.Width = 400;
+                panelDataViewLeft.Dock = DockStyle.Left;
+            }
+        }
+
+        public void SaveMeting(Meting m)
+        {
+          
+            heartBeat.updateValue(m.HeartBeat);
+            RPM.updateValue(m.RPM);
+            speed.updateValue(m.Speed*100);
+            distance.updateValue(m.Distance*100);
+            power.updateValue(m.Power);
+            energy.updateValue(m.Energy);
+            actualpower.updateValue(m.ActualPower);
+            time.updateValue(m.Seconds);
+
+            if (count >= 10)
+            {
+                count = 0;
+                panelGraphView.updateAllCharts(client.Metingen);
+            }
+
+            count++;
+        }
+
+        public void LoadGraph()
+        {
+            panelGraphView.updateAllCharts(client.Metingen);
+        }
+    }
+}

+ 120 - 0
ErgometerIPR/ErgometerDoctorApplication/Client/SessionWindow.resx

@@ -0,0 +1,120 @@
+<?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>
+</root>

+ 84 - 0
ErgometerIPR/ErgometerDoctorApplication/ConActiveSessions.cs

@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.AccessControl;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public class ConActiveSessions : Panel
+    {
+
+        private FlowLayoutPanel flowlayout;
+
+        public ConActiveSessions() : base()
+        {
+            labelActiveSessions = new Label();
+            // 
+            // ConActiveSessions
+            // 
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "ConActiveSessions";
+            this.Size = new System.Drawing.Size(584, 459);
+            this.TabIndex = 0;
+            // 
+            // labelActiveSessions
+            // 
+            this.labelActiveSessions.Anchor = System.Windows.Forms.AnchorStyles.Top | AnchorStyles.Left;
+            this.labelActiveSessions.AutoSize = true;
+            this.labelActiveSessions.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelActiveSessions.Location = new System.Drawing.Point(20, 20);
+            this.labelActiveSessions.Name = "labelActiveSessions";
+            this.labelActiveSessions.Size = new System.Drawing.Size(103, 21);
+            this.labelActiveSessions.TabIndex = 3;
+            this.labelActiveSessions.Text = "Er zijn geen actieve sessies.";
+
+            flowlayout = new FlowLayoutPanel();
+
+            flowlayout.Dock = DockStyle.Fill;
+            flowlayout.BackColor = System.Drawing.Color.WhiteSmoke;
+            flowlayout.Location = new System.Drawing.Point(0, 0);
+            flowlayout.Name = "flowlayout";
+            flowlayout.Padding = new Padding(15);
+            flowlayout.AutoScroll = true;
+
+            this.Controls.Add(labelActiveSessions);
+            this.Controls.Add(flowlayout);
+
+            //this.Controls.Add(data);
+
+            updateActiveSessions(MainClient.activesessions);
+            
+        }
+
+        public System.Windows.Forms.Label labelActiveSessions;
+
+        public void updateActiveSessions(Dictionary<int, string> actives)
+        {
+            flowlayout.Controls.Clear();
+
+            foreach (KeyValuePair<int, string> pair in actives)
+            {
+
+                flowlayout.Controls.Add(new SessionPanel(pair.Key, pair.Value, true,0));
+            }
+        }
+
+		/*
+        private void data_CellContentClick(object sender, DataGridViewCellEventArgs e)
+        {
+            if (data.Rows[e.RowIndex].Cells[1].Value != null)
+            {
+                MainClient.StartNewCLient(data.Rows[e.RowIndex].Cells[0].Value + "", int.Parse(data.Rows[e.RowIndex].Cells[1].Value + ""));
+            }
+        }
+
+        public System.Windows.Forms.DataGridViewTextBoxColumn name;
+        public System.Windows.Forms.DataGridViewTextBoxColumn sessionId;
+        public System.Windows.Forms.DataGridView data;
+        */
+    }
+}

+ 72 - 0
ErgometerIPR/ErgometerDoctorApplication/ConClientBroadcast.cs

@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public class ConClientBroadcast : Panel
+    { 
+
+        public ConClientBroadcast() : base()
+        {
+
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "ConClientBroadcast";
+            this.Size = new System.Drawing.Size(584, 459);
+            this.TabIndex = 0;
+
+            buttonBroadcast = new Button();
+            textBoxBroadcast = new TextBox();
+
+            // 
+            // buttonLogin
+            // 
+            this.buttonBroadcast.Anchor = AnchorStyles.Left | AnchorStyles.Top;
+            this.buttonBroadcast.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonBroadcast.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.buttonBroadcast.Location = new System.Drawing.Point(200, 20);
+            this.buttonBroadcast.Name = "buttonCreate";
+            this.buttonBroadcast.Size = new System.Drawing.Size(168, 31);
+            this.buttonBroadcast.TabIndex = 3;
+            this.buttonBroadcast.Text = "Broadcast";
+            this.buttonBroadcast.UseVisualStyleBackColor = true;
+            this.buttonBroadcast.Click += new System.EventHandler(this.buttonBroadcast_Click);
+            // 
+            // textBoxPassword
+            // 
+            this.textBoxBroadcast.Anchor = AnchorStyles.Left | AnchorStyles.Top;
+            this.textBoxBroadcast.Location = new System.Drawing.Point(20, 20);
+            this.textBoxBroadcast.MaxLength = 16;
+            this.textBoxBroadcast.Name = "textBoxPassword";
+            this.textBoxBroadcast.Size = new System.Drawing.Size(167, 20);
+            this.textBoxBroadcast.TabIndex = 2;
+            this.textBoxBroadcast.KeyDown += TextBoxBroadcast_KeyDown;
+
+            this.Controls.Add(textBoxBroadcast);
+            this.Controls.Add(buttonBroadcast);
+
+
+        }
+
+        private void TextBoxBroadcast_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.KeyCode == Keys.Enter)
+            {
+                buttonBroadcast_Click(this, new EventArgs());
+            }
+        }
+
+        private void buttonBroadcast_Click(object sender, EventArgs e)
+        {
+            MainClient.SendNetCommand(new ErgometerLibrary.NetCommand(textBoxBroadcast.Text, MainClient.Session));
+            textBoxBroadcast.Text = "";
+        }
+
+        public System.Windows.Forms.TextBox textBoxBroadcast;
+        public System.Windows.Forms.Button buttonBroadcast;
+    }
+}

+ 150 - 0
ErgometerIPR/ErgometerDoctorApplication/ConClientData.cs

@@ -0,0 +1,150 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Security.AccessControl;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public class ConClientData : Panel
+    {
+        public System.Windows.Forms.TextBox textBoxPassword;
+        public System.Windows.Forms.TextBox textBoxUsername;
+        public System.Windows.Forms.Button buttonCreate;
+        public System.Windows.Forms.ListBox listUsers;
+        public System.Windows.Forms.Label newUsername;
+        public System.Windows.Forms.Label newPassword;
+
+        public ConClientData() : base()
+        {
+            this.buttonCreate = new System.Windows.Forms.Button();
+            this.textBoxPassword = new System.Windows.Forms.TextBox();
+            this.textBoxUsername = new System.Windows.Forms.TextBox();
+            this.listUsers = new System.Windows.Forms.ListBox();
+            this.newUsername = new System.Windows.Forms.Label();
+            this.newPassword = new System.Windows.Forms.Label();
+
+            // 
+            // buttonLogin
+            // 
+            this.buttonCreate.Anchor = System.Windows.Forms.AnchorStyles.Left;
+            this.buttonCreate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonCreate.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.buttonCreate.Location = new System.Drawing.Point(20, 215);
+            this.buttonCreate.Name = "buttonCreate";
+            this.buttonCreate.Size = new System.Drawing.Size(168, 31);
+            this.buttonCreate.TabIndex = 3;
+            this.buttonCreate.Text = "Aanmaken";
+            this.buttonCreate.BackColor = Color.LightGray;
+            this.buttonCreate.Click += new System.EventHandler(this.buttonCreate_Click);
+            // 
+            // textBoxPassword
+            // 
+            this.textBoxPassword.Anchor = System.Windows.Forms.AnchorStyles.Left;
+            this.textBoxPassword.Location = new System.Drawing.Point(170, 180);
+            this.textBoxPassword.MaxLength = 16;
+            this.textBoxPassword.Name = "textBoxPassword";
+            this.textBoxPassword.Size = new System.Drawing.Size(167, 60);
+            this.textBoxPassword.TabIndex = 2;
+            this.textBoxPassword.KeyDown += TextBoxEnterPress;
+            // 
+            // textBoxUsername
+            // 
+            this.textBoxUsername.Anchor = System.Windows.Forms.AnchorStyles.Left;
+            this.textBoxUsername.Location = new System.Drawing.Point(170, 150);
+            this.textBoxUsername.MaxLength = 16;
+            this.textBoxUsername.Name = "textBoxUsername";
+            this.textBoxUsername.Size = new System.Drawing.Size(167, 20);
+            this.textBoxUsername.TabIndex = 2;
+            this.textBoxUsername.KeyDown += TextBoxEnterPress;
+            //
+            // listUsers
+            //
+            this.listUsers.Anchor = System.Windows.Forms.AnchorStyles.Left;
+            this.listUsers.Location = new System.Drawing.Point(20, -150);
+            this.listUsers.Name = "listUsers";
+            this.listUsers.Size = new System.Drawing.Size(200, 280);
+            this.listUsers.Items.Add("Geen gebruikers");
+            //
+            // newPassword
+            //
+            this.newPassword.Anchor = System.Windows.Forms.AnchorStyles.Left;
+            this.newPassword.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.newPassword.ForeColor = Color.Black;
+            this.newPassword.Location = new System.Drawing.Point(20, 182);
+            this.newPassword.Name = "newPassword";
+            this.newPassword.Size = new System.Drawing.Size(167, 20);
+            this.newPassword.TabIndex = 3;
+            this.newPassword.Text = "Nieuw wachtwoord";
+            //
+            // newUsername
+            //
+            this.newUsername.Anchor = System.Windows.Forms.AnchorStyles.Left;
+            this.newUsername.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.newUsername.Location = new System.Drawing.Point(20, 152);
+            this.newUsername.Name = "newUsername";
+            this.newUsername.Size = new System.Drawing.Size(167, 20);
+            this.newUsername.TabIndex = 3;
+            this.newUsername.Text = "Nieuwe gebruikersnaam";
+
+            this.Controls.Add(this.listUsers);
+            this.Controls.Add(this.buttonCreate);
+            this.Controls.Add(this.textBoxUsername);
+            this.Controls.Add(this.textBoxPassword);
+            this.Controls.Add(this.newUsername);
+            this.Controls.Add(this.newPassword);
+            // 
+            // ConClientData
+            // 
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(20, 0);
+            this.Name = "ConClientData";
+            this.Size = new System.Drawing.Size(584, 459);
+            this.TabIndex = 0;
+
+
+
+            this.BackColor = System.Drawing.Color.White;
+        }
+
+        private void TextBoxEnterPress(object sender, KeyEventArgs e)
+        {
+            if (e.KeyCode == Keys.Enter)
+            {
+                buttonCreate_Click(this, new EventArgs());
+            }
+        }
+
+        internal void updateUsers(Dictionary<string, string> users)
+        {
+            this.listUsers.Items.Clear();
+
+            foreach(KeyValuePair<string, string> user  in users)
+            {
+                this.listUsers.Items.Add(user.Key + ": " + user.Value);
+            }
+        }
+
+        private void buttonCreate_Click(object sender, EventArgs e)
+        {
+            if (!MainClient.users.ContainsKey(textBoxUsername.Text))
+            {
+                MainClient.SendNetCommand(new NetCommand(textBoxUsername.Text, textBoxPassword.Text, MainClient.Session));
+                MainClient.SendNetCommand(new NetCommand(NetCommand.RequestType.USERS, MainClient.Session));
+
+                textBoxUsername.Text = "";
+
+                Thread.Sleep(250);
+                updateUsers(MainClient.users);
+            }
+
+            
+            textBoxPassword.Text = "";
+        }
+    }
+}

+ 116 - 0
ErgometerIPR/ErgometerDoctorApplication/ConPanelLogin.cs

@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public class ConPanelLogin:Panel
+    {
+
+        MainWindow mainWindow;
+
+        public ConPanelLogin(Form mainWindow) : base()
+        {
+            this.mainWindow = (MainWindow)mainWindow;
+            this.textBoxPassword = new System.Windows.Forms.TextBox();
+            this.pictureBox1 = new System.Windows.Forms.PictureBox();
+            this.buttonLogin = new System.Windows.Forms.Button();
+            this.labelPassword = new System.Windows.Forms.Label();
+            this.labelLoginInfo = new System.Windows.Forms.Label();
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+            // 
+            // Container
+            // 
+            this.BackColor = System.Drawing.Color.White;
+            this.Controls.Add(this.labelLoginInfo);
+            this.Controls.Add(this.labelPassword);
+            this.Controls.Add(this.buttonLogin);
+            this.Controls.Add(this.pictureBox1);
+            this.Controls.Add(this.textBoxPassword);
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            // 
+            // textBoxPassword
+            // 
+            this.textBoxPassword.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.textBoxPassword.Location = new System.Drawing.Point(15, 70);
+            this.textBoxPassword.Name = "textBoxPassword";
+            this.textBoxPassword.PasswordChar = '*';
+            this.textBoxPassword.Size = new System.Drawing.Size(150, 20);
+            this.textBoxPassword.TabIndex = 0;
+            this.textBoxPassword.KeyDown += TextBoxPassword_KeyDown;
+            // 
+            // pictureBox1
+            // 
+            this.pictureBox1.Image = ((System.Drawing.Image)Properties.Resources.imageDoctor);
+            this.pictureBox1.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.pictureBox1.Location = new System.Drawing.Point(0, -150);
+            this.pictureBox1.Name = "pictureBox1";
+            this.pictureBox1.Size = new System.Drawing.Size(175, 175);
+            this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+
+            // 
+            // buttonLogin
+            // 
+            this.buttonLogin.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.buttonLogin.BackColor = System.Drawing.SystemColors.Highlight;
+            this.buttonLogin.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.buttonLogin.Font = new System.Drawing.Font("Segoe UI Semibold", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.buttonLogin.ForeColor = System.Drawing.Color.White;
+            this.buttonLogin.Location = new System.Drawing.Point(15, 105);
+            this.buttonLogin.Name = "buttonLogin";
+            this.buttonLogin.Size = new System.Drawing.Size(150, 30);
+            this.buttonLogin.TabIndex = 2;
+            this.buttonLogin.Text = "Log In";
+            this.buttonLogin.UseVisualStyleBackColor = false;
+            this.buttonLogin.Click += new System.EventHandler(this.buttonLogin_Click);
+            // 
+            // labelPassword
+            // 
+            this.labelPassword.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.labelPassword.AutoSize = true;
+            this.labelPassword.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelPassword.Location = new System.Drawing.Point(11, 40);
+            this.labelPassword.Name = "labelPassword";
+            this.labelPassword.Size = new System.Drawing.Size(103, 21);
+            this.labelPassword.TabIndex = 3;
+            this.labelPassword.Text = "Wachtwoord";
+            //
+            // labelLoginInfo
+            //
+            this.labelLoginInfo.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.labelLoginInfo.AutoSize = true;
+            this.labelLoginInfo.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelLoginInfo.ForeColor = System.Drawing.Color.Red;
+            this.labelLoginInfo.Location = new System.Drawing.Point(11, 140);
+            this.labelLoginInfo.Name = "labelLoginInfo";
+            this.labelLoginInfo.Size = new System.Drawing.Size(103, 21);
+            this.labelLoginInfo.TabIndex = 4;
+            this.labelLoginInfo.Text = "";
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+
+        }
+
+        private void TextBoxPassword_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.KeyCode == Keys.Enter)
+            {
+                buttonLogin_Click(this, new EventArgs());
+            }
+        }
+
+        private void buttonLogin_Click(object sender, EventArgs e)
+        {
+            mainWindow.validateLogin();
+        }
+        public System.Windows.Forms.TextBox textBoxPassword;
+        private PictureBox pictureBox1;
+        private System.Windows.Forms.Button buttonLogin;
+        private System.Windows.Forms.Label labelPassword;
+        public System.Windows.Forms.Label labelLoginInfo;
+    }
+    
+}

+ 65 - 0
ErgometerIPR/ErgometerDoctorApplication/ConSessionHistory.cs

@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public class ConSessionHistory : Panel
+    {
+        private FlowLayoutPanel flowlayout;
+
+        public ConSessionHistory() : base()
+        {
+            labelSessionHistory = new Label();
+
+            this.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Name = "ConSessionHistory";
+            this.Size = new System.Drawing.Size(584, 459);
+            this.TabIndex = 0;
+            // 
+            // labelSessionHistory
+            // 
+            this.labelSessionHistory.Anchor = System.Windows.Forms.AnchorStyles.Top | AnchorStyles.Left;
+            this.labelSessionHistory.AutoSize = true;
+            this.labelSessionHistory.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelSessionHistory.Location = new System.Drawing.Point(20, 20);
+            this.labelSessionHistory.Name = "labelSessionHistory";
+            this.labelSessionHistory.Size = new System.Drawing.Size(103, 21);
+            this.labelSessionHistory.TabIndex = 3;
+            this.labelSessionHistory.Text = "Er zijn geen oude sessies.";
+
+            flowlayout = new FlowLayoutPanel();
+
+            flowlayout.Dock = DockStyle.Fill;
+            flowlayout.BackColor = System.Drawing.Color.WhiteSmoke;
+            flowlayout.Location = new System.Drawing.Point(0, 0);
+            flowlayout.Name = "flowlayout";
+            flowlayout.Padding = new Padding(15);
+            flowlayout.AutoScroll = true;
+
+            this.Controls.Add(labelSessionHistory);
+            this.Controls.Add(flowlayout);
+
+            //this.Controls.Add(data);
+
+            updateHistory(MainClient.oldSessionsData);
+
+        }
+
+        public System.Windows.Forms.Label labelSessionHistory;
+
+        public void updateHistory(List<Tuple<string, double, int>> historys)
+        {
+            flowlayout.Controls.Clear();
+
+            foreach (Tuple<string,double,int> sessiondata in historys)
+            {
+                flowlayout.Controls.Add(new SessionPanel(sessiondata.Item3, sessiondata.Item1, false,sessiondata.Item2));
+            }
+        }
+    }
+}

+ 144 - 0
ErgometerIPR/ErgometerDoctorApplication/ErgometerDoctorApplication.csproj

@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{E543FF58-161A-4A41-AAE7-651327834362}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ErgometerDoctorApplication</RootNamespace>
+    <AssemblyName>ErgometerDoctorApplication</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ErgometerLibrary, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\ErgometerLibrary\ErgometerLibrary\ErgometerLibrary\bin\Debug\ErgometerLibrary.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Windows.Forms.DataVisualization" />
+    <Reference Include="System.Windows.Forms.DataVisualization.Design" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Client\ChartPanel.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Client\ClientThread.cs" />
+    <Compile Include="Client\PanelClientChat.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Client\PanelClientData.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Client\PanelClientSetData.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Client\PanelGraphView.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Client\SessionWindow.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Client\SessionWindow.Designer.cs">
+      <DependentUpon>SessionWindow.cs</DependentUpon>
+    </Compile>
+    <Compile Include="ConClientData.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="ConPanelLogin.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="ConClientBroadcast.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="ConSessionHistory.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="ConActiveSessions.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="MainClient.cs" />
+    <Compile Include="MainWindow.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="MainWindow.Designer.cs">
+      <DependentUpon>MainWindow.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SessionPanel.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <EmbeddedResource Include="MainWindow.resx">
+      <DependentUpon>MainWindow.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+      <DesignTime>True</DesignTime>
+    </Compile>
+    <EmbeddedResource Include="Client\SessionWindow.resx">
+      <DependentUpon>SessionWindow.cs</DependentUpon>
+    </EmbeddedResource>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\doctorImage.png" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 276 - 0
ErgometerIPR/ErgometerDoctorApplication/MainClient.cs

@@ -0,0 +1,276 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ErgometerDoctorApplication
+{
+    class MainClient
+    {
+
+        public static TcpClient Server { get; set; }
+
+        public static bool loggedin;
+
+        private static Thread t;
+        private static bool running;
+
+        public static int Session;
+
+        public static string HOST = "127.0.0.1";
+        public static int PORT = 8888;
+
+
+        //Server information
+        public static List<ClientThread> clients;
+        public static Dictionary<string, string> users;
+        public static List<Tuple<string, double, int>> oldSessionsData;
+
+        public static void RemoveActiveClient(ClientThread clientThread)
+        {
+            clients.Remove(clientThread);
+        }
+
+        public static Dictionary<int, string> activesessions;
+
+        static MainClient()
+        {
+            Server = new TcpClient();
+
+            loggedin = false;
+
+            clients = new List<ClientThread>();
+            users = new Dictionary<string, string>();
+            activesessions = new Dictionary<int, string>();
+            oldSessionsData = new List<Tuple<string, double, int>>();
+        }
+
+        public static bool Connect(string password, out string error)
+        {
+            error = "Succes";
+
+            if (Server == null || !Server.Connected)
+            {
+                if (Server == null)
+                    Server = new TcpClient();
+
+                try
+                {
+                    Server.Connect(HOST, PORT);
+                }
+                catch (Exception e)
+                {
+                    error = "Server is niet online.";
+                    return false;
+                }
+
+                NetCommand net = NetHelper.ReadNetCommand(Server);
+                if (net.Type == NetCommand.CommandType.SESSION)
+                    Session = net.Session;
+                else
+                    throw new Exception("Session not assigned");
+
+                running = true;
+                t = new Thread(run);
+                t.IsBackground = true;
+                t.Start();
+            }
+
+            if (!loggedin)
+            {
+                NetCommand command = new NetCommand("Doctor0tVfW", true, password, Session);
+                NetHelper.SendNetCommand(Server, command);
+
+                NetCommand response = NetHelper.ReadNetCommand(Server);
+                if (response.Type == NetCommand.CommandType.RESPONSE && response.Response == NetCommand.ResponseType.LOGINWRONG)
+                {
+                    loggedin = false;
+                    error = "Het wachtwoord is onjuist.";
+                    return false;
+                }
+
+                loggedin = true;
+            }
+
+            
+            SendNetCommand(new NetCommand(NetCommand.RequestType.SESSIONDATA, Session));
+            Thread.Sleep(15);
+            SendNetCommand(new NetCommand(NetCommand.RequestType.USERS, Session));
+
+            Thread.Sleep(200);
+
+            return true;
+        }
+
+        public static void Disconnect()
+        {
+
+            if (Server != null && Server.Connected)
+            {
+                NetHelper.SendNetCommand(Server, new NetCommand(NetCommand.CommandType.LOGOUT, Session));
+                loggedin = false;
+                running = false;
+                Server.Close();
+                Server = null;
+            }
+        }
+
+        public static void run()
+        {
+            while (running)
+            {
+                if (loggedin && Server.Connected && Server.Available > 0)
+                {
+                    NetCommand command = NetHelper.ReadNetCommand(Server);
+                    HandleNetCommand(command);
+
+                }
+            }
+
+            if(Server != null)
+                Server.Close();
+        }
+
+        private static bool UsersBeingSent = false;
+        private static int UsersSent = 0;
+        private static int UsersLength = 0;
+
+        private static bool SessionsBeingSent = false;
+        private static int SessionsSent = 0;
+        private static int SessionsLength = 0;
+
+        private static bool ActiveSessionsBeingSent = false;
+        private static int ActiveSessionsSent = 0;
+        private static int ActiveSessionsLength = 0;
+
+        private static void HandleNetCommand(NetCommand command)
+        {
+            switch (command.Type)
+            {
+                case NetCommand.CommandType.LENGTH:
+                    switch (command.Length)
+                    {
+                        case NetCommand.LengthType.USERS:
+                            users.Clear();
+                            UsersBeingSent = true;
+                            UsersSent = 0;
+                            UsersLength = command.LengthValue;
+                            break;
+                        case NetCommand.LengthType.SESSIONS:
+                            oldSessionsData.Clear();
+                            SessionsBeingSent = true;
+                            SessionsSent = 0;
+                            SessionsLength = command.LengthValue;
+                            break;
+                        case NetCommand.LengthType.SESSIONDATA:
+                            activesessions.Clear();
+                            ActiveSessionsBeingSent = true;
+                            ActiveSessionsSent = 0;
+                            ActiveSessionsLength = command.LengthValue;
+                            break;
+                        default:
+                            throw new FormatException("Error in NetCommand: Length type is not recognised");
+                    }
+                    break;
+                case NetCommand.CommandType.ERROR:
+                    Console.WriteLine("An error occured, ignoring");
+                    break;
+                case NetCommand.CommandType.USER:
+                    if(UsersBeingSent)
+                    {
+                        users.Add(command.DisplayName, command.Password);
+                        UsersSent++;
+                        if (UsersSent >= UsersLength)
+                            UsersBeingSent = false;
+                    }
+                    break;
+                case NetCommand.CommandType.SESSIONDATA:
+                    if (ActiveSessionsBeingSent)
+                    {
+                        activesessions.Add(command.Session, command.DisplayName);
+                        ActiveSessionsSent++;
+                        if (ActiveSessionsSent >= ActiveSessionsLength)
+                            ActiveSessionsBeingSent = false;
+                    }
+                    if (SessionsBeingSent)
+                    {
+                        oldSessionsData.Add(new Tuple<string, double, int>(command.DisplayName, command.Timestamp, command.Session));
+                        SessionsSent++;
+                        if (SessionsSent >= SessionsLength)
+                            SessionsBeingSent = false;
+                    }
+                    break;
+                default:
+                    HandToClient(command);
+                    break;
+            }
+        }
+
+        private static void HandToClient(NetCommand command)
+        {
+            foreach (ClientThread cl in clients)
+            {
+                if (cl.Session == command.Session)
+                {
+                    cl.HandleCommand(command);
+                }
+            }
+        }
+
+        public static void SendNetCommand(NetCommand command)
+        {
+            if(! NetHelper.SendNetCommand(Server, command))
+            {
+                Disconnect();
+            }
+        }
+
+        private static bool IsSessionRunning(int session)
+        {
+            foreach (ClientThread cl in clients)
+            {
+                if (cl.Session == session)
+                    return true;
+            }
+
+            return false;
+        }
+
+        public static void StartNewClient(string name, int session)
+        {
+            if (IsSessionRunning(session))
+                return;
+
+            //Start new client
+            ClientThread cl = new ClientThread(name, session, false);
+            clients.Add(cl);
+
+            //Run client on new thread
+            Thread thread = new Thread(new ThreadStart(cl.run));
+            thread.IsBackground = true;
+            thread.Start();
+        }
+
+        public static void StartOldClient(string name, int session)
+        {
+            if (IsSessionRunning(session))
+                return;
+
+            SendNetCommand(new NetCommand(NetCommand.RequestType.OLDDATA, session));
+            SendNetCommand(new NetCommand(NetCommand.RequestType.CHAT, session));
+
+            //Start new client
+            ClientThread cl = new ClientThread(name, session, true);
+            clients.Add(cl);
+
+            //Run client on new thread
+            Thread thread = new Thread(new ThreadStart(cl.run));
+            thread.IsBackground = true;
+            thread.Start();
+        }
+    }
+}

+ 320 - 0
ErgometerIPR/ErgometerDoctorApplication/MainWindow.Designer.cs

@@ -0,0 +1,320 @@
+using System;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    partial class MainWindow
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.MenuPanel = new System.Windows.Forms.Panel();
+            this.BtnLogout = new System.Windows.Forms.Button();
+            this.BtnSessionHistory = new System.Windows.Forms.Button();
+            this.BtnBroadcast = new System.Windows.Forms.Button();
+            this.label2 = new System.Windows.Forms.Label();
+            this.label1 = new System.Windows.Forms.Label();
+            this.BtnClientData = new System.Windows.Forms.Button();
+            this.BtnActiveSessions = new System.Windows.Forms.Button();
+            this.LblHoofdvenster = new System.Windows.Forms.Label();
+            this.menuStrip1 = new System.Windows.Forms.MenuStrip();
+            this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+            this.panel1 = new System.Windows.Forms.Panel();
+            this.HeaderLabel = new System.Windows.Forms.Label();
+            this.panel3 = new System.Windows.Forms.Panel();
+            this.MainContainer = new System.Windows.Forms.Panel();
+            this.conActiveSessions = new ErgometerDoctorApplication.ConActiveSessions();
+            this.conClientData = new ErgometerDoctorApplication.ConClientData();
+            this.conSessionHistory = new ErgometerDoctorApplication.ConSessionHistory();
+            this.conClientBroadcast = new ErgometerDoctorApplication.ConClientBroadcast();
+            this.conPanelLogin = new ErgometerDoctorApplication.ConPanelLogin(this);
+            this.updateTimer = new Timer();
+            MainContainer.Visible = false;
+            panel1.Visible = false;
+            MenuPanel.Visible = false;
+            menuStrip1.Visible = false;
+            // 
+            // MenuPanel
+            // 
+            this.MenuPanel.BackColor = System.Drawing.SystemColors.ControlLight;
+            this.MenuPanel.Controls.Add(this.BtnLogout);
+            this.MenuPanel.Controls.Add(this.BtnSessionHistory);
+            this.MenuPanel.Controls.Add(this.BtnBroadcast);
+            this.MenuPanel.Controls.Add(this.label2);
+            this.MenuPanel.Controls.Add(this.label1);
+            this.MenuPanel.Controls.Add(this.BtnClientData);
+            this.MenuPanel.Controls.Add(this.BtnActiveSessions);
+            this.MenuPanel.Controls.Add(this.LblHoofdvenster);
+            this.MenuPanel.Dock = System.Windows.Forms.DockStyle.Left;
+            this.MenuPanel.Location = new System.Drawing.Point(0, 24);
+            this.MenuPanel.Margin = new System.Windows.Forms.Padding(0);
+            this.MenuPanel.Name = "MenuPanel";
+            this.MenuPanel.Size = new System.Drawing.Size(200, 537);
+            this.MenuPanel.TabIndex = 0;
+
+            // 
+            // BtnLogout
+            // 
+            this.BtnLogout.BackColor = System.Drawing.Color.DarkGray;
+            this.BtnLogout.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.BtnLogout.FlatAppearance.BorderSize = 0;
+            this.BtnLogout.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.BtnLogout.ForeColor = System.Drawing.Color.White;
+            this.BtnLogout.Location = new System.Drawing.Point(0, 205);
+            this.BtnLogout.Name = "BtnLogout";
+            this.BtnLogout.Size = new System.Drawing.Size(200, 35);
+            this.BtnLogout.Text = "Uitloggen";
+            this.BtnLogout.UseVisualStyleBackColor = false;
+            this.BtnLogout.Click += new System.EventHandler(this.buttonLogout_Click);
+            // 
+            // BtnSessionHistory
+            // 
+            this.BtnSessionHistory.BackColor = System.Drawing.Color.DarkGray;
+            this.BtnSessionHistory.Dock = System.Windows.Forms.DockStyle.Top;
+            this.BtnSessionHistory.FlatAppearance.BorderSize = 0;
+            this.BtnSessionHistory.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.BtnSessionHistory.ForeColor = System.Drawing.Color.White;
+            this.BtnSessionHistory.Location = new System.Drawing.Point(0, 205);
+            this.BtnSessionHistory.Name = "BtnSessionHistory";
+            this.BtnSessionHistory.Size = new System.Drawing.Size(200, 35);
+            this.BtnSessionHistory.TabIndex = 7;
+            this.BtnSessionHistory.Text = "Sessie Geschiedenis";
+            this.BtnSessionHistory.UseVisualStyleBackColor = false;
+            this.BtnSessionHistory.Click += new System.EventHandler(this.BtnSessionHistory_Click);
+            // 
+            // label2
+            // 
+            this.label2.Dock = System.Windows.Forms.DockStyle.Top;
+            this.label2.Location = new System.Drawing.Point(0, 180);
+            this.label2.Margin = new System.Windows.Forms.Padding(6, 3, 6, 3);
+            this.label2.Name = "label2";
+            this.label2.Padding = new System.Windows.Forms.Padding(5, 4, 0, 0);
+            this.label2.Size = new System.Drawing.Size(200, 25);
+            this.label2.TabIndex = 6;
+            this.label2.Text = "SESSIE BEHEER";
+            this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+            //
+            // updateTimer
+            //
+            this.updateTimer.Interval = 3000;
+            this.updateTimer.Tick += new EventHandler(this.updateTimer_tick);
+            // 
+            // label1
+            // 
+            this.label1.Dock = System.Windows.Forms.DockStyle.Top;
+            this.label1.Location = new System.Drawing.Point(0, 95);
+            this.label1.Margin = new System.Windows.Forms.Padding(6, 3, 6, 3);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(200, 50);
+            this.label1.TabIndex = 5;
+            // 
+            // BtnBroadcast
+            // 
+            this.BtnBroadcast.BackColor = System.Drawing.Color.DarkGray;
+            this.BtnBroadcast.Dock = System.Windows.Forms.DockStyle.Top;
+            this.BtnBroadcast.FlatAppearance.BorderSize = 0;
+            this.BtnBroadcast.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.BtnBroadcast.ForeColor = System.Drawing.Color.White;
+            this.BtnBroadcast.Location = new System.Drawing.Point(0, 95);
+            this.BtnBroadcast.Name = "BtnBroadcast";
+            this.BtnBroadcast.Size = new System.Drawing.Size(200, 35);
+            this.BtnBroadcast.TabIndex = 7;
+            this.BtnBroadcast.Text = "Broadcast";
+            this.BtnBroadcast.UseVisualStyleBackColor = false;
+            this.BtnBroadcast.Click += new System.EventHandler(this.BtnBroadcast_Click);
+            // 
+            // BtnClientData
+            // 
+            this.BtnClientData.BackColor = System.Drawing.Color.DarkGray;
+            this.BtnClientData.Dock = System.Windows.Forms.DockStyle.Top;
+            this.BtnClientData.FlatAppearance.BorderSize = 0;
+            this.BtnClientData.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.BtnClientData.ForeColor = System.Drawing.Color.White;
+            this.BtnClientData.Location = new System.Drawing.Point(0, 60);
+            this.BtnClientData.Name = "BtnClientData";
+            this.BtnClientData.Size = new System.Drawing.Size(200, 35);
+            this.BtnClientData.TabIndex = 4;
+            this.BtnClientData.Text = "Clientenbestand";
+            this.BtnClientData.UseVisualStyleBackColor = false;
+            this.BtnClientData.Click += new System.EventHandler(this.BtnClientData_Click);
+            // 
+            // BtnActiveSessions
+            // 
+            this.BtnActiveSessions.BackColor = System.Drawing.Color.DarkGray;
+            this.BtnActiveSessions.Dock = System.Windows.Forms.DockStyle.Top;
+            this.BtnActiveSessions.FlatAppearance.BorderSize = 0;
+            this.BtnActiveSessions.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.BtnActiveSessions.ForeColor = System.Drawing.Color.White;
+            this.BtnActiveSessions.Location = new System.Drawing.Point(0, 25);
+            this.BtnActiveSessions.Name = "BtnActiveSessions";
+            this.BtnActiveSessions.Size = new System.Drawing.Size(200, 35);
+            this.BtnActiveSessions.TabIndex = 3;
+            this.BtnActiveSessions.Text = "Actieve Sessies";
+            this.BtnActiveSessions.UseVisualStyleBackColor = false;
+            this.BtnActiveSessions.Click += new System.EventHandler(this.BtnActiveSessions_Click);
+            // 
+            // LblHoofdvenster
+            // 
+            this.LblHoofdvenster.Dock = System.Windows.Forms.DockStyle.Top;
+            this.LblHoofdvenster.Location = new System.Drawing.Point(0, 0);
+            this.LblHoofdvenster.Margin = new System.Windows.Forms.Padding(6, 3, 6, 3);
+            this.LblHoofdvenster.Name = "LblHoofdvenster";
+            this.LblHoofdvenster.Padding = new System.Windows.Forms.Padding(5, 4, 0, 0);
+            this.LblHoofdvenster.Size = new System.Drawing.Size(200, 25);
+            this.LblHoofdvenster.TabIndex = 0;
+            this.LblHoofdvenster.Text = "HOOFDVENSTER";
+            this.LblHoofdvenster.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+            // 
+            // menuStrip1
+            // 
+            this.menuStrip1.BackColor = System.Drawing.Color.DimGray;
+            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.fileToolStripMenuItem,
+            this.editToolStripMenuItem,
+            this.viewToolStripMenuItem});
+            this.menuStrip1.Location = new System.Drawing.Point(0, 0);
+            this.menuStrip1.Name = "menuStrip1";
+            this.menuStrip1.Size = new System.Drawing.Size(784, 24);
+            this.menuStrip1.TabIndex = 1;
+            this.menuStrip1.Text = "menuStrip1";
+            // 
+            // fileToolStripMenuItem
+            // 
+            this.fileToolStripMenuItem.ForeColor = System.Drawing.Color.White;
+            this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
+            this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
+            this.fileToolStripMenuItem.Text = "File";
+            // 
+            // editToolStripMenuItem
+            // 
+            this.editToolStripMenuItem.ForeColor = System.Drawing.Color.White;
+            this.editToolStripMenuItem.Name = "editToolStripMenuItem";
+            this.editToolStripMenuItem.Size = new System.Drawing.Size(39, 20);
+            this.editToolStripMenuItem.Text = "Edit";
+            // 
+            // viewToolStripMenuItem
+            // 
+            this.viewToolStripMenuItem.ForeColor = System.Drawing.Color.White;
+            this.viewToolStripMenuItem.Name = "viewToolStripMenuItem";
+            this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
+            this.viewToolStripMenuItem.Text = "View";
+            // 
+            // panel1
+            // 
+            this.panel1.BackColor = System.Drawing.Color.White;
+            this.panel1.Controls.Add(this.HeaderLabel);
+            this.panel1.Controls.Add(this.panel3);
+            this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
+            this.panel1.Location = new System.Drawing.Point(200, 24);
+            this.panel1.Name = "panel1";
+            this.panel1.Size = new System.Drawing.Size(584, 78);
+            this.panel1.TabIndex = 2;
+            // 
+            // HeaderLabel
+            // 
+            this.HeaderLabel.Dock = System.Windows.Forms.DockStyle.Top;
+            this.HeaderLabel.Font = new System.Drawing.Font("Segoe UI Semibold", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.HeaderLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
+            this.HeaderLabel.Location = new System.Drawing.Point(0, 0);
+            this.HeaderLabel.Name = "HeaderLabel";
+            this.HeaderLabel.Padding = new System.Windows.Forms.Padding(8, 12, 0, 0);
+            this.HeaderLabel.Size = new System.Drawing.Size(584, 50);
+            this.HeaderLabel.TabIndex = 1;
+            this.HeaderLabel.Text = "Actieve Sessies";
+            // 
+            // panel3
+            // 
+            this.panel3.BackColor = System.Drawing.Color.Silver;
+            this.panel3.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.panel3.ForeColor = System.Drawing.Color.Black;
+            this.panel3.Location = new System.Drawing.Point(0, 74);
+            this.panel3.Name = "panel3";
+            this.panel3.Size = new System.Drawing.Size(584, 4);
+            this.panel3.TabIndex = 0;
+            // 
+            // MainContainer
+            // 
+            this.MainContainer.Controls.Add(this.conActiveSessions);
+            this.MainContainer.Controls.Add(this.conClientData);
+            this.MainContainer.Controls.Add(this.conSessionHistory);
+            this.MainContainer.Controls.Add(this.conClientBroadcast);
+            this.MainContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.MainContainer.Location = new System.Drawing.Point(200, 102);
+            this.MainContainer.Name = "MainContainer";
+            this.MainContainer.Size = new System.Drawing.Size(584, 459);
+            this.MainContainer.TabIndex = 3;
+            // 
+            // MainWindow
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(700, 500);
+            this.MinimumSize = new System.Drawing.Size(650, 550);
+            this.Controls.Add(this.MainContainer);
+            this.Controls.Add(this.panel1);
+            this.Controls.Add(this.MenuPanel);
+            this.Controls.Add(this.menuStrip1);
+            this.Controls.Add(this.conPanelLogin);
+
+            this.MainMenuStrip = this.menuStrip1;
+            this.Name = "MainWindow";
+            this.Text = "Dokter applicatie";
+            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
+
+        }
+
+
+        #endregion
+
+        private Panel MenuPanel;
+        private Label LblHoofdvenster;
+        private MenuStrip menuStrip1;
+        private ToolStripMenuItem fileToolStripMenuItem;
+        private ToolStripMenuItem editToolStripMenuItem;
+        private ToolStripMenuItem viewToolStripMenuItem;
+        private Button BtnActiveSessions;
+        private Button BtnBroadcast;
+        private Button BtnLogout;
+        private Button BtnSessionHistory;
+        private Button BtnClientData;
+        private Label label2;
+        private Label label1;
+        private Panel panel1;
+        private Panel panel3;
+        public Label HeaderLabel;
+        public Timer updateTimer;
+        public Panel MainContainer;
+        public ConActiveSessions conActiveSessions;
+        public ConSessionHistory conSessionHistory;
+        public ConClientData conClientData;
+        public ConPanelLogin conPanelLogin;
+        public ConClientBroadcast conClientBroadcast;
+
+    }
+}
+

+ 147 - 0
ErgometerIPR/ErgometerDoctorApplication/MainWindow.cs

@@ -0,0 +1,147 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    public partial class MainWindow : Form
+    {
+        private int request;
+
+        public MainWindow()
+        {
+            InitializeComponent();
+            conPanelLogin.BringToFront();
+            request = 2;
+            updateTimer.Start();
+            
+        }
+
+        private void BtnActiveSessions_Click(object sender, EventArgs e)
+        {
+            this.HeaderLabel.Text = "Actieve Sessies";
+
+            if(MainClient.activesessions.Count > 0)
+            {
+                conActiveSessions.labelActiveSessions.Text = "";
+                conActiveSessions.updateActiveSessions(MainClient.activesessions);
+            }
+            else
+            {
+                conActiveSessions.updateActiveSessions(MainClient.activesessions);
+                conActiveSessions.labelActiveSessions.Text = "Er zijn geen actieve sessies.";
+            }
+
+            conActiveSessions.BringToFront();
+        }
+
+        private void BtnClientData_Click(object sender, EventArgs e)
+        {
+            this.HeaderLabel.Text = "Clientenbestand";
+            
+
+            if (MainClient.users.Count > 0)
+            {
+                conClientData.updateUsers(MainClient.users);
+            }
+
+            conClientData.BringToFront();
+        }
+
+        private void BtnBroadcast_Click(object sender, EventArgs e)
+        {
+            this.HeaderLabel.Text = "Broadcast";
+            conClientBroadcast.BringToFront();
+        }
+
+        private void BtnSessionHistory_Click(object sender, EventArgs e)
+        {
+            this.HeaderLabel.Text = "Sessie geschiedenis";
+
+            if (MainClient.oldSessionsData.Count > 0)
+            {
+                conSessionHistory.labelSessionHistory.Text = "";
+                conSessionHistory.updateHistory(MainClient.oldSessionsData);
+            }
+            else
+            {
+                conSessionHistory.updateHistory(MainClient.oldSessionsData);
+                conSessionHistory.labelSessionHistory.Text = "Er zijn geen oude sessies.";
+            }
+
+            conSessionHistory.BringToFront();
+        }
+        public void validateLogin()
+        {
+            string error = "";
+            bool connect = MainClient.Connect(conPanelLogin.textBoxPassword.Text, out error);
+
+            if (connect)
+            {
+                conPanelLogin.textBoxPassword.Text = "";
+                conPanelLogin.labelLoginInfo.Text = "";
+
+                if (MainClient.activesessions.Count > 0)
+                {
+                    conActiveSessions.labelActiveSessions.Text = "";
+                    conActiveSessions.updateActiveSessions(MainClient.activesessions);
+                }
+
+                showDashboard();
+            }
+            else
+            {
+                conPanelLogin.labelLoginInfo.Text = error;
+                showLoginScreen();
+            }
+        }
+
+        private void buttonLogout_Click(object sender, EventArgs e)
+        {
+            MainClient.Disconnect();
+            showLoginScreen();
+        }
+
+        private void showDashboard()
+        {
+            conPanelLogin.Visible = false;
+            MainContainer.Visible = true;
+            panel1.Visible = true;
+            MenuPanel.Visible = true;
+            menuStrip1.Visible = true;
+        }
+
+        private void showLoginScreen()
+        {
+            MainContainer.Visible = false;
+            panel1.Visible = false;
+            MenuPanel.Visible = false;
+            menuStrip1.Visible = false;
+            conPanelLogin.Visible = true;
+            conPanelLogin.BringToFront();
+        }
+
+        private void updateTimer_tick(object sender, EventArgs e)
+        {
+            if (request == 0)
+                MainClient.SendNetCommand(new NetCommand(NetCommand.RequestType.USERS, MainClient.Session));
+            else if (request == 1)
+                MainClient.SendNetCommand(new NetCommand(NetCommand.RequestType.SESSIONDATA, MainClient.Session));
+            else if (request == 2)
+                MainClient.SendNetCommand(new NetCommand(NetCommand.RequestType.ALLSESSIONS, MainClient.Session));
+
+            request ++;
+            if (request > 2)
+            {
+                request = 0;
+            }
+        }
+    }
+}

+ 126 - 0
ErgometerIPR/ErgometerDoctorApplication/MainWindow.resx

@@ -0,0 +1,126 @@
+<?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>
+  <metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>25</value>
+  </metadata>
+</root>

+ 22 - 0
ErgometerIPR/ErgometerDoctorApplication/Program.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new MainWindow());
+        }
+    }
+}

+ 36 - 0
ErgometerIPR/ErgometerDoctorApplication/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ErgometerDoctorApplication")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ErgometerDoctorApplication")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e543ff58-161a-4a41-aae7-651327834362")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 73 - 0
ErgometerIPR/ErgometerDoctorApplication/Properties/Resources.Designer.cs

@@ -0,0 +1,73 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.0
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace ErgometerDoctorApplication.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", "4.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("ErgometerDoctorApplication.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.Drawing.Bitmap.
+        /// </summary>
+        internal static System.Drawing.Bitmap imageDoctor {
+            get {
+                object obj = ResourceManager.GetObject("imageDoctor", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+    }
+}

+ 124 - 0
ErgometerIPR/ErgometerDoctorApplication/Properties/Resources.resx

@@ -0,0 +1,124 @@
+<?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="imageDoctor" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\doctorImage.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+</root>

+ 30 - 0
ErgometerIPR/ErgometerDoctorApplication/Properties/Settings.Designer.cs

@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <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 ErgometerDoctorApplication.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+    {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default
+        {
+            get
+            {
+                return defaultInstance;
+            }
+        }
+    }
+}

+ 7 - 0
ErgometerIPR/ErgometerDoctorApplication/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

BIN
ErgometerIPR/ErgometerDoctorApplication/Resources/doctorImage.png


+ 91 - 0
ErgometerIPR/ErgometerDoctorApplication/SessionPanel.cs

@@ -0,0 +1,91 @@
+using System.Windows.Forms;
+
+namespace ErgometerDoctorApplication
+{
+    class SessionPanel : Panel
+    {
+        private int Session;
+        private string name;
+        private bool IsNew;
+        private double timestamp;
+
+        public SessionPanel(int session, string name, bool isNew,double timestamp) : base()
+        {
+            this.timestamp = timestamp;
+            Session = session;
+            this.name = name;
+            IsNew = isNew;
+
+            this.Location = new System.Drawing.Point(0, 0);
+            this.Size = new System.Drawing.Size(180, 100);
+            this.BackColor = System.Drawing.Color.DarkGray;
+
+            this.Click += SessionPanel_Click;
+            this.MouseEnter += SessionPanel_MouseEnter;
+            this.MouseLeave += SessionPanel_MouseLeave;
+            this.Cursor = Cursors.Hand;
+
+            this.labelTimestamp = new Label();
+            this.labelName = new System.Windows.Forms.Label();
+
+            // 
+            // labelActiveSessions
+            // 
+            this.labelName.Anchor = System.Windows.Forms.AnchorStyles.None;
+            this.labelName.AutoSize = true;
+            this.labelName.Font = new System.Drawing.Font("Segoe UI Semibold", 18F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelName.Location = new System.Drawing.Point(10, 10);
+            this.labelName.ForeColor = System.Drawing.Color.White;
+            this.labelName.Name = "labelActiveSessions";
+            this.labelName.Size = new System.Drawing.Size(103, 21);
+            this.labelName.TabIndex = 3;
+            this.labelName.Text = name;
+            this.labelName.Click += SessionPanel_Click;
+            this.labelName.MouseEnter += SessionPanel_MouseEnter;
+            this.labelName.MouseLeave += SessionPanel_MouseLeave;
+            this.labelName.Cursor = Cursors.Hand;
+
+            this.labelTimestamp.Name = "labelTimeStamp";
+            this.labelTimestamp.Anchor = AnchorStyles.None;
+            this.labelTimestamp.Text = ErgometerLibrary.Helper.MillisecondsToTime(timestamp);
+            this.labelTimestamp.Location = new System.Drawing.Point(10, 40);
+            this.labelTimestamp.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.labelTimestamp.ForeColor = System.Drawing.Color.White;
+            this.labelTimestamp.Size = new System.Drawing.Size(103, 21);
+            this.labelTimestamp.Click += SessionPanel_Click;
+            this.labelTimestamp.MouseEnter += SessionPanel_MouseEnter;
+            this.labelTimestamp.MouseLeave += SessionPanel_MouseLeave;
+
+            if (isNew)
+                labelTimestamp.Visible = false;
+
+            this.Controls.Add(labelName);
+            this.Controls.Add(labelTimestamp);
+        }
+
+        private void SessionPanel_MouseEnter(object sender, System.EventArgs e)
+        {
+            this.BackColor = System.Drawing.Color.Gray;
+            this.labelName.ForeColor = System.Drawing.Color.WhiteSmoke;
+            labelTimestamp.ForeColor = System.Drawing.Color.WhiteSmoke;
+        }
+
+        private void SessionPanel_MouseLeave(object sender, System.EventArgs e)
+        {
+            this.BackColor = System.Drawing.Color.DarkGray;
+            this.labelName.ForeColor = System.Drawing.Color.White;
+            this.labelTimestamp.ForeColor = System.Drawing.Color.White;
+        }
+
+        private void SessionPanel_Click(object sender, System.EventArgs e)
+        {
+            if(IsNew)
+                MainClient.StartNewClient(name, Session);
+            else
+                MainClient.StartOldClient(name, Session);
+        }
+
+        public System.Windows.Forms.Label labelName;
+        public Label labelTimestamp;
+    }
+}

+ 22 - 0
ErgometerIPR/ErgometerIPR.sln

@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.23107.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErgometerIPR", "ErgometerIPR\ErgometerIPR.csproj", "{2E76E1E6-CBA7-46EA-858A-223B13F193A8}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2E76E1E6-CBA7-46EA-858A-223B13F193A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2E76E1E6-CBA7-46EA-858A-223B13F193A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2E76E1E6-CBA7-46EA-858A-223B13F193A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2E76E1E6-CBA7-46EA-858A-223B13F193A8}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 162 - 0
ErgometerIPR/ErgometerLibrary/AESEncrypt.cs

@@ -0,0 +1,162 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ErgometerLibrary
+{
+    static class AESEncrypt
+    {
+        // Change these keys
+        private static byte[] Key = { 47, 20, 192, 222, 214, 221, 193, 151, 182, 182, 20, 246, 80, 235, 182, 216, 116, 141, 188, 191, 13, 159, 1, 137, 151, 150, 29, 171, 240, 21, 251, 252  };
+        private static byte[] Vector = { 147, 16, 78, 223, 97, 189, 43, 197, 244, 102, 242, 123, 184, 101, 75, 203 };
+
+
+        private static ICryptoTransform EncryptorTransform, DecryptorTransform;
+        private static System.Text.UTF8Encoding UTFEncoder;
+
+        static AESEncrypt()
+        {
+            //This is our encryption method
+            RijndaelManaged rm = new RijndaelManaged();
+
+            //Create an encryptor and a decryptor using our encryption method, key, and vector.
+            EncryptorTransform = rm.CreateEncryptor(Key, Vector);
+            DecryptorTransform = rm.CreateDecryptor(Key, Vector);
+
+            //Used to translate bytes to text and vice versa
+            UTFEncoder = new System.Text.UTF8Encoding();
+        }
+
+        /// -------------- Two Utility Methods (not used but may be useful) -----------
+        /// Generates an encryption key.
+        static public byte[] GenerateEncryptionKey()
+        {
+            //Generate a Key.
+            RijndaelManaged rm = new RijndaelManaged();
+            rm.GenerateKey();
+            return rm.Key;
+        }
+
+        /// Generates a unique encryption vector
+        static public byte[] GenerateEncryptionVector()
+        {
+            //Generate a Vector
+            RijndaelManaged rm = new RijndaelManaged();
+            rm.GenerateIV();
+            return rm.IV;
+        }
+
+
+        /// ----------- The commonly used methods ------------------------------    
+        /// Encrypt some text and return a string suitable for passing in a URL.
+        public static string EncryptToString(string TextValue)
+        {
+            return ByteArrToString(Encrypt(TextValue));
+        }
+
+        /// Encrypt some text and return an encrypted byte array.
+        public static byte[] Encrypt(string TextValue)
+        {
+            //Translates our text value into a byte array.
+            Byte[] bytes = UTFEncoder.GetBytes(TextValue);
+
+            //Used to stream the data in and out of the CryptoStream.
+            MemoryStream memoryStream = new MemoryStream();
+
+            /*
+             * We will have to write the unencrypted bytes to the stream,
+             * then read the encrypted result back from the stream.
+             */
+            #region Write the decrypted value to the encryption stream
+            CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write);
+            cs.Write(bytes, 0, bytes.Length);
+            cs.FlushFinalBlock();
+            #endregion
+
+            #region Read encrypted value back out of the stream
+            memoryStream.Position = 0;
+            byte[] encrypted = new byte[memoryStream.Length];
+            memoryStream.Read(encrypted, 0, encrypted.Length);
+            #endregion
+
+            //Clean up.
+            cs.Close();
+            memoryStream.Close();
+
+            return encrypted;
+        }
+
+        /// The other side: Decryption methods
+        public static string DecryptString(string EncryptedString)
+        {
+            return Decrypt(StrToByteArray(EncryptedString));
+        }
+
+        /// Decryption when working with byte arrays.    
+        public static string Decrypt(byte[] EncryptedValue)
+        {
+            #region Write the encrypted value to the decryption stream
+            MemoryStream encryptedStream = new MemoryStream();
+            CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write);
+            decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length);
+            decryptStream.FlushFinalBlock();
+            #endregion
+
+            #region Read the decrypted value from the stream.
+            encryptedStream.Position = 0;
+            Byte[] decryptedBytes = new Byte[encryptedStream.Length];
+            encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
+            encryptedStream.Close();
+            #endregion
+            return UTFEncoder.GetString(decryptedBytes);
+        }
+
+        /// Convert a string to a byte array.  NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so).
+        //      System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
+        //      return encoding.GetBytes(str);
+        // However, this results in character values that cannot be passed in a URL.  So, instead, I just
+        // lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100).
+        public static byte[] StrToByteArray(string str)
+        {
+            if (str.Length == 0)
+                throw new Exception("Invalid string value in StrToByteArray");
+
+            byte val;
+            byte[] byteArr = new byte[str.Length / 3];
+            int i = 0;
+            int j = 0;
+            do
+            {
+                val = byte.Parse(str.Substring(i, 3));
+                byteArr[j++] = val;
+                i += 3;
+            }
+            while (i < str.Length);
+            return byteArr;
+        }
+
+        // Same comment as above.  Normally the conversion would use an ASCII encoding in the other direction:
+        //      System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
+        //      return enc.GetString(byteArr);    
+        public static string ByteArrToString(byte[] byteArr)
+        {
+            byte val;
+            string tempStr = "";
+            for (int i = 0; i <= byteArr.GetUpperBound(0); i++)
+            {
+                val = byteArr[i];
+                if (val < (byte)10)
+                    tempStr += "00" + val.ToString();
+                else if (val < (byte)100)
+                    tempStr += "0" + val.ToString();
+                else
+                    tempStr += val.ToString();
+            }
+            return tempStr;
+        }
+    }
+}

+ 63 - 0
ErgometerIPR/ErgometerLibrary/Chat/ChatItem.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ErgometerLibrary.Chat
+{
+    public class ChatItem : Panel
+    {
+        private Label messageLabel, timeLabel;
+
+        public ChatItem(ChatMessage chat) : base()
+        {
+            this.messageLabel = new Label();
+            this.timeLabel = new Label();
+
+            this.AutoSize = true;
+            this.setAppearance(chat.IsDoctor);
+            this.Controls.Add(this.messageLabel);
+            this.Controls.Add(this.timeLabel);
+            this.MinimumSize = new System.Drawing.Size(150, 60);
+            this.Name = "messageContainer";
+            this.Padding = new System.Windows.Forms.Padding(6);
+
+            //
+            // Message Label
+            // 
+            this.messageLabel.AutoSize = true;
+            this.messageLabel.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.messageLabel.Font = new System.Drawing.Font("Segoe UI Semibold", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.messageLabel.Location = new System.Drawing.Point(6, 6);
+            this.messageLabel.MaximumSize = new System.Drawing.Size(250, 0);
+            this.messageLabel.Size = new System.Drawing.Size(121, 20);
+            this.messageLabel.Text = chat.Message.Replace("\n", "");
+            // 
+            // Time Label
+            // 
+            this.timeLabel.AutoSize = true;
+            this.timeLabel.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.timeLabel.Font = new System.Drawing.Font("Segoe UI Semilight", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.timeLabel.Location = new System.Drawing.Point(6, 26);
+            this.timeLabel.Margin = new System.Windows.Forms.Padding(6);
+            this.timeLabel.Size = new System.Drawing.Size(32, 13);
+            this.timeLabel.Text = Helper.MillisecondsToTime(chat.TimeStamp);
+        }
+
+        private void setAppearance(bool isDoctor)
+        {
+            if (isDoctor)
+            {
+                this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))));
+                this.Dock = DockStyle.Right;
+            }
+            else
+            {
+                this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
+                this.Dock = DockStyle.Left;
+            }
+        }
+    }
+}

+ 23 - 0
ErgometerIPR/ErgometerLibrary/ChatMessage.cs

@@ -0,0 +1,23 @@
+namespace ErgometerLibrary
+{
+    public class ChatMessage
+    {
+        public string Message { get; }
+        public string Name { get; }
+        public double TimeStamp { get; set;}
+        public bool IsDoctor { get; set; }
+
+        public ChatMessage(string name, string message, bool isDoctor)
+        {
+            Name = name;
+            Message = message;
+            TimeStamp = Helper.Now;
+            IsDoctor = isDoctor;
+        }
+
+        public override string ToString()
+        {
+            return $"[{Name}] <{TimeStamp}> - {Message}";
+        }
+    }
+}

+ 77 - 0
ErgometerIPR/ErgometerLibrary/ComPort.cs

@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.IO.Ports;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ErgometerLibrary
+{
+    public class ComPort
+    {
+        private SerialPort comPort;
+
+        public ComPort()
+        {
+            comPort = null;
+        }
+
+        public Boolean Connect(string port)
+        {
+            comPort = new SerialPort();
+            comPort.PortName = port;
+            comPort.DataBits = 8;
+            comPort.Parity = Parity.None;
+            comPort.StopBits = StopBits.One;
+            comPort.BaudRate = 9600;
+            comPort.ReadTimeout = 1500;
+            try {
+                comPort.Open();
+            }
+            catch(Exception e)
+            {
+                return false;
+            }
+
+            return comPort.IsOpen;
+        }
+
+        public Boolean Disconnect()
+        {
+            comPort.Close();
+            return !comPort.IsOpen;
+        }
+
+        public Boolean IsOpen()
+        {
+            if (comPort != null)
+                return comPort.IsOpen;
+            else
+                return false;
+        }
+
+        public void Write(string input)
+        {
+            if (IsOpen())
+            {
+                comPort.WriteLine(input);
+            }
+        }
+
+        public string Read()
+        {
+            if (IsOpen())
+            {
+                try {
+                    return comPort.ReadLine();
+                }
+                catch(TimeoutException e)
+                {
+                    return "err";
+                }
+            }
+
+            return "";
+        }
+    }
+}

+ 72 - 0
ErgometerIPR/ErgometerLibrary/ErgometerLibrary.csproj

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{CC20FF4E-8751-42A1-A32B-0E5B22452CAC}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ErgometerLibrary</RootNamespace>
+    <AssemblyName>ErgometerLibrary</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AESEncrypt.cs" />
+    <Compile Include="ChatMessage.cs" />
+    <Compile Include="Chat\ChatItem.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Helper.cs" />
+    <Compile Include="NetCommand.cs" />
+    <Compile Include="ComPort.cs" />
+    <Compile Include="Meting.cs" />
+    <Compile Include="NetHelper.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 32 - 0
ErgometerIPR/ErgometerLibrary/Helper.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ErgometerLibrary
+{
+    public class Helper
+    {
+        public static double Now { get { return (DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; } }
+        
+        public static string MillisecondsToTime(double millis)
+        {
+            DateTime time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            string timestr = time.AddMilliseconds(millis) + "";
+            return timestr;
+        }
+
+        public static string Base64Encode(string plainText)
+        {
+            var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
+            return System.Convert.ToBase64String(plainTextBytes);
+        }
+
+        public static string Base64Decode(string base64EncodedData)
+        {
+            var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
+            return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
+        }
+    }
+}

+ 103 - 0
ErgometerIPR/ErgometerLibrary/Meting.cs

@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ErgometerLibrary
+{
+    public class Meting
+    {
+        public int HeartBeat { get; set; }
+        public int RPM { get; set; }
+        public double Speed { get; set; }
+        public double Distance { get; set; }
+        public int Power { get; set; }
+        public int Energy { get; set; }
+        public int Seconds { get; set; }
+        public int ActualPower { get; set; }
+        public double TimeStamp { get; }
+
+        public Meting(int heartbeat, int rpm, double speed, double distance, int power, int energy, int seconds, int actualpower, double timestamp)
+        {
+            HeartBeat = heartbeat;
+            RPM = rpm;
+            Speed = speed;
+            Distance = distance;
+            Power = power;
+            Energy = energy;
+            Seconds = seconds;
+            ActualPower = actualpower;
+            TimeStamp = timestamp;
+        }
+
+        public override string ToString()
+        {
+            string temp = "";
+            temp += "Heartbeat: " + HeartBeat + "\n";
+            temp += "RPM: " + RPM + "\n";
+            temp += "Speed: " + Speed + "\n";
+            temp += "Distance: " + Distance + "\n";
+            temp += "Power: " + Power + "\n";
+            temp += "Energy: " + Energy + "\n";
+            temp += "Seconds: " + Seconds + "\n";
+            temp += "ActualPower: " + ActualPower + "\n";
+            return temp;
+        }
+
+        public string ToCommand()
+        {
+            string temp = "";
+            temp += HeartBeat + "»";
+            temp += RPM + "»";
+            temp += Speed + "»";
+            temp += Distance + "»";
+            temp += Power + "»";
+            temp += Energy + "»";
+            temp += Seconds + "»";
+            temp += ActualPower + "»";
+            temp += TimeStamp;
+            return temp;
+        }
+
+        public static Meting Parse(string input)
+        {
+            return Parse(input, '\t');
+        }
+
+        public static Meting Parse(string input, char delimiter)
+        {
+            string[] status = input.Split(delimiter);
+            if (status.Length != 8 && status.Length != 9)
+            {
+                throw new FormatException("Error in Meting: Arguments do not match");
+            }
+            int heartbeat = int.Parse(status[0]);
+            int rpm = int.Parse(status[1]);
+            double speed = double.Parse(status[2]) / 10;
+            double distance = double.Parse(status[3]) / 10;
+            int power = int.Parse(status[4]);
+            int energy = int.Parse(status[5]);
+            int actualpower = int.Parse(status[7]);
+
+            double timestamp = 0;
+            if (status.Length == 9)
+                timestamp = double.Parse(status[8]);
+            else
+                timestamp = Helper.Now;
+
+            string[] temp = status[6].Split(':');
+            int seconds = 0;
+            if (temp.Length == 2)
+            {
+                seconds = (int.Parse(temp[0]) * 60) + (int.Parse(temp[1]));
+            }
+            else
+            {
+                seconds = int.Parse(status[6]);
+            }
+
+            return new Meting(heartbeat, rpm, speed, distance, power, energy, seconds, actualpower,timestamp);
+        }
+    }
+}

+ 424 - 0
ErgometerIPR/ErgometerLibrary/NetCommand.cs

@@ -0,0 +1,424 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Win32;
+
+namespace ErgometerLibrary
+{
+    public class NetCommand
+    {
+        public enum CommandType { LOGIN, DATA, CHAT, LOGOUT, SESSION, VALUESET, USER, RESPONSE, REQUEST, LENGTH, SESSIONDATA, ERROR, BROADCAST }
+        public enum RequestType { USERS, ALLSESSIONS, OLDDATA, SESSIONDATA, CHAT }
+        public enum ResponseType { LOGINOK, LOGINWRONG, ERROR, NOTLOGGEDIN }
+        public enum ValueType { TIME, POWER, ENERGY, DISTANCE }
+        public enum LengthType { USERS, SESSIONS, SESSIONDATA, DATA }
+
+        public double Timestamp { get; set; }
+        public int Session { get; set; }
+        public CommandType Type { get; set; }
+        public ResponseType Response { get; set; }
+        public ValueType Value { get; set; }
+        public RequestType Request { get; set; }
+        public LengthType Length { get; set; }
+        public int SetValue { get; set; }
+        public string DisplayName { get; set; }
+        public bool IsDoctor { get; set; }
+        public string Password { get; set; }
+        public string ChatMessage { get; set; }
+        public Meting Meting { get; set; }
+        public int LengthValue { get; set; }
+
+        //SESSION
+        public NetCommand(int session)
+        {
+            Type = CommandType.SESSION;
+            Session = session;
+            Timestamp = Helper.Now;
+        }
+
+        //SESSIONDATA
+        public NetCommand(string name, double timestamp, int session)
+        {
+            Type = CommandType.SESSIONDATA;
+            Session = session;
+            Timestamp = timestamp;
+            DisplayName = name;
+        }
+
+        //RESPONSE
+        public NetCommand(ResponseType response, int session)
+        {
+            Type = CommandType.RESPONSE;
+            Session = session;
+            Timestamp = Helper.Now;
+            Response = response;
+        }
+
+        //Length
+        public NetCommand(LengthType lengthtype, int length, int session)
+        {
+            Type = CommandType.LENGTH;
+            Length = lengthtype;
+            Session = session;
+            Timestamp = Helper.Now;
+            LengthValue = length;
+        }
+
+        //REQUEST
+        public NetCommand(RequestType request, int session)
+        {
+            Type = CommandType.REQUEST;
+            Session = session;
+            Timestamp = Helper.Now;
+            Request = request;
+        }
+
+        //STANDARD
+        public NetCommand(CommandType commandtype, int session)
+        {
+            Type = commandtype;
+            Session = session;
+            Timestamp = Helper.Now;
+        }
+
+        //METING
+        public NetCommand(Meting m, int session)
+        {
+            Type = CommandType.DATA;
+            Session = session;
+            Timestamp = Helper.Now;
+
+            Meting = m;
+        }
+
+        //CHAT
+        public NetCommand(string chat, bool isDoctor, int session)
+        {
+            Type = CommandType.CHAT;
+            Session = session;
+            IsDoctor = isDoctor;
+            Timestamp = Helper.Now;
+
+            ChatMessage = chat.Replace("\n", "");
+        }
+
+        //BROADCAST
+        public NetCommand(string broadcast, int session)
+        {
+            Type = CommandType.BROADCAST;
+            Session = session;
+            Timestamp = Helper.Now;
+
+            ChatMessage = broadcast.Replace("\n", "");
+        }
+
+        //SETVALUE
+        public NetCommand(ValueType value, int val, int session)
+        {
+            Type = CommandType.VALUESET;
+            Session = session;
+            Value = value;
+            SetValue = val;
+        }
+
+        //USER
+        public NetCommand(string username, string password, int session)
+        {
+            Type = CommandType.USER;
+            Session = session;
+            DisplayName = username;
+            Password = password;
+        }
+
+        //LOGIN
+        public NetCommand(string name, bool doctor, string password, int session)
+        {
+            Type = CommandType.LOGIN;
+            Session = session;
+            Timestamp = Helper.Now;
+
+            DisplayName = name;
+            IsDoctor = doctor;
+            Password = password;
+        }
+
+        public static NetCommand Parse(string command)
+        {
+            string[] com = command.Split('»');
+
+            int comType = 0;
+            try
+            {
+                comType = int.Parse(com[0]);
+            }
+            catch(Exception e)
+            {
+                return new NetCommand(CommandType.ERROR, 0);
+            }
+
+            int session = 0;
+            if (com[1].StartsWith("ses"))
+                session = int.Parse(com[1].Substring(3));
+            else
+                throw new FormatException("Error in NetCommand: " + com[1] + " is not a valid session.");
+
+            string[] args = new string[com.Length - 2];
+            for (int i = 2; i < com.Length; i++)
+            {
+                args[i - 2] = com[i];
+            }
+
+            switch (comType)
+            {
+                case 1:
+                    return ParseLoginRequest(session, args);
+                case 2:
+                    return ParseData(session, args);
+                case 3:
+                    return ParseChatMessage(session, args);
+                case 4:
+                    return ParseLogoutRequest(session, args);
+                case 5:
+                    return ParseSession(session);
+                case 6:
+                    return ParseResponse(session, args);
+                case 7:
+                    return ParseValue(session, args);
+                case 8:
+                    return ParseUser(session, args);
+                case 9:
+                    return ParseRequest(session, args);
+                case 10:
+                    return ParseLength(session, args);
+                case 11:
+                    return ParseSessionData(session, args);
+                case 12:
+                    return ParseBroadcast(session, args);
+                default:
+                    throw new FormatException("Error in NetCommand: " + comType + " is not a valid command type.");
+            }
+        }
+
+        private static NetCommand ParseBroadcast(int session, string[] args)
+        {
+            if (args.Length != 1)
+                throw new MissingFieldException("Error in NetCommand: Broadcast Message is missing arguments");
+
+            NetCommand temp = new NetCommand(args[0], session);
+
+            return temp;
+        }
+
+        private static NetCommand ParseSessionData(int session, string[] args)
+        {
+            if (args.Length != 2)
+                throw new MissingFieldException("Error in NetCommand: Session Data is missing arguments");
+
+            NetCommand temp = new NetCommand(args[0], double.Parse(args[1]), session);
+
+            return temp;
+        }
+
+        private static NetCommand ParseLength(int session, string[] args)
+        {
+            if (args.Length != 2)
+                throw new MissingFieldException("Error in NetCommand: Length is missing arguments");
+
+            switch (args[0])
+            {
+                case "users":
+                    return new NetCommand(LengthType.USERS, int.Parse(args[1]), session);
+                case "sessiondata":
+                    return new NetCommand(LengthType.SESSIONDATA, int.Parse(args[1]), session);
+                case "sessions":
+                    return new NetCommand(LengthType.SESSIONS, int.Parse(args[1]), session);
+                case "data":
+                    return new NetCommand(LengthType.DATA, int.Parse(args[1]), session);
+                default:
+                    throw new FormatException("Error in NetCommand: Length type not recognised");
+            }
+        }
+
+        private static NetCommand ParseRequest(int session, string[] args)
+        {
+            if (args.Length != 1)
+                throw new MissingFieldException("Error in NetCommand: Request is missing arguments");
+
+            switch (args[0])
+            {
+                case "users":
+                    return new NetCommand(RequestType.USERS, session);
+                case "allsessions":
+                    return new NetCommand(RequestType.ALLSESSIONS, session);
+                case "olddata":
+                    return new NetCommand(RequestType.OLDDATA, session);
+                case "sessiondata":
+                    return new NetCommand(RequestType.SESSIONDATA, session);
+                case "chat":
+                    return new NetCommand(RequestType.CHAT, session);
+                default:
+                    throw new FormatException("Error in NetCommand: Request type not recognised");
+            }
+        }
+
+        private static NetCommand ParseUser(int session, string[] args)
+        {
+            if (args.Length != 2)
+                throw new MissingFieldException("Error in NetCommand: User is missing arguments");
+
+            NetCommand temp = new NetCommand(args[0], Helper.Base64Decode(args[1]), session);
+
+            return temp;
+        }
+
+        private static NetCommand ParseValue(int session, string[] args)
+        {
+            if (args.Length != 2)
+                throw new MissingFieldException("Error in NetCommand: SetValue is missing arguments");
+
+            switch (args[0])
+            {
+                case "time":
+                    return new NetCommand(ValueType.TIME, int.Parse(args[1]), session);
+                case "power":
+                    return new NetCommand(ValueType.POWER, int.Parse(args[1]), session);
+                case "energy":
+                    return new NetCommand(ValueType.ENERGY, int.Parse(args[1]), session);
+                case "distance":
+                    return new NetCommand(ValueType.DISTANCE, int.Parse(args[1]), session);
+                default:
+                    throw new FormatException("Error in NetCommand: SetValue type not recognised");
+            }
+        }
+
+        private static NetCommand ParseResponse(int session, string[] args)
+        {
+            if (args.Length != 1)
+                throw new MissingFieldException("Error in NetCommand: Response is missing arguments");
+
+            switch (args[0])
+            {
+                case "loginok":
+                    return new NetCommand(ResponseType.LOGINOK, session);
+                case "loginwrong":
+                    return new NetCommand(ResponseType.LOGINWRONG, session);
+                case "notloggedin":
+                    return new NetCommand(ResponseType.NOTLOGGEDIN, session);
+                case "error":
+                    return new NetCommand(ResponseType.ERROR, session);
+                default:
+                    throw new FormatException("Error in NetCommand: Response type not recognised");
+            }
+        }
+
+        private static NetCommand ParseSession(int session)
+        {
+            NetCommand temp = new NetCommand(CommandType.SESSION, session);
+            return temp;
+        }
+
+        private static NetCommand ParseLogoutRequest(int session, string[] args)
+        {
+            if (args.Length != 1)
+                throw new MissingFieldException("Error in NetCommand: Logout Request is missing arguments");
+
+            NetCommand temp = new NetCommand(CommandType.LOGOUT, session);
+            if (args[0] != "logout")
+                throw new FormatException("Error in NetCommand: " + args[0] + " is not a valid logout request");
+
+            return temp;
+        }
+
+        private static NetCommand ParseChatMessage(int session, string[] args)
+        {
+            if (args.Length != 2)
+                throw new MissingFieldException("Error in NetCommand: Chat Message is missing arguments");
+
+            NetCommand temp = new NetCommand(CommandType.CHAT, session);
+            temp.ChatMessage = args[0];
+            temp.IsDoctor = bool.Parse(args[1]);
+
+            return temp;
+        }
+
+        private static NetCommand ParseData(int session, string[] args)
+        {
+            if (args.Length != 9)
+                throw new MissingFieldException("Error in NetCommand: Data is missing arguments");
+
+            NetCommand temp = new NetCommand(CommandType.DATA, session);
+            temp.Meting = Meting.Parse(string.Join("\t", args));
+
+            return temp;
+        }
+
+        private static NetCommand ParseLoginRequest(int session, string[] args)
+        {
+            bool doctor = bool.Parse(args[2]);
+            if (args.Length != 3)
+                throw new MissingFieldException("Error in NetCommand: Doctor login is missing arguments");
+
+            NetCommand temp = new NetCommand(CommandType.LOGIN, session);
+            temp.IsDoctor = doctor;
+            temp.DisplayName = args[0];
+            temp.Password = Helper.Base64Decode(args[1]);
+
+            return temp;
+        }
+
+        public override string ToString()
+        {
+            string command = "";
+
+            switch (Type)
+            {
+                case CommandType.LOGIN:
+                    command += "1»ses" + Session + "»" + DisplayName + "»" + Helper.Base64Encode(Password) + "»" + IsDoctor;
+                    break;
+                case CommandType.DATA:
+                    command += "2»ses" + Session + "»" + Meting.ToCommand();
+                    break;
+                case CommandType.CHAT:
+                    command += "3»ses" + Session + "»" + ChatMessage + "»" + IsDoctor;
+                    break;
+                case CommandType.LOGOUT:
+                    command += "4»ses" + Session + "»logout";
+                    break;
+                case CommandType.SESSION:
+                    command += "5»ses" + Session;
+                    break;
+                case CommandType.RESPONSE:
+                    command += "6»ses" + Session + "»" + Response.ToString().ToLower();
+                    break;
+                case CommandType.VALUESET:
+                    command += "7»ses" + Session + "»" + Value.ToString().ToLower() + "»" + SetValue;
+                    break;
+                case CommandType.USER:
+                    command += "8»ses" + Session + "»" + DisplayName + "»" + Helper.Base64Encode(Password);
+                    break;
+                case CommandType.REQUEST:
+                    command += "9»ses" + Session + "»" + Request.ToString().ToLower();
+                    break;
+                case CommandType.LENGTH:
+                    command += "10»ses" + Session + "»" + Length.ToString().ToLower() + "»" + LengthValue;
+                    break;
+                case CommandType.SESSIONDATA:
+                    command += "11»ses" + Session + "»" + DisplayName + "»" + Timestamp;
+                    break;
+                case CommandType.BROADCAST:
+                    command += "12»ses" + Session + "»" + ChatMessage;
+                    break;
+                case CommandType.ERROR:
+                    command += "ERROR IN NETCOMMAND";
+                    break;
+
+                default:
+                    throw new FormatException("Error in NetCommand: Cannot find type of command");
+            }
+
+            return command;
+        }
+    }
+}

+ 135 - 0
ErgometerIPR/ErgometerLibrary/NetHelper.cs

@@ -0,0 +1,135 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Text;
+
+namespace ErgometerLibrary
+{
+    public class NetHelper
+    {
+        public static bool SendNetCommand(TcpClient client, NetCommand command)
+        {
+            /*
+            byte[] b = Encoding.Unicode.GetBytes(command.ToString());
+            client.GetStream().Write(b, 0, b.Length);
+            client.GetStream().Flush();
+            */
+            return SendString(client, command.ToString());
+        }
+
+        public static bool SendString(TcpClient client, string command)
+        {
+            /*
+            byte[] b = Encoding.Unicode.GetBytes(command);
+            client.GetStream().Write(b, 0, b.Length);
+            client.GetStream().Flush();
+            */
+
+            if (client != null && client.Connected)
+            {
+                try
+                {
+                    StreamWriter wr = new StreamWriter(client.GetStream(), Encoding.Unicode);
+                    wr.WriteLine(AESEncrypt.EncryptToString(command));
+                    wr.Flush();
+                    return true;
+                }
+                catch (Exception e)
+                {
+                    return false;
+                }
+            }
+            else
+                return false;
+        }
+
+        public static NetCommand ReadNetCommand(TcpClient client)
+        {
+            /*
+            byte[] bytesFrom = new byte[(int) client.ReceiveBufferSize];
+            client.GetStream().Read(bytesFrom, 0, (int)client.ReceiveBufferSize);
+            string response = Encoding.Unicode.GetString(bytesFrom);
+            NetCommand net = NetCommand.Parse(response);
+            return net;
+            */
+
+            string str;
+            NetCommand net;
+            str = ReadString(client);
+
+            if (str != "")
+            { 
+                try
+                {
+                    str = AESEncrypt.DecryptString(str);
+                }
+                catch (Exception e)
+                {
+                    str = "";
+                    net = new NetCommand(NetCommand.CommandType.ERROR, 0);
+                }
+                try {
+                    net = NetCommand.Parse(str);
+                }
+                catch (Exception e)
+                {
+                    net = new NetCommand(NetCommand.CommandType.ERROR, 0);
+                }
+            }
+            else
+                net = new NetCommand(NetCommand.CommandType.ERROR, 0);
+            return net;
+        }
+
+        public static string ReadString(TcpClient client)
+        {
+            /*
+            byte[] bytesFrom = new byte[(int)client.ReceiveBufferSize];
+            client.GetStream().Read(bytesFrom, 0, (int)client.ReceiveBufferSize);
+            string response = Encoding.Unicode.GetString(bytesFrom);
+            return response;
+            */
+            if (client != null && client.Connected)
+            {
+                try {
+                    StreamReader rd = new StreamReader(client.GetStream(), Encoding.Unicode);
+                    string str = rd.ReadLine();
+                    return str;
+                }
+                catch(Exception e)
+                {
+                    return "";
+                }
+            }
+            else
+                return "";
+        }
+
+        public static IPAddress GetIP(string ipstring)
+        {
+            IPAddress ip;
+
+            bool ipIsOk = IPAddress.TryParse(ipstring, out ip);
+            if (!ipIsOk) { return null; }
+
+            return ip;
+        }
+
+        public static IPAddress GetIP()
+        {
+            IPHostEntry host;
+            string localIP = "?";
+            host = Dns.GetHostEntry(Dns.GetHostName());
+            foreach (IPAddress ip in host.AddressList)
+            {
+                if (ip.AddressFamily == AddressFamily.InterNetwork)
+                {
+                    localIP = ip.ToString();
+                }
+            }
+            return GetIP(localIP);
+        }
+    }
+}

+ 36 - 0
ErgometerIPR/ErgometerLibrary/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ErgometerLibrary")]
+[assembly: AssemblyDescription("Library with the most common methods and classes for the Ergometer")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Projectgroep A5")]
+[assembly: AssemblyProduct("ErgometerLibrary")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("cc20ff4e-8751-42a1-a32b-0e5b22452cac")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.2.0.0")]
+[assembly: AssemblyFileVersion("1.0.3.7")]

+ 4 - 0
ErgometerIPR/ErgometerLibrary/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net452" />
+</packages>

+ 6 - 0
ErgometerIPR/ErgometerServer/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
+    </startup>
+</configuration>

+ 137 - 0
ErgometerIPR/ErgometerServer/ClientThread.cs

@@ -0,0 +1,137 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ErgometerServer
+{
+    class ClientThread
+    {
+        TcpClient client;
+        Server server;
+
+        public string name;
+        public int session { get; }
+
+        bool running;
+        bool loggedin;
+
+        List<Meting> metingen;
+        List<ChatMessage> chat;
+
+        public ClientThread(TcpClient client, Server server)
+        {
+            this.client = client;
+            this.server = server;
+            this.name = "Unknown";
+            this.session = 0;
+            this.running = false;
+            this.loggedin = false;
+
+            metingen = new List<Meting>();
+            chat = new List<ChatMessage>();
+            session = FileHandler.GenerateSession();
+            Console.WriteLine("Generated new session: " + session);
+        }
+
+        public void run()
+        {
+            running = true;
+
+            NetHelper.SendNetCommand(client, new NetCommand(session));
+
+            while (running)
+            {
+                NetCommand input = NetHelper.ReadNetCommand(client);
+
+                switch(input.Type)
+                {
+                    case NetCommand.CommandType.SESSION:
+
+                        break;
+                    case NetCommand.CommandType.LOGIN:
+                        if(! server.CheckPassword(input.DisplayName, input.Password))
+                        {
+                            NetHelper.SendNetCommand(client, new NetCommand(NetCommand.ResponseType.LOGINWRONG, session));
+                            loggedin = false;
+                        }
+                        else
+                        {
+                            NetHelper.SendNetCommand(client, new NetCommand(NetCommand.ResponseType.LOGINOK, session));
+                            loggedin = true;
+
+                            if (input.IsDoctor)
+                            {
+                                server.ChangeClientToDoctor(client, this);
+                                Console.WriteLine("Doctor connected");
+                                running = false;
+                            }
+                            else
+                            {
+                                name = input.DisplayName;
+                                loggedin = true;
+                                FileHandler.CreateSession(session, name);
+                            }
+                        }
+                        break;
+                    case NetCommand.CommandType.DATA:
+                        if (loggedin)
+                        {
+                            metingen.Add(input.Meting);
+                            server.SendToDoctor(input);
+                        }
+                        else
+                            NetHelper.SendNetCommand(client, new NetCommand(NetCommand.ResponseType.NOTLOGGEDIN, session));
+
+                        break;
+                    case NetCommand.CommandType.CHAT:
+                        if (loggedin)
+                        {
+                            chat.Add(new ChatMessage(name, input.ChatMessage, false));
+                            server.SendToDoctor(input);
+                        }
+                        else
+                            NetHelper.SendNetCommand(client, new NetCommand(NetCommand.ResponseType.NOTLOGGEDIN, session));
+                        break;
+                    case NetCommand.CommandType.LOGOUT:
+                        loggedin = false;
+                        running = false;
+                        Console.WriteLine(name + " logged out");
+                        FileHandler.WriteMetingen(session, metingen);
+                        FileHandler.WriteChat(session, chat);
+                        client.Close();
+                        break;
+                    case NetCommand.CommandType.ERROR:
+                        Console.WriteLine("An error occured, assuming client disconnected");
+                        loggedin = false;
+                        running = false;
+                        Console.WriteLine(name + " logged out due to an error");
+                        FileHandler.WriteMetingen(session, metingen);
+                        FileHandler.WriteChat(session, chat);
+                        client.Close();
+                        break;
+                    default:
+                        if(loggedin)
+                            throw new FormatException("Unknown command");
+                        break;
+                }
+            }
+
+            server.RemoveActiveSession(this);
+        }
+
+        public void SendToClient(NetCommand command)
+        {
+            NetHelper.SendNetCommand(client, command);
+            if (command.Type == NetCommand.CommandType.CHAT)
+            {
+                chat.Add(new ChatMessage("Doctor", command.ChatMessage, true));
+            }
+        }
+    }
+}

+ 121 - 0
ErgometerIPR/ErgometerServer/DoctorThread.cs

@@ -0,0 +1,121 @@
+using System;
+using System.Collections;
+using System.Net.Sockets;
+using System.Runtime.Remoting.Lifetime;
+using System.Threading;
+using ErgometerLibrary;
+using System.Collections.Generic;
+
+namespace ErgometerServer
+{
+    class DoctorThread
+    {
+        TcpClient client;
+        Server server;
+
+        bool running;
+
+        public DoctorThread(TcpClient client, Server server)
+        {
+            this.client = client;
+            this.server = server;
+
+            this.running = false;
+        }
+
+        public void run()
+        {
+            running = true;
+            while (running)
+            {
+                NetCommand input = NetHelper.ReadNetCommand(client);
+
+                switch (input.Type)
+                {
+                    case NetCommand.CommandType.LOGOUT:
+                        running = false;
+                        client.Close();
+                        Console.WriteLine("Doctor logged out");
+                        break;
+                    case NetCommand.CommandType.CHAT:
+                        server.SendToClient(input);
+                        break;
+                    case NetCommand.CommandType.BROADCAST:
+                        server.BroadcastToClients(input.ChatMessage);
+                        break;
+                    case NetCommand.CommandType.VALUESET:
+                        server.SendToClient(input);
+                        break;
+                    case NetCommand.CommandType.USER:
+                        server.AddUser(input.DisplayName, input.Password);
+                        break;
+                    case NetCommand.CommandType.REQUEST:
+                        switch (input.Request)
+                        {
+                            case NetCommand.RequestType.USERS:
+                                sendToDoctor(new NetCommand(NetCommand.LengthType.USERS, server.users.Count-1, input.Session));
+                                foreach (KeyValuePair<string, string> user in server.users)
+                                {
+                                    Thread.Sleep(10);
+                                    if(user.Key != "Doctor0tVfW")
+                                        sendToDoctor(new NetCommand(user.Key, user.Value, input.Session));
+                                }
+                                break;
+                            case NetCommand.RequestType.CHAT:
+                                List<ChatMessage> chat = FileHandler.ReadChat(input.Session);
+                                foreach (ChatMessage msg in chat)
+                                {
+                                    Thread.Sleep(10);
+                                    sendToDoctor(new NetCommand(msg.Message, msg.IsDoctor, input.Session));
+                                }
+                                break;
+                            case NetCommand.RequestType.OLDDATA:
+                                List<Meting> metingen = FileHandler.ReadMetingen(input.Session);
+                                foreach (Meting meting in metingen)
+                                {
+                                    Thread.Sleep(10);
+                                    sendToDoctor(new NetCommand(meting, input.Session));      
+                                }
+                                break;
+                            case NetCommand.RequestType.ALLSESSIONS:
+                                List<Tuple<int, string, double>> sessions = FileHandler.GetAllSessions();
+                                sendToDoctor(new NetCommand(NetCommand.LengthType.SESSIONS, sessions.Count, input.Session));
+                                foreach(Tuple<int,string,double> session in sessions)
+                                {
+                                    sendToDoctor(new NetCommand(session.Item2, session.Item3, session.Item1));
+                                    
+                                    Thread.Sleep(10);
+                                }
+                                break;
+                            case NetCommand.RequestType.SESSIONDATA:
+                                List<Tuple<int, string>> currentsessionsdata = server.GetRunningSessionsData();
+                                sendToDoctor(new NetCommand(NetCommand.LengthType.SESSIONDATA, currentsessionsdata.Count, input.Session));
+                                foreach (Tuple<int, string> ses in currentsessionsdata)
+                                {
+                                    sendToDoctor(new NetCommand(ses.Item2, Helper.Now, ses.Item1));
+                                    Thread.Sleep(10);
+                                }
+                                break;
+                            default:
+                                throw new FormatException("Unknown Command");
+                        }
+                        
+                        break;
+                    case NetCommand.CommandType.ERROR:
+                        Console.WriteLine("An error occured, assuming docter disconnected");
+                        running = false;
+                        Console.WriteLine("Doctor logged out due to an error");
+                        client.Close();
+                        break;
+                    default:
+                        throw new FormatException("Unknown Command");
+                }
+            }
+        }
+
+        public void sendToDoctor(NetCommand command)
+        {
+            NetHelper.SendNetCommand(client, command);
+        }
+    }
+}

+ 72 - 0
ErgometerIPR/ErgometerServer/ErgometerServer.csproj

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{398293F9-9DF4-4F7A-AC85-6CF488B08B29}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ErgometerServer</RootNamespace>
+    <AssemblyName>ErgometerServer</AssemblyName>
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ErgometerLibrary, Version=1.0.3.5, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\ErgometerLibrary\ErgometerLibrary\ErgometerLibrary\bin\Debug\ErgometerLibrary.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ClientThread.cs" />
+    <Compile Include="DoctorThread.cs" />
+    <Compile Include="FileHandler.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Server.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 204 - 0
ErgometerIPR/ErgometerServer/FileHandler.cs

@@ -0,0 +1,204 @@
+using ErgometerLibrary;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace ErgometerServer
+{
+    public class FileHandler
+    {
+        public static string DataFolder { get; } = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments), "Ergometer");
+        public static string UsersFile { get; } = Path.Combine(DataFolder, "users.ergo");
+
+        public static void CheckStorage()
+        {
+            if (!Directory.Exists(DataFolder))
+            {
+                Directory.CreateDirectory(DataFolder);
+            }
+
+            if (!File.Exists(UsersFile))
+            {
+                using (Stream stream = File.Open(UsersFile, FileMode.Create))
+                {
+                    BinaryWriter writer = new BinaryWriter(stream);
+                    writer.Write(1);
+                    writer.Write("Doctor0tVfW");
+                    writer.Write(Helper.Base64Encode("password"));
+                }
+            }
+        }
+
+        //SESSION 
+        public static int GenerateSession()
+        {
+            string[] existingSessions = Directory.GetDirectories(DataFolder);
+
+            Random rand = new Random();
+            int sessionID = rand.Next(0, int.MaxValue);
+
+
+            while (existingSessions.Contains(sessionID.ToString()))
+            {
+                sessionID = rand.Next(int.MinValue, int.MaxValue);
+            }
+
+            return sessionID;
+        }
+
+        public static void CreateSession(int session, string naam)
+        {
+            Directory.CreateDirectory(GetSessionFolder(session));
+
+            using (File.Create(Path.Combine(GetSessionFile(session)))) ;
+            using (File.Create(Path.Combine(GetSessionMetingen(session)))) ;
+            using (File.Create(Path.Combine(GetSessionChat(session)))) ;
+
+            File.WriteAllText(GetSessionFile(session), naam + Environment.NewLine + Helper.Now);
+            Console.WriteLine("Created session at " + Helper.MillisecondsToTime(Helper.Now));
+        }
+
+        public static void WriteMetingen(int session, List<Meting> metingen)
+        {
+            if (metingen.Count <= 20 && Directory.Exists(GetSessionFolder(session)))
+            {
+                Directory.Delete(GetSessionFolder(session), true);
+            }
+            else
+            {
+                string json = Newtonsoft.Json.JsonConvert.SerializeObject(metingen.ToArray());
+                File.WriteAllText(GetSessionMetingen(session), json);
+                Console.WriteLine("Writing metingen: " + GetSessionMetingen(session));
+                File.WriteAllText(GetSessionFile(session), File.ReadAllText(GetSessionFile(session)) + Environment.NewLine + Helper.Now);
+            }
+            
+        }
+
+        public static List<Meting> ReadMetingen(int session)
+        {
+            string json = File.ReadAllText(GetSessionMetingen(session));
+
+            List<Meting> metingen = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Meting>>(json);
+            Console.WriteLine("Reading metingen: " + GetSessionMetingen(session));
+            return metingen;
+        }
+
+        public static List<Tuple<int, string, double>> GetAllSessions()
+        {
+            string[] directories = Directory.GetDirectories(DataFolder);
+            List<Tuple<int,string,double>> sessiondata = new List<Tuple<int, string, double>>();
+
+            for (int i = 0; i < directories.Length; i++)
+            {
+                string directoryname = Path.GetFileName(directories[i]);
+
+                string props = File.ReadAllText(GetSessionFile(int.Parse(directoryname)));
+
+                string[] stringSeparators = new string[] { "\r\n" };
+                string[] properties = props.Split(stringSeparators, StringSplitOptions.None);
+
+                int session = int.Parse(directoryname);
+
+                bool active = false;
+
+                foreach(ClientThread t in Server.clients)
+                {
+                    if (t.session == session)
+                        active = true;
+                }
+
+                string name = properties[0];
+                double date = double.Parse(properties[1]);
+
+                if (!active)
+                {
+                    Tuple<int, string, double> tup = new Tuple<int, string, double>(session, name, date);
+                    sessiondata.Add(tup);
+                }
+            }
+
+            return sessiondata;
+        }
+
+        public static void WriteChat(int session, List<ChatMessage> chat)
+        {
+            if (Directory.Exists(GetSessionFolder(session)))
+            {
+                /*
+                string write = "";
+                foreach (ChatMessage c in chat)
+                {
+                    write += c.ToString() + "\n";
+                }
+
+                File.WriteAllText(GetSessionChat(session), write);
+                Console.WriteLine("Writing chat: " + GetSessionChat(session));
+                */
+                string json = Newtonsoft.Json.JsonConvert.SerializeObject(chat.ToArray());
+                File.WriteAllText(GetSessionChat(session), json);
+                Console.WriteLine("Writing chat: " + GetSessionChat(session));
+            }
+        }
+
+        public static List<ChatMessage> ReadChat(int session)
+        {
+            string json = File.ReadAllText(GetSessionChat(session));
+
+            List<ChatMessage> chat = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ChatMessage>>(json);
+            return chat;
+        }
+
+        private static string GetSessionFolder(int session)
+        {
+            return Path.Combine(DataFolder, session.ToString());
+        }
+        private static string GetSessionFile(int session)
+        {
+            return Path.Combine(DataFolder, session.ToString(), "session.prop");
+        }
+        private static string GetSessionMetingen(int session)
+        {
+            return Path.Combine(DataFolder, session.ToString(), "metingen.ergo");
+        }
+        private static string GetSessionChat(int session)
+        {
+            return Path.Combine(DataFolder, session.ToString(), "chat.ergo");
+        }
+
+        //USER MANAGEMENT
+        public static Dictionary<string, string> LoadUsers()
+        {
+            Dictionary<string, string> users = new Dictionary<string, string>();
+
+            using (Stream stream = File.Open(UsersFile, FileMode.Open))
+            {
+                BinaryReader reader = new BinaryReader(stream);
+                int count = reader.ReadInt32();
+                for (int n = 0; n < count; n++)
+                {
+                    var key = reader.ReadString();
+                    var value = Helper.Base64Decode(reader.ReadString());
+                    users.Add(key, value);
+                }
+            }
+
+            return users;
+        }
+
+        public static void SaveUsers(Dictionary<string, string> users)
+        {
+            using (Stream stream = File.Open(UsersFile, FileMode.Open))
+            {
+                BinaryWriter writer = new BinaryWriter(stream);
+                writer.Write(users.Count);
+                foreach (var kvp in users)
+                {
+                    writer.Write(kvp.Key);
+                    writer.Write(Helper.Base64Encode(kvp.Value));
+                }
+                writer.Flush();
+            }
+        }
+    }
+}

+ 36 - 0
ErgometerIPR/ErgometerServer/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ErgometerServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ErgometerServer")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("398293f9-9df4-4f7a-ac85-6cf488b08b29")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 167 - 0
ErgometerIPR/ErgometerServer/Server.cs

@@ -0,0 +1,167 @@
+using ErgometerLibrary;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+
+namespace ErgometerServer
+{
+    class Server
+    {
+        static void Main(string[] args)
+        {
+            new Server();
+        }
+
+        public static List<ClientThread> clients = new List<ClientThread>();
+        private DoctorThread doctor;
+        public Dictionary<string, string> users;
+
+        public Server()
+        {
+            AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnProcessExit);
+
+            FileHandler.CheckStorage();
+
+            users = FileHandler.LoadUsers();
+
+            TcpListener listener = new TcpListener(NetHelper.GetIP("127.0.0.1"), 8888);
+            //TcpListener listener = new TcpListener(NetHelper.GetIP(GetIp()), 8888);
+            listener.Start();
+
+            Console.WriteLine("Server started successfully...");
+
+            while (true)
+            {
+                Console.WriteLine("Waiting for connection with client...");
+
+                //AcceptTcpClient waits for a connection from the client
+                TcpClient client = listener.AcceptTcpClient();
+
+                Console.WriteLine("Client connected");
+
+                //Start new client
+                ClientThread cl = new ClientThread(client, this);
+                clients.Add(cl);
+
+                //Run client on new thread
+                Thread thread = new Thread(new ThreadStart(cl.run));
+                thread.IsBackground = true;
+                thread.Start();
+            }
+        }
+
+        public void ChangeClientToDoctor(TcpClient client, ClientThread clth)
+        {
+            clients.Remove(clth);
+            doctor = new DoctorThread(client, this);
+            Thread thread = new Thread(new ThreadStart(doctor.run));
+            thread.IsBackground = true;
+            thread.Start();
+        }
+
+        public void SendToDoctor(NetCommand command)
+        {
+            if (doctor != null)
+            {
+                doctor.sendToDoctor(command);
+            }
+        }
+
+        public void BroadcastToClients(string message)
+        {
+            foreach (ClientThread clientThread in clients)
+            {
+                    clientThread.SendToClient(new NetCommand(message, true, clientThread.session));
+            }
+        }
+
+        public void SendToClient(NetCommand command)
+        {
+            foreach (ClientThread clientThread in clients)
+            {
+                if (clientThread.session == command.Session)
+                {
+                    clientThread.SendToClient(command);
+                }
+            }
+        }
+
+        public void AddUser(string name, string password)
+        {
+            users.Add(name, password);
+            FileHandler.SaveUsers(users);
+        }
+
+        public void AddUser(Dictionary<string, string> users)
+        {
+            foreach(KeyValuePair<string, string> user in users)
+            {
+                users.Add(user.Key, user.Value);
+            }
+            
+            FileHandler.SaveUsers(users);
+        }
+
+        public bool CheckPassword(string name, string password)
+        {
+            string pass;
+            bool isOk = users.TryGetValue(name, out pass);
+
+            if (!isOk) return false;
+
+            return pass == password;
+        }
+
+        public List<int> GetRunningSessions()
+        {
+            List<int> sessions = new List<int>();
+            foreach (ClientThread thread in clients)
+            {
+                sessions.Add(thread.session);
+            }
+            return sessions;
+        }
+
+        public List<Tuple<int, string>> GetRunningSessionsData()
+        {
+            List<Tuple<int, string>> sessions = new List<Tuple<int, string>>();
+            foreach (ClientThread thread in clients)
+            {
+                sessions.Add(new Tuple<int, string>(thread.session, thread.name));
+            }
+            return sessions;
+        }
+
+        internal void RemoveActiveSession(ClientThread clientThread)
+        {
+            clients.Remove(clientThread);
+        }
+
+        private string GeneratePassword(int len = 8)
+        {
+            string pass = "";
+
+            char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
+
+            Random rand = new Random();
+
+            for (int i=0; i<=len; i++)
+            {
+                pass += chars[rand.Next(0, chars.Length - 1)];
+            }
+
+            return pass;
+        }
+
+        private static void OnProcessExit(object sender, EventArgs e)
+        {
+            Console.WriteLine("Closing server");
+        }
+    }
+
+}

+ 4 - 0
ErgometerIPR/ErgometerServer/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net452" />
+</packages>