diff --git a/Client/Client.cs b/Client/Client.cs new file mode 100644 index 0000000..e6727d3 --- /dev/null +++ b/Client/Client.cs @@ -0,0 +1,133 @@ +using System; +using System.Net.Sockets; +using ProftaakRH; + +namespace Client +{ + class Client : IDataReceiver + { + private TcpClient client; + private NetworkStream stream; + private byte[] buffer = new byte[1024]; + private int bytesReceived; + private bool connected; + private byte clientId = 0; + + + public Client() : this("localhost", 5555) + { + + } + + public Client(string adress, int port) + { + this.client = new TcpClient(); + this.bytesReceived = 0; + this.connected = false; + client.BeginConnect(adress, port, new AsyncCallback(OnConnect), null); + } + + private void OnConnect(IAsyncResult ar) + { + this.client.EndConnect(ar); + Console.WriteLine("Verbonden!"); + + + this.stream = this.client.GetStream(); + + //TODO File in lezen + Console.WriteLine("enter username"); + string username = Console.ReadLine(); + Console.WriteLine("enter password"); + string password = Console.ReadLine(); + + byte[] message = DataParser.getJsonMessage(DataParser.GetLoginJson(username, password), this.clientId); + + this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); + + this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); + + //TODO lees OK message + //temp moet eigenlijk een ok bericht ontvangen + this.connected = true; + } + + private void OnRead(IAsyncResult ar) + { + int receivedBytes = this.stream.EndRead(ar); + byte[] lengthBytes = new byte[4]; + + Array.Copy(this.buffer, 0, lengthBytes, 0, 4); + + int expectedMessageLength = BitConverter.ToInt32(lengthBytes); + + if (expectedMessageLength > this.buffer.Length) + { + throw new OutOfMemoryException("buffer to small"); + } + + if (expectedMessageLength > this.bytesReceived + receivedBytes) + { + //message hasn't completely arrived yet + this.bytesReceived += receivedBytes; + this.stream.BeginRead(this.buffer, this.bytesReceived, this.buffer.Length - this.bytesReceived, new AsyncCallback(OnRead), null); + + } + else + { + //message completely arrived + if (expectedMessageLength != this.bytesReceived + receivedBytes) + { + Console.WriteLine("something has gone completely wrong"); + } + + string identifier; + bool isJson = DataParser.getJsonIdentifier(this.buffer, out identifier); + if (isJson) + { + throw new NotImplementedException(); + } + else if (DataParser.isRawData(this.buffer)) + { + throw new NotImplementedException(); + } + } + this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); + + } + + private void OnWrite(IAsyncResult ar) + { + this.stream.EndWrite(ar); + } + + #region interface + //maybe move this to other place + public void BPM(byte[] bytes) + { + if (bytes == null) + { + throw new ArgumentNullException("no bytes"); + } + byte[] message = DataParser.GetRawDataMessage(bytes, clientId); + this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); + } + + public void Bike(byte[] bytes) + { + if (bytes == null) + { + throw new ArgumentNullException("no bytes"); + } + byte[] message = DataParser.GetRawDataMessage(bytes, clientId); + this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); + } + + #endregion + + public bool IsConnected() + { + return this.connected; + } + } +} diff --git a/Client/Client.csproj b/Client/Client.csproj index b664ee3..dd9af6e 100644 --- a/Client/Client.csproj +++ b/Client/Client.csproj @@ -5,8 +5,13 @@ netcoreapp3.1 + + + + + diff --git a/Client/DataParser.cs b/Client/DataParser.cs new file mode 100644 index 0000000..14014d6 --- /dev/null +++ b/Client/DataParser.cs @@ -0,0 +1,83 @@ +using Newtonsoft.Json; +using System; +using System.Linq; +using System.Text; + +namespace Client +{ + class DataParser + { + public static byte[] GetLoginJson(string mUsername, string mPassword) + { + dynamic json = new + { + identifier = "LOGIN", + data = new + { + username = mUsername, + password = mPassword, + } + }; + + return Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(json)); + } + + public static bool getJsonIdentifier(byte[] bytes, out string identifier) + { + if (bytes.Length <= 6) + { + throw new ArgumentException("bytes to short"); + } + byte messageId = bytes[4]; + + if (messageId == 1) + { + dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(bytes.Skip(6).ToArray())); + identifier = json.identifier; + return true; + } + else + { + identifier = ""; + return false; + } + } + + public static bool isRawData(byte[] bytes) + { + if (bytes.Length <= 6) + { + throw new ArgumentException("bytes to short"); + } + return bytes[5] == 0x02; + } + + private static byte[] getMessage(byte[] payload, byte messageId, byte clientId) + { + byte[] res = new byte[payload.Length + 6]; + + Array.Copy(BitConverter.GetBytes(payload.Length + 6), 0, res, 0, 4); + res[4] = messageId; + Array.Copy(payload, 0, res, 6, payload.Length); + + return res; + } + + public static byte[] GetRawDataMessage(byte[] payload, byte clientId) + { + return getMessage(payload, 0x02, clientId); + } + + public static byte[] getJsonMessage(byte[] payload, byte clientId) + { + return getMessage(payload, 0x01, clientId); + } + + public static byte[] getJsonMessage(string message, byte clientId) + { + return getJsonMessage(Encoding.ASCII.GetBytes(message), clientId); + } + + + } +} diff --git a/Client/Program.cs b/Client/Program.cs index 920b199..e98dfc7 100644 --- a/Client/Program.cs +++ b/Client/Program.cs @@ -1,4 +1,5 @@ using System; +using Hardware; namespace Client { @@ -7,6 +8,27 @@ namespace Client static void Main(string[] args) { Console.WriteLine("Hello World!"); + //connect fiets? + + + Client client = new Client(); + + + while (!client.IsConnected()) + { + + } + BLEHandler bLEHandler = new BLEHandler(client); + + bLEHandler.Connect(); + + //BikeSimulator bikeSimulator = new BikeSimulator(client); + + //bikeSimulator.StartSimulation(); + + while (true) + { + } } } } diff --git a/Message/Message.cs b/Message/Message.cs index 6852548..34c0ff5 100644 --- a/Message/Message.cs +++ b/Message/Message.cs @@ -8,6 +8,11 @@ namespace Message /// public class Message { + + public static void Main(string[] args) + { + + } /// /// identifier for the message /// diff --git a/ProftaakRH/BLEHandler.cs b/ProftaakRH/BLEHandler.cs index 9df61d8..238bb4c 100644 --- a/ProftaakRH/BLEHandler.cs +++ b/ProftaakRH/BLEHandler.cs @@ -4,15 +4,16 @@ using System.Text; using Avans.TI.BLE; using System.Threading; using System.Security.Cryptography; +using ProftaakRH; namespace Hardware { /// /// BLEHandler class that handles connection and traffic to and from the bike /// - class BLEHandler + public class BLEHandler { - IDataConverter dataConverter; + IDataReceiver dataReceiver; private BLE bleBike; private BLE bleHeart; public bool Running { get; set; } @@ -20,10 +21,10 @@ namespace Hardware /// /// Makes a new BLEHandler object /// - /// the dataconverter object - public BLEHandler(IDataConverter dataConverter) + /// the dataconverter object + public BLEHandler(IDataReceiver dataReceiver) { - this.dataConverter = dataConverter; + this.dataReceiver = dataReceiver; } /// @@ -119,16 +120,16 @@ namespace Hardware /// the value changed event private void BleBike_SubscriptionValueChanged(object sender, BLESubscriptionValueChangedEventArgs e) { - + if (e.ServiceName == "6e40fec2-b5a3-f393-e0a9-e50e24dcca9e") { byte[] payload = new byte[8]; Array.Copy(e.Data, 4, payload, 0, 8); - this.dataConverter.Bike(payload); + this.dataReceiver.Bike(payload); } else if (e.ServiceName == "00002a37-0000-1000-8000-00805f9b34fb") { - this.dataConverter.BPM(e.Data); + this.dataReceiver.BPM(e.Data); } else { @@ -164,7 +165,7 @@ namespace Hardware antMessage[i] = 0xFF; } antMessage[11] = (byte)Math.Max(Math.Min(Math.Round(percentage / 0.5), 255), 0); - + byte checksum = 0; for (int i = 0; i < 12; i++) diff --git a/ProftaakRH/BikeSimulator.cs b/ProftaakRH/BikeSimulator.cs index 5664f9e..304a00d 100644 --- a/ProftaakRH/BikeSimulator.cs +++ b/ProftaakRH/BikeSimulator.cs @@ -1,4 +1,5 @@ using LibNoise.Primitive; +using ProftaakRH; using System; using System.Collections.Generic; using System.Linq; @@ -9,9 +10,9 @@ using System.Threading; namespace Hardware.Simulators { - class BikeSimulator : IHandler + public class BikeSimulator : IHandler { - IDataConverter dataConverter; + IDataReceiver dataReceiver; private int elapsedTime = 0; private int eventCounter = 0; private double distanceTraveled = 0; @@ -29,10 +30,11 @@ namespace Hardware.Simulators - public BikeSimulator(IDataConverter dataConverter) + public BikeSimulator(IDataReceiver dataReceiver) { - this.dataConverter = dataConverter; + this.dataReceiver = dataReceiver; } + public void StartSimulation() { //Example BLE Message @@ -41,16 +43,16 @@ namespace Hardware.Simulators float x = 0.0f; //Perlin for Random values - ImprovedPerlin improvedPerlin = new ImprovedPerlin(0,LibNoise.NoiseQuality.Best); - + ImprovedPerlin improvedPerlin = new ImprovedPerlin(0, LibNoise.NoiseQuality.Best); + while (true) { - CalculateVariables(improvedPerlin.GetValue(x)+1); + CalculateVariables(improvedPerlin.GetValue(x) + 1); //Simulate sending data - dataConverter.Bike(GenerateBike0x19()); - dataConverter.Bike(GenerateBike0x10()); - dataConverter.BPM(GenerateHeart()); + dataReceiver.Bike(GenerateBike0x19()); + dataReceiver.Bike(GenerateBike0x10()); + dataReceiver.BPM(GenerateHeart()); Thread.Sleep(1000); @@ -65,21 +67,21 @@ namespace Hardware.Simulators private byte[] GenerateBike0x19() { byte statByte = (byte)(powerArray[1] >> 4); - byte[] bikeByte = { 0x19, Convert.ToByte(eventCounter%256), Convert.ToByte(cadence%254), accPowerArray[0], accPowerArray[1], powerArray[0], statByte, 0x20 }; + byte[] bikeByte = { 0x19, Convert.ToByte(eventCounter % 256), Convert.ToByte(cadence % 254), accPowerArray[0], accPowerArray[1], powerArray[0], statByte, 0x20 }; return bikeByte; } //Generate an ANT message for page 0x10 private byte[] GenerateBike0x10() { - 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, Convert.ToByte(equipmentType), Convert.ToByte(elapsedTime * 4 % 64), Convert.ToByte(distanceTraveled), speedArray[0], speedArray[1], Convert.ToByte(BPM), 0xFF }; return bikeByte; } //Generate an ANT message for BPM private byte[] GenerateHeart() { - byte[] hartByte = { 0x00, Convert.ToByte(BPM)}; + byte[] hartByte = { 0x00, Convert.ToByte(BPM) }; return hartByte; } @@ -114,13 +116,13 @@ namespace Hardware.Simulators //Input perlin value private void CalculateVariables(float perlin) { - this.speed = perlin * 5 / 0.01 ; + this.speed = perlin * 5 / 0.01; short sped = (short)speed; speedArray = BitConverter.GetBytes(sped); - this.distanceTraveled = (distanceTraveled+(speed*0.01)) % 256; - this.BPM = (int) (perlin * 80); - this.cadence = (int)speed/6; - this.power = ((1 + resistance) * speed)/14 % 4094; + this.distanceTraveled = (distanceTraveled + (speed * 0.01)) % 256; + this.BPM = (int)(perlin * 80); + this.cadence = (int)speed / 6; + this.power = ((1 + resistance) * speed) / 14 % 4094; this.accPower = (this.accPower + this.power) % 65536; // TO DO power to power LSB & MSN powerArray = BitConverter.GetBytes((short)this.power); @@ -131,9 +133,9 @@ namespace Hardware.Simulators public void setResistance(byte[] bytes) { //TODO check if message is correct - if(bytes.Length == 13) + if (bytes.Length == 13) { - this.resistance = Convert.ToDouble(bytes[11])/2; + this.resistance = Convert.ToDouble(bytes[11]) / 2; } } } diff --git a/ProftaakRH/DataConverter.cs b/ProftaakRH/DataConverter.cs index 7c93ff2..69eb49e 100644 --- a/ProftaakRH/DataConverter.cs +++ b/ProftaakRH/DataConverter.cs @@ -1,4 +1,5 @@ -using System; +using ProftaakRH; +using System; using System.Collections.Generic; using System.Text; @@ -7,7 +8,7 @@ namespace Hardware /// /// DataConverter class that handles all conversion of received data from the BLE bike. /// - class DataConverter : IDataConverter + class DataConverter : IDataReceiver { /// /// Receives, parses and displays any incoming data from the bike. @@ -22,7 +23,7 @@ namespace Hardware else if (bytes.Length == 8) { - + switch (bytes[0]) { case 0x10: @@ -37,7 +38,7 @@ namespace Hardware Console.WriteLine($"Speed is : {input * 0.01}m/s (Range 65.534m/4)"); if (bytes[6] != 0xFF) { - Console.WriteLine("Heart rate byte: {0}", Convert.ToString(bytes[6],2)); + Console.WriteLine("Heart rate byte: {0}", Convert.ToString(bytes[6], 2)); } break; case 0x19: @@ -45,17 +46,17 @@ namespace Hardware if (bytes[2] != 0xFF) { Console.WriteLine($"Instantaneous cadence: {bytes[2]} RPM (Range 0-254)"); - + } int accumPower = bytes[3] | (bytes[4] << 8); - + Console.WriteLine($"Accumulated power: {accumPower} watt (Rollover 65536)"); - int instantPower = (bytes[5]) | (bytes[6] & 0b00001111)<<8; - + int instantPower = (bytes[5]) | (bytes[6] & 0b00001111) << 8; + if (instantPower != 0xFFF) - Console.WriteLine($"Instant power: {instantPower} watt (Range 0-4094)"); + Console.WriteLine($"Instant power: {instantPower} watt (Range 0-4094)"); int trainerStatus = bytes[6] & 0b11110000; // bit 4-7 int flags = bytes[7] >> 4; @@ -103,13 +104,4 @@ namespace Hardware Console.WriteLine(); } } - - /// - /// Dataconverter interface for handling data received from the bike - /// - interface IDataConverter - { - void BPM(byte[] bytes); - void Bike(byte[] bytes); - } } diff --git a/ProftaakRH/IDataReceiver.cs b/ProftaakRH/IDataReceiver.cs new file mode 100644 index 0000000..7105c47 --- /dev/null +++ b/ProftaakRH/IDataReceiver.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProftaakRH +{ + public interface IDataReceiver + { + void BPM(byte[] bytes); + void Bike(byte[] bytes); + } +} diff --git a/ProftaakRH/Main.cs b/ProftaakRH/Main.cs index 0938089..5ffcab4 100644 --- a/ProftaakRH/Main.cs +++ b/ProftaakRH/Main.cs @@ -7,15 +7,15 @@ using Hardware.Simulators; namespace ProftaakRH { - class Program + class Program { static void Main(string[] agrs) { - IDataConverter dataConverter = new DataConverter(); - BLEHandler bLEHandler = new BLEHandler(dataConverter); - //BikeSimulator bikeSimulator = new BikeSimulator(dataConverter); - //bikeSimulator.setResistance(bikeSimulator.GenerateResistance(1f)); - //bikeSimulator.StartSimulation(); + IDataReceiver dataReceiver = new DataConverter(); + BLEHandler bLEHandler = new BLEHandler(dataReceiver); + BikeSimulator bikeSimulator = new BikeSimulator(dataReceiver); + bikeSimulator.setResistance(bikeSimulator.GenerateResistance(1f)); + bikeSimulator.StartSimulation(); bool running = true; @@ -24,7 +24,7 @@ namespace ProftaakRH string input = Console.ReadLine(); input.ToLower(); input.Trim(); - if(input == "quit") + if (input == "quit") { running = false; break; diff --git a/ProftaakRH/ProftaakRH.csproj b/ProftaakRH/ProftaakRH.csproj index 8f98a2c..d6280ab 100644 --- a/ProftaakRH/ProftaakRH.csproj +++ b/ProftaakRH/ProftaakRH.csproj @@ -7,6 +7,7 @@ + diff --git a/RH-Engine/Command.cs b/RH-Engine/Command.cs index 6491de4..3ef3bc1 100644 --- a/RH-Engine/Command.cs +++ b/RH-Engine/Command.cs @@ -1,10 +1,6 @@ using LibNoise.Primitive; using Newtonsoft.Json; using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Threading; namespace RH_Engine { @@ -16,9 +12,7 @@ namespace RH_Engine public const string STANDARD_LEFTHAND = "LeftHand"; public const string STANDARD_RIGHTHAND = "RightHand"; - - - string tunnelID; + private string tunnelID; public Command(string tunnelID) { @@ -35,10 +29,10 @@ namespace RH_Engine size = sizeArray, heights = heightsArray } - }; return JsonConvert.SerializeObject(Payload(payload)); } + public string AddLayer(string uid, string texture) { dynamic payload = new @@ -56,6 +50,7 @@ namespace RH_Engine }; return JsonConvert.SerializeObject(Payload(payload)); } + public string UpdateTerrain() { dynamic payload = new @@ -63,7 +58,6 @@ namespace RH_Engine id = "scene/terrain/update", data = new { - } }; return JsonConvert.SerializeObject(Payload(payload)); @@ -91,37 +85,135 @@ namespace RH_Engine public string DeleteNode(string uuid) { - dynamic payload = new { id = "scene/node/delete", data = new { id = uuid, - } - }; return JsonConvert.SerializeObject(Payload(payload)); - } - public string AddBikeModel() + public string addPanel(string serialToSend, string uuidBike) { - return AddModel("bike", "data\\NetworkEngine\\models\\bike\\bike.fbx"); + dynamic payload = new + { + id = "scene/node/add", + serial = serialToSend, + data = new + { + name = "dashboard", + parent = uuidBike, + components = new + { + panel = new + { + size = new int[] { 1, 1 }, + resolution = new int[] { 512, 512 }, + background = new int[] { 1, 0, 0, 0 }, + castShadow = false + } + } + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); } - public string AddModel(string nodeName, string fileLocation) + public string ColorPanel(string uuidPanel) { - return AddModel(nodeName, fileLocation, null, new float[] { 0, 0, 0 }, 1, new float[] { 0, 0, 0 }); + dynamic payload = new + { + id = "scene/panel/setclearcolor", + data = new + { + id = uuidPanel, + color = new int[] { 1, 1, 1, 1 } + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); } - public string AddModel(string nodeName, string fileLocation, float[] positionVector, float scalar, float[] rotationVector) + public string SwapPanel(string uuid) { - return AddModel(nodeName, fileLocation, null, positionVector, scalar, rotationVector); + dynamic payload = new + { + id = "scene/panel/swap", + data = new + { + id = uuid + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); } - public string AddModel(string nodeName, string fileLocation, string animationLocation, float[] positionVector, float scalar, float[] rotationVector) + public string bikeSpeed(string uuidPanel, double speed) + { + dynamic payload = new + { + id = "scene/panel/drawtext", + data = new + { + id = uuidPanel, + text = "Bike speed placeholder", + position = new int[] { 0, 0 }, + size = 32.0, + color = new int[] { 0, 0, 0, 1 }, + font = "segoeui" + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); + } + + public string SwapPanelCommand(string uuid) + { + dynamic payload = new + { + id = "scene/panel/swap", + data = new + { + id = uuid + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); + } + + public string ClearPanel(string uuid) + { + dynamic payload = new + { + id = "scene/panel/clear", + data = new + { + id = uuid + } + }; + + return JsonConvert.SerializeObject(Payload(payload)); + } + + public string AddBikeModel(string serial) + { + return AddModel("bike", serial, "data\\NetworkEngine\\models\\bike\\bike.fbx"); + } + + 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 }); + } + + public string AddModel(string nodeName, string serial, string fileLocation, float[] positionVector, float scalar, float[] rotationVector) + { + return AddModel(nodeName, serial, fileLocation, null, positionVector, scalar, rotationVector); + } + + public string AddModel(string nodeName, string serialToSend, string fileLocation, string animationLocation, float[] positionVector, float scalar, float[] rotationVector) { string namename = nodeName; bool animatedBool = false; @@ -133,6 +225,7 @@ namespace RH_Engine dynamic payload = new { id = "scene/node/add", + serial = serialToSend, data = new { name = namename, @@ -143,7 +236,6 @@ namespace RH_Engine position = positionVector, scale = scalar, rotation = rotationVector - }, model = new { @@ -154,7 +246,6 @@ namespace RH_Engine }, } } - }; return JsonConvert.SerializeObject(Payload(payload)); } @@ -184,14 +275,14 @@ namespace RH_Engine return JsonConvert.SerializeObject(Payload(payload)); } - - public string RouteCommand() + public string RouteCommand(string serialToSend) { ImprovedPerlin improvedPerlin = new ImprovedPerlin(4325, LibNoise.NoiseQuality.Best); Random r = new Random(); dynamic payload = new { id = "route/add", + serial = serialToSend, data = new { nodes = new dynamic[] @@ -241,13 +332,44 @@ namespace RH_Engine private int[] GetDir() { Random rng = new Random(); - int[] dir = {rng.Next(50), 0, rng.Next(50)}; + int[] dir = { rng.Next(50), 0, rng.Next(50) }; return dir; } - public string FollowRouteCommand() + public string RouteFollow(string routeID, string nodeID, float speedValue) { - return ""; + return RouteFollow(routeID, nodeID, speedValue, new float[] { 0, 0, 0 }); + } + + public string RouteFollow(string routeID, string nodeID, float speedValue, float[] rotateOffsetVector, float[] positionOffsetVector) + { + return RouteFollow(routeID, nodeID, speedValue, 0, "XYZ", 1, true, rotateOffsetVector, positionOffsetVector); + } + + public string RouteFollow(string routeID, string nodeID, float speedValue, float[] positionOffsetVector) + { + return RouteFollow(routeID, nodeID, speedValue, 0, "XYZ", 1, true, new float[] { 0, 0, 0 }, positionOffsetVector); + } + private string RouteFollow(string routeID, string nodeID, float speedValue, float offsetValue, string rotateValue, float smoothingValue, bool followHeightValue, float[] rotateOffsetVector, float[] positionOffsetVector) + { + dynamic payload = new + { + id = "route/follow", + data = new + { + route = routeID, + node = nodeID, + speed = speedValue, + offset = offsetValue, + rotate = rotateValue, + smoothing = smoothingValue, + followHeight = followHeightValue, + rotateOffset = rotateOffsetVector, + positionOffset = positionOffsetVector + + } + }; + return JsonConvert.SerializeObject(Payload(payload)); } public string RoadCommand(string uuid_route) @@ -268,11 +390,12 @@ namespace RH_Engine return JsonConvert.SerializeObject(Payload(payload)); } - public string GetSceneInfoCommand() + public string GetSceneInfoCommand(string serialToSend) { dynamic payload = new { - id = "scene/get" + id = "scene/get", + serial = serialToSend }; return JsonConvert.SerializeObject(Payload(payload)); @@ -282,7 +405,8 @@ namespace RH_Engine { dynamic payload = new { - id = "scene/reset" + id = "scene/reset", + serial = "reset" }; return JsonConvert.SerializeObject(Payload(payload)); @@ -295,7 +419,6 @@ namespace RH_Engine throw new Exception("The time must be between 0 and 24!"); } - dynamic payload = new { id = "scene/skybox/settime", @@ -303,13 +426,10 @@ namespace RH_Engine { time = timeToSet } - }; return JsonConvert.SerializeObject(Payload(payload)); - } - private object Payload(dynamic message) { return new @@ -322,8 +442,5 @@ namespace RH_Engine } }; } - - - } -} +} \ No newline at end of file diff --git a/RH-Engine/JSONParser.cs b/RH-Engine/JSONParser.cs index 2f1f903..8621aff 100644 --- a/RH-Engine/JSONParser.cs +++ b/RH-Engine/JSONParser.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Sockets; -using System.Text; -using Newtonsoft.Json; +using Newtonsoft.Json; +using System; namespace RH_Engine { @@ -27,14 +23,13 @@ namespace RH_Engine } return res; - } public static string GetSessionID(string msg, PC[] PCs) { dynamic jsonData = JsonConvert.DeserializeObject(msg); Newtonsoft.Json.Linq.JArray data = jsonData.data; - for (int i = data.Count-1; i >= 0; i--) + for (int i = data.Count - 1; i >= 0; i--) { dynamic d = data[i]; foreach (PC pc in PCs) @@ -50,6 +45,18 @@ namespace RH_Engine return null; } + public static string GetSerial(string json) + { + dynamic jsonData = JsonConvert.DeserializeObject(json); + return jsonData.data.data.serial; + } + + public static string GetID(string json) + { + dynamic d = JsonConvert.DeserializeObject(json); + return d.id; + } + public static string GetTunnelID(string json) { dynamic jsonData = JsonConvert.DeserializeObject(json); @@ -60,15 +67,30 @@ namespace RH_Engine return null; } - public static string GetRouteID(string json) + /// + /// method to get the uuid from requests for adding a node,route or road + /// + /// the json response froo the server + /// the uuid of the created object + public static string GetResponseUuid(string json) { dynamic jsonData = JsonConvert.DeserializeObject(json); - if (jsonData.data.status == "ok") + if (jsonData.data.data.status == "ok") { - return jsonData.data.uuid; + return jsonData.data.data.data.uuid; } return null; } + public static string getPanelID(string json) + { + dynamic jsonData = JsonConvert.DeserializeObject(json); + if (jsonData.data.data.data.name == "dashboard") + { + Console.WriteLine(jsonData.data.data.data.uuid); + return jsonData.data.data.data.uuid; + } + return null; + } } -} +} \ No newline at end of file diff --git a/RH-Engine/Program.cs b/RH-Engine/Program.cs index 5955866..63c86fb 100644 --- a/RH-Engine/Program.cs +++ b/RH-Engine/Program.cs @@ -1,35 +1,97 @@ -using LibNoise.Primitive; +using LibNoise.Primitive; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; -using System.Globalization; -using System.IO; +using System.Collections.Generic; using System.Net.Sockets; -using System.Runtime.Intrinsics.X86; -using System.Security.Cryptography.X509Certificates; using System.Text; -using System.Threading; namespace RH_Engine { + public delegate void HandleSerial(string message); - internal class Program + class Program { private static PC[] PCs = { //new PC("DESKTOP-M2CIH87", "Fabian"), - new PC("T470S", "Shinichi"), + //new PC("T470S", "Shinichi"), //new PC("DESKTOP-DHS478C", "semme"), + new PC("HP-ZBOOK-SEM", "Sem"), //new PC("DESKTOP-TV73FKO", "Wouter"), - //new PC("DESKTOP-SINMKT1", "Ralf"), + new PC("DESKTOP-SINMKT1", "Ralf van Aert"), //new PC("NA", "Bart") }; + + private static ServerResponseReader serverResponseReader; + private static string sessionId = string.Empty; + private static string tunnelId = string.Empty; + private static string routeId = string.Empty; + private static string panelId = string.Empty; + private static string bikeId = string.Empty; + + private static Dictionary serialResponses = new Dictionary(); + private static void Main(string[] args) { TcpClient client = new TcpClient("145.48.6.10", 6666); CreateConnection(client.GetStream()); + } + /// + /// initializes and starts the reading of the responses from the vr server + /// + /// the networkstream + private static void initReader(NetworkStream stream) + { + serverResponseReader = new ServerResponseReader(stream); + serverResponseReader.callback = HandleResponse; + serverResponseReader.StartRead(); + } + /// + /// callback method that handles responses from the server + /// + /// the response message from the server + public static void HandleResponse(string message) + { + string id = JSONParser.GetID(message); + + // because the first messages don't have a serial, we need to check on the id + if (id == "session/list") + { + sessionId = JSONParser.GetSessionID(message, PCs); + } + else if (id == "tunnel/create") + { + tunnelId = JSONParser.GetTunnelID(message); + if (tunnelId == null) + { + Console.WriteLine("could not find a valid tunnel id!"); + return; + } + } + + if (message.Contains("serial")) + { + //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); + } + } + + /// + /// 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. + /// + /// the networkstream to use + /// the message to send + /// the serial to check for + /// the code to be executed upon reveiving a reply from the server with the specified serial + public static void SendMessageAndOnResponse(NetworkStream stream, string message, string serial, HandleSerial action) + { + serialResponses.Add(serial, action); + WriteTextMessage(stream, message); } /// @@ -47,65 +109,30 @@ namespace RH_Engine stream.Write(res); - //Console.WriteLine("sent message " + message); + Console.WriteLine("sent message " + message); } - /// - /// reads a response from the server - /// - /// the network stream to use - /// the returned message from the server - public static string ReadPrefMessage(NetworkStream stream) - { - byte[] lengthBytes = new byte[4]; - - stream.Read(lengthBytes, 0, 4); - Console.WriteLine("read message.."); - - int length = BitConverter.ToInt32(lengthBytes); - - //Console.WriteLine("length is: " + length); - - byte[] buffer = new byte[length]; - int totalRead = 0; - - //read bytes until stream indicates there are no more - do - { - int read = stream.Read(buffer, totalRead, buffer.Length - totalRead); - totalRead += read; - //Console.WriteLine("ReadMessage: " + read); - } while (totalRead < length); - - return Encoding.UTF8.GetString(buffer, 0, totalRead); - } /// /// connects to the server and creates the tunnel /// /// the network stream to use private static void CreateConnection(NetworkStream stream) { - WriteTextMessage(stream, "{\r\n\"id\" : \"session/list\"\r\n}"); - string id = JSONParser.GetSessionID(ReadPrefMessage(stream), PCs); + initReader(stream); - string tunnelCreate = "{\"id\" : \"tunnel/create\", \"data\" : {\"session\" : \"" + id + "\"}}"; + WriteTextMessage(stream, "{\r\n\"id\" : \"session/list\",\r\n\"serial\" : \"list\"\r\n}"); + + // wait until we have got a sessionId + while (sessionId == string.Empty) { } + + string tunnelCreate = "{\"id\" : \"tunnel/create\", \"data\" : {\"session\" : \"" + sessionId + "\"}}"; WriteTextMessage(stream, tunnelCreate); - string tunnelResponse = ReadPrefMessage(stream); - - Console.WriteLine(tunnelResponse); - - string tunnelID = JSONParser.GetTunnelID(tunnelResponse); - if (tunnelID == null) - { - Console.WriteLine("could not find a valid tunnel id!"); - return; - } - - sendCommands(stream, tunnelID); - - + // wait until we have a tunnel id + while (tunnelId == string.Empty) { } + Console.WriteLine("got tunnel id! sending commands..."); + sendCommands(stream, tunnelId); } /// @@ -117,27 +144,40 @@ namespace RH_Engine { Command mainCommand = new Command(tunnelID); - WriteTextMessage(stream, mainCommand.ResetScene()); - ReadPrefMessage(stream); - string routeid = CreateRoute(stream, mainCommand); + SendMessageAndOnResponse(stream, mainCommand.RouteCommand("routeID"), "routeID", (message) => routeId = JSONParser.GetResponseUuid(message)); - WriteTextMessage(stream, mainCommand.TerrainCommand(new int[] { 256, 256 }, null)); - Console.WriteLine(ReadPrefMessage(stream)); - string command; + //WriteTextMessage(stream, mainCommand.TerrainCommand(new int[] { 256, 256 }, null)); + //string command; - command = mainCommand.AddBikeModel(); + SendMessageAndOnResponse(stream, mainCommand.AddBikeModel("bikeID"), "bikeID", (message) => bikeId = JSONParser.GetResponseUuid(message)); - WriteTextMessage(stream, command); + SendMessageAndOnResponse(stream, mainCommand.addPanel("panelID", bikeId), "panelID", + (message) => + { + panelId = JSONParser.GetResponseUuid(message); + while (bikeId == string.Empty) { } + WriteTextMessage(stream, mainCommand.RouteFollow(routeId, bikeId, 5, new float[] { 0, -(float)Math.PI / 2f, 0 }, new float[] { 0, 0, 0 })); + }); - Console.WriteLine(ReadPrefMessage(stream)); + Console.WriteLine("id of head " + GetId(Command.STANDARD_HEAD, stream, mainCommand)); - command = mainCommand.AddModel("car", "data\\customModels\\TeslaRoadster.fbx"); - - WriteTextMessage(stream, command); - - Console.WriteLine(ReadPrefMessage(stream)); + //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)); } /// @@ -160,19 +200,6 @@ namespace RH_Engine } Console.WriteLine("Could not find id of " + name); return null; - - } - - public static string CreateRoute(NetworkStream stream, Command createGraphics) - { - WriteTextMessage(stream, createGraphics.RouteCommand()); - dynamic response = JsonConvert.DeserializeObject(ReadPrefMessage(stream)); - if (response.data.data.id == "route/add") - { - return response.data.data.data.uuid; - } - return null; - } public static void CreateTerrain(NetworkStream stream, Command createGraphics) @@ -185,12 +212,9 @@ namespace RH_Engine height[i] = improvedPerlin.GetValue(x / 10, x / 10, x * 100) + 1; x += 0.001f; } - WriteTextMessage(stream, createGraphics.TerrainCommand(new int[] { 256, 256 }, height)); - Console.WriteLine(ReadPrefMessage(stream)); WriteTextMessage(stream, createGraphics.AddNodeCommand()); - Console.WriteLine(ReadPrefMessage(stream)); } /// @@ -201,9 +225,14 @@ namespace RH_Engine /// all the children objects in the current scene public static JArray GetChildren(NetworkStream stream, Command createGraphics) { - WriteTextMessage(stream, createGraphics.GetSceneInfoCommand()); - dynamic response = JsonConvert.DeserializeObject(ReadPrefMessage(stream)); - return response.data.data.data.children; + JArray res = null; + SendMessageAndOnResponse(stream, createGraphics.GetSceneInfoCommand("getChildren"), "getChildren", (message) => + { + dynamic response = JsonConvert.DeserializeObject(message); + res = response.data.data.data.children; + }); + while (res == null) { } + return res; } /// @@ -225,15 +254,7 @@ namespace RH_Engine } return res; - } - - public static string getUUIDFromResponse(string response) - { - dynamic JSON = JsonConvert.DeserializeObject(response); - return JSON.data.data.data.uuid; - } - } /// @@ -246,6 +267,7 @@ namespace RH_Engine this.host = host; this.user = user; } + public string host { get; } public string user { get; } diff --git a/RH-Engine/ServerResponseReader.cs b/RH-Engine/ServerResponseReader.cs new file mode 100644 index 0000000..85e7f00 --- /dev/null +++ b/RH-Engine/ServerResponseReader.cs @@ -0,0 +1,77 @@ +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading; + +namespace RH_Engine +{ + public delegate void OnResponse(string response); + + class ServerResponseReader + { + public OnResponse callback + { + get; set; + } + + public NetworkStream Stream { get; } + + public ServerResponseReader(NetworkStream stream) + { + this.Stream = stream; + } + + public void StartRead() + { + Thread t = new Thread(() => + { + if (this.callback == null) + { + throw new Exception("Callback not initialized!"); + } + else + { + Console.WriteLine("Starting loop for reading"); + while (true) + { + string res = ReadPrefMessage(Stream); + //Console.WriteLine("[SERVERRESPONSEREADER] got message from server: " + res); + this.callback(res); + } + } + }); + + t.Start(); + } + + /// + /// reads a response from the server + /// + /// the network stream to use + /// the returned message from the server + public static string ReadPrefMessage(NetworkStream stream) + { + byte[] lengthBytes = new byte[4]; + + int streamread = stream.Read(lengthBytes, 0, 4); + //Console.WriteLine("read message.. " + streamread); + + int length = BitConverter.ToInt32(lengthBytes); + + //Console.WriteLine("length is: " + length); + + byte[] buffer = new byte[length]; + int totalRead = 0; + + //read bytes until stream indicates there are no more + do + { + int read = stream.Read(buffer, totalRead, buffer.Length - totalRead); + totalRead += read; + //Console.WriteLine("ReadMessage: " + read); + } while (totalRead < length); + + return Encoding.UTF8.GetString(buffer, 0, totalRead); + } + } +} \ No newline at end of file diff --git a/Server/Client.cs b/Server/Client.cs new file mode 100644 index 0000000..9dfc946 --- /dev/null +++ b/Server/Client.cs @@ -0,0 +1,87 @@ +using System; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using Newtonsoft.Json; + +namespace Server +{ + class Client + { + private Communication communication; + private TcpClient tcpClient; + private NetworkStream stream; + private byte[] buffer = new byte[1024]; + private byte[] totalBuffer = new byte[1024]; + private int bytesReceived; + + + public string Username { get; set; } + + public Client(Communication communication, TcpClient tcpClient) + { + this.communication = communication; + this.tcpClient = tcpClient; + this.stream = this.tcpClient.GetStream(); + stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null); + } + + private void OnRead(IAsyncResult ar) + { + int receivedBytes = this.stream.EndRead(ar); + byte[] lengthBytes = new byte[4]; + + Array.Copy(this.buffer, 0, lengthBytes, 0, 4); + + int expectedMessageLength = BitConverter.ToInt32(lengthBytes); + + if (expectedMessageLength > this.buffer.Length) + { + throw new OutOfMemoryException("buffer to small"); + } + + if (expectedMessageLength > this.bytesReceived + receivedBytes) + { + //message hasn't completely arrived yet + this.bytesReceived += receivedBytes; + Console.WriteLine("segmented message, {0} arrived", receivedBytes); + this.stream.BeginRead(this.buffer, this.bytesReceived, this.buffer.Length - this.bytesReceived, new AsyncCallback(OnRead), null); + + } + else + { + //message completely arrived + if (expectedMessageLength != this.bytesReceived + receivedBytes) + { + Console.WriteLine("something has gone completely wrong"); + Console.WriteLine($"expected: {expectedMessageLength} bytesReceive: {bytesReceived} receivedBytes: {receivedBytes}"); + Console.WriteLine($"received WEIRD data {BitConverter.ToString(buffer.Take(receivedBytes).ToArray())} string {Encoding.ASCII.GetString(buffer.Take(receivedBytes).ToArray())}"); + + } + else if (buffer[4] == 0x02) + { + Console.WriteLine($"received raw data {BitConverter.ToString(buffer.Skip(5).Take(expectedMessageLength).ToArray())}"); + } + else if (buffer[4] == 0x01) + { + byte[] packet = new byte[expectedMessageLength]; + Console.WriteLine(Encoding.ASCII.GetString(buffer) + " " + expectedMessageLength); + Array.Copy(buffer, 5, packet, 0, expectedMessageLength - 5); + Console.WriteLine(Encoding.ASCII.GetString(packet)); + HandleData(Encoding.ASCII.GetString(packet)); + } + this.bytesReceived = 0; + + } + + this.stream.BeginRead(this.buffer, 0, this.buffer.Length, new AsyncCallback(OnRead), null); + + } + + private void HandleData(string packet) + { + Console.WriteLine("Data " + packet); + JsonConvert.DeserializeObject(packet); + } + } +} diff --git a/Server/Communication.cs b/Server/Communication.cs new file mode 100644 index 0000000..1eed0b0 --- /dev/null +++ b/Server/Communication.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.IO.Pipes; +using System.Net.Sockets; +using System.Text; + +namespace Server +{ + class Communication + { + private TcpListener listener; + private List clients; + + public Communication(TcpListener listener) + { + this.listener = listener; + this.clients = new List(); + } + + public void Start() + { + listener.Start(); + listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null); + } + + private void OnConnect(IAsyncResult ar) + { + var tcpClient = listener.EndAcceptTcpClient(ar); + Console.WriteLine($"Client connected from {tcpClient.Client.RemoteEndPoint}"); + clients.Add(new Client(this, tcpClient)); + listener.BeginAcceptTcpClient(new AsyncCallback(OnConnect), null); + } + + internal void Disconnect(Client client) + { + clients.Remove(client); + } + } +} diff --git a/Server/Program.cs b/Server/Program.cs index 72c96d1..cd980a4 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -1,4 +1,5 @@ -using System; +using System.Net; +using System.Net.Sockets; namespace Server { @@ -6,7 +7,13 @@ namespace Server { static void Main(string[] args) { - Console.WriteLine("Hello World!"); + Communication communication = new Communication(new TcpListener(IPAddress.Any, 5555)); + communication.Start(); + + while (true) + { + + } } } } diff --git a/Server/Server.csproj b/Server/Server.csproj index 4c98a00..0eaee1b 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -6,7 +6,7 @@ - +