No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

commonitor.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * Copyright (C) 2018 dimercur
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "commonitor.h"
  18. #include <iostream>
  19. #include <sys/socket.h>
  20. #include <netdb.h>
  21. #include <unistd.h>
  22. #include <arpa/inet.h>
  23. #include <netinet/in.h>
  24. #include <algorithm>
  25. #include <stdexcept>
  26. #include <string>
  27. /*
  28. * @brief Constants used for sending commands to monitor
  29. */
  30. const string LABEL_MONITOR_ANSWER_ACK = "AACK";
  31. const string LABEL_MONITOR_ANSWER_NACK = "ANAK";
  32. const string LABEL_MONITOR_ANSWER_LOST_DMB= "ATIM";
  33. const string LABEL_MONITOR_ANSWER_TIMEOUT= "ATIM";
  34. const string LABEL_MONITOR_ANSWER_CMD_REJECTED= "ACRJ";
  35. const string LABEL_MONITOR_MESSAGE = "MSSG";
  36. const string LABEL_MONITOR_CAMERA_OPEN= "COPN";
  37. const string LABEL_MONITOR_CAMERA_CLOSE= "CCLS";
  38. const string LABEL_MONITOR_CAMERA_IMAGE = "CIMG";
  39. const string LABEL_MONITOR_CAMERA_ARENA_ASK = "CASA";
  40. const string LABEL_MONITOR_CAMERA_ARENA_INFIRME = "CAIN";
  41. const string LABEL_MONITOR_CAMERA_ARENA_CONFIRM = "CACO";
  42. const string LABEL_MONITOR_CAMERA_POSITION_COMPUTE= "CPCO";
  43. const string LABEL_MONITOR_CAMERA_POSITION_STOP= "CPST";
  44. const string LABEL_MONITOR_CAMERA_POSITION = "CPOS";
  45. const string LABEL_MONITOR_ROBOT_COM_OPEN = "ROPN";
  46. const string LABEL_MONITOR_ROBOT_COM_CLOSE = "RCLS";
  47. const string LABEL_MONITOR_ROBOT_PING = "RPIN";
  48. const string LABEL_MONITOR_ROBOT_RESET = "RRST";
  49. const string LABEL_MONITOR_ROBOT_START_WITHOUT_WD= "RSOW";
  50. const string LABEL_MONITOR_ROBOT_START_WITH_WD= "RSWW";
  51. const string LABEL_MONITOR_ROBOT_RELOAD_WD = "RLDW";
  52. const string LABEL_MONITOR_ROBOT_MOVE = "RMOV";
  53. const string LABEL_MONITOR_ROBOT_TURN = "RTRN";
  54. const string LABEL_MONITOR_ROBOT_GO_FORWARD = "RGFW";
  55. const string LABEL_MONITOR_ROBOT_GO_BACKWARD = "RGBW";
  56. const string LABEL_MONITOR_ROBOT_GO_LEFT = "RGLF";
  57. const string LABEL_MONITOR_ROBOT_GO_RIGHT = "RGRI";
  58. const string LABEL_MONITOR_ROBOT_STOP = "RSTP";
  59. const string LABEL_MONITOR_ROBOT_POWEROFF = "RPOF";
  60. const string LABEL_MONITOR_ROBOT_BATTERY_LEVEL = "RBLV";
  61. const string LABEL_MONITOR_ROBOT_GET_BATTERY = "RGBT";
  62. const string LABEL_MONITOR_ROBOT_GET_STATE = "RGST";
  63. const string LABEL_MONITOR_ROBOT_CURRENT_STATE = "RCST";
  64. const string LABEL_SEPARATOR_CHAR = ":";
  65. /**
  66. * Create a server and open a socket over TCP
  67. *
  68. * @param port Port used for communication
  69. * @return Socket number
  70. * @throw std::runtime_error if it fails
  71. */
  72. int ComMonitor::Open(int port) {
  73. struct sockaddr_in server;
  74. socketFD = socket(AF_INET, SOCK_STREAM, 0);
  75. if (socketFD < 0) {
  76. throw std::runtime_error{"ComMonitor::Open : Can not create socket"};
  77. }
  78. server.sin_addr.s_addr = INADDR_ANY;
  79. server.sin_family = AF_INET;
  80. server.sin_port = htons(port);
  81. if (bind(socketFD, (struct sockaddr *) &server, sizeof (server)) < 0) {
  82. throw std::runtime_error{"ComMonitor::Open : Can not bind socket on port " + std::to_string(port)};
  83. }
  84. listen(socketFD, 1);
  85. return socketFD;
  86. }
  87. /**
  88. * Close socket and server
  89. */
  90. void ComMonitor::Close() {
  91. close(socketFD);
  92. socketFD = -1;
  93. }
  94. /**
  95. * Wait for a client to connect
  96. * @return Client number
  97. * @throw std::runtime_error if it fails
  98. */
  99. int ComMonitor::AcceptClient() {
  100. struct sockaddr_in client;
  101. int c = sizeof (struct sockaddr_in);
  102. clientID = accept(socketFD, (struct sockaddr *) &client, (socklen_t*) & c);
  103. if (clientID < 0)
  104. throw std::runtime_error {
  105. "ComMonitor::AcceptClient : Accept failed"
  106. };
  107. return clientID;
  108. }
  109. /**
  110. * Send a message to monitor
  111. *
  112. * @param msg Message to send to monitor
  113. * @attention Message given in parameter will be destroyed (delete) after being sent. No need for user to delete message after that.
  114. * @warning Write is not thread safe : check that multiple tasks can't access this method simultaneously
  115. */
  116. void ComMonitor::Write(Message &msg) {
  117. string str;
  118. // Call user method before Write
  119. Write_Pre();
  120. /* Convert message to string to send to monitor */
  121. str = MessageToString(msg);
  122. //cout << "Message sent to monitor: " << str->c_str() << endl;
  123. write(clientID, str.c_str(), str.length());
  124. delete(&msg);
  125. // Call user method after write
  126. Write_Post();
  127. }
  128. /**
  129. * Receive a message from monitor
  130. *
  131. * @return Message received from monitor
  132. * @attention Message provided is produced by the method. You must delete it when you are done using it
  133. * @warning Read is not thread safe : check that multiple tasks can't access this method simultaneously
  134. */
  135. Message *ComMonitor::Read() {
  136. char length = 0;
  137. string s;
  138. char data;
  139. bool endReception=false;
  140. Message *msg;
  141. // Call user method before read
  142. Read_Pre();
  143. if (clientID > 0) {
  144. while (!endReception) {
  145. if ((length = recv(clientID, (void*) &data, 1, MSG_WAITALL)) > 0) {
  146. if (data != '\n') {
  147. s+=data;
  148. } else endReception = true;
  149. }
  150. }
  151. if (length<=0) msg = new Message(MESSAGE_MONITOR_LOST);
  152. else {
  153. msg=StringToMessage(s);
  154. }
  155. }
  156. // Call user method after read
  157. Read_Post();
  158. return msg;
  159. }
  160. /**
  161. * Method used internally to convert a message content to a string that can be sent over TCP
  162. * @param msg Message to be converted
  163. * @return A string, image of the message
  164. */
  165. string ComMonitor::MessageToString(Message &msg) {
  166. int id;
  167. string str;
  168. Message *localMsg = &msg;
  169. Position pos;
  170. id = msg.GetID();
  171. switch (id) {
  172. case MESSAGE_ANSWER:
  173. switch (((MessageAnswer*)localMsg)->GetAnswer()) {
  174. case ANSWER_ACK:
  175. str.append(LABEL_MONITOR_ANSWER_ACK);
  176. break;
  177. case ANSWER_NACK:
  178. str.append(LABEL_MONITOR_ANSWER_NACK);
  179. break;
  180. case ANSWER_LOST_ROBOT:
  181. str.append(LABEL_MONITOR_ANSWER_LOST_DMB);
  182. break;
  183. case ANSWER_ROBOT_TIMEOUT:
  184. str.append(LABEL_MONITOR_ANSWER_TIMEOUT);
  185. break;
  186. case ANSWER_ROBOT_UNKNOWN_COMMAND:
  187. str.append(LABEL_MONITOR_ANSWER_CMD_REJECTED);
  188. break;
  189. case ANSWER_ROBOT_ERROR:
  190. str.append(LABEL_MONITOR_ANSWER_CMD_REJECTED);
  191. break;
  192. default:
  193. str.append(LABEL_MONITOR_ANSWER_NACK);
  194. };
  195. break;
  196. case MESSAGE_POSITION:
  197. pos = ((MessagePosition*)&msg)->GetPosition();
  198. str.append(LABEL_MONITOR_CAMERA_POSITION + LABEL_SEPARATOR_CHAR + to_string(pos.robotId) + ";" +
  199. to_string(pos.angle) + ";" + to_string(pos.center.x) + ";" + to_string(pos.center.y) + ";" +
  200. to_string(pos.direction.x) + ";" + to_string(pos.direction.y));
  201. break;
  202. case MESSAGE_IMAGE:
  203. str.append(LABEL_MONITOR_CAMERA_IMAGE + LABEL_SEPARATOR_CHAR + ((MessageImg*) &msg)->GetImage()->ToBase64());
  204. break;
  205. case MESSAGE_ROBOT_BATTERY_LEVEL:
  206. str.append(LABEL_MONITOR_ROBOT_BATTERY_LEVEL + LABEL_SEPARATOR_CHAR + to_string(((MessageBattery*) &msg)->GetLevel()));
  207. break;
  208. case MESSAGE_ROBOT_CURRENT_STATE:
  209. str.append(LABEL_MONITOR_ROBOT_CURRENT_STATE + LABEL_SEPARATOR_CHAR + to_string(((MessageState*) &msg)->GetState()));
  210. break;
  211. case MESSAGE_LOG:
  212. str.append(LABEL_MONITOR_MESSAGE + LABEL_SEPARATOR_CHAR + ((MessageString*) &msg)->GetString());
  213. break;
  214. case MESSAGE_EMPTY:
  215. str.append(""); //empty string
  216. break;
  217. default:
  218. throw std::runtime_error
  219. {
  220. "ComMonitor::MessageToString (from ComMonitor::Write): Invalid message to send (" + msg.ToString()
  221. };
  222. }
  223. str.append("\n");
  224. return str;
  225. }
  226. /**
  227. * Method used internally to convert a string received over TCP to a message
  228. * @param s String containing message
  229. * @return A message, image of the string
  230. */
  231. Message *ComMonitor::StringToMessage(string &s) {
  232. Message *msg;
  233. size_t pos;
  234. string org =s;
  235. string tokenCmd;
  236. string tokenData;
  237. /* Separate command from data if string contains a ':' */
  238. if ((pos=org.find(LABEL_SEPARATOR_CHAR)) != string::npos) {
  239. tokenCmd = org.substr(0,pos);
  240. org.erase(0,pos+1);
  241. tokenData=org;
  242. } else tokenCmd=org;
  243. /* Convert command to message */
  244. if (tokenCmd.find(LABEL_MONITOR_ROBOT_MOVE)!= string::npos) {
  245. msg = new MessageInt(MESSAGE_ROBOT_MOVE,stoi(tokenData));
  246. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_TURN)!= string::npos) {
  247. msg = new MessageInt(MESSAGE_ROBOT_TURN,stoi(tokenData));
  248. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_START_WITHOUT_WD)!= string::npos) {
  249. msg = new Message(MESSAGE_ROBOT_START_WITHOUT_WD);
  250. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_START_WITH_WD)!= string::npos) {
  251. msg = new Message(MESSAGE_ROBOT_START_WITH_WD);
  252. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_RELOAD_WD)!= string::npos) {
  253. msg = new Message(MESSAGE_ROBOT_RELOAD_WD);
  254. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_PING)!= string::npos) {
  255. msg = new Message(MESSAGE_ROBOT_PING);
  256. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_RESET)!= string::npos) {
  257. msg = new Message(MESSAGE_ROBOT_RESET);
  258. } else if (tokenCmd.find(LABEL_MONITOR_CAMERA_ARENA_ASK)!= string::npos) {
  259. msg = new Message(MESSAGE_ASK_ARENA);
  260. } else if (tokenCmd.find(LABEL_MONITOR_CAMERA_ARENA_CONFIRM)!= string::npos) {
  261. msg = new Message(MESSAGE_ARENA_CONFIRM);
  262. } else if (tokenCmd.find(LABEL_MONITOR_CAMERA_ARENA_INFIRME)!= string::npos) {
  263. msg = new Message(MESSAGE_ARENA_INFIRM);
  264. } else if (tokenCmd.find(LABEL_MONITOR_CAMERA_CLOSE)!= string::npos) {
  265. msg = new Message(MESSAGE_CAM_CLOSE);
  266. } else if (tokenCmd.find(LABEL_MONITOR_CAMERA_OPEN)!= string::npos) {
  267. msg = new Message(MESSAGE_CAM_OPEN);
  268. } else if (tokenCmd.find(LABEL_MONITOR_CAMERA_POSITION_COMPUTE)!= string::npos) {
  269. msg = new Message(MESSAGE_COMPUTE_POSITION);
  270. } else if (tokenCmd.find(LABEL_MONITOR_CAMERA_POSITION_STOP)!= string::npos) {
  271. msg = new Message(MESSAGE_STOP_COMPUTE_POSITION);
  272. } else if (tokenCmd.find(LABEL_MONITOR_MESSAGE)!= string::npos) {
  273. msg = new MessageString(MESSAGE_LOG,tokenData);
  274. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_COM_CLOSE)!= string::npos) {
  275. msg = new Message(MESSAGE_CLOSE_COM);
  276. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_COM_OPEN)!= string::npos) {
  277. msg = new Message(MESSAGE_OPEN_COM);
  278. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_GET_BATTERY)!= string::npos) {
  279. msg = new Message(MESSAGE_ROBOT_GET_BATTERY);
  280. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_GET_STATE)!= string::npos) {
  281. msg = new Message(MESSAGE_ROBOT_GET_STATE);
  282. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_GO_FORWARD)!= string::npos) {
  283. msg = new Message(MESSAGE_ROBOT_GO_FORWARD);
  284. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_GO_BACKWARD)!= string::npos) {
  285. msg = new Message(MESSAGE_ROBOT_GO_BACK);
  286. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_GO_LEFT)!= string::npos) {
  287. msg = new Message(MESSAGE_ROBOT_GO_LEFT);
  288. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_GO_RIGHT)!= string::npos) {
  289. msg = new Message(MESSAGE_ROBOT_GO_RIGHT);
  290. } else if (tokenCmd.find(LABEL_MONITOR_ROBOT_POWEROFF)!= string::npos) {
  291. msg = new Message(MESSAGE_ROBOT_POWEROFF);
  292. } else {
  293. msg = new Message(MESSAGE_EMPTY);
  294. }
  295. return msg;
  296. }