59 Commits

Author SHA1 Message Date
Sem van der Hoeven
1f163325cf [FIX] fixed the panel not showing, it was because of the animation. removed it for now and it works 2020-10-29 17:09:20 +01:00
Sem van der Hoeven
1c7f9cf70a [FIX] fixed doctor buffer overflow 2020-10-28 13:23:20 +01:00
Sem van der Hoeven
5f2e325cb1 [ADD] added chat to all method from docter, it works but there is sometimes an error in the doctor client app that the buffer in OnRead is full, so will try to fix that tomorrow 2020-10-27 21:35:07 +01:00
Sem van der Hoeven
cda8b47ca3 [
ADD] added message sending to all clients, doesn't work yet
2020-10-27 21:24:47 +01:00
Sem van der Hoeven
fab3ed7705 [EDIT] made seperate method for sending message 2020-10-27 20:59:46 +01:00
shinichi
aeb5d59ce9 implemented nextfocuable 2020-10-19 15:32:14 +02:00
shinichi
ab1662f0fe Merge branch 'develop' into NextFocusOnEnter 2020-10-19 15:15:34 +02:00
shinichi
f07c3f9484 moving and fixing 2020-10-19 15:14:01 +02:00
fabjuuuh
2adfcc5bd7 fix 2020-10-19 15:13:27 +02:00
shinichi
3acdc942bc move files and copy code
from stackoverflow :P
2020-10-19 14:53:47 +02:00
shinichi
84cbcb4a6d send data to doctor 2020-10-19 14:35:51 +02:00
Logophilist
8385f09313 Bike animation added 2020-10-19 14:25:09 +02:00
fabjuuuh
3ea42b65ed Merge branch 'dataOnTabs' into develop 2020-10-19 14:11:59 +02:00
Sem van der Hoeven
55d3dd4eee actually fixed overflow exception 2020-10-19 14:09:03 +02:00
fabjuuuh
960327a3e3 Merge remote-tracking branch 'origin/develop' into dataOnTabs 2020-10-19 14:05:55 +02:00
fabjuuuh
083f27411e chart 2020-10-19 14:02:42 +02:00
shinichi
d9c8b7c6df Merge remote-tracking branch 'origin/develop' into develop 2020-10-19 14:02:07 +02:00
shinichi
de9716128c restyle tabheader 2020-10-19 14:02:03 +02:00
Sem van der Hoeven
f934dee2d0 made overflow return 255 instead of 0 2020-10-19 14:01:39 +02:00
Sem van der Hoeven
107d95b81a fixed overflowexception 2020-10-19 13:59:47 +02:00
Sem van der Hoeven
c50f898ec0 Merge branch 'develop' of https://github.com/SemvdH/Proftaak-RH-B4 into develop 2020-10-19 13:32:33 +02:00
Sem van der Hoeven
fb443a33d7 add send message 2020-10-19 13:32:26 +02:00
Sem van der Hoeven
8249632d00 add set resistance 2020-10-19 13:31:29 +02:00
shinichi
134bf235c3 multiple clients works 2020-10-19 13:24:38 +02:00
shinichi
bc738d0fa3 Merge remote-tracking branch 'origin/develop' into develop 2020-10-19 12:52:39 +02:00
shinichi
2ecc90ff2c doctor can now disconnect 2020-10-19 12:52:35 +02:00
Sem van der Hoeven
6a9e2b57ac Merge branch 'develop' of https://github.com/SemvdH/Proftaak-RH-B4 into develop 2020-10-19 12:49:09 +02:00
Sem van der Hoeven
973ff20da4 small typo 2020-10-19 12:49:04 +02:00
shinichi
d98c32a508 Merge remote-tracking branch 'origin/develop' into develop 2020-10-19 12:24:09 +02:00
shinichi
dcf6c3c6d0 client can see if doctor connected 2020-10-19 12:23:52 +02:00
Sem van der Hoeven
689f7030e4 added displaying of last doctor message in vr scene 2020-10-19 12:20:26 +02:00
shinichi
4a238d9207 Auto stash before checking out "HEAD" 2020-10-19 12:07:00 +02:00
Sem van der Hoeven
31be096b94 added small comments 2020-10-19 11:57:42 +02:00
Sem van der Hoeven
7eb7b03d4f Merge branch 'develop' of https://github.com/SemvdH/Proftaak-RH-B4 into develop 2020-10-19 11:55:34 +02:00
Sem van der Hoeven
17a17e3c6d added comments to dataparser 2020-10-19 11:55:20 +02:00
shinichi
163d2321cc username back added to tabs 2020-10-19 11:49:34 +02:00
shinichi
c9e913474c Merge remote-tracking branch 'origin/develop' into develop 2020-10-19 11:26:18 +02:00
shinichi
63b5c6ab73 removed unnecessary code 2020-10-19 11:26:09 +02:00
Sem van der Hoeven
6b355a0b72 added resistance editing from client to vr engine 2020-10-19 11:26:04 +02:00
fabjuuuh
9a46b17067 Merge remote-tracking branch 'origin/develop' into dataOnTabs 2020-10-19 11:20:28 +02:00
shinichi
b748bcf5c8 binded commands 2020-10-19 11:19:57 +02:00
fabjuuuh
62525f3a23 Merge remote-tracking branch 'origin/develop' into dataOnTabs 2020-10-19 11:14:57 +02:00
fabjuuuh
783c40d7d3 rip 2020-10-19 11:14:05 +02:00
shinichi
e9e3381960 icon works 2020-10-16 16:32:17 +02:00
shinichi
75ff7fe336 Merge remote-tracking branch 'origin/develop' into develop 2020-10-16 16:24:13 +02:00
shinichi
cc046d6611 wip 2020-10-16 16:24:07 +02:00
fabjuuuh
5751bbed81 Progress with structure to send data 2020-10-16 16:23:50 +02:00
Sem van der Hoeven
a76433803c Merge branch 'develop' of https://github.com/SemvdH/Proftaak-RH-B4 into develop 2020-10-16 15:39:28 +02:00
Sem van der Hoeven
ae01646de6 added doctor icon 2020-10-16 15:39:17 +02:00
shinichi
e8a4901f09 fix 2020-10-16 15:15:09 +02:00
fabjuuuh
b868515ade Merge branch 'newDoctor' into develop 2020-10-16 15:06:52 +02:00
fabjuuuh
93eeea856f errors 2020-10-16 15:06:38 +02:00
fabjuuuh
0427fa89aa Merge remote-tracking branch 'origin/develop' into newDoctor 2020-10-16 15:04:16 +02:00
shinichi
fd9b321292 doctor can see patients who logged on before 2020-10-16 15:02:19 +02:00
shinichi
6fb9d0efaa Merge branch 'doctor-client-connecting' into develop 2020-10-16 12:49:18 +02:00
shinichi
540a640bc6 removed debuggers 2020-10-16 12:49:06 +02:00
shinichi
777ed65707 Merge branch 'develop' into doctor-client-connecting 2020-10-16 12:19:04 +02:00
shinichi
44abffd7e7 closing windows works 2020-10-16 12:18:46 +02:00
shinichi
9ef51ddeca connecting to doctor after works 2020-10-16 12:18:03 +02:00
36 changed files with 936 additions and 270 deletions

View File

@@ -19,11 +19,11 @@
</DataTemplate> </DataTemplate>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/Fonts.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Fonts.xaml"/>
<ResourceDictionary Source="Styles/Colors.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Colors.xaml"/>
<ResourceDictionary Source="Styles/Buttons.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Buttons.xaml"/>
<ResourceDictionary Source="Styles/Texts.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Texts.xaml"/>
<ResourceDictionary Source="Styles/Windows.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Windows.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>

View File

@@ -7,6 +7,14 @@
<ApplicationIcon>Images\Logo\icon1.ico</ApplicationIcon> <ApplicationIcon>Images\Logo\icon1.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="Images\CoolBackground.jpg" /> <None Remove="Images\CoolBackground.jpg" />
<None Remove="Images\Icons\CheckMark.png" /> <None Remove="Images\Icons\CheckMark.png" />
@@ -21,13 +29,13 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Images\Icons\CheckMark.png"> <Content Include="Images\Icons\CheckMark.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Images\Icons\CrossMark.png"> <Content Include="Images\Icons\CrossMark.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Images\Logo\icon1.ico"> <Content Include="Images\Logo\icon1.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Images\re15.jpg"> <Content Include="Images\re15.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>

View File

@@ -43,6 +43,7 @@ namespace ClientApp.Utils
/// </summary> /// </summary>
private void initEngine() private void initEngine()
{ {
Debug.WriteLine("[CLIENT] init engine");
engineConnection = EngineConnection.INSTANCE; engineConnection = EngineConnection.INSTANCE;
engineConnection.OnNoTunnelId = RetryEngineConnection; engineConnection.OnNoTunnelId = RetryEngineConnection;
engineConnection.OnSuccessFullConnection = engineConnected; engineConnection.OnSuccessFullConnection = engineConnected;
@@ -88,6 +89,7 @@ namespace ClientApp.Utils
/// <param name="ar">the result of the async read</param> /// <param name="ar">the result of the async read</param>
private void OnRead(IAsyncResult ar) private void OnRead(IAsyncResult ar)
{ {
Debug.WriteLine("got message in client app");
if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead)) if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead))
return; return;
@@ -136,7 +138,7 @@ namespace ClientApp.Utils
} }
break; break;
case DataParser.START_SESSION: case DataParser.START_SESSION:
Console.WriteLine("Session started!"); Debug.WriteLine("Session started!");
this.sessionRunning = true; this.sessionRunning = true;
if (engineConnection.Connected && !engineConnection.FollowingRoute) engineConnection.StartRouteFollow(); if (engineConnection.Connected && !engineConnection.FollowingRoute) engineConnection.StartRouteFollow();
Debug.WriteLine("start"); Debug.WriteLine("start");
@@ -147,24 +149,39 @@ namespace ClientApp.Utils
Debug.WriteLine("stop"); Debug.WriteLine("stop");
break; break;
case DataParser.SET_RESISTANCE: case DataParser.SET_RESISTANCE:
Console.WriteLine("Set resistance identifier"); Debug.WriteLine("Set resistance identifier");
if (this.handler == null) if (this.handler == null)
{ {
Console.WriteLine("handler is null"); // send that the operation was not successful if the handler is null
Debug.WriteLine("handler is null");
sendMessage(DataParser.getSetResistanceResponseJson(false)); sendMessage(DataParser.getSetResistanceResponseJson(false));
} }
else else
{ {
this.handler.setResistance(DataParser.getResistanceFromJson(payloadbytes)); // set the resistance in the vr scene and send that it was successful
float resistance = DataParser.getResistanceFromJson(payloadbytes);
Debug.WriteLine("resistance set was " + resistance);
this.handler.setResistance(resistance);
engineConnection.BikeResistance = resistance;
sendMessage(DataParser.getSetResistanceResponseJson(true)); sendMessage(DataParser.getSetResistanceResponseJson(true));
} }
break; break;
case DataParser.MESSAGE:
Debug.WriteLine("client has received message from doctor");
engineConnection.DoctorMessage = DataParser.getChatMessageFromJson(payloadbytes);
break;
case DataParser.NEW_CONNECTION:
this.LoginViewModel.DoctorConnected(DataParser.getUsernameFromJson(payloadbytes));
break;
case DataParser.DISCONNECT:
this.LoginViewModel.DoctorDisconnected(DataParser.getUsernameFromJson(payloadbytes));
break;
default: default:
Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}"); Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}");
break; break;
} }
} }
else if (DataParser.isRawData(messageBytes)) else if (DataParser.isRawDataBikeServer(messageBytes))
{ {
Console.WriteLine($"Received data: {BitConverter.ToString(payloadbytes)}"); Console.WriteLine($"Received data: {BitConverter.ToString(payloadbytes)}");
} }
@@ -173,6 +190,9 @@ namespace ClientApp.Utils
expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0);
} }
if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.client.Connected)
return;
ar.AsyncWaitHandle.WaitOne();
this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null);
} }
@@ -211,7 +231,7 @@ namespace ClientApp.Utils
{ {
throw new ArgumentNullException("no bytes"); throw new ArgumentNullException("no bytes");
} }
byte[] message = DataParser.GetRawDataMessage(bytes); byte[] message = DataParser.GetRawBPMDataMessageServer(bytes);
if (engineConnection.Connected && engineConnection.FollowingRoute) if (engineConnection.Connected && engineConnection.FollowingRoute)
{ {
@@ -238,7 +258,7 @@ namespace ClientApp.Utils
{ {
throw new ArgumentNullException("no bytes"); throw new ArgumentNullException("no bytes");
} }
byte[] message = DataParser.GetRawDataMessage(bytes); byte[] message = DataParser.GetRawBikeDataMessageServer(bytes);
bool canSendToEngine = engineConnection.Connected && engineConnection.FollowingRoute; bool canSendToEngine = engineConnection.Connected && engineConnection.FollowingRoute;
switch (bytes[0]) switch (bytes[0])
{ {
@@ -301,6 +321,7 @@ namespace ClientApp.Utils
this.stream.Dispose(); this.stream.Dispose();
this.client.Dispose(); this.client.Dispose();
this.handler.stop(); this.handler.stop();
this.engineConnection.Stop();
} }
} }
} }

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using RH_Engine; using RH_Engine;
@@ -43,8 +43,8 @@ namespace ClientApp.Utils
private static string headId = string.Empty; private static string headId = string.Empty;
private static string groundPlaneId = string.Empty; private static string groundPlaneId = string.Empty;
private static string terrainId = string.Empty; private static string terrainId = string.Empty;
private static string lastMessage = "No message received yet";
public string DoctorMessage { get; set; }
public float BikeSpeed { get; set; } public float BikeSpeed { get; set; }
public float BikePower { get; set; } public float BikePower { get; set; }
public float BikeBPM { get; set; } public float BikeBPM { get; set; }
@@ -65,16 +65,17 @@ namespace ClientApp.Utils
BikePower = 0; BikePower = 0;
BikeBPM = 0; BikeBPM = 0;
BikeResistance = 50; BikeResistance = 50;
DoctorMessage = "No message received yet";
updateTimer = new System.Timers.Timer(1000); updateTimer = new System.Timers.Timer(1000);
updateTimer.Elapsed += UpdateTimer_Elapsed; updateTimer.Elapsed += UpdateTimer_Elapsed;
updateTimer.AutoReset = true; updateTimer.AutoReset = true;
updateTimer.Enabled = false; updateTimer.Enabled = false;
noVRResponseTimer = new System.Timers.Timer(15000); noVRResponseTimer = new System.Timers.Timer(30000);
noVRResponseTimer.Elapsed += noVRResponseTimeout; noVRResponseTimer.Elapsed += noVRResponseTimeout;
noVRResponseTimer.AutoReset = false; noVRResponseTimer.AutoReset = false;
noVRResponseTimer.Enabled = false; noVRResponseTimer.Enabled = false;
} }
private void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) private void UpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
@@ -178,7 +179,7 @@ namespace ClientApp.Utils
Console.WriteLine("set tunnel id to " + tunnelId); Console.WriteLine("set tunnel id to " + tunnelId);
if (tunnelId == null) if (tunnelId == null)
{ {
Write("could not find a valid tunnel id!"); //Write("could not find a valid tunnel id!");
OnNoTunnelId?.Invoke(); OnNoTunnelId?.Invoke();
Connected = false; Connected = false;
FollowingRoute = false; FollowingRoute = false;
@@ -224,7 +225,6 @@ namespace ClientApp.Utils
string handLeftId = JSONParser.GetIdSceneInfoChild(message, "LeftHand"); string handLeftId = JSONParser.GetIdSceneInfoChild(message, "LeftHand");
string handRightId = JSONParser.GetIdSceneInfoChild(message, "RightHand"); string handRightId = JSONParser.GetIdSceneInfoChild(message, "RightHand");
groundPlaneId = JSONParser.GetIdSceneInfoChild(message, "GroundPlane"); groundPlaneId = JSONParser.GetIdSceneInfoChild(message, "GroundPlane");
Write("--- Ground plane id is " + groundPlaneId);
}); });
// add the route and set the route id // add the route and set the route id
CreateTerrain(); CreateTerrain();
@@ -243,7 +243,7 @@ namespace ClientApp.Utils
SendMessageAndOnResponse(mainCommand.addPanel("panelAdd", bikeId), "panelAdd", SendMessageAndOnResponse(mainCommand.addPanel("panelAdd", bikeId), "panelAdd",
(message) => (message) =>
{ {
Write("got panel id");
panelId = JSONParser.getPanelID(message); panelId = JSONParser.getPanelID(message);
WriteTextMessage(mainCommand.ColorPanel(panelId)); WriteTextMessage(mainCommand.ColorPanel(panelId));
@@ -256,9 +256,9 @@ namespace ClientApp.Utils
WriteTextMessage(mainCommand.ShowRoute("showRouteFalse", false)); WriteTextMessage(mainCommand.ShowRoute("showRouteFalse", false));
}); });
}); });
setEnvironment(); setEnvironment();
} }
private void setEnvironment() private void setEnvironment()
@@ -295,6 +295,7 @@ namespace ClientApp.Utils
public void UpdateInfoPanel() public void UpdateInfoPanel()
{ {
Write("updating info panel");
ShowPanel(BikeSpeed, (int)BikeBPM, (int)BikePower, (int)BikeResistance); ShowPanel(BikeSpeed, (int)BikeBPM, (int)BikePower, (int)BikeResistance);
WriteTextMessage(mainCommand.RouteSpeed(BikeSpeed, bikeId)); WriteTextMessage(mainCommand.RouteSpeed(BikeSpeed, bikeId));
WriteTextMessage(mainCommand.RouteSpeed(BikeSpeed, cameraId)); WriteTextMessage(mainCommand.RouteSpeed(BikeSpeed, cameraId));
@@ -324,7 +325,7 @@ namespace ClientApp.Utils
{ {
// TODO check if is drawn // TODO check if is drawn
}); });
SendMessageAndOnResponse(mainCommand.showMessage(panelId, "message", lastMessage), "message", SendMessageAndOnResponse(mainCommand.showMessage(panelId, "message", DoctorMessage), "message",
(message) => (message) =>
{ {
// TODO check if is drawn // TODO check if is drawn
@@ -337,6 +338,7 @@ namespace ClientApp.Utils
private void SetFollowSpeed(float speed) private void SetFollowSpeed(float speed)
{ {
Write("starting route follow");
WriteTextMessage(mainCommand.RouteFollow(routeId, bikeId, speed, new float[] { 0, -(float)Math.PI / 2f, 0 }, new float[] { 0, 0, 0 })); WriteTextMessage(mainCommand.RouteFollow(routeId, bikeId, speed, new float[] { 0, -(float)Math.PI / 2f, 0 }, new float[] { 0, 0, 0 }));
WriteTextMessage(mainCommand.RouteFollow(routeId, cameraId, speed)); WriteTextMessage(mainCommand.RouteFollow(routeId, cameraId, speed));
} }
@@ -348,7 +350,7 @@ namespace ClientApp.Utils
ImprovedPerlin improvedPerlin = new ImprovedPerlin(0, LibNoise.NoiseQuality.Best); ImprovedPerlin improvedPerlin = new ImprovedPerlin(0, LibNoise.NoiseQuality.Best);
for (int i = 0; i < 256 * 256; i++) for (int i = 0; i < 256 * 256; i++)
{ {
height[i] = improvedPerlin.GetValue(x /10, x / 10, x * 100) / 3.5f + 1; height[i] = improvedPerlin.GetValue(x / 10, x / 10, x * 100) / 3.5f + 1;
//if (height[i] > 1.1f) //if (height[i] > 1.1f)
//{ //{

View File

@@ -42,5 +42,15 @@ namespace ClientApp.ViewModels
this.MainWindowViewModel.SelectedViewModel = new MainViewModel(MainWindowViewModel); this.MainWindowViewModel.SelectedViewModel = new MainViewModel(MainWindowViewModel);
} }
} }
internal void DoctorConnected(string name)
{
this.MainWindowViewModel.InfoModel.DoctorConnected = true;
}
internal void DoctorDisconnected(string name)
{
this.MainWindowViewModel.InfoModel.DoctorConnected = false;
}
} }
} }

View File

@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ClientApp.Views" xmlns:local="clr-namespace:ClientApp.Views"
xmlns:viewModels="clr-namespace:ClientApp.ViewModels" xmlns:viewModels="clr-namespace:ClientApp.ViewModels"
xmlns:Util="clr-namespace:Util.MagicCode"
mc:Ignorable="d" mc:Ignorable="d"
ShowsNavigationUI="False" ShowsNavigationUI="False"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
@@ -14,9 +15,9 @@
</DockPanel.Background> </DockPanel.Background>
<StackPanel VerticalAlignment="Center" Width="auto"> <StackPanel VerticalAlignment="Center" Width="auto">
<Label Content="Username" HorizontalContentAlignment="Center" /> <Label Content="Username" HorizontalContentAlignment="Center" />
<TextBox x:Name="Username" Text="{Binding Username}" TextWrapping="Wrap" Width="120"/> <TextBox x:Name="Username" Text="{Binding Username}" TextWrapping="Wrap" Width="120" Util:FocusAdvancement.AdvancesByEnterKey="True" />
<Label Content="Password" HorizontalContentAlignment="Center"/> <Label Content="Password" HorizontalContentAlignment="Center"/>
<PasswordBox x:Name="Password" Width="120"/> <PasswordBox x:Name="Password" Width="120" Util:FocusAdvancement.AdvancesByEnterKey="True"/>
<Button x:Name="Login" Content="Login" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=Password}" Margin="0,20,0,0" Width="120"/> <Button x:Name="Login" Content="Login" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=Password}" Margin="0,20,0,0" Width="120"/>
<Popup IsOpen="{Binding InvertedLoginStatus}" PopupAnimation = "Slide" HorizontalAlignment="Center"> <Popup IsOpen="{Binding InvertedLoginStatus}" PopupAnimation = "Slide" HorizontalAlignment="Center">
<Label Content="Login failed" Foreground="Red" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Background="Transparent"/> <Label Content="Login failed" Foreground="Red" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Background="Transparent"/>

View File

@@ -9,22 +9,22 @@
<ResourceDictionary> <ResourceDictionary>
<DataTemplate DataType="{x:Type viewModels:MainViewModel}"> <DataTemplate DataType="{x:Type viewModels:MainViewModel}">
<views:MainView /> <views:MainView />
<!-- This is a UserControl --> <!-- This is a Page -->
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type viewModels:LoginViewModel}"> <DataTemplate DataType="{x:Type viewModels:LoginViewModel}">
<views:LoginView /> <views:LoginView />
<!-- This is a UserControl --> <!-- This is a Page -->
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ClientInfoViewModel}"> <DataTemplate DataType="{x:Type viewModels:ClientInfoViewModel}">
<views:ClientInfoView/> <views:ClientInfoView/>
</DataTemplate> </DataTemplate>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles/Fonts.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Fonts.xaml"/>
<ResourceDictionary Source="Styles/Colors.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Colors.xaml"/>
<ResourceDictionary Source="Styles/Buttons.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Buttons.xaml"/>
<ResourceDictionary Source="Styles/Texts.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Texts.xaml"/>
<ResourceDictionary Source="Styles/Windows.xaml"/> <ResourceDictionary Source="WPFStuff/Styles/Windows.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -1,21 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
</PropertyGroup> <ApplicationIcon>doctor.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="4.3.0" /> <None Remove="img\doctor.ico" />
<PackageReference Include="MvvmLightLibsStd10" Version="5.4.1.1" /> <None Remove="img\patient.png" />
<PackageReference Include="PropertyChanged.Fody" Version="3.2.9" /> </ItemGroup>
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ProftaakRH\ProftaakRH.csproj" /> <Content Include="img\doctor.ico">
</ItemGroup> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="img\patient.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="..\Hashing\Hashing.projitems" Label="Shared" /> <ItemGroup>
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="4.3.0" />
<PackageReference Include="LiveCharts.Wpf" Version="0.9.7" />
<PackageReference Include="MvvmLightLibsStd10" Version="5.4.1.1" />
<PackageReference Include="PropertyChanged.Fody" Version="3.2.9" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ProftaakRH\ProftaakRH.csproj" />
</ItemGroup>
<Import Project="..\Hashing\Hashing.projitems" Label="Shared" />
</Project> </Project>

127
DoctorApp/Models/Chart.cs Normal file
View File

@@ -0,0 +1,127 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using LiveCharts;
using LiveCharts.Configurations;
using Util;
namespace DoctorApp.Models
{
class Chart : ObservableObject,INotifyPropertyChanged
{
private double _axisMax;
private double _axisMin;
private double _trend;
public event PropertyChangedEventHandler PropertyChanged;
public ChartValues<MeasureModel> ChartValues { get; set; }
public Func<double, string> DateTimeFormatter { get; set; }
public PatientInfo PatientInfo { get; set; }
public double AxisStep { get; set; }
public double AxisUnit { get; set; }
public double AxisMax
{
get { return _axisMax; }
set
{
_axisMax = value;
OnPropertyChanged("AxisMax");
}
}
public double AxisMin
{
get { return _axisMin; }
set
{
_axisMin = value;
OnPropertyChanged("AxisMin");
}
}
public bool IsReading { get; set; }
public Chart(PatientInfo patientInfo)
{
var mapper = Mappers.Xy<MeasureModel>()
.X(model => model.DateTime.Ticks)
.Y(model => model.Value);
Charting.For<MeasureModel>(mapper);
ChartValues = new ChartValues<MeasureModel>();
DateTimeFormatter = value => new DateTime((long)value).ToString("mm:ss");
AxisStep = TimeSpan.FromSeconds(1).Ticks;
AxisUnit = TimeSpan.TicksPerSecond;
SetAxisLimits(DateTime.Now);
IsReading = true;
ChartValues.Add(new MeasureModel
{
DateTime = DateTime.Now,
Value = 8
});
}
private void SetAxisLimits(DateTime now)
{
AxisMax = now.Ticks + TimeSpan.FromSeconds(1).Ticks; // lets force the axis to be 1 second ahead
AxisMin = now.Ticks - TimeSpan.FromSeconds(8).Ticks; // and 8 seconds behind
}
protected virtual void OnPropertyChanged(string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void NewValue(double value)
{
var now = DateTime.Now;
_trend = value;
ChartValues.Add(new MeasureModel
{
DateTime = now,
Value = _trend
});
SetAxisLimits(now);
if (ChartValues.Count > 150) ChartValues.RemoveAt(0);
}
public void Clear()
{
Debug.WriteLine("clear");
ChartValues.Clear();
}
}
public class MeasureModel
{
public DateTime DateTime { get; set; }
public double Value { get; set; }
}
}

View File

@@ -0,0 +1,25 @@
using System.Collections.ObjectModel;
using Util;
namespace DoctorApp.Models
{
class PatientInfo : ObservableObject
{
public ObservableCollection<string> ChatLog { get; set; }
public string Username { get; set; }
public string Status { get; set; }
public double Speed { get; set; }
public int BPM { get; set; }
public float Resistance { get; set; }
public int Acc_Power { get; set; }
public int Curr_Power { get; set; }
public int Distance { get; set; }
}
}

View File

@@ -10,7 +10,7 @@ using Util;
namespace DoctorApp.Utils namespace DoctorApp.Utils
{ {
public delegate void EngineCallback(); public delegate void EngineCallback();
public class Client : IDataReceiver public class Client
{ {
private TcpClient client; private TcpClient client;
private NetworkStream stream; private NetworkStream stream;
@@ -18,8 +18,6 @@ namespace DoctorApp.Utils
private bool connected; private bool connected;
private byte[] totalBuffer = new byte[1024]; private byte[] totalBuffer = new byte[1024];
private int totalBufferReceived = 0; private int totalBufferReceived = 0;
private bool sessionRunning = false;
private IHandler handler = null;
private LoginViewModel LoginViewModel; private LoginViewModel LoginViewModel;
private MainViewModel MainViewModel; private MainViewModel MainViewModel;
private ClientInfoViewModel ClientInfoViewModel; private ClientInfoViewModel ClientInfoViewModel;
@@ -83,6 +81,7 @@ namespace DoctorApp.Utils
string identifier; string identifier;
bool isJson = DataParser.getJsonIdentifier(messageBytes, out identifier); bool isJson = DataParser.getJsonIdentifier(messageBytes, out identifier);
if (isJson) if (isJson)
{ {
switch (identifier) switch (identifier)
@@ -91,7 +90,7 @@ namespace DoctorApp.Utils
string responseStatus = DataParser.getResponseStatus(payloadbytes); string responseStatus = DataParser.getResponseStatus(payloadbytes);
if (responseStatus == "OK") if (responseStatus == "OK")
{ {
Debug.WriteLine("Username and password correct!"); Debug.WriteLine("Doctor Username and password correct!");
this.LoginViewModel.setLoginStatus(true); this.LoginViewModel.setLoginStatus(true);
this.connected = true; this.connected = true;
@@ -102,49 +101,41 @@ namespace DoctorApp.Utils
Debug.WriteLine($"login failed \"{responseStatus}\""); Debug.WriteLine($"login failed \"{responseStatus}\"");
} }
break; break;
/*case DataParser.START_SESSION: case DataParser.START_SESSION:
Console.WriteLine("Session started!"); Console.WriteLine("Session started!");
this.sessionRunning = true;
sendMessage(DataParser.getStartSessionJson());
break; break;
case DataParser.STOP_SESSION: case DataParser.STOP_SESSION:
Console.WriteLine("Stop session identifier"); Console.WriteLine("Stop session identifier");
this.sessionRunning = false; break;
sendMessage(DataParser.getStopSessionJson());
break;*/
case DataParser.SET_RESISTANCE: case DataParser.SET_RESISTANCE:
Console.WriteLine("Set resistance identifier"); Console.WriteLine("Set resistance identifier");
if (this.handler == null)
{
Console.WriteLine("handler is null");
sendMessage(DataParser.getSetResistanceResponseJson(false));
}
else
{
this.handler.setResistance(DataParser.getResistanceFromJson(payloadbytes));
sendMessage(DataParser.getSetResistanceResponseJson(true));
}
break; break;
case DataParser.NEW_CONNECTION: case DataParser.NEW_CONNECTION:
this.MainViewModel.NewConnectedUser(DataParser.getUsernameFromResponseJson(payloadbytes)); this.MainViewModel.NewConnectedUser(DataParser.getUsernameFromJson(payloadbytes));
break; break;
case DataParser.DISCONNECT: case DataParser.DISCONNECT:
this.MainViewModel.DisconnectedUser(DataParser.getUsernameFromResponseJson(payloadbytes)); this.MainViewModel.DisconnectedUser(DataParser.getUsernameFromJson(payloadbytes));
break; break;
default: default:
Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}"); Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}");
break; break;
} }
} }
else if (DataParser.isRawData(messageBytes)) else if (DataParser.isRawDataBikeDoctor(messageBytes))
{ {
Console.WriteLine($"Received data: {BitConverter.ToString(payloadbytes)}"); MainViewModel.TransferDataToClientBike(payloadbytes);
} }
else if (DataParser.isRawDataBPMDoctor(messageBytes))
{
MainViewModel.TransferDataToClientBPM(payloadbytes);
}
Array.Copy(totalBuffer, expectedMessageLength, totalBuffer, 0, (totalBufferReceived - expectedMessageLength)); //maybe unsafe idk
totalBufferReceived -= expectedMessageLength; totalBufferReceived -= expectedMessageLength;
expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0);
} }
if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.client.Connected)
return;
this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null);
} }
@@ -167,63 +158,6 @@ namespace DoctorApp.Utils
this.stream.EndWrite(ar); this.stream.EndWrite(ar);
} }
#region interface
//maybe move this to other place
/// <summary>
/// bpm method for receiving the BPM value from the bluetooth bike or the simulation
/// </summary>
/// <param name="bytes">the message</param>
public void BPM(byte[] bytes)
{
if (!sessionRunning)
{
return;
}
if (bytes == null)
{
throw new ArgumentNullException("no bytes");
}
byte[] message = DataParser.GetRawDataMessage(bytes);
this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null);
}
/// <summary>
/// method for receiving the bike message from the bluetooth bike or the simulation
/// </summary>
/// <param name="bytes">the message</param>
public void Bike(byte[] bytes)
{
if (!sessionRunning)
{
return;
}
if (bytes == null)
{
throw new ArgumentNullException("no bytes");
}
byte[] message = DataParser.GetRawDataMessage(bytes);
/* switch (bytes[0])
{
case 0x10:
if (canSendToEngine) engineConnection.BikeSpeed = (bytes[4] | (bytes[5] << 8)) * 0.01f;
break;
case 0x19:
if (canSendToEngine) engineConnection.BikePower = (bytes[5]) | (bytes[6] & 0b00001111) << 8;
break;
}*/
this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null);
}
#endregion
/// <summary> /// <summary>
/// wether or not the client stream is connected /// wether or not the client stream is connected
/// </summary> /// </summary>
@@ -240,21 +174,12 @@ namespace DoctorApp.Utils
string hashPassword = Util.Hasher.HashString(password); string hashPassword = Util.Hasher.HashString(password);
byte[] message = DataParser.getJsonMessage(DataParser.GetLoginJson(username, hashPassword)); byte[] message = DataParser.getJsonMessage(DataParser.LoginAsDoctor(username, hashPassword));
this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null);
} }
/// <summary>
/// sets the handler for the client, so either the bike simulator or the bluetooth bike handler
/// </summary>
/// <param name="handler"></param>
public void SetHandler(IHandler handler)
{
this.handler = handler;
}
internal void SetLoginViewModel(LoginViewModel loginViewModel) internal void SetLoginViewModel(LoginViewModel loginViewModel)
{ {
this.LoginViewModel = loginViewModel; this.LoginViewModel = loginViewModel;
@@ -273,9 +198,9 @@ namespace DoctorApp.Utils
public void Dispose() public void Dispose()
{ {
Debug.WriteLine("client dispose called"); Debug.WriteLine("client dispose called");
sendMessage(DataParser.getDisconnectJson(LoginViewModel.Username));
this.stream.Dispose(); this.stream.Dispose();
this.client.Dispose(); this.client.Dispose();
this.handler?.stop();
} }
} }
} }

View File

@@ -1,9 +1,11 @@
using DoctorApp.Utils; using DoctorApp.Models;
using DoctorApp.Utils;
using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Command;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Text; using System.Text;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
@@ -11,24 +13,21 @@ using Util;
namespace DoctorApp.ViewModels namespace DoctorApp.ViewModels
{ {
class ClientInfoViewModel : ObservableObject class ClientInfoViewModel : ObservableObject
{ {
public ObservableCollection<string> ChatLog { get; set; } public PatientInfo PatientInfo { get; set; }
public string Username { get; set; }
public string Status { get; set; } private string _mySelectedItem;
public string MySelectedItem
public int Speed { get; set; } {
get { return _mySelectedItem; }
public int BPM { get; set; } set
{
public int Resistance { get; set; } Chart.Clear();
public int Acc_Power { get; set; } _mySelectedItem = value;
}
public int Curr_Power { get; set; } }
public int Distance { get; set; }
public ICommand StartSession { get; set; } public ICommand StartSession { get; set; }
@@ -44,36 +43,106 @@ namespace DoctorApp.ViewModels
public MainWindowViewModel MainWindowViewModel { get; set; } public MainWindowViewModel MainWindowViewModel { get; set; }
private Client client; private Client client;
private MainViewModel parent;
public ClientInfoViewModel(MainWindowViewModel mainWindowViewModel) public Chart Chart { get; set; }
public ClientInfoViewModel(MainViewModel parent,MainWindowViewModel mainWindowViewModel, string username)
{ {
MainWindowViewModel = mainWindowViewModel; MainWindowViewModel = mainWindowViewModel;
ChatLog = new ObservableCollection<string>(); this.parent = parent;
this.PatientInfo = new PatientInfo() { Username = username, Status = "Waiting to start" };
this.Chart = new Chart(this.PatientInfo);
PatientInfo.ChatLog = new ObservableCollection<string>();
client = mainWindowViewModel.client; client = mainWindowViewModel.client;
StartSession = new RelayCommand(()=>{ StartSession = new RelayCommand(() =>
client.sendMessage(DataParser.getStartSessionJson(Username)); {
Status = "Session started"; client.sendMessage(DataParser.getStartSessionJson(PatientInfo.Username));
PatientInfo.Status = "Session started";
}); });
StopSession = new RelayCommand(() => { StopSession = new RelayCommand(() =>
client.sendMessage(DataParser.getStopSessionJson(Username)); {
Status = "Session stopped, waiting to start again."; client.sendMessage(DataParser.getStopSessionJson(PatientInfo.Username));
PatientInfo.Status = "Session stopped, waiting to start again.";
}); });
Chat = new RelayCommand<object>((parameter) => Chat = new RelayCommand<object>((parameter) =>
{ {
client.sendMessage(DataParser.getChatJson(Username, ((TextBox)parameter).Text)); SendMessageToClient(PatientInfo.Username, ((TextBox)parameter).Text);
ChatLog.Add(DateTime.Now+": "+ ((TextBox)parameter).Text);
}); });
//TODO RelayCommand ChatToAll //TODO RelayCommand ChatToAll
SetResistance = new RelayCommand<object>((parameter) => ChatToAll = new RelayCommand<object>((parameter) =>
{ {
client.sendMessage(DataParser.getSetResistanceJson(Username, float.Parse(((TextBox)parameter).Text))); Debug.WriteLine("[CLIENTINFOVIEWMODEL] sending message to all clients");
this.parent?.SendToAllClients(((TextBox)parameter).Text);
}); });
SetResistance = new RelayCommand<object>((parameter) =>
{
Debug.WriteLine("resistance");
//client.sendMessage(DataParser.getSetResistanceJson(PatientInfo.Username, float.Parse(((TextBox)parameter).Text)));
PatientInfo.Resistance = float.Parse(((TextBox)parameter).Text);
});
}
public void SendMessageToClient(string username, string text)
{
client.sendMessage(DataParser.getChatJson(username, text));
PatientInfo.ChatLog.Add(DateTime.Now + ": " + text);
}
public void BPMData(byte [] bytes)
{
//TODO
//Parsen van de data you fuck
if(bytes[0] == 0x00)
{
}
else
{
PatientInfo.BPM = bytes[1];
if (MySelectedItem == "BPM")
{
Chart.NewValue(PatientInfo.BPM);
}
}
}
public void BikeData(byte[] bytes)
{
//TODO
//Parsen van de data you fuck
switch (bytes[0])
{
case 0x10:
if (bytes[1] != 25)
{
throw new Exception();
}
PatientInfo.Distance = bytes[3];
PatientInfo.Speed = (bytes[4] | (bytes[5] << 8)) * 0.01;
if (MySelectedItem == "Speed")
{
Chart.NewValue(PatientInfo.Speed);
}
break;
case 0x19:
PatientInfo.Acc_Power = bytes[3] | (bytes[4] << 8);
PatientInfo.Curr_Power = (bytes[5]) | (bytes[6] & 0b00001111) << 8;
break;
default:
Debug.WriteLine("rip");
break;
}
} }

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Text; using System.Text;
using System.Windows.Controls; using System.Windows.Controls;
using Util; using Util;
@@ -21,18 +22,15 @@ namespace DoctorApp.ViewModels
{ {
this.MainWindowViewModel = mainWindowViewModel; this.MainWindowViewModel = mainWindowViewModel;
client = this.MainWindowViewModel.client; client = this.MainWindowViewModel.client;
Tabs= new ObservableCollection<ClientInfoViewModel>(); Tabs = new ObservableCollection<ClientInfoViewModel>();
} }
public void NewConnectedUser(string username) public void NewConnectedUser(string username)
{ {
Debug.WriteLine("new tab with name " + username);
App.Current.Dispatcher.Invoke((Action)delegate App.Current.Dispatcher.Invoke((Action)delegate
{ {
Tabs.Add(new ClientInfoViewModel(MainWindowViewModel) Tabs.Add(new ClientInfoViewModel(this,MainWindowViewModel, username));
{
Username = username,
Status = "Waiting to start"
});
}); });
} }
@@ -42,7 +40,7 @@ namespace DoctorApp.ViewModels
{ {
foreach (ClientInfoViewModel item in Tabs) foreach (ClientInfoViewModel item in Tabs)
{ {
if (item.Username == username) if (item.PatientInfo.Username == username)
{ {
Tabs.Remove(item); Tabs.Remove(item);
break; break;
@@ -50,7 +48,40 @@ namespace DoctorApp.ViewModels
} }
}); });
} }
public void TransferDataToClientBike(byte[] bytes)
{
string username = DataParser.getNameFromBytesBike(bytes);
foreach(ClientInfoViewModel item in Tabs)
{
if(item.PatientInfo.Username == username)
{
item.BikeData(DataParser.getDataWithoutName(bytes,0,8));
}
}
}
public void TransferDataToClientBPM(byte[] bytes)
{
string username = DataParser.getNameFromBytesBPM(bytes);
foreach (ClientInfoViewModel item in Tabs)
{
if (item.PatientInfo.Username == username)
{
item.BikeData(DataParser.getDataWithoutName(bytes, 0,2));
}
}
}
internal void SendToAllClients(string text)
{
Debug.WriteLine("[MAINVIEWMODEL] Sending message to all clients: " + text);
foreach (ClientInfoViewModel item in Tabs)
{
item.SendMessageToClient(item.PatientInfo.Username, text);
}
}
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Windows.Input;
using DoctorApp.Models; using DoctorApp.Models;
using DoctorApp.Utils; using DoctorApp.Utils;
using Util.MagicCode; using Util.MagicCode;
using System;
namespace DoctorApp.ViewModels namespace DoctorApp.ViewModels
{ {

View File

@@ -5,8 +5,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DoctorApp.Views" xmlns:local="clr-namespace:DoctorApp.Views"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
> d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="15,5,15,15"> <Grid Margin="15,5,15,15">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/> <ColumnDefinition Width="5*"/>
@@ -24,8 +24,8 @@
<Setter Property="Margin" Value="0,0,20,0"/> <Setter Property="Margin" Value="0,0,20,0"/>
</Style> </Style>
</StackPanel.Resources> </StackPanel.Resources>
<Label Content="{Binding Path=Username}"/> <Label Content="{Binding Path=PatientInfo.Username}"/>
<Label Content="{Binding Path=Status}"/> <Label Content="{Binding Path=PatientInfo.Status}"/>
</StackPanel> </StackPanel>
<StackPanel Margin="0,10,0,0" Grid.RowSpan="2" Grid.Row="1"> <StackPanel Margin="0,10,0,0" Grid.RowSpan="2" Grid.Row="1">
<StackPanel.Resources> <StackPanel.Resources>
@@ -39,9 +39,9 @@
<Label Content="Current BPM" Width="110" DockPanel.Dock="Top"/> <Label Content="Current BPM" Width="110" DockPanel.Dock="Top"/>
</DockPanel> </DockPanel>
<DockPanel Height="26" LastChildFill="False" HorizontalAlignment="Stretch"> <DockPanel Height="26" LastChildFill="False" HorizontalAlignment="Stretch">
<TextBox Name="textBox_Resistance" Text="{Binding Path=Resistance}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Right" IsReadOnly="true"/> <TextBox Name="textBox_Resistance" Text="{Binding Path=PatientInfo.Resistance}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Right" IsReadOnly="true"/>
<TextBox Name="textBox_CurrentSpeed" Text="{Binding Path=Speed}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Left" IsReadOnly="true"/> <TextBox Name="textBox_CurrentSpeed" Text="{Binding Path=PatientInfo.Speed}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Left" IsReadOnly="true"/>
<TextBox Name="textBox_CurrentBPM" Text="{Binding Path=BPM}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Top" Height="26" IsReadOnly="true"/> <TextBox Name="textBox_CurrentBPM" Text="{Binding Path=PatientInfo.BPM}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Top" Height="26" IsReadOnly="true"/>
</DockPanel> </DockPanel>
<DockPanel Height="26" LastChildFill="False"> <DockPanel Height="26" LastChildFill="False">
<Label Content="Distance Covered" Width="110" DockPanel.Dock="Right"/> <Label Content="Distance Covered" Width="110" DockPanel.Dock="Right"/>
@@ -49,19 +49,42 @@
<Label Content="Acc. Power" Width="110" DockPanel.Dock="Top"/> <Label Content="Acc. Power" Width="110" DockPanel.Dock="Top"/>
</DockPanel> </DockPanel>
<DockPanel Height="26" LastChildFill="False"> <DockPanel Height="26" LastChildFill="False">
<TextBox Name="textBox_DistanceCovered" Text="{Binding Path=Distance}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Right" IsReadOnly="true"/> <TextBox Name="textBox_DistanceCovered" Text="{Binding Path=PatientInfo.Distance}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Right" IsReadOnly="true"/>
<TextBox Name="textBox_CurrentPower" Text="{Binding Path=Curr_Power}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Left" IsReadOnly="true"/> <TextBox Name="textBox_CurrentPower" Text="{Binding Path=PatientInfo.Curr_Power}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Left" IsReadOnly="true"/>
<TextBox Name="textBox_AccPower" Text="{Binding Path=Acc_Power}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Top" Height="26" IsReadOnly="true"/> <TextBox Name="textBox_AccPower" Text="{Binding Path=PatientInfo.Acc_Power}" TextWrapping="Wrap" Width="110" DockPanel.Dock="Top" Height="26" IsReadOnly="true"/>
</DockPanel> </DockPanel>
</StackPanel> </StackPanel>
<ListBox Name="ChatBox" ItemsSource="{Binding ChatLog}" Grid.Column="1" Margin="59,41,0,0" Grid.RowSpan="3"/> <ListBox Name="ChatBox" ItemsSource="{Binding PatientInfo.ChatLog}" Grid.Column="1" Margin="59,41,0,0" Grid.RowSpan="3"/>
<TextBox Name="textBox_Chat" Grid.Column="1" HorizontalAlignment="Left" Margin="59,10,0,0" Grid.Row="3" Text="TextBox" TextWrapping="Wrap" VerticalAlignment="Top" Width="235"/> <TextBox Name="textBox_Chat" Grid.Column="1" HorizontalAlignment="Left" Margin="59,10,0,0" Grid.Row="3" Text="" TextWrapping="Wrap" VerticalAlignment="Top" Width="235"/>
<Button x:Name="Send" Content="Send" Grid.Column="1" HorizontalAlignment="Left" Margin="59,33,0,0" Grid.Row="3" VerticalAlignment="Top" Command="{Binding Chat}" CommandParameter="{Binding ElementName=textBox_Chat}"/> <Button x:Name="Send" Content="Send" Grid.Column="1" HorizontalAlignment="Left" Margin="59,33,0,0" Grid.Row="3" VerticalAlignment="Top" Command="{Binding Chat}" CommandParameter="{Binding ElementName=textBox_Chat}"/>
<Button x:Name="SendToAll" Content="Send to all clients" Grid.Column="1" HorizontalAlignment="Left" Margin="107,33,0,0" Grid.Row="3" VerticalAlignment="Top" Command="{Binding ChatToAll}" CommandParameter="{Binding ElementName=textBox_Chat}"/>
<Button Content="Start Session" Grid.Column="1" HorizontalAlignment="Left" Margin="69,86,0,0" Grid.Row="3" VerticalAlignment="Top" Width="97" Command="{Binding StartSession}" CommandParameter=""/> <Button Content="Start Session" Grid.Column="1" HorizontalAlignment="Left" Margin="69,86,0,0" Grid.Row="3" VerticalAlignment="Top" Width="97" Command="{Binding StartSession}" CommandParameter=""/>
<Button Content="Stop Session" Grid.Column="1" HorizontalAlignment="Left" Margin="187,86,0,0" Grid.Row="3" VerticalAlignment="Top" Width="97" Command="{Binding StopSession}" CommandParameter=""/> <Button Content="Stop Session" Grid.Column="1" HorizontalAlignment="Left" Margin="187,86,0,0" Grid.Row="3" VerticalAlignment="Top" Width="97" Command="{Binding StopSession}" CommandParameter=""/>
<TextBox x:Name="textBox_SetResistance" Grid.Column="1" HorizontalAlignment="Left" Margin="69,128,0,0" Grid.Row="3" TextWrapping="Wrap" VerticalAlignment="Top" Width="97"/> <TextBox x:Name="textBox_SetResistance" Grid.Column="1" HorizontalAlignment="Left" Margin="69,128,0,0" Grid.Row="3" TextWrapping="Wrap" VerticalAlignment="Top" Width="97"/>
<Button Content="Set Resistance" Grid.Column="1" HorizontalAlignment="Left" Margin="187,128,0,0" Grid.Row="3" VerticalAlignment="Top" Width="97" Height="18" Command="{Binding SetResistance}" CommandParameter="{Binding ElementName=textBox_SetResistance}"/> <Button Content="Set Resistance" Grid.Column="1" HorizontalAlignment="Left" Margin="187,128,0,0" Grid.Row="3" VerticalAlignment="Top" Width="97" Height="18" Command="{Binding SetResistance}" CommandParameter="{Binding ElementName=textBox_SetResistance}"/>
<Canvas Grid.Row="3" Background="White" Margin="0,33,0,0"/> <lvc:CartesianChart Grid.Row="3" AnimationsSpeed="0:0:0.5" Hoverable="False" DataTooltip="{x:Null}" Margin="0,33,0,-5">
<ComboBox Name="DropBox" HorizontalAlignment="Left" Margin="0,6,0,0" Grid.Row="3" VerticalAlignment="Top" Width="190"/> <lvc:CartesianChart.Series>
<lvc:LineSeries Values="{Binding Chart.ChartValues}"
PointGeometry="{x:Null}"
LineSmoothness="1"
StrokeThickness="6"
Stroke="#F34336"
Fill="Transparent"/>
</lvc:CartesianChart.Series>
<lvc:CartesianChart.AxisX>
<lvc:Axis LabelFormatter="{Binding Chart.DateTimeFormatter}"
MaxValue="{Binding Chart.AxisMax}"
MinValue="{Binding Chart.AxisMin}"
Unit="{Binding Chart.AxisUnit}">
<lvc:Axis.Separator>
<lvc:Separator Step="{Binding Chart.AxisStep}" />
</lvc:Axis.Separator>
</lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
<ComboBox Name="DropBox" HorizontalAlignment="Left" Margin="0,6,0,0" Grid.Row="3" VerticalAlignment="Top" Width="190" SelectedItem="{Binding Path=MySelectedItem}">
<ComboBoxItem Content="Speed" IsSelected="True"></ComboBoxItem>
<ComboBoxItem Content="BPM"></ComboBoxItem>
</ComboBox>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DoctorApp.Views" xmlns:local="clr-namespace:DoctorApp.Views"
xmlns:viewModels="clr-namespace:DoctorApp.ViewModels" xmlns:viewModels="clr-namespace:DoctorApp.ViewModels"
xmlns:Util="clr-namespace:Util.MagicCode"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
> >
@@ -12,9 +13,9 @@
<DockPanel> <DockPanel>
<StackPanel VerticalAlignment="Center" Width="auto"> <StackPanel VerticalAlignment="Center" Width="auto">
<Label Content="Username" HorizontalContentAlignment="Center" /> <Label Content="Username" HorizontalContentAlignment="Center" />
<TextBox x:Name="Username" Text="{Binding Username}" TextWrapping="Wrap" Width="120"/> <TextBox x:Name="Username" Text="{Binding Username}" TextWrapping="Wrap" Width="120" Util:FocusAdvancement.AdvancesByEnterKey="True"/>
<Label Content="Password" HorizontalContentAlignment="Center"/> <Label Content="Password" HorizontalContentAlignment="Center"/>
<PasswordBox x:Name="Password" Width="120"/> <PasswordBox x:Name="Password" Width="120" Util:FocusAdvancement.AdvancesByEnterKey="True"/>
<Button x:Name="Login" Content="Login" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=Password}" Margin="0,20,0,0" Width="120"/> <Button x:Name="Login" Content="Login" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=Password}" Margin="0,20,0,0" Width="120"/>
<Popup IsOpen="{Binding InvertedLoginStatus}" PopupAnimation = "Fade" HorizontalAlignment="Left"> <Popup IsOpen="{Binding InvertedLoginStatus}" PopupAnimation = "Fade" HorizontalAlignment="Left">
<Label Content="Login failed" Foreground="Red" Background="#FFFF" /> <Label Content="Login failed" Foreground="Red" Background="#FFFF" />

View File

@@ -11,7 +11,10 @@
<TabControl TabStripPlacement="Left" ItemsSource="{Binding Tabs}" SelectedItem="{Binding Selected}"> <TabControl TabStripPlacement="Left" ItemsSource="{Binding Tabs}" SelectedItem="{Binding Selected}">
<TabControl.ItemTemplate> <TabControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding Username}"/> <StackPanel Orientation="Horizontal">
<Image Source="/img/patient.png" Width="25" Margin="0 0 5 0"/>
<TextBlock Text="{Binding PatientInfo.Username}" FontSize="20" MaxWidth="100" Width="100" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</DataTemplate> </DataTemplate>
</TabControl.ItemTemplate> </TabControl.ItemTemplate>
<TabControl.ContentTemplate> <TabControl.ContentTemplate>

View File

@@ -8,7 +8,9 @@
Background="Transparent" Background="Transparent"
WindowStyle="None" WindowStyle="None"
AllowsTransparency="True" AllowsTransparency="True"
Title="MainWindow" Height="450" Width="800"> MinHeight="{Binding MinimumHeight}"
MinWidth="{Binding MinimumWidth}"
Title="MainWindow" Height="500" Width="900">
<Window.Resources> <Window.Resources>
<Style TargetType="{x:Type local:MainWindow}"> <Style TargetType="{x:Type local:MainWindow}">
<Setter Property="Template"> <Setter Property="Template">
@@ -52,7 +54,7 @@
<!-- icon --> <!-- icon -->
<Button Grid.Column="0" Style="{StaticResource SystemIconButton}" Command="{Binding MenuCommand}"> <Button Grid.Column="0" Style="{StaticResource SystemIconButton}" Command="{Binding MenuCommand}">
<Image Source="/Images/Logo/icon1.ico"/> <Image Source="/img/doctor.ico"/>
<!--<TextBlock Text="icon"/>--> <!--<TextBlock Text="icon"/>-->
</Button> </Button>

BIN
DoctorApp/doctor.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

BIN
DoctorApp/img/doctor.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

BIN
DoctorApp/img/patient.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,9 +1,11 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
using System; using System;
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime; using System.Runtime.InteropServices.WindowsRuntime;
using System.Security.Cryptography;
using System.Text; using System.Text;
namespace Util namespace Util
@@ -40,6 +42,16 @@ namespace Util
return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)); return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json));
} }
internal static string getNameFromBytesBike(byte[] bytes)
{
return getName(bytes, 8, bytes.Length - 8);
}
/// <summary>
/// converts the given string parameter into a message using our protocol.
/// </summary>
/// <param name="messageToSend">the message string to send</param>
/// <returns>a byte array using our protocol to send the message</returns>
public static byte[] GetMessageToSend(string messageToSend) public static byte[] GetMessageToSend(string messageToSend)
{ {
dynamic json = new dynamic json = new
@@ -53,6 +65,24 @@ namespace Util
return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)); return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json));
} }
internal static string getNameFromBytesBPM(byte[] bytes)
{
return getName(bytes, 2, bytes.Length - 2);
}
private static string getName(byte[] bytes , int offset, int lenght)
{
byte[] nameArray = new byte[lenght];
Array.Copy(bytes, offset, nameArray, 0, lenght);
return Encoding.UTF8.GetString(nameArray);
}
/// <summary>
/// creates a message for when the doctor wants to log in.
/// </summary>
/// <param name="mUsername">the username of the doctor</param>
/// <param name="mPassword">the (hashed) password of the doctor</param>
/// <returns>a byte array using our protocol that contains the username and password of the doctor</returns>
public static byte[] LoginAsDoctor(string mUsername, string mPassword) public static byte[] LoginAsDoctor(string mUsername, string mPassword)
{ {
dynamic json = new dynamic json = new
@@ -68,6 +98,13 @@ namespace Util
return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)); return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json));
} }
/// <summary>
/// gets the username and password from a given message array.
/// </summary>
/// <param name="jsonbytes">the array of bytes containing the message</param>
/// <param name="username">the username variable that the username will be put into</param>
/// <param name="password">the password variable that the password will be put into</param>
/// <returns><c>true</c> if the username and password were received correctly, <c>false</c> otherwise</returns>
public static bool GetUsernamePassword(byte[] jsonbytes, out string username, out string password) public static bool GetUsernamePassword(byte[] jsonbytes, out string username, out string password)
{ {
dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(jsonbytes)); dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(jsonbytes));
@@ -85,6 +122,12 @@ namespace Util
} }
} }
/// <summary>
/// gets message using our protocol of the given identifier and data.
/// </summary>
/// <param name="mIdentifier">the identifier string of the message</param>
/// <param name="data">the payload data of the message</param>
/// <returns>a byte array containing the json message with the given parameters, using our protocol.</returns>
private static byte[] getJsonMessage(string mIdentifier, dynamic data) private static byte[] getJsonMessage(string mIdentifier, dynamic data)
{ {
dynamic json = new dynamic json = new
@@ -95,6 +138,11 @@ namespace Util
return getMessage(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)), 0x01); return getMessage(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)), 0x01);
} }
/// <summary>
/// gets a message using our protocol with only the given identifier string.
/// </summary>
/// <param name="mIdentifier">the identifier to put into the message</param>
/// <returns>a byte array containing the json with only the identifier, using our protocol.</returns>
private static byte[] getJsonMessage(string mIdentifier) private static byte[] getJsonMessage(string mIdentifier)
{ {
dynamic json = new dynamic json = new
@@ -104,11 +152,21 @@ namespace Util
return getMessage(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)), 0x01); return getMessage(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)), 0x01);
} }
/// <summary>
/// gets the login response of the given status
/// </summary>
/// <param name="mStatus">the status of the response</param>
/// <returns>a byte array containing the response for the given status, using our protocol.</returns>
public static byte[] getLoginResponse(string mStatus) public static byte[] getLoginResponse(string mStatus)
{ {
return getJsonMessage(LOGIN_RESPONSE, new { status = mStatus }); return getJsonMessage(LOGIN_RESPONSE, new { status = mStatus });
} }
/// <summary>
/// gets the status of the given json message
/// </summary>
/// <param name="json">the byte array containing a json message using our protocol</param>
/// <returns>the response of the message</returns>
public static string getResponseStatus(byte[] json) public static string getResponseStatus(byte[] json)
{ {
return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.status; return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.status;
@@ -146,7 +204,7 @@ namespace Util
/// </summary> /// </summary>
/// <param name="bytes">message</param> /// <param name="bytes">message</param>
/// <returns>if message contains raw data</returns> /// <returns>if message contains raw data</returns>
public static bool isRawData(byte[] bytes) public static bool isRawDataBikeServer(byte[] bytes)
{ {
if (bytes.Length <= 5) if (bytes.Length <= 5)
{ {
@@ -155,6 +213,34 @@ namespace Util
return bytes[4] == 0x02; return bytes[4] == 0x02;
} }
public static bool isRawDataBPMServer(byte[] bytes)
{
if (bytes.Length <= 5)
{
throw new ArgumentException("bytes to short");
}
return bytes[4] == 0x03;
}
public static bool isRawDataBikeDoctor(byte[] bytes)
{
if (bytes.Length <= 5)
{
throw new ArgumentException("bytes to short");
}
return bytes[4] == 0x04;
}
public static bool isRawDataBPMDoctor(byte[] bytes)
{
if (bytes.Length <= 5)
{
throw new ArgumentException("bytes to short");
}
return bytes[4] == 0x05;
}
/// <summary> /// <summary>
/// constructs a message with the payload, messageId and clientId /// constructs a message with the payload, messageId and clientId
/// </summary> /// </summary>
@@ -179,11 +265,34 @@ namespace Util
/// <param name="payload"></param> /// <param name="payload"></param>
/// <param name="clientId"></param> /// <param name="clientId"></param>
/// <returns>the message ready for sending</returns> /// <returns>the message ready for sending</returns>
public static byte[] GetRawDataMessage(byte[] payload) public static byte[] GetRawBikeDataMessageServer(byte[] payload)
{ {
return getMessage(payload, 0x02); return getMessage(payload, 0x02);
} }
public static byte[] GetRawBPMDataMessageServer(byte[] payload)
{
return getMessage(payload, 0x03);
}
public static byte[] GetRawBikeDataDoctor(byte[] payload, string username)
{
return GetRawDataDoctor(payload, username, 0x04);
}
public static byte[] GetRawBPMDataDoctor(byte[] payload, string username)
{
return GetRawDataDoctor(payload,username,0x05);
}
private static byte[] GetRawDataDoctor(byte[] payload, string username, byte messageID)
{
return getMessage(payload.Concat(Encoding.ASCII.GetBytes(username)).ToArray(), messageID);
}
/// <summary> /// <summary>
/// constructs a message with the payload and clientId and assumes the payload is json /// constructs a message with the payload and clientId and assumes the payload is json
/// </summary> /// </summary>
@@ -195,6 +304,11 @@ namespace Util
return getMessage(payload, 0x01); return getMessage(payload, 0x01);
} }
/// <summary>
/// gets the message to start a session with the given user username
/// </summary>
/// <param name="user">the username of the user we want to start the session for</param>
/// <returns>a byte array containing the message to start the session of the given user, using our protocol.</returns>
public static byte[] getStartSessionJson(string user) public static byte[] getStartSessionJson(string user)
{ {
dynamic data = new dynamic data = new
@@ -204,6 +318,11 @@ namespace Util
return getJsonMessage(START_SESSION, data); return getJsonMessage(START_SESSION, data);
} }
/// <summary>
/// gets the message to stop a session with the given user username
/// </summary>
/// <param name="user">the username of the user we want to stop the session for</param>
/// <returns>a byte array containing the message to stop the session of the given user, using our protocol.</returns>
public static byte[] getStopSessionJson(string user) public static byte[] getStopSessionJson(string user)
{ {
dynamic data = new dynamic data = new
@@ -212,7 +331,13 @@ namespace Util
}; };
return getJsonMessage(STOP_SESSION, data); return getJsonMessage(STOP_SESSION, data);
} }
/// <summary>
/// gets the message to set the resistance of the given user with the given resistance.
/// </summary>
/// <param name="user">the username to set the resistance of.</param>
/// <param name="mResistance">the resistance value to set</param>
/// <returns>a byte array containing a json messsage to set the user's resistance, using our protocol.</returns>
public static byte[] getSetResistanceJson(string user,float mResistance) public static byte[] getSetResistanceJson(string user,float mResistance)
{ {
dynamic data = new dynamic data = new
@@ -223,6 +348,11 @@ namespace Util
return getJsonMessage(SET_RESISTANCE, data); return getJsonMessage(SET_RESISTANCE, data);
} }
/// <summary>
/// gets the response message with the given value.
/// </summary>
/// <param name="mWorked">the boolean value to indicate if the operation we want to send a response for was successful or not.</param>
/// <returns>a byte array containing a json message with the response and the given value.</returns>
public static byte[] getSetResistanceResponseJson(bool mWorked) public static byte[] getSetResistanceResponseJson(bool mWorked)
{ {
dynamic data = new dynamic data = new
@@ -232,8 +362,15 @@ namespace Util
return getJsonMessage(SET_RESISTANCE, data); return getJsonMessage(SET_RESISTANCE, data);
} }
/// <summary>
/// gets the message to indicate a new connection for the given user.
/// </summary>
/// <param name="user">the username of the user to start a connection for.</param>
/// <returns>a byte array containing a json message to indicate a new connection for the given user, using our protocol.</returns>
public static byte[] getNewConnectionJson(string user) public static byte[] getNewConnectionJson(string user)
{ {
if (user == null)
throw new ArgumentNullException("user null");
dynamic data = new dynamic data = new
{ {
username = user username = user
@@ -241,6 +378,11 @@ namespace Util
return getJsonMessage(NEW_CONNECTION, data); return getJsonMessage(NEW_CONNECTION, data);
} }
/// <summary>
/// gets the message for when a user has been disconnected.
/// </summary>
/// <param name="user">the username of the user that has been disconnected</param>
/// <returns>a byte array containing a json message to indicate that the given user has disconnected, using our protocol.</returns>
public static byte[] getDisconnectJson(string user) public static byte[] getDisconnectJson(string user)
{ {
dynamic data = new dynamic data = new
@@ -250,31 +392,63 @@ namespace Util
return getJsonMessage(DISCONNECT, data); return getJsonMessage(DISCONNECT, data);
} }
/// <summary>
/// gets the resistance from the given json message
/// </summary>
/// <param name="json">the json messag</param>
/// <returns>the resistance that was in the message</returns>
public static float getResistanceFromJson(byte[] json) public static float getResistanceFromJson(byte[] json)
{ {
return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.resistance; return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.resistance;
} }
/// <summary>
/// gets the resistance response from the given json message
/// </summary>
/// <param name="json">the byte array containin the json message</param>
/// <returns>the response of the message, so wether it was successful or not.</returns>
public static bool getResistanceFromResponseJson(byte[] json) public static bool getResistanceFromResponseJson(byte[] json)
{ {
Debug.WriteLine("got message " + Encoding.ASCII.GetString(json));
return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.worked; return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.worked;
} }
/// <summary>
/// gets the username from the given response message.
/// </summary>
/// <param name="json">the byte array containin the json message</param>
/// <returns>the username in the message.</returns>
public static string getUsernameFromResponseJson(byte[] json) public static string getUsernameFromResponseJson(byte[] json)
{ {
return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.username; return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.username;
} }
/// <summary>
/// gets the chat message from the given json message.
/// </summary>
/// <param name="json">the byte array containin the json message</param>
/// <returns>the chat message in the json message</returns>
public static string getChatMessageFromJson(byte[] json) public static string getChatMessageFromJson(byte[] json)
{ {
return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.chat; return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.chat;
} }
/// <summary>
/// gets the username from the given json message.
/// </summary>
/// <param name="json">the byte array containin the json message</param>
/// <returns>the username that is in the message</returns>
public static string getUsernameFromJson(byte[] json) public static string getUsernameFromJson(byte[] json)
{ {
return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.username; return ((dynamic)JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json))).data.username;
} }
/// <summary>
/// gets the byte array with the json message to send a message with the given parameters.
/// </summary>
/// <param name="user">the username of the user that wants to send the message</param>
/// <param name="message">the message the user wants to send</param>
/// <returns>a byte array containing a json message with the username and corresponding message, using our protocol.</returns>
public static byte[] getChatJson(string user, string message) public static byte[] getChatJson(string user, string message)
{ {
dynamic data = new dynamic data = new
@@ -285,6 +459,13 @@ namespace Util
return getJsonMessage(MESSAGE, data); return getJsonMessage(MESSAGE, data);
} }
public static byte[] getDataWithoutName(byte[] bytes, int offset, int length)
{
byte[] data = new byte[length];
Array.Copy(bytes, offset, data, 0, length);
return data;
}
} }
} }

View File

@@ -11,27 +11,28 @@
<ItemGroup> <ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)DataParser.cs" /> <Compile Include="$(MSBuildThisFileDirectory)DataParser.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Hasher.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Hasher.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MagicCode\WindowResizer.cs" /> <Compile Include="$(MSBuildThisFileDirectory)WPFStuff\MagicCode\FocusAdvancement.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ObservableObject.cs" /> <Compile Include="$(MSBuildThisFileDirectory)WPFStuff\MagicCode\WindowResizer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)WPFStuff\ObservableObject.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Include="$(MSBuildThisFileDirectory)Styles\Buttons.xaml"> <Page Include="$(MSBuildThisFileDirectory)WPFStuff\Styles\Buttons.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="$(MSBuildThisFileDirectory)Styles\Colors.xaml"> <Page Include="$(MSBuildThisFileDirectory)WPFStuff\Styles\Colors.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="$(MSBuildThisFileDirectory)Styles\Fonts.xaml"> <Page Include="$(MSBuildThisFileDirectory)WPFStuff\Styles\Fonts.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="$(MSBuildThisFileDirectory)Styles\Texts.xaml"> <Page Include="$(MSBuildThisFileDirectory)WPFStuff\Styles\Texts.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="$(MSBuildThisFileDirectory)Styles\Windows.xaml"> <Page Include="$(MSBuildThisFileDirectory)WPFStuff\Styles\Windows.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>

View File

@@ -0,0 +1,40 @@
using System;
using System.Windows;
using System.Windows.Input;
namespace Util.MagicCode
{
public static class FocusAdvancement
{
public static bool GetAdvancesByEnterKey(DependencyObject obj)
{
return (bool)obj.GetValue(AdvancesByEnterKeyProperty);
}
public static void SetAdvancesByEnterKey(DependencyObject obj, bool value)
{
obj.SetValue(AdvancesByEnterKeyProperty, value);
}
public static readonly DependencyProperty AdvancesByEnterKeyProperty =
DependencyProperty.RegisterAttached("AdvancesByEnterKey", typeof(bool), typeof(FocusAdvancement),
new UIPropertyMetadata(OnAdvancesByEnterKeyPropertyChanged));
static void OnAdvancesByEnterKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as UIElement;
if (element == null) return;
if ((bool)e.NewValue) element.KeyDown += Keydown;
else element.KeyDown -= Keydown;
}
static void Keydown(object sender, KeyEventArgs e)
{
if (!e.Key.Equals(Key.Enter)) return;
var element = sender as UIElement;
if (element != null) element.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}

View File

@@ -0,0 +1,65 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClientApp">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Colors.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type Button}" x:Key="Hoverless">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type Button}" x:Key="SystemIconButton" BasedOn="{StaticResource Hoverless}" >
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Padding" Value="4"/>
</Style>
<Style TargetType="{x:Type Button}" x:Key="WindowControlButton">
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Foreground" Value="{StaticResource ForegroundMainBrush}"/>
<Setter Property="Padding" Value="6"/>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="2"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource BackgroundSemiLightBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Button}" x:Key="WindowCloseButton" BasedOn="{StaticResource WindowControlButton}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,25 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClientApp">
<Color x:Key="BackgroundLight">#efefef</Color>
<SolidColorBrush x:Key="BackgroundLightBrush" Color="{StaticResource BackgroundLight}"/>
<Color x:Key="BackgroundVeryLight">#fafafa</Color>
<SolidColorBrush x:Key="BackgroundVeryLightBrush" Color="{StaticResource BackgroundVeryLight}"/>
<Color x:Key="BackgroundSemiLight">#d7d7d7</Color>
<SolidColorBrush x:Key="BackgroundSemiLightBrush" Color="{StaticResource BackgroundSemiLight}"/>
<Color x:Key="ForegroundMain">#686868</Color>
<SolidColorBrush x:Key="ForegroundMainBrush" Color="{StaticResource ForegroundMain}"/>
<Color x:Key="ForegroundVeryDark">#000</Color>
<SolidColorBrush x:Key="ForegroundVeryDarkBrush" Color="{StaticResource ForegroundVeryDark}"/>
<Color x:Key="ForegroundWhite">#fff</Color>
<SolidColorBrush x:Key="ForegroundWhiteBrush" Color="{StaticResource ForegroundWhite}"/>
</ResourceDictionary>

View File

@@ -0,0 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClientApp">
</ResourceDictionary>

View File

@@ -0,0 +1,11 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClientApp">
<Style TargetType="{x:Type TextBlock}" x:Key="HeaderText">
<Setter Property="Foreground" Value="{StaticResource ForegroundMainBrush}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0 4"/>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClientApp">
</ResourceDictionary>

View File

@@ -93,19 +93,26 @@ namespace Hardware.Simulators
//Generate an ANT message for page 0x10 //Generate an ANT message for page 0x10
private byte[] GenerateBike0x10() private byte[] GenerateBike0x10()
{ {
//SOMEONE FIX THIS!!!!!!!!!
try try
{ {
byte[] bikeByte = { 0x10, Convert.ToByte(equipmentType), Convert.ToByte(elapsedTime * 4 % 64), Convert.ToByte(distanceTraveled), speedArray[0], speedArray[1], Convert.ToByte(BPM), 0xFF }; byte[] bikeByte = { 0x10, check(equipmentType), check(elapsedTime * 4 % 64), check((int)Math.Round(distanceTraveled)), speedArray[0], speedArray[1], check(BPM), 0xFF };
return bikeByte; return bikeByte;
} }
catch (OverflowException e) catch (OverflowException e)
{ {
Debug.WriteLine(e); Debug.WriteLine(e);
return GenerateBike0x10(); byte[] res = { 0x10,0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0xFF};
return res;
} }
} }
private byte check(int value)
{
return value > 255 ? Convert.ToByte(255) : value < 0 ? Convert.ToByte(0) : Convert.ToByte(value);
}
//Generate an ANT message for BPM //Generate an ANT message for BPM
private byte[] GenerateHeart() private byte[] GenerateHeart()
{ {

View File

@@ -124,11 +124,13 @@ namespace RH_Engine
position = new float[] position = new float[]
{ {
-1.5f, 1f, 0f -1.5f, 1f, 0f
//0f,0f,0f
}, },
scale = 1, scale = 1,
rotation = new int[] rotation = new int[]
{ {
-30, 90,0 -30, 90,0
//0,0,0
} }
}, },
panel = new panel = new
@@ -253,6 +255,11 @@ namespace RH_Engine
return AddModel("bike", serial, "data\\NetworkEngine\\models\\bike\\bike.fbx"); return AddModel("bike", serial, "data\\NetworkEngine\\models\\bike\\bike.fbx");
} }
public string AddBikeModelAnim(string serial, float scalar)
{
return AddModel("bike", serial, "data\\NetworkEngine\\models\\bike\\bike_anim.fbx", "Armature|Fietsen", new float[] { 0, 0, 0 }, scalar, new float[] { 0, 0, 0 });
}
public string AddModel(string nodeName, string serial, string fileLocation) public string AddModel(string nodeName, string serial, string fileLocation)
{ {
return AddModel(nodeName, serial, fileLocation, null, new float[] { 0, 0, 0 }, 1, new float[] { 0, 0, 0 }); return AddModel(nodeName, serial, fileLocation, null, new float[] { 0, 0, 0 }, 1, new float[] { 0, 0, 0 });

View File

@@ -94,7 +94,7 @@ namespace RH_Engine
if (serialResponses.ContainsKey(serial)) if (serialResponses.ContainsKey(serial))
{ {
serialResponses[serial].Invoke(message); serialResponses[serial].Invoke(message);
serialResponses.Remove(serial); //serialResponses.Remove(serial);
} }
} }
} }
@@ -181,39 +181,41 @@ namespace RH_Engine
//Force(stream, mainCommand.DeleteNode(handRightId, "deleteHandR"), "deleteHandR", (message) => Console.WriteLine("Right hand deleted")); //Force(stream, mainCommand.DeleteNode(handRightId, "deleteHandR"), "deleteHandR", (message) => Console.WriteLine("Right hand deleted"));
}); });
CreateTerrain(stream, mainCommand); //CreateTerrain(stream, mainCommand);
//Add route, bike and put camera and bike to follow route at same speed. //Add route, bike and put camera and bike to follow route at same speed.
SendMessageAndOnResponse(stream, mainCommand.RouteCommand("routeID"), "routeID", (message) => routeId = JSONParser.GetResponseUuid(message)); //SendMessageAndOnResponse(stream, mainCommand.RouteCommand("routeID"), "routeID", (message) => routeId = JSONParser.GetResponseUuid(message));
SendMessageAndOnResponse(stream, mainCommand.AddBikeModel("bikeID"), "bikeID", SendMessageAndOnResponse(stream, mainCommand.AddBikeModelAnim("bikeID",0.01f), "bikeID",
(message) => (message) =>
{ {
bikeId = JSONParser.GetResponseUuid(message); bikeId = JSONParser.GetResponseUuid(message);
Console.WriteLine("got bike id " + bikeId);
SendMessageAndOnResponse(stream, mainCommand.addPanel("panelAdd", bikeId), "panelAdd", SendMessageAndOnResponse(stream, mainCommand.addPanel("panelAdd", bikeId), "panelAdd",
(message) => (message) =>
{ {
bool speedReplied = false; bool speedReplied = false;
bool moveReplied = true; bool moveReplied = true;
Console.WriteLine(message);
panelId = JSONParser.getPanelID(message); panelId = JSONParser.getPanelID(message);
Console.WriteLine("got panel id " + panelId);
showPanel(stream, mainCommand); showPanel(stream, mainCommand);
//while (!(speedReplied && moveReplied)) { } //while (!(speedReplied && moveReplied)) { }
while (cameraId == string.Empty) { } //while (cameraId == string.Empty) { }
SetFollowSpeed(5.0f, stream, mainCommand); //SetFollowSpeed(5.0f, stream, mainCommand);
WriteTextMessage(stream, mainCommand.RoadCommand(routeId, "road")); //WriteTextMessage(stream, mainCommand.RoadCommand(routeId, "road"));
WriteTextMessage(stream, mainCommand.ShowRoute("showRouteFalse", false)); //WriteTextMessage(stream, mainCommand.ShowRoute("showRouteFalse", false));
}); });
}); });
string groundplaneId = GetId("GroundPlane", stream, mainCommand); //string groundplaneId = GetId("GroundPlane", stream, mainCommand);
WriteTextMessage(stream, mainCommand.DeleteNode(groundplaneId, "none")); //WriteTextMessage(stream, mainCommand.DeleteNode(groundplaneId, "none"));
PlaceHouses(stream, mainCommand); //PlaceHouses(stream, mainCommand);
WriteTextMessage(stream, mainCommand.SkyboxCommand(DateTime.Now.Hour)); //WriteTextMessage(stream, mainCommand.SkyboxCommand(DateTime.Now.Hour));
} }
@@ -343,31 +345,36 @@ namespace RH_Engine
private static void showPanel(NetworkStream stream, Command mainCommand) private static void showPanel(NetworkStream stream, Command mainCommand)
{ {
WriteTextMessage(stream, mainCommand.ColorPanel(panelId)); //WriteTextMessage(stream, mainCommand.ColorPanel(panelId));
WriteTextMessage(stream, mainCommand.ClearPanel(panelId)); WriteTextMessage(stream, mainCommand.ClearPanel(panelId));
SendMessageAndOnResponse(stream, mainCommand.showBikespeed(panelId, "bikeSpeed", bikeSpeed), "bikeSpeed", SendMessageAndOnResponse(stream, mainCommand.showBikespeed(panelId, "bikeSpeed", bikeSpeed), "bikeSpeed",
(message) => (message) =>
{ {
Console.WriteLine(message);
// TODO check if is drawn // TODO check if is drawn
}); });
SendMessageAndOnResponse(stream, mainCommand.showHeartrate(panelId, "bpm", bpm), "bpm", SendMessageAndOnResponse(stream, mainCommand.showHeartrate(panelId, "bpm", bpm), "bpm",
(message) => (message) =>
{ {
Console.WriteLine(message);
// TODO check if is drawn // TODO check if is drawn
}); });
SendMessageAndOnResponse(stream, mainCommand.showPower(panelId, "power", power), "power", SendMessageAndOnResponse(stream, mainCommand.showPower(panelId, "power", power), "power",
(message) => (message) =>
{ {
Console.WriteLine(message);
// TODO check if is drawn // TODO check if is drawn
}); });
SendMessageAndOnResponse(stream, mainCommand.showResistance(panelId, "resistance", resistance), "resistance", SendMessageAndOnResponse(stream, mainCommand.showResistance(panelId, "resistance", resistance), "resistance",
(message) => (message) =>
{ {
Console.WriteLine(message);
// TODO check if is drawn // TODO check if is drawn
}); });
SendMessageAndOnResponse(stream, mainCommand.showMessage(panelId, "message", lastMessage), "message", SendMessageAndOnResponse(stream, mainCommand.showMessage(panelId, "message", lastMessage), "message",
(message) => (message) =>
{ {
Console.WriteLine(message);
// TODO check if is drawn // TODO check if is drawn
}); });

View File

@@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Timers;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Diagnostics;
using Util; using Util;
namespace Server namespace Server
@@ -20,6 +22,9 @@ namespace Server
public string username = null; public string username = null;
private DateTime sessionStart; private DateTime sessionStart;
private string fileName; private string fileName;
private Timer timer;
private byte[] BikeDataBuffer;
private byte[] BPMDataBuffer;
public Client(Communication communication, TcpClient tcpClient) public Client(Communication communication, TcpClient tcpClient)
{ {
@@ -28,12 +33,18 @@ namespace Server
this.tcpClient = tcpClient; this.tcpClient = tcpClient;
this.stream = this.tcpClient.GetStream(); this.stream = this.tcpClient.GetStream();
this.fileName = Directory.GetCurrentDirectory() + "/userInfo.dat"; this.fileName = Directory.GetCurrentDirectory() + "/userInfo.dat";
this.timer = new Timer();
this.BikeDataBuffer = new byte[16];
this.BPMDataBuffer = new byte[2];
this.timer.Interval = 1000;
this.timer.AutoReset = true;
this.timer.Elapsed += SendDataToDoctor;
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null); stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null);
} }
private void OnRead(IAsyncResult ar) private void OnRead(IAsyncResult ar)
{ {
if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead)) if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.tcpClient.Client.Connected)
return; return;
int receivedBytes = this.stream.EndRead(ar); int receivedBytes = this.stream.EndRead(ar);
@@ -64,6 +75,8 @@ namespace Server
} }
} }
if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.tcpClient.Client.Connected)
return;
this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null);
} }
@@ -91,36 +104,43 @@ namespace Server
string identifier; string identifier;
bool isJson = DataParser.getJsonIdentifier(message, out identifier); bool isJson = DataParser.getJsonIdentifier(message, out identifier);
if (isJson) if (isJson)
{ {
switch (identifier) switch (identifier)
{ {
case DataParser.LOGIN: case DataParser.LOGIN:
handleLogin(payloadbytes); if (handleLogin(payloadbytes))
communication.NewLogin(this);
break; break;
case DataParser.LOGIN_DOCTOR: case DataParser.LOGIN_DOCTOR:
if (communication.doctor != null) if (communication.Doctor != null)
return; return;
if (handleLogin(payloadbytes)) if (handleLogin(payloadbytes))
{ {
communication.doctor = this; communication.Doctor = this;
Console.WriteLine("Set doctor to " + communication.doctor + " , this is " + this);
} }
break; break;
case DataParser.START_SESSION: case DataParser.START_SESSION:
this.communication.StartSessionUser(DataParser.getUsernameFromJson(payloadbytes)); this.communication.StartSessionUser(DataParser.getUsernameFromJson(payloadbytes));
this.timer.Start();
break; break;
case DataParser.STOP_SESSION: case DataParser.STOP_SESSION:
this.communication.StopSessionUser(DataParser.getUsernameFromJson(payloadbytes)); this.communication.StopSessionUser(DataParser.getUsernameFromJson(payloadbytes));
this.timer.Stop();
break; break;
case DataParser.SET_RESISTANCE: case DataParser.SET_RESISTANCE:
bool worked = DataParser.getResistanceFromResponseJson(payloadbytes); //bool worked = DataParser.getResistanceFromResponseJson(payloadbytes);
Console.WriteLine($"set resistance worked is " + worked); communication.SendMessageToClient(DataParser.getUsernameFromJson(payloadbytes), message);
//set resistance on doctor GUI //set resistance on doctor GUI
break; break;
case DataParser.DISCONNECT: case DataParser.DISCONNECT:
communication.Disconnect(this); communication.LogOff(this);
break;
case DataParser.MESSAGE:
communication.SendMessageToClient(DataParser.getUsernameFromJson(payloadbytes), message);
break; break;
default: default:
Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}"); Console.WriteLine($"Received json with identifier {identifier}:\n{Encoding.ASCII.GetString(payloadbytes)}");
@@ -132,25 +152,17 @@ namespace Server
dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payloadbytes)); dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payloadbytes));
} }
else if (DataParser.isRawData(message)) else if (DataParser.isRawDataBikeServer(message))
{ {
// print the raw data saveData?.WriteDataRAWBike(payloadbytes);
Console.WriteLine(BitConverter.ToString(payloadbytes)); Array.Copy(this.BikeDataBuffer, 0, this.BikeDataBuffer, 8, 8);
// TODO change, checking for length is not that safe Array.Copy(payloadbytes, 0, this.BikeDataBuffer, 0, 8);
if (payloadbytes.Length == 8) }
{ else if (DataParser.isRawDataBPMServer(message))
saveData?.WriteDataRAWBike(payloadbytes); {
} saveData?.WriteDataRAWBPM(payloadbytes);
else if (payloadbytes.Length == 2) Array.Copy(payloadbytes, 0, this.BikeDataBuffer, 0, 2);
{
saveData?.WriteDataRAWBPM(payloadbytes);
}
else
{
Console.WriteLine("received raw data with weird lenght " + BitConverter.ToString(payloadbytes));
}
} }
} }
@@ -166,8 +178,6 @@ namespace Server
Console.WriteLine("Log in"); Console.WriteLine("Log in");
this.username = username; this.username = username;
sendMessage(DataParser.getLoginResponse("OK")); sendMessage(DataParser.getLoginResponse("OK"));
//sendMessage(DataParser.getStartSessionJson());
communication.NewLogin(this);
return true; return true;
} }
else else
@@ -251,5 +261,12 @@ namespace Server
{ {
this.saveData = null; this.saveData = null;
} }
private void SendDataToDoctor(object sender, ElapsedEventArgs e)
{
this.communication.Doctor?.sendMessage(DataParser.GetRawBikeDataDoctor(this.BikeDataBuffer.Take(8).ToArray(), this.username));
this.communication.Doctor?.sendMessage(DataParser.GetRawBikeDataDoctor(this.BikeDataBuffer.Skip(8).ToArray(), this.username));
this.communication.Doctor?.sendMessage(DataParser.GetRawBikeDataDoctor(this.BikeDataBuffer, this.username));
}
} }
} }

View File

@@ -1,9 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text;
using Util; using Util;
namespace Server namespace Server
@@ -12,7 +9,24 @@ namespace Server
{ {
private TcpListener listener; private TcpListener listener;
private List<Client> clients; private List<Client> clients;
public Client doctor; private Client mDoctor;
public Client Doctor
{
get
{
return this.mDoctor;
}
set
{
this.mDoctor = value;
if (this.mDoctor != null)
this.clients.ForEach((client) =>
{
this.mDoctor.sendMessage(DataParser.getNewConnectionJson(client.username));
client.sendMessage(DataParser.getNewConnectionJson(this.mDoctor.username));
});
}
}
public Communication(TcpListener listener) public Communication(TcpListener listener)
{ {
this.listener = listener; this.listener = listener;
@@ -33,34 +47,39 @@ namespace Server
var tcpClient = listener.EndAcceptTcpClient(ar); var tcpClient = listener.EndAcceptTcpClient(ar);
Console.WriteLine($"Client connected from {tcpClient.Client.RemoteEndPoint}"); Console.WriteLine($"Client connected from {tcpClient.Client.RemoteEndPoint}");
clients.Add(new Client(this, tcpClient)); new Client(this, tcpClient);
listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null); listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null);
} }
internal void Disconnect(Client client)
{
clients.Remove(client);
doctor.sendMessage(DataParser.getDisconnectJson(client.username));
}
public void NewLogin(Client client) public void NewLogin(Client client)
{ {
if (doctor == null) this.clients.Add(client);
if (this.Doctor != null)
{ {
doctor = client; Doctor.sendMessage(DataParser.getNewConnectionJson(client.username));
client.sendMessage(DataParser.getNewConnectionJson(Doctor.username));
} }
else }
public void LogOff(Client client)
{
if (this.Doctor == client)
{ {
doctor.sendMessage(DataParser.getNewConnectionJson(client.username)); this.clients.ForEach((client) =>
{
client.sendMessage(DataParser.getDisconnectJson(this.mDoctor.username));
});
this.Doctor = null;
} }
Doctor?.sendMessage(DataParser.getDisconnectJson(client.username));
this.clients.Remove(client);
} }
public void StartSessionUser(string user) public void StartSessionUser(string user)
{ {
foreach(Client client in clients) foreach (Client client in clients)
{ {
if(client.username == user) if (client.username == user)
{ {
client.sendMessage(DataParser.getStartSessionJson(user)); client.sendMessage(DataParser.getStartSessionJson(user));
client.StartSession(); client.StartSession();
@@ -80,5 +99,16 @@ namespace Server
} }
} }
public void SendMessageToClient(string user, byte[] message)
{
foreach (Client c in clients)
{
if (c.username == user)
{
c.sendMessage(message);
}
}
}
} }
} }