diff --git a/Client/Client.cs b/Client/Client.cs index 1a3392a..008c09d 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -31,22 +31,46 @@ namespace Client client.BeginConnect(adress, port, new AsyncCallback(OnConnect), null); } + /// + /// initializes the VR engine and sets the callbacks + /// private void initEngine() { engineConnection = EngineConnection.INSTANCE; engineConnection.OnNoTunnelId = retryEngineConnection; + engineConnection.OnSuccessFullConnection = engineConnected; if (!engineConnection.Connected) engineConnection.Connect(); } + /// + /// retries to connect to the VR engine if no tunnel id was found + /// private void retryEngineConnection() { Console.WriteLine("-- Could not connect to the VR engine. Please make sure you are running the simulation!"); - Console.WriteLine("-- Press any key to retry connecting to the VR engine."); - Console.ReadKey(); - - engineConnection.CreateConnection(); + Console.WriteLine("-- Press ENTER to retry connecting to the VR engine."); + Console.WriteLine("-- Press 'q' and then ENTER to not connect to the VR engine"); + string input = Console.ReadLine(); + if (input == string.Empty) engineConnection.CreateConnection(); + else + { + Console.WriteLine("Skipping connecting to VR engine..."); + engineConnection.Stop(); + } + } + private void engineConnected() + { + Console.WriteLine("successfully connected to VR engine"); + engineConnection.initScene(); + if (engineConnection.Connected && sessionRunning && !engineConnection.FollowingRoute) engineConnection.StartRouteFollow(); + } + + /// + /// callback method for when the TCP client is connected + /// + /// the result of the async read private void OnConnect(IAsyncResult ar) { this.client.EndConnect(ar); @@ -60,6 +84,10 @@ namespace Client this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); } + /// + /// callback method for when there is a message read + /// + /// the result of the async read private void OnRead(IAsyncResult ar) { int receivedBytes = this.stream.EndRead(ar); @@ -93,6 +121,7 @@ namespace Client string responseStatus = DataParser.getResponseStatus(payloadbytes); if (responseStatus == "OK") { + Console.WriteLine("Username and password correct!"); this.connected = true; initEngine(); } @@ -103,14 +132,18 @@ namespace Client } break; case DataParser.START_SESSION: + Console.WriteLine("Session started!"); this.sessionRunning = true; + if (engineConnection.Connected && !engineConnection.FollowingRoute) engineConnection.StartRouteFollow(); sendMessage(DataParser.getStartSessionJson()); break; case DataParser.STOP_SESSION: + Console.WriteLine("Stop session identifier"); this.sessionRunning = false; sendMessage(DataParser.getStopSessionJson()); break; case DataParser.SET_RESISTANCE: + Console.WriteLine("Set resistance identifier"); if (this.handler == null) { Console.WriteLine("handler is null"); @@ -140,11 +173,19 @@ namespace Client } + /// + /// starts sending a message to the server + /// + /// the message to send private void sendMessage(byte[] message) { stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); } + /// + /// callback method for when a message is fully written to the server + /// + /// the async result representing the asynchronous call private void OnWrite(IAsyncResult ar) { this.stream.EndWrite(ar); @@ -152,6 +193,10 @@ namespace Client #region interface //maybe move this to other place + /// + /// bpm method for receiving the BPM value from the bluetooth bike or the simulation + /// + /// the message public void BPM(byte[] bytes) { if (!sessionRunning) @@ -166,6 +211,10 @@ namespace Client this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); } + /// + /// method for receiving the bike message from the bluetooth bike or the simulation + /// + /// the message public void Bike(byte[] bytes) { if (!sessionRunning) @@ -182,10 +231,17 @@ namespace Client #endregion + /// + /// wether or not the client stream is connected + /// + /// true if it's connected, false if not public bool IsConnected() { return this.connected; } + /// + /// tries to log in to the server by asking for a username and password + /// private void tryLogin() { //TODO File in lezen @@ -203,6 +259,10 @@ namespace Client this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); } + /// + /// sets the handler for the client, so either the bike simulator or the bluetooth bike handler + /// + /// public void setHandler(IHandler handler) { this.handler = handler; diff --git a/Client/EngineConnection.cs b/Client/EngineConnection.cs index 4905911..5a89713 100644 --- a/Client/EngineConnection.cs +++ b/Client/EngineConnection.cs @@ -8,12 +8,14 @@ namespace Client { public delegate void HandleSerial(string message); public delegate void HandleNoTunnelId(); + public delegate void OnSuccessfullConnection(); public sealed class EngineConnection { private static EngineConnection instance = null; private static readonly object padlock = new object(); public HandleNoTunnelId OnNoTunnelId; + public OnSuccessfullConnection OnSuccessFullConnection; private static PC[] PCs = { @@ -29,9 +31,13 @@ namespace Client private static ServerResponseReader serverResponseReader; private static string sessionId = string.Empty; private static string tunnelId = string.Empty; + private static string cameraId = string.Empty; private static string routeId = string.Empty; private static string panelId = string.Empty; private static string bikeId = string.Empty; + private static string headId = string.Empty; + + public bool FollowingRoute = false; private static NetworkStream stream; @@ -45,6 +51,9 @@ namespace Client } + /// + /// Singleton constructor + /// public static EngineConnection INSTANCE { get @@ -60,6 +69,11 @@ namespace Client } } + + + /// + /// connects to the vr engine and initalizes the serverResponseReader + /// public void Connect() { TcpClient client = new TcpClient("145.48.6.10", 6666); @@ -68,6 +82,18 @@ namespace Client CreateConnection(); } + /// + /// initializes and starts the reading of the responses from the vr server + /// + /// the networkstream + private void initReader() + { + serverResponseReader = new ServerResponseReader(stream); + serverResponseReader.callback = HandleResponse; + serverResponseReader.StartRead(); + } + + #region VR Message traffic /// /// connects to the server and creates the tunnel /// @@ -84,26 +110,8 @@ namespace Client WriteTextMessage(tunnelCreate); - // wait until we have a tunnel id - while (tunnelId == string.Empty) { } - if (tunnelId != null) - { - Write("got tunnel id! " + tunnelId); - } - mainCommand = new Command(tunnelId); } - /// - /// initializes and starts the reading of the responses from the vr server - /// - /// the networkstream - private void initReader() - { - serverResponseReader = new ServerResponseReader(stream); - serverResponseReader.callback = HandleResponse; - serverResponseReader.StartRead(); - Connected = true; - } /// /// callback method that handles responses from the server @@ -121,12 +129,19 @@ namespace Client else if (id == "tunnel/create") { tunnelId = JSONParser.GetTunnelID(message); + Console.WriteLine("set tunnel id to " + tunnelId); if (tunnelId == null) { Write("could not find a valid tunnel id!"); OnNoTunnelId?.Invoke(); Connected = false; + FollowingRoute = false; return; + } else + { + Write("got tunnel id! " + tunnelId); + Connected = true; + OnSuccessFullConnection?.Invoke(); } } @@ -139,6 +154,95 @@ namespace Client } } + public void initScene() + { + Write("initializing scene..."); + mainCommand = new Command(tunnelId); + + // reset the scene + WriteTextMessage(mainCommand.ResetScene()); + + //Get sceneinfo and set the id's + SendMessageAndOnResponse(mainCommand.GetSceneInfoCommand("sceneinfo"), "sceneinfo", + (message) => + { + //Console.WriteLine("\r\n\r\n\r\nscene info" + message); + cameraId = JSONParser.GetIdSceneInfoChild(message, "Camera"); + string headId = JSONParser.GetIdSceneInfoChild(message, "Head"); + string handLeftId = JSONParser.GetIdSceneInfoChild(message, "LeftHand"); + string handRightId = JSONParser.GetIdSceneInfoChild(message, "RightHand"); + + //Force(stream, mainCommand.DeleteNode(handLeftId, "deleteHandL"), "deleteHandL", (message) => Console.WriteLine("Left hand deleted")); + //Force(stream, mainCommand.DeleteNode(handRightId, "deleteHandR"), "deleteHandR", (message) => Console.WriteLine("Right hand deleted")); + }); + // add the route and set the route id + SendMessageAndOnResponse(mainCommand.RouteCommand("routeID"), "routeID", (message) => routeId = JSONParser.GetResponseUuid(message)); + } + + internal void StartRouteFollow() + { + Write("Starting route follow..."); + FollowingRoute = true; + + SendMessageAndOnResponse(mainCommand.AddBikeModel("bikeID"), "bikeID", + (message) => + { + bikeId = JSONParser.GetResponseUuid(message); + SendMessageAndOnResponse(mainCommand.addPanel("panelAdd", bikeId), "panelAdd", + (message) => + { + + panelId = JSONParser.getPanelID(message); + WriteTextMessage(mainCommand.ColorPanel(panelId)); + WriteTextMessage(mainCommand.ClearPanel(panelId)); + + + showPanel(mainCommand, 5.3, 83, 52, 53); + + while (cameraId == string.Empty) { } + SetFollowSpeed(5.0f); + }); + }); + } + + private void showPanel(Command mainCommand, double bikeSpeed, int bpm, int power, int resistance) + { + SendMessageAndOnResponse(mainCommand.showBikespeed(panelId, "bikeSpeed", bikeSpeed), "bikeSpeed", + (message) => + { + // TODO check if is drawn + }); + SendMessageAndOnResponse(mainCommand.showHeartrate(panelId, "bpm", bpm), "bpm", + (message) => + { + // TODO check if is drawn + }); + SendMessageAndOnResponse(mainCommand.showPower(panelId, "power", power), "power", + (message) => + { + // TODO check if is drawn + }); + SendMessageAndOnResponse(mainCommand.showResistance(panelId, "resistance", resistance), "resistance", + (message) => + { + // TODO check if is drawn + }); + + // Check if every text is drawn! + + WriteTextMessage(mainCommand.SwapPanel(panelId)); + } + + private void SetFollowSpeed(float speed) + { + 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)); + } + + #endregion + + #region message send/receive + /// /// method that sends the speciefied message with the specified serial, and executes the given action upon receivind a reply from the server with this serial. /// @@ -169,6 +273,14 @@ namespace Client //Write("sent message " + message); } + + #endregion + + public void Stop() + { + serverResponseReader.Stop(); + + } public void Write(string msg) { Console.WriteLine( "[ENGINECONNECT] " + msg); diff --git a/Client/Program.cs b/Client/Program.cs index 89ed605..80b7fd8 100644 --- a/Client/Program.cs +++ b/Client/Program.cs @@ -11,7 +11,7 @@ namespace Client { static void Main(string[] args) { - Console.WriteLine("Hello World!"); + Console.WriteLine("// Connecting... //"); //connect fiets? Client client = new Client(); @@ -21,18 +21,18 @@ namespace Client { } - BLEHandler bLEHandler = new BLEHandler(client); + //BLEHandler bLEHandler = new BLEHandler(client); - bLEHandler.Connect(); + //bLEHandler.Connect(); - client.setHandler(bLEHandler); + //client.setHandler(bLEHandler); - //BikeSimulator bikeSimulator = new BikeSimulator(client); + BikeSimulator bikeSimulator = new BikeSimulator(client); - //bikeSimulator.StartSimulation(); + bikeSimulator.StartSimulation(); - //client.setHandler(bikeSimulator); + client.setHandler(bikeSimulator); while (true) { diff --git a/ProftaakRH/BLEHandler.cs b/ProftaakRH/BLEHandler.cs index 269b0a1..c368072 100644 --- a/ProftaakRH/BLEHandler.cs +++ b/ProftaakRH/BLEHandler.cs @@ -44,6 +44,7 @@ namespace Hardware /// public void Connect() { + BLE bleBike = new BLE(); Thread.Sleep(1000); // We need some time to list available devices diff --git a/ProftaakRH/BikeSimulator.cs b/ProftaakRH/BikeSimulator.cs index 3d11209..4dad948 100644 --- a/ProftaakRH/BikeSimulator.cs +++ b/ProftaakRH/BikeSimulator.cs @@ -47,6 +47,7 @@ namespace Hardware.Simulators public void StartSimulation() { + Console.WriteLine("simulating bike..."); //Example BLE Message //4A-09-4E-05-19-16-00-FF-28-00-00-20-F0 diff --git a/RH-Engine/Command.cs b/RH-Engine/Command.cs index 3875448..ba8a6c0 100644 --- a/RH-Engine/Command.cs +++ b/RH-Engine/Command.cs @@ -164,7 +164,7 @@ namespace RH_Engine return JsonConvert.SerializeObject(Payload(payload)); } - public string bikeSpeed(string uuidPanel, string serialCode, double speed) + private string showOnPanel(string uuidPanel, string serialCode, string mText, int index) { dynamic payload = new { @@ -173,9 +173,9 @@ namespace RH_Engine data = new { id = uuidPanel, - text = "Speed: " + speed.ToString(), - position = new int[] { 4, 24 }, - size = 36.0, + text = mText, + position = new int[] { 4, 24 + index * 32 }, + size = 32.0, color = new int[] { 0, 0, 0, 1 }, font = "segoeui" } @@ -184,6 +184,43 @@ namespace RH_Engine return JsonConvert.SerializeObject(Payload(payload)); } + + public string showBikespeed(string uuidPanel, string serialCode, double speed) + { + //dynamic payload = new + //{ + // id = "scene/panel/drawtext", + // serial = serialCode, + // data = new + // { + // id = uuidPanel, + // text = "Speed: " + speed + " m/s", + // position = new int[] { 4, 24 }, + // size = 36.0, + // color = new int[] { 0, 0, 0, 1 }, + // font = "segoeui" + // } + //}; + + //return JsonConvert.SerializeObject(Payload(payload)); + return showOnPanel(uuidPanel, serialCode, "Speed: " + speed + " m/s", 0); + } + + public string showHeartrate(string uuidPanel, string serialCode, int bpm) + { + return showOnPanel(uuidPanel, serialCode, "Heartrate: " + bpm + " bpm", 1); + } + + public string showPower(string uuidPanel, string serialCode, double power) + { + return showOnPanel(uuidPanel, serialCode, "Inst. Power: " + power + " W", 2); + } + + public string showResistance(string uuidPanel, string serialCode, double resistance) + { + return showOnPanel(uuidPanel, serialCode, "Resistance: " + resistance + " %", 3); + } + public string SwapPanelCommand(string uuid) { dynamic payload = new diff --git a/RH-Engine/Program.cs b/RH-Engine/Program.cs index bfac8c8..dc33e25 100644 --- a/RH-Engine/Program.cs +++ b/RH-Engine/Program.cs @@ -17,9 +17,9 @@ namespace RH_Engine //new PC("DESKTOP-M2CIH87", "Fabian"), //new PC("T470S", "Shinichi"), //new PC("DESKTOP-DHS478C", "semme"), - //new PC("HP-ZBOOK-SEM", "Sem"), + new PC("HP-ZBOOK-SEM", "Sem"), //new PC("DESKTOP-TV73FKO", "Wouter"), - new PC("DESKTOP-SINMKT1", "Ralf van Aert"), + //new PC("DESKTOP-SINMKT1", "Ralf van Aert"), //new PC("NA", "Bart") }; @@ -81,7 +81,11 @@ namespace RH_Engine //Console.WriteLine("GOT MESSAGE WITH SERIAL: " + message + "\n\n\n"); string serial = JSONParser.GetSerial(message); //Console.WriteLine("Got serial " + serial); - if (serialResponses.ContainsKey(serial)) serialResponses[serial].Invoke(message); + if (serialResponses.ContainsKey(serial)) + { + serialResponses[serial].Invoke(message); + serialResponses.Remove(serial); + } } } @@ -181,19 +185,9 @@ namespace RH_Engine panelId = JSONParser.getPanelID(message); WriteTextMessage(stream, mainCommand.ColorPanel(panelId)); WriteTextMessage(stream, mainCommand.ClearPanel(panelId)); - - SendMessageAndOnResponse(stream, mainCommand.MoveTo(panelId, "panelMove", new float[] { 0f, 0f, 0f }, "Z", 1, 5), "panelMove", - (message) => - { - Console.WriteLine(message); - - SendMessageAndOnResponse(stream, mainCommand.bikeSpeed(panelId, "bikeSpeed", 5.0), "bikeSpeed", - (message) => - { - WriteTextMessage(stream, mainCommand.SwapPanel(panelId)); - }); - }); + + showPanel(stream, mainCommand, 5.3, 83, 52, 53); //while (!(speedReplied && moveReplied)) { } @@ -225,6 +219,27 @@ namespace RH_Engine //WriteTextMessage(stream, mainCommand.TerrainCommand(new int[] { 256, 256 }, null)); //string command; + + + + //Console.WriteLine("id of head " + GetId(Command.STANDARD_HEAD, stream, mainCommand)); + + //command = mainCommand.AddModel("car", "data\\customModels\\TeslaRoadster.fbx"); + //WriteTextMessage(stream, command); + + //command = mainCommand.addPanel(); + // WriteTextMessage(stream, command); + // string response = ReadPrefMessage(stream); + // Console.WriteLine("add Panel response: \n\r" + response); + // string uuidPanel = JSONParser.getPanelID(response); + // WriteTextMessage(stream, mainCommand.ClearPanel(uuidPanel)); + // Console.WriteLine(ReadPrefMessage(stream)); + // WriteTextMessage(stream, mainCommand.bikeSpeed(uuidPanel, 2.42)); + // Console.WriteLine(ReadPrefMessage(stream)); + // WriteTextMessage(stream, mainCommand.ColorPanel(uuidPanel)); + // Console.WriteLine("Color panel: " + ReadPrefMessage(stream)); + // WriteTextMessage(stream, mainCommand.SwapPanel(uuidPanel)); + // Console.WriteLine("Swap panel: " + ReadPrefMessage(stream)); Console.WriteLine("id of head " + GetId(Command.STANDARD_HEAD, stream, mainCommand)); } @@ -304,11 +319,39 @@ namespace RH_Engine return res; } + + private static void showPanel(NetworkStream stream, Command mainCommand, double bikeSpeed, int bpm, int power, int resistance) + { + SendMessageAndOnResponse(stream, mainCommand.showBikespeed(panelId, "bikeSpeed", bikeSpeed), "bikeSpeed", + (message) => + { + // TODO check if is drawn + }); + SendMessageAndOnResponse(stream, mainCommand.showHeartrate(panelId, "bpm", bpm), "bpm", + (message) => + { + // TODO check if is drawn + }); + SendMessageAndOnResponse(stream, mainCommand.showPower(panelId, "power", power), "power", + (message) => + { + // TODO check if is drawn + }); + SendMessageAndOnResponse(stream, mainCommand.showResistance(panelId, "resistance", resistance), "resistance", + (message) => + { + // TODO check if is drawn + }); + + // Check if every text is drawn! + + WriteTextMessage(stream, mainCommand.SwapPanel(panelId)); + } + private static void SetFollowSpeed(float speed, NetworkStream stream, Command mainCommand) { WriteTextMessage(stream, mainCommand.RouteFollow(routeId, bikeId, speed, new float[] { 0, -(float)Math.PI / 2f, 0 }, new float[] { 0, 0, 0 })); WriteTextMessage(stream, mainCommand.RouteFollow(routeId, cameraId, speed)); - //WriteTextMessage(stream, mainCommand.RouteFollow(routeId, panelId, speed, 1f, "XYZ", 1, false, new float[] { 0, 0, 0 }, new float[] { 0f, 5f, 5f })); } //string routeID, string nodeID, float speedValue, float offsetValue, string rotateValue, float smoothingValue, bool followHeightValue, float[] rotateOffsetVector, float[] positionOffsetVector) private static void Force(NetworkStream stream, string message, string serial, HandleSerial action) diff --git a/RH-Engine/ServerResponseReader.cs b/RH-Engine/ServerResponseReader.cs index 17e86ba..bafa442 100644 --- a/RH-Engine/ServerResponseReader.cs +++ b/RH-Engine/ServerResponseReader.cs @@ -9,6 +9,8 @@ namespace RH_Engine public class ServerResponseReader { + private bool running; + private Thread t; public OnResponse callback { get; set; @@ -23,7 +25,7 @@ namespace RH_Engine public void StartRead() { - Thread t = new Thread(() => + t = new Thread(() => { if (this.callback == null) { @@ -31,8 +33,9 @@ namespace RH_Engine } else { + running = true; Console.WriteLine("[SERVERRESPONSEREADER] Starting loop for reading"); - while (true) + while (running) { string res = ReadPrefMessage(Stream); //Console.WriteLine("[SERVERRESPONSEREADER] got message from server: " + res); @@ -44,6 +47,13 @@ namespace RH_Engine t.Start(); } + public void Stop() + { + running = false; + t.Join(); + Stream.Close(); + } + /// /// reads a response from the server /// diff --git a/Server/Client.cs b/Server/Client.cs index 9091295..3fa7ba0 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -142,7 +142,9 @@ namespace Server } else if (DataParser.isRawData(message)) { + // print the raw data Console.WriteLine(BitConverter.ToString(payloadbytes)); + // TODO change, checking for length is not that safe if (payloadbytes.Length == 8) { saveData?.WriteDataRAWBike(payloadbytes); @@ -167,7 +169,6 @@ namespace Server private bool verifyLogin(string username, string password) { - Console.WriteLine("got hashes " + username + "\n" + password); if (!File.Exists(fileName))