From 8bf6c73dbb4f43b64f27fdad7eff4145a91ef921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20DI=20MERCURIO?= Date: Fri, 4 Jan 2019 16:55:48 +0100 Subject: [PATCH] images are now sent using base64. 40fps on localhost, test to be done on raspberry --- .vscode/c_cpp_properties.json | 16 - .vscode/tasks.json | 16 - software/monitor/monitor/Client.cs | 168 +++- software/monitor/monitor/CommandManager.cs | 8 +- .../monitor/monitor/DestijlCommandManager.cs | 305 +++++-- software/monitor/monitor/MonitorUI.cs | 195 ++-- software/monitor/monitor/monitor | Bin 104960 -> 107520 bytes software/raspberry/superviseur-robot/.dep.inc | 5 - .../raspberry/superviseur-robot/.idea/.name | 1 - .../.idea/codeStyles/Project.xml | 29 - .../superviseur-robot/.idea/misc.xml | 7 - .../superviseur-robot/.idea/modules.xml | 8 - .../.idea/superviseur-robot.iml | 2 - .../raspberry/superviseur-robot/.idea/vcs.xml | 6 - .../superviseur-robot/.idea/workspace.xml | 864 ------------------ .../GNU-Linux/superviseur-robot | Bin 956776 -> 1101728 bytes .../superviseur-robot/lib/base64/.gitignore | 2 + .../superviseur-robot/lib/base64/LICENSE | 19 + .../superviseur-robot/lib/base64/README.md | 7 + .../superviseur-robot/lib/base64/base64.cpp | 122 +++ .../superviseur-robot/lib/base64/base64.h | 14 + .../lib/base64/compile-and-run-test | 2 + .../superviseur-robot/lib/base64/test.cpp | 56 ++ .../superviseur-robot/lib/camera.cpp | 46 +- .../raspberry/superviseur-robot/lib/camera.h | 18 +- .../superviseur-robot/lib/commonitor.cpp | 48 +- .../superviseur-robot/lib/commonitor.h | 6 +- .../raspberry/superviseur-robot/lib/img.cpp | 64 +- .../raspberry/superviseur-robot/lib/img.h | 31 +- .../superviseur-robot/lib/messages.cpp | 6 +- .../superviseur-robot/lib/messages.h | 10 +- software/raspberry/superviseur-robot/main.cpp | 7 +- .../nbproject/Makefile-Debug.mk | 6 + .../nbproject/Makefile-Debug__Pthread_.mk | 6 + .../nbproject/Makefile-Debug__RPI_.mk | 6 + .../nbproject/Makefile-Release.mk | 6 + .../nbproject/configurations.xml | 42 + .../nbproject/private/private.xml | 3 +- .../superviseur-robot/tasks_pthread.cpp | 150 ++- .../superviseur-robot/tasks_pthread.h | 3 + 40 files changed, 1021 insertions(+), 1289 deletions(-) delete mode 100644 .vscode/c_cpp_properties.json delete mode 100644 .vscode/tasks.json delete mode 100644 software/raspberry/superviseur-robot/.dep.inc delete mode 100644 software/raspberry/superviseur-robot/.idea/.name delete mode 100644 software/raspberry/superviseur-robot/.idea/codeStyles/Project.xml delete mode 100644 software/raspberry/superviseur-robot/.idea/misc.xml delete mode 100644 software/raspberry/superviseur-robot/.idea/modules.xml delete mode 100644 software/raspberry/superviseur-robot/.idea/superviseur-robot.iml delete mode 100644 software/raspberry/superviseur-robot/.idea/vcs.xml delete mode 100644 software/raspberry/superviseur-robot/.idea/workspace.xml create mode 100644 software/raspberry/superviseur-robot/lib/base64/.gitignore create mode 100644 software/raspberry/superviseur-robot/lib/base64/LICENSE create mode 100644 software/raspberry/superviseur-robot/lib/base64/README.md create mode 100644 software/raspberry/superviseur-robot/lib/base64/base64.cpp create mode 100644 software/raspberry/superviseur-robot/lib/base64/base64.h create mode 100755 software/raspberry/superviseur-robot/lib/base64/compile-and-run-test create mode 100644 software/raspberry/superviseur-robot/lib/base64/test.cpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index ee202d8..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "configurations": [ - { - "name": "Linux", - "includePath": [ - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "/usr/bin/clang", - "cStandard": "c11", - "cppStandard": "c++17", - "intelliSenseMode": "clang-x64" - } - ], - "version": 4 -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 29327bf..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "taskName": "Compile on raspberry", - "command": "rsync -az '${file}' 10.105.1.6:~ && ssh server.example.org 'chmod +x ./${fileBasename}; ./${fileBasename}'", - "type": "shell", - "group": { - "kind": "build", - "isDefault": true - } - } - ] -} \ No newline at end of file diff --git a/software/monitor/monitor/Client.cs b/software/monitor/monitor/Client.cs index 48bb9c9..b6afe8a 100644 --- a/software/monitor/monitor/Client.cs +++ b/software/monitor/monitor/Client.cs @@ -23,6 +23,8 @@ using System; using System.Net.Sockets; using System.Text; +using System.Threading; + namespace monitor { /// @@ -66,21 +68,26 @@ namespace monitor /// private static byte[] receiveBuffer; - private static int initialReceiveBufferIndex = 0; + //private static int initialReceiveBufferIndex = 0; /// /// String containing received message from tcp server /// private static StringBuilder message = new StringBuilder(); - private static int newLength = 1; - private static int packetCounter = 0; + //private static int newLength = 1; + //private static int packetCounter = 0; /// /// Callback to send received message to upper level /// - public delegate void ReadEvent(string msg, byte[] buffer); + public delegate void ReadEvent(string msg); public static ReadEvent readEvent = null; + /// + /// Thread used in reception + /// + private static Thread readThread; + /// /// Open connection to server "host", on default port number. /// @@ -114,7 +121,12 @@ namespace monitor // received data are stored in buffer // Next reading will be done in ReadCallback method - stream.BeginRead(buffer, 0, newLength, new AsyncCallback(ReadCallback), message); + stream.BeginRead(buffer, 0, 1, new AsyncCallback(ReadCallback), message); + + // Start reading thread + //message.Clear(); + //readThread = new Thread(new ThreadStart(ReadCallback)); + //readThread.Start(); } catch (ArgumentNullException e) { @@ -144,19 +156,142 @@ namespace monitor if (client != null) client.Close(); } + /// + /// Callback call by stream.BeginRead after reception of newLength data + /// + //private static void ReadCallback() + //{ + // char character; + // int data; + // byte[] buffer=new byte[4096]; + // int lengthRead; + + // while (client.Connected) + // { + // try + // { + // //data = stream.ReadByte(); + // lengthRead = stream.Read(buffer, 0, buffer.Length); + // } + // catch (ObjectDisposedException) + // { + // Console.WriteLine("Connection to server dropped (object disposed)!"); + // return; + // } + // catch (System.IO.IOException) + // { + // Console.WriteLine("Connection to server dropped (other error)"); + // return; + // } + + // if (lengthRead > 0) // a data was read + // { + // //character = (char)data; + // var str = System.Text.Encoding.Default.GetString(buffer); + // int indexOf = str.IndexOf('\n'); + + // //if (character != '\n') + // if (indexOf == -1) // \n doesn't exists + // { + // message.Append(str); + + // //if (receiveBuffer == null) receiveBuffer = new byte[1]; + // //else Array.Resize(ref receiveBuffer, receiveBuffer.Length + 1); // resize currrent buffer + + // //receiveBuffer[receiveBuffer.Length - 1] = (byte)data; + // } + // else // end of string found + // { + // message.Append((str.Substring(0,indexOf))); + // readEvent?.Invoke(message.ToString(), receiveBuffer); + + // message.Clear(); + // receiveBuffer = null; + // } + // } + // } + //} + /// /// Callback call by stream.BeginRead after reception of newLength data /// /// Not sure of what is it, but needed for terminate reading + //private static void ReadCallback(IAsyncResult ar) + //{ + // if (client.Connected) + // { + // int bytesRead; + + // try + // { + // // Termintae read operation, and get number of byte stored in buffer + // bytesRead = stream.EndRead(ar); + // } + // catch (ObjectDisposedException e) + // { + // Console.WriteLine("Connection to server dropped: " + e.ToString()); + // return; + // } + + // newLength = 1; + + // // if number of byte read is not 0, concatenate string and buffer + // if (bytesRead > 0) + // { + // packetCounter++; + + // if (packetCounter >= 3) + // { + // //Console.WriteLine("Supplementary packet " + packetCounter); + // } + + // // Append new data to current string (expecting data are ascii) + // message.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead)); + + // // Similarly, append received bytes to current buffer + // if (receiveBuffer == null) receiveBuffer = new byte[bytesRead]; + // else Array.Resize(ref receiveBuffer, initialReceiveBufferIndex + bytesRead); // resize currrent buffer + + // System.Buffer.BlockCopy(buffer, 0, receiveBuffer, initialReceiveBufferIndex, bytesRead); // and add received data + // initialReceiveBufferIndex = receiveBuffer.Length; // move last index of current buffer + // } + + // // if it remains received data, prepare for a new reading (get another buffer to append to current one) + // if (client.Available > 0) + // { + // newLength = client.Available; + // if (newLength > BufferMaxSize) newLength = BufferMaxSize; + // else newLength = client.Available; + // } + // else + // { + // // no more data to read, buffer and string can be send to upper level + // readEvent?.Invoke(message.ToString(), receiveBuffer); + + // message.Clear(); + // receiveBuffer = null; + // initialReceiveBufferIndex = 0; + // packetCounter = 0; + // } + + // // Prepare for reading new data + // if (newLength> BufferMaxSize) newLength = BufferMaxSize; + // if (newLength <= 0) newLength = 1; + // stream.BeginRead(buffer, 0, newLength, new AsyncCallback(ReadCallback), message); + // } + //} + private static void ReadCallback(IAsyncResult ar) { + int newLength = 1; + if (client.Connected) { int bytesRead; try { - // Termintae read operation, and get number of byte stored in buffer + // Terminate read operation, and get number of byte stored in buffer bytesRead = stream.EndRead(ar); } catch (ObjectDisposedException e) @@ -165,27 +300,13 @@ namespace monitor return; } - newLength = 1; + //newLength = 1; // if number of byte read is not 0, concatenate string and buffer if (bytesRead > 0) { - packetCounter++; - - if (packetCounter >= 3) - { - //Console.WriteLine("Supplementary packet " + packetCounter); - } - // Append new data to current string (expecting data are ascii) message.Append(Encoding.ASCII.GetString(buffer, 0, bytesRead)); - - // Similarly, append received bytes to current buffer - if (receiveBuffer == null) receiveBuffer = new byte[bytesRead]; - else Array.Resize(ref receiveBuffer, initialReceiveBufferIndex + bytesRead); // resize currrent buffer - - System.Buffer.BlockCopy(buffer, 0, receiveBuffer, initialReceiveBufferIndex, bytesRead); // and add received data - initialReceiveBufferIndex = receiveBuffer.Length; // move last index of current buffer } // if it remains received data, prepare for a new reading (get another buffer to append to current one) @@ -198,12 +319,9 @@ namespace monitor else { // no more data to read, buffer and string can be send to upper level - readEvent?.Invoke(message.ToString(), receiveBuffer); + readEvent?.Invoke(message.ToString()); message.Clear(); - receiveBuffer = null; - initialReceiveBufferIndex = 0; - packetCounter = 0; } // Prepare for reading new data diff --git a/software/monitor/monitor/CommandManager.cs b/software/monitor/monitor/CommandManager.cs index 803e229..03efac1 100644 --- a/software/monitor/monitor/CommandManager.cs +++ b/software/monitor/monitor/CommandManager.cs @@ -33,7 +33,7 @@ namespace monitor /// /// Callback for sending received data to upper level /// - public delegate void CommandReceivedEvent(string msg, byte[] buffer); + public delegate void CommandReceivedEvent(string msg); public CommandReceivedEvent commandReceivedEvent = null; /// @@ -122,7 +122,7 @@ namespace monitor /// /// Message received from server /// Raw buffer reived from server - private void OnMessageReception(string message, byte[] buffer) + private void OnMessageReception(string message) { waitTimer.Stop(); // Stop timeout stopwatch @@ -144,7 +144,7 @@ namespace monitor waitForAcknowledge = false; - this.commandReceivedEvent?.Invoke(message, buffer); + this.commandReceivedEvent?.Invoke(message); } } @@ -158,7 +158,7 @@ namespace monitor messageReceived = null; // set buffer and message as null to indicate that no message was received // and call to OnMessagereception is due to timeout - OnMessageReception(messageReceived, null); + OnMessageReception(messageReceived); } /// diff --git a/software/monitor/monitor/DestijlCommandManager.cs b/software/monitor/monitor/DestijlCommandManager.cs index 2f85469..3257eb8 100644 --- a/software/monitor/monitor/DestijlCommandManager.cs +++ b/software/monitor/monitor/DestijlCommandManager.cs @@ -20,6 +20,7 @@ // along with this program. If not, see . using System; +using System.Globalization; namespace monitor { @@ -28,47 +29,84 @@ namespace monitor /// public static class DestijlCommandList { - public const string HeaderMtsComDmb = "COM"; - public const string HeaderMtsDmbOrder = "DMB"; - public const string HeaderMtsCamera = "CAM"; - public const string HeaderMtsMessage = "MSG"; + public const string ANSWER_ACK = "AACK"; + public const string ANSWER_NACK = "ANAK"; + public const string ANSWER_COM_ERROR = "ACER"; + public const string ANSWER_TIMEOUT = "ATIM"; + public const string ANSWER_CMD_REJECTED = "ACRJ"; + public const string MESSAGE = "MSSG"; + public const string CAMERA_OPEN = "COPN"; + public const string CAMERA_CLOSE = "CCLS"; + public const string CAMERA_IMAGE = "CIMG"; + public const string CAMERA_ARENA_ASK = "CASA"; + public const string CAMERA_ARENA_INFIRM = "CAIN"; + public const string CAMERA_ARENA_CONFIRM = "CACO"; + public const string CAMERA_POSITION_COMPUTE = "CPCO"; + public const string CAMERA_POSITION_STOP = "CPST"; + public const string CAMERA_POSITION = "CPOS"; + public const string ROBOT_COM_OPEN = "ROPN"; + public const string ROBOT_COM_CLOSE = "RCLS"; + public const string ROBOT_PING = "RPIN"; + public const string ROBOT_RESET = "RRST"; + public const string ROBOT_START_WITHOUT_WD = "RSOW"; + public const string ROBOT_START_WITH_WD = "RSWW"; + public const string ROBOT_RELOAD_WD = "RLDW"; + public const string ROBOT_MOVE = "RMOV"; + public const string ROBOT_TURN = "RTRN"; + public const string ROBOT_GO_FORWARD = "RGFW"; + public const string ROBOT_GO_BACKWARD = "RGBW"; + public const string ROBOT_GO_LEFT = "RGLF"; + public const string ROBOT_GO_RIGHT = "RGRI"; + public const string ROBOT_STOP = "RSTP"; + public const string ROBOT_POWEROFF = "RPOF"; + public const string ROBOT_BATTERY_LEVEL = "RBLV"; + public const string ROBOT_GET_BATTERY = "RGBT"; + public const string ROBOT_GET_STATE = "RGST"; + public const string ROBOT_CURRENT_STATE = "RCST"; - public const string DataComOpen = "o"; - public const string DataComClose = "C"; + public const char SEPARATOR_CHAR = ':'; - public const string DataCamOpen = "A"; - public const string DataCamClose = "I"; - public const string DataCamAskArena = "y"; - public const string DataCamArenaConfirm = "x"; - public const string DataCamInfirm = "z"; - public const string DataCamComputePosition = "p"; - public const string DataCamStopComputePosition = "s"; + //public const string HeaderMtsComDmb = "COM"; + //public const string HeaderMtsDmbOrder = "DMB"; + //public const string HeaderMtsCamera = "CAM"; + //public const string HeaderMtsMessage = "MSG"; - public const string HeaderStmAck = "ACK"; - public const string HeaderStmNoAck = "NAK"; - public const string HeaderStmLostDmb = "LCD"; - public const string HeaderStmImage = "IMG"; - public const string HeaderStmPos = "POS"; - public const string HeaderStmMes = "MSG"; - public const string HeaderStmBat = "BAT"; + //public const string DataComOpen = "o"; + //public const string DataComClose = "C"; + + //public const string DataCamOpen = "A"; + //public const string DataCamClose = "I"; + //public const string DataCamAskArena = "y"; + //public const string DataCamArenaConfirm = "x"; + //public const string DataCamInfirm = "z"; + //public const string DataCamComputePosition = "p"; + //public const string DataCamStopComputePosition = "s"; + + //public const string HeaderStmAck = "ACK"; + //public const string HeaderStmNoAck = "NAK"; + //public const string HeaderStmLostDmb = "LCD"; + //public const string HeaderStmImage = "IMG"; + //public const string HeaderStmPos = "POS"; + //public const string HeaderStmMes = "MSG"; + //public const string HeaderStmBat = "BAT"; } /// /// Commands used for robot messages /// - public static class RobotCommandList - { - public const string RobotPing = "p"; - public const string RobotReset = "r"; - public const string RobotStartWithoutWatchdog = "u"; - public const string RobotStartWithWatchdog = "W"; - public const string RobotGetBattery = "v"; - public const string RobotGetBusyState = "b"; - public const string RobotMove = "M"; - public const string RobotTurn = "T"; - public const string RobotGetVersion = "V"; - public const string RobotPowerOff = "z"; - } + //public static class RobotCommandList + //{ + // public const string RobotPing = "p"; + // public const string RobotReset = "r"; + // public const string RobotStartWithoutWatchdog = "u"; + // public const string RobotStartWithWatchdog = "W"; + // public const string RobotGetBattery = "v"; + // public const string RobotGetBusyState = "b"; + // public const string RobotMove = "M"; + // public const string RobotTurn = "T"; + // public const string RobotGetVersion = "V"; + // public const string RobotPowerOff = "z"; + //} /// /// Specialization class for command manager, which implemnent destijl protocol between monitor and server @@ -93,7 +131,7 @@ namespace monitor /// /// Callback for sending received data to application level /// - public delegate void CommandReceivedEvent(string header, string data, byte[] buffer); + public delegate void CommandReceivedEvent(string header, string data); public CommandReceivedEvent commandReceivedEvent = null; /// @@ -114,6 +152,34 @@ namespace monitor CommunicationLostWithServer } + public struct Point { + public double x; + public double y; + } + + public class Position { + public int robotID; + public double angle; + public Point centre; + public Point direction; + + public Position() { + robotID = 0; + angle = 0.0; + centre.x = 0.0; + centre.y = 0.0; + direction.x = 0.0; + direction.y = 0.0; + } + + public override string ToString() { + string s = "ID: " + robotID + ", Angle: " + angle + + ", Centre (x: " + centre.x + ", y: " + centre.y + + "), Direction (x: " + direction.x + ", y: " + direction.y + ")"; + return s; + } + } + /// /// Initializes a new instance of the class. /// @@ -138,10 +204,13 @@ namespace monitor /// /// String containing received message /// Raw buffer to be used when data are not in ascii format (image for example) - private void OnCommandReceived(string msg, byte[] buffer) + private void OnCommandReceived(string msg) { - // Firstly, split message in (at least) two part : header, and data - string[] msgs = msg.Split(':'); + // Firstly, remove ending \n and everything after + string[] msgsCarriageReturn = msg.Split('\n'); + + // Second, split message in (at least) two part : header, and data + string[] msgs = msgsCarriageReturn[0].Split(DestijlCommandList.SEPARATOR_CHAR); // If it exist at least on element in string array, it should be command header if (msgs.Length >= 1) receivedHeader = msgs[0]; @@ -152,7 +221,7 @@ namespace monitor else receivedData = null; // when split is done, provide data to application - this.commandReceivedEvent?.Invoke(receivedHeader, receivedData, buffer); + this.commandReceivedEvent?.Invoke(receivedHeader, receivedData); } /// @@ -193,7 +262,17 @@ namespace monitor /// Data part of the command private string CreateCommand(string header, string data) { - return header + ":" + data; + return header + DestijlCommandList.SEPARATOR_CHAR + data+"\n"; + } + + /// + /// Creates the command to send to server, based on header + /// + /// The command string + /// Header part of the command + private string CreateCommand(string header) + { + return header + DestijlCommandList.SEPARATOR_CHAR+"\n"; } /// @@ -215,9 +294,9 @@ namespace monitor if (answer != null) { // if command is not acknowledged, return Rejected - if (answer.ToUpper().Contains(DestijlCommandList.HeaderStmNoAck)) status = CommandStatus.Rejected; + if (answer.ToUpper().Contains(DestijlCommandList.ANSWER_NACK)) status = CommandStatus.Rejected; // if communication is lost with robot, return CommunicationLostWithRobot - else if (answer.ToUpper().Contains(DestijlCommandList.HeaderStmLostDmb)) status = CommandStatus.CommunicationLostWithRobot; + else if (answer.ToUpper().Contains(DestijlCommandList.ANSWER_TIMEOUT)) status = CommandStatus.CommunicationLostWithRobot; // if answer is empty, communication with robot is lost else if (answer.Length == 0) status = CommandStatus.CommunicationLostWithServer; //else status = CommandStatus.InvalidAnswer; @@ -237,7 +316,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsComDmb, DestijlCommandList.DataComOpen), + CreateCommand(DestijlCommandList.ROBOT_COM_OPEN), out answer, this.timeout); @@ -254,7 +333,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsComDmb, DestijlCommandList.DataComClose), + CreateCommand(DestijlCommandList.ROBOT_COM_CLOSE), out answer, this.timeout); @@ -271,7 +350,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotPing), + CreateCommand(DestijlCommandList.ROBOT_PING), out answer, this.timeout); @@ -288,7 +367,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotReset), + CreateCommand(DestijlCommandList.ROBOT_RESET), out answer, 0); @@ -305,7 +384,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotStartWithWatchdog), + CreateCommand(DestijlCommandList.ROBOT_START_WITH_WD), out answer, this.timeout); @@ -322,7 +401,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotStartWithoutWatchdog), + CreateCommand(DestijlCommandList.ROBOT_START_WITHOUT_WD), out answer, this.timeout); @@ -340,7 +419,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotMove + "=" + distance), + CreateCommand(DestijlCommandList.ROBOT_MOVE, Convert.ToString(distance)), out answer, 0); @@ -358,7 +437,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotTurn + "=" + angle), + CreateCommand(DestijlCommandList.ROBOT_TURN, Convert.ToString(angle)), out answer, 0); @@ -375,48 +454,13 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotGetBattery), + CreateCommand(DestijlCommandList.ROBOT_GET_BATTERY), out answer, 0); return DecodeStatus(localStatus, answer); } - /// - /// Request robot firmware version - /// - /// Command status (see DecodeStatus) - /// todo - public CommandStatus RobotGetVersion(out string version) - { - CommandManager.CommandManagerStatus localStatus; - CommandStatus status = CommandStatus.Success; - version = ""; - - string answer; - - localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotGetVersion), - out answer, - this.timeout); - - if (localStatus == CommandManager.CommandManagerStatus.AnswerReceived) - { - string[] msg = answer.Split(':'); - - if (msg.Length > 1) - { - version = msg[1]; - } - } - else if (localStatus == CommandManager.CommandManagerStatus.Timeout) - { - status = CommandStatus.CommunicationLostWithServer; - } - - return status; - } - /// /// Power off robot /// @@ -427,7 +471,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsDmbOrder, RobotCommandList.RobotPowerOff), + CreateCommand(DestijlCommandList.ROBOT_POWEROFF), out answer, 0); @@ -444,7 +488,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsCamera, DestijlCommandList.DataCamOpen), + CreateCommand(DestijlCommandList.CAMERA_OPEN), out answer, this.timeout); @@ -461,7 +505,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsCamera, DestijlCommandList.DataCamClose), + CreateCommand(DestijlCommandList.CAMERA_CLOSE), out answer, 0); @@ -478,7 +522,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsCamera, DestijlCommandList.DataCamAskArena), + CreateCommand(DestijlCommandList.CAMERA_ARENA_ASK), out answer, 0); @@ -495,7 +539,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsCamera, DestijlCommandList.DataCamArenaConfirm), + CreateCommand(DestijlCommandList.CAMERA_ARENA_CONFIRM), out answer, 0); @@ -512,7 +556,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsCamera, DestijlCommandList.DataCamInfirm), + CreateCommand(DestijlCommandList.CAMERA_ARENA_INFIRM), out answer, 0); @@ -529,7 +573,7 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsCamera, DestijlCommandList.DataCamComputePosition), + CreateCommand(DestijlCommandList.CAMERA_POSITION_COMPUTE), out answer, 0); @@ -546,11 +590,86 @@ namespace monitor string answer; localStatus = commandManager.SendCommand( - CreateCommand(DestijlCommandList.HeaderMtsCamera, DestijlCommandList.DataCamStopComputePosition), + CreateCommand(DestijlCommandList.CAMERA_POSITION_STOP), out answer, 0); return DecodeStatus(localStatus, answer); } + + public static Position DecodePosition(string data) { + Position pos = new Position(); + + pos.robotID = 0; + pos.angle = 0.0; + pos.centre.x = 0.0; + pos.centre.y=0.0; + pos.direction.x = 0.0; + pos.direction.y = 0.0; + + string[] parts = data.Split(';'); + + //for (int i = 0; i < parts.Length; i++) { + // Console.WriteLine(parts[i]); + //} + + NumberFormatInfo provider = new NumberFormatInfo(); + provider.NumberDecimalSeparator = "."; + provider.NumberGroupSeparator = ","; + provider.NumberGroupSizes = new int[] { 3 }; + + if (parts.Length == 6) { + pos.robotID = Convert.ToInt32(parts[0]); + + try + { + pos.angle = Convert.ToDouble(parts[1]); + } catch (FormatException) + { + pos.angle = Convert.ToDouble(parts[1],provider); + } + + try + { + pos.centre.x = Convert.ToDouble(parts[2]); + } catch (FormatException) + { + pos.centre.x = Convert.ToDouble(parts[2], provider); + } + + try + { + pos.centre.y = Convert.ToDouble(parts[3]); + } + catch (FormatException) + { + pos.centre.y = Convert.ToDouble(parts[3], provider); + } + + try + { + pos.direction.x = Convert.ToDouble(parts[4]); + } + catch (FormatException) + { + pos.direction.x = Convert.ToDouble(parts[4], provider); + } + + try + { + pos.direction.y = Convert.ToDouble(parts[5]); + } + catch (FormatException) + { + pos.direction.y = Convert.ToDouble(parts[5], provider); + } + + } else { + // misformatted data, return 0 filled position + Console.WriteLine("Misformated position"); + } + + return pos; + } } } diff --git a/software/monitor/monitor/MonitorUI.cs b/software/monitor/monitor/MonitorUI.cs index d042c15..0835562 100644 --- a/software/monitor/monitor/MonitorUI.cs +++ b/software/monitor/monitor/MonitorUI.cs @@ -23,6 +23,7 @@ using System; using Gtk; using Gdk; +using Cairo; using monitor; @@ -41,6 +42,11 @@ public partial class MainWindow : Gtk.Window /// private Pixbuf drawingareaCameraPixbuf; + /// + /// Position used for displaying position + /// + private DestijlCommandManager.Position position=new DestijlCommandManager.Position(); + /// /// List of availble state for the application /// @@ -200,8 +206,8 @@ public partial class MainWindow : Gtk.Window a.RetVal = true; } - private byte[] imageComplete; - private byte[] imageInProgress; + //private byte[] imageComplete; + //private byte[] imageInProgress; /// /// Callback called when new message is received from server @@ -209,17 +215,20 @@ public partial class MainWindow : Gtk.Window /// Header of message /// Data of message /// Raw buffer corresponding of received message - public void OnCommandReceivedEvent(string header, string data, byte[] buffer) + public void OnCommandReceivedEvent(string header, string data) { - if (buffer==null) + if (header == null) { // we have lost server ChangeState(SystemState.NotConnected); - MessagePopup(MessageType.Error, + Gtk.Application.Invoke(delegate + { + MessagePopup(MessageType.Error, ButtonsType.Ok, "Server lost", "Server is down: disconnecting"); - cmdManager.Close(); + cmdManager.Close(); + }); } // if we have received a valid message @@ -228,75 +237,104 @@ public partial class MainWindow : Gtk.Window #if DEBUG // print message content if (header.Length > 4) - Console.WriteLine("Bad header(" + buffer.Length + ")"); - else - Console.WriteLine("Received header (" + header.Length + "): " + header); + Console.WriteLine("Bad header(" + header.Length + ")"); + //else + // Console.WriteLine("Received header (" + header.Length + "): " + header); //if (header.ToUpper() != DestijlCommandList.HeaderStmImage) //{ // if (data != null) Console.WriteLine("Received data (" + data.Length + "): " + data); //} #endif // Image management - if (header == DestijlCommandList.HeaderStmImage) - { - imageComplete = imageInProgress; - imageInProgress = buffer; - } - else - { - if (imageInProgress == null) imageInProgress = buffer; - else - { - Array.Resize(ref imageInProgress, imageInProgress.Length + buffer.Length); - System.Buffer.BlockCopy(buffer, 0, imageInProgress, imageInProgress.Length - buffer.Length, buffer.Length); - } - } + //if (header == DestijlCommandList.CAMERA_IMAGE) + //{ + // imageComplete = imageInProgress; + // //TODO: Decoder le base64 pour recuperer le JPG + // imageInProgress = buffer; + //} + //else + //{ + // if (imageInProgress == null) imageInProgress = buffer; + // else + // { + // Array.Resize(ref imageInProgress, imageInProgress.Length + buffer.Length); + // System.Buffer.BlockCopy(buffer, 0, imageInProgress, imageInProgress.Length - buffer.Length, buffer.Length); + // } + //} // depending on message received (based on header) // launch correponding action - if (header.ToUpper() == DestijlCommandList.HeaderStmBat) + header = header.ToUpper(); + + if (header == DestijlCommandList.ROBOT_BATTERY_LEVEL) { + string batLevel = ""; + switch (data[0]) { case '2': - labelBatteryLevel.Text = "High"; + batLevel = "High"; break; case '1': - labelBatteryLevel.Text = "Low"; + batLevel = "Low"; break; case '0': - labelBatteryLevel.Text = "Empty"; + batLevel = "Empty"; break; default: - labelBatteryLevel.Text = "Invalid value"; + batLevel = "Invalid value"; break; } + + Gtk.Application.Invoke(delegate + { + labelBatteryLevel.Text = batLevel; + }); } - else if (header.ToUpper() == DestijlCommandList.HeaderStmImage) + else if (header == DestijlCommandList.CAMERA_IMAGE) { // if message is an image, convert it to a pixbuf // that can be displayed - if (imageComplete != null) - { - byte[] image = new byte[imageComplete.Length - 4]; - System.Buffer.BlockCopy(imageComplete, 4, image, 0, image.Length); + //if (imageComplete != null) + //{ + //TODO: Decoder le base64 et convertir en JPG + byte[] image = Convert.FromBase64String(data); + //byte[] image = new byte[imageComplete.Length - 4]; + //System.Buffer.BlockCopy(imageComplete, 4, image, 0, image.Length); - imageReceivedCounter++; - try + imageReceivedCounter++; + + try + { + drawingareaCameraPixbuf = new Pixbuf(image); + + Gtk.Application.Invoke(delegate { - drawingareaCameraPixbuf = new Pixbuf(image); drawingAreaCamera.QueueDraw(); - } - catch (GLib.GException) - { - badImageReceivedCounter++; -#if DEBUG - Console.WriteLine("Bad Image: " + badImageReceivedCounter + - " / " + imageReceivedCounter + - " (" + badImageReceivedCounter * 100 / imageReceivedCounter + "%)"); -#endif - } + }); } + catch (GLib.GException) + { + badImageReceivedCounter++; +#if DEBUG + Console.WriteLine("Bad Image: " + badImageReceivedCounter + + " / " + imageReceivedCounter + + " (" + badImageReceivedCounter * 100 / imageReceivedCounter + "%)"); +#endif + } + //} + } + else if (header == DestijlCommandList.CAMERA_POSITION) + { + //Console.WriteLine("Pos data: " + data); + + position = DestijlCommandManager.DecodePosition(data); + //Console.WriteLine("decoded position: " + position.ToString()); + + Gtk.Application.Invoke(delegate + { + drawingAreaCamera.QueueDraw(); + }); } } } @@ -417,10 +455,10 @@ public partial class MainWindow : Gtk.Window DestijlCommandManager.CommandStatus status; //if robot is not activated - if (buttonRobotActivation.Label == "Activate") + if (buttonRobotActivation.Label == "Activate") { // if a startup with watchdog is requested - if (radioButtonWithWatchdog.Active) + if (radioButtonWithWatchdog.Active) { status = cmdManager.RobotStartWithWatchdog(); } @@ -557,9 +595,7 @@ public partial class MainWindow : Gtk.Window { if (cmdManager.CameraClose() != DestijlCommandManager.CommandStatus.Success) { - MessagePopup(MessageType.Error, - ButtonsType.Ok, "Error", - "Error when closing camera: bad answer for supervisor or timeout"); + Console.WriteLine("Error when closing camera: bad answer for supervisor or timeout"); } } else // camera is not active, switch it on @@ -569,10 +605,8 @@ public partial class MainWindow : Gtk.Window if (cmdManager.CameraOpen() != DestijlCommandManager.CommandStatus.Success) { - MessagePopup(MessageType.Error, - ButtonsType.Ok, "Error", - "Error when opening camera: bad answer for supervisor or timeout"); - checkButtonCameraOn.Active = false; + Console.WriteLine("Error when opening camera: bad answer for supervisor or timeout"); + //checkButtonCameraOn.Active = false; } } } @@ -589,20 +623,16 @@ public partial class MainWindow : Gtk.Window { if (cmdManager.CameraStopComputePosition() != DestijlCommandManager.CommandStatus.Success) { - MessagePopup(MessageType.Error, - ButtonsType.Ok, "Error", - "Error when stopping position reception: bad answer for supervisor or timeout"); + Console.WriteLine("Error when stopping position reception: bad answer for supervisor or timeout"); } } else // start reception of robot position { if (cmdManager.CameraComputePosition() != DestijlCommandManager.CommandStatus.Success) { - MessagePopup(MessageType.Error, - ButtonsType.Ok, "Error", - "Error when starting getting robot position: bad answer for supervisor or timeout"); + Console.WriteLine("Error when starting getting robot position: bad answer for supervisor or timeout"); - checkButtonRobotPosition.Active = false; + //checkButtonRobotPosition.Active = false; } } } @@ -657,6 +687,47 @@ public partial class MainWindow : Gtk.Window (areaHeight - displayPixbuf.Height) / 2, displayPixbuf.Width, displayPixbuf.Height, RgbDither.Normal, 0, 0); + + if (checkButtonRobotPosition.Active) { + Cairo.Context cr = Gdk.CairoHelper.Create(area.GdkWindow); + Cairo.Color textFontColor = new Cairo.Color(0.8, 0, 0); + + cr.SelectFontFace("Cantarell", FontSlant.Normal, FontWeight.Bold); + cr.SetSourceColor(textFontColor); + cr.SetFontSize(16); + + double space = 0.0; + string text = "Direction (" + position.direction.x.ToString("0.##") + " ; " + position.direction.y.ToString("0.##") +")"; + TextExtents te = cr.TextExtents(text); + cr.MoveTo(areaWidth - te.Width-5, + areaHeight - te.Height -5); + space = te.Height; + cr.ShowText(text); + + text = "Centre (" + position.centre.x.ToString("0.##") + " ; " + position.centre.y.ToString("0.##") + ")"; + te = cr.TextExtents(text); + cr.MoveTo(areaWidth - te.Width - 5, + areaHeight - te.Height - 5 - space-5); + space = space+ te.Height+5; + cr.ShowText(text); + + text = "Angle: " + position.angle.ToString("0.##"); + te = cr.TextExtents(text); + cr.MoveTo(areaWidth - te.Width - 5, + areaHeight - te.Height - 5 - space - 5); + space = space+ te.Height+5; + cr.ShowText(text); + + text = "ID: " + position.robotID; + te = cr.TextExtents(text); + cr.MoveTo(areaWidth - te.Width - 5, + areaHeight - te.Height - 5 - space-5); + + cr.ShowText(text); + + ((IDisposable)cr.GetTarget()).Dispose(); + ((IDisposable)cr).Dispose(); + } } /// diff --git a/software/monitor/monitor/monitor b/software/monitor/monitor/monitor index d65f28ccb20963cd6bfb8e2953b14a070e75a2b9..fe4e2743dfa7e2b83d2925399e2192d89f31c66b 100755 GIT binary patch delta 24038 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 P%}4dymES7|oBaO|hC-zr delta 21098 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 Zr_re@?$Uo2a>49J?YoWtFm7xQ{Wldx0-yi@ diff --git a/software/raspberry/superviseur-robot/.dep.inc b/software/raspberry/superviseur-robot/.dep.inc deleted file mode 100644 index 38ba445..0000000 --- a/software/raspberry/superviseur-robot/.dep.inc +++ /dev/null @@ -1,5 +0,0 @@ -# This code depends on make tool being used -DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES} ${TESTOBJECTFILES})) -ifneq (${DEPFILES},) -include ${DEPFILES} -endif diff --git a/software/raspberry/superviseur-robot/.idea/.name b/software/raspberry/superviseur-robot/.idea/.name deleted file mode 100644 index 02eef87..0000000 --- a/software/raspberry/superviseur-robot/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -ProjDestijl \ No newline at end of file diff --git a/software/raspberry/superviseur-robot/.idea/codeStyles/Project.xml b/software/raspberry/superviseur-robot/.idea/codeStyles/Project.xml deleted file mode 100644 index 30aa626..0000000 --- a/software/raspberry/superviseur-robot/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/software/raspberry/superviseur-robot/.idea/misc.xml b/software/raspberry/superviseur-robot/.idea/misc.xml deleted file mode 100644 index 8822db8..0000000 --- a/software/raspberry/superviseur-robot/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/software/raspberry/superviseur-robot/.idea/modules.xml b/software/raspberry/superviseur-robot/.idea/modules.xml deleted file mode 100644 index 7a92ef3..0000000 --- a/software/raspberry/superviseur-robot/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/software/raspberry/superviseur-robot/.idea/superviseur-robot.iml b/software/raspberry/superviseur-robot/.idea/superviseur-robot.iml deleted file mode 100644 index f08604b..0000000 --- a/software/raspberry/superviseur-robot/.idea/superviseur-robot.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/software/raspberry/superviseur-robot/.idea/vcs.xml b/software/raspberry/superviseur-robot/.idea/vcs.xml deleted file mode 100644 index c2365ab..0000000 --- a/software/raspberry/superviseur-robot/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/software/raspberry/superviseur-robot/.idea/workspace.xml b/software/raspberry/superviseur-robot/.idea/workspace.xml deleted file mode 100644 index 2579f0f..0000000 --- a/software/raspberry/superviseur-robot/.idea/workspace.xml +++ /dev/null @@ -1,864 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - DEFINITION_ORDER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -