/* * Copyright (C) 2018 dimercur * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "comgui.h" #include #include #include #include #include #include #include #include #include /* * Constants used for sending commands to gui */ const string LABEL_GUI_ANGULAR_POSITION = "AngularPosition"; const string LABEL_GUI_ANGULAR_SPEED = "AngularSpeed"; const string LABEL_GUI_BATTERY_LEVEL = "Battery"; const string LABEL_GUI_LINEAR_SPEED = "LinearSpeed"; const string LABEL_GUI_USER_PRESENCE = "User"; const string LABEL_GUI_BETA_ANGLE = "Beta"; const string LABEL_GUI_TORQUE = "Torque"; const string LABEL_GUI_EMERGENCY_STOP = "Emergency"; const string LABEL_GUI_LOG = "Log"; /** * Create a server and open a socket over TCP * * @param port Port used for communication * @return Socket number * @throw std::runtime_error if it fails */ int ComGui::Open(int port) { struct sockaddr_in server; socketFD = socket(AF_INET, SOCK_STREAM, 0); if (socketFD < 0) { throw std::runtime_error{"ComGui::Open : Can not create socket"}; } server.sin_addr.s_addr = INADDR_ANY; server.sin_family = AF_INET; server.sin_port = htons(port); if (bind(socketFD, (struct sockaddr *) &server, sizeof (server)) < 0) { throw std::runtime_error{"ComGui::Open : Can not bind socket on port " + std::to_string(port)}; } listen(socketFD, 1); return socketFD; } /** * Close socket and server */ void ComGui::Close() { close(socketFD); socketFD = -1; } /** * Wait for a client to connect * @return Client number * @throw std::runtime_error if it fails */ int ComGui::AcceptClient() { struct sockaddr_in client; int c = sizeof (struct sockaddr_in); clientID = accept(socketFD, (struct sockaddr *) &client, (socklen_t*) & c); if (clientID < 0) throw std::runtime_error { "ComGui::AcceptClient : Accept failed" }; return clientID; } /** * Send a message to GUI * * @param msg Message to send to GUI * @attention Message given in parameter will be destroyed (delete) after being sent. No need for user to delete message after that. * @warning Write is not thread safe : check that multiple tasks can't access this method simultaneously */ void ComGui::Write(Message* msg) { string *str; // Call user method before Write Write_Pre(); /* Convert message to string to send to GUI */ str = MessageToString(msg); //cout << "Message sent to GUI: " << str->c_str() << endl; write(clientID, str->c_str(), str->length()); delete(str); // Call user method after write Write_Post(); } /** * Method used internally to convert a message content to a string that can be sent over TCP * @param msg Message to be converted * @return A string, image of the message */ string *ComGui::MessageToString(Message *msg) { int id; string *str; if (msg != NULL) { id = msg->GetID(); switch (id) { case MESSAGE_ANGLE_POSITION: str = new string(LABEL_GUI_ANGULAR_POSITION + "=" + to_string(((MessageFloat*) msg)->GetValue()) + "\n"); replace(str->begin(), str->end(), '.', ','); // Mono C# require float to have a , instead of a . break; case MESSAGE_ANGULAR_SPEED: str = new string(LABEL_GUI_ANGULAR_SPEED + "=" + to_string(((MessageFloat*) msg)->GetValue()) + "\n"); replace(str->begin(), str->end(), '.', ','); // Mono C# require float to have a , instead of a . break; case MESSAGE_BATTERY: str = new string(LABEL_GUI_BATTERY_LEVEL + "=" + to_string(((MessageFloat*) msg)->GetValue()) + "\n"); replace(str->begin(), str->end(), '.', ','); // Mono C# require float to have a , instead of a . break; case MESSAGE_BETA: str = new string(LABEL_GUI_BETA_ANGLE + "=" + to_string(((MessageFloat*) msg)->GetValue()) + "\n"); replace(str->begin(), str->end(), '.', ','); // Mono C# require float to have a , instead of a . break; case MESSAGE_LINEAR_SPEED: str = new string(LABEL_GUI_LINEAR_SPEED + "=" + to_string(((MessageFloat*) msg)->GetValue()) + "\n"); replace(str->begin(), str->end(), '.', ','); // Mono C# require float to have a , instead of a . break; case MESSAGE_TORQUE: str = new string(LABEL_GUI_TORQUE + "=" + to_string(((MessageFloat*) msg)->GetValue()) + "\n"); replace(str->begin(), str->end(), '.', ','); // Mono C# require float to have a , instead of a . break; case MESSAGE_EMERGENCY_STOP: str = new string(LABEL_GUI_EMERGENCY_STOP + "="); if (((MessageBool*) msg)->GetState()) str->append("True\n"); else str->append("False\n"); break; case MESSAGE_USER_PRESENCE: str = new string(LABEL_GUI_USER_PRESENCE + "="); if (((MessageBool*) msg)->GetState()) str->append("True\n"); else str->append("False\n"); break; case MESSAGE_EMPTY: str = new string(""); //empty string break; case MESSAGE_LOG: str = new string(LABEL_GUI_LOG + "=" + ((MessageString*) msg)->GetString() + "\n"); break; default: str = new string(""); //empty string break; } } return str; }