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.

tasks.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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 "tasks.h"
  18. #include <stdexcept>
  19. // Déclaration des priorités des taches
  20. #define PRIORITY_TSERVER 30
  21. #define PRIORITY_TOPENCOMROBOT 20
  22. #define PRIORITY_TMOVE 20
  23. #define PRIORITY_TSENDTOMON 22
  24. #define PRIORITY_TRECEIVEFROMMON 25
  25. #define PRIORITY_TSTARTROBOT 20
  26. #define PRIORITY_TCAMERA 21
  27. /*
  28. * Some remarks:
  29. * 1- This program is mostly a template. It shows you how to create tasks, semaphore
  30. * message queues, mutex ... and how to use them
  31. *
  32. * 2- semDumber is, as name say, useless. Its goal is only to show you how to use semaphore
  33. *
  34. * 3- Data flow is probably not optimal
  35. *
  36. * 4- Take into account that ComRobot::Write will block your task when serial buffer is full,
  37. * time for internal buffer to flush
  38. *
  39. * 5- Same behavior existe for ComMonitor::Write !
  40. *
  41. * 6- When you want to write something in terminal, use cout and terminate with endl and flush
  42. *
  43. * 7- Good luck !
  44. */
  45. /**
  46. * @brief Initialisation des structures de l'application (tâches, mutex,
  47. * semaphore, etc.)
  48. */
  49. void Tasks::Init() {
  50. int status;
  51. int err;
  52. /**************************************************************************************/
  53. /* Mutex creation */
  54. /**************************************************************************************/
  55. if (err = rt_mutex_create(&mutex_monitor, NULL)) {
  56. cerr << "Error mutex create: " << strerror(-err) << endl << flush;
  57. exit(EXIT_FAILURE);
  58. }
  59. if (err = rt_mutex_create(&mutex_robot, NULL)) {
  60. cerr << "Error mutex create: " << strerror(-err) << endl << flush;
  61. exit(EXIT_FAILURE);
  62. }
  63. if (err = rt_mutex_create(&mutex_robotStarted, NULL)) {
  64. cerr << "Error mutex create: " << strerror(-err) << endl << flush;
  65. exit(EXIT_FAILURE);
  66. }
  67. if (err = rt_mutex_create(&mutex_move, NULL)) {
  68. cerr << "Error mutex create: " << strerror(-err) << endl << flush;
  69. exit(EXIT_FAILURE);
  70. }
  71. cout << "Mutexes created successfully" << endl << flush;
  72. /**************************************************************************************/
  73. /* Semaphors creation */
  74. /**************************************************************************************/
  75. if (err = rt_sem_create(&sem_barrier, NULL, 0, S_FIFO)) {
  76. cerr << "Error semaphore create: " << strerror(-err) << endl << flush;
  77. exit(EXIT_FAILURE);
  78. }
  79. if (err = rt_sem_create(&sem_openComRobot, NULL, 0, S_FIFO)) {
  80. cerr << "Error semaphore create: " << strerror(-err) << endl << flush;
  81. exit(EXIT_FAILURE);
  82. }
  83. if (err = rt_sem_create(&sem_serverOk, NULL, 0, S_FIFO)) {
  84. cerr << "Error semaphore create: " << strerror(-err) << endl << flush;
  85. exit(EXIT_FAILURE);
  86. }
  87. if (err = rt_sem_create(&sem_startRobot, NULL, 0, S_FIFO)) {
  88. cerr << "Error semaphore create: " << strerror(-err) << endl << flush;
  89. exit(EXIT_FAILURE);
  90. }
  91. cout << "Semaphores created successfully" << endl << flush;
  92. /**************************************************************************************/
  93. /* Tasks creation */
  94. /**************************************************************************************/
  95. if (err = rt_task_create(&th_server, "th_server", 0, PRIORITY_TSERVER, 0)) {
  96. cerr << "Error task create: " << strerror(-err) << endl << flush;
  97. exit(EXIT_FAILURE);
  98. }
  99. if (err = rt_task_create(&th_sendToMon, "th_sendToMon", 0, PRIORITY_TSENDTOMON, 0)) {
  100. cerr << "Error task create: " << strerror(-err) << endl << flush;
  101. exit(EXIT_FAILURE);
  102. }
  103. if (err = rt_task_create(&th_receiveFromMon, "th_receiveFromMon", 0, PRIORITY_TRECEIVEFROMMON, 0)) {
  104. cerr << "Error task create: " << strerror(-err) << endl << flush;
  105. exit(EXIT_FAILURE);
  106. }
  107. if (err = rt_task_create(&th_openComRobot, "th_openComRobot", 0, PRIORITY_TOPENCOMROBOT, 0)) {
  108. cerr << "Error task create: " << strerror(-err) << endl << flush;
  109. exit(EXIT_FAILURE);
  110. }
  111. if (err = rt_task_create(&th_startRobot, "th_startRobot", 0, PRIORITY_TSTARTROBOT, 0)) {
  112. cerr << "Error task create: " << strerror(-err) << endl << flush;
  113. exit(EXIT_FAILURE);
  114. }
  115. if (err = rt_task_create(&th_move, "th_move", 0, PRIORITY_TMOVE, 0)) {
  116. cerr << "Error task create: " << strerror(-err) << endl << flush;
  117. exit(EXIT_FAILURE);
  118. }
  119. cout << "Tasks created successfully" << endl << flush;
  120. /**************************************************************************************/
  121. /* Message queues creation */
  122. /**************************************************************************************/
  123. if ((err = rt_queue_create(&q_messageToMon, "q_messageToMon", sizeof (Message*)*50, Q_UNLIMITED, Q_FIFO)) < 0) {
  124. cerr << "Error msg queue create: " << strerror(-err) << endl << flush;
  125. exit(EXIT_FAILURE);
  126. }
  127. cout << "Queues created successfully" << endl << flush;
  128. }
  129. /**
  130. * @brief Démarrage des tâches
  131. */
  132. void Tasks::Run() {
  133. rt_task_set_priority(NULL, T_LOPRIO);
  134. int err;
  135. if (err = rt_task_start(&th_server, (void(*)(void*)) & Tasks::ServerTask, this)) {
  136. cerr << "Error task start: " << strerror(-err) << endl << flush;
  137. exit(EXIT_FAILURE);
  138. }
  139. /**/if (err = rt_task_start(&th_sendToMon, (void(*)(void*)) & Tasks::SendToMonTask, this)) {
  140. cerr << "Error task start: " << strerror(-err) << endl << flush;
  141. exit(EXIT_FAILURE);
  142. }/**/
  143. /**/if (err = rt_task_start(&th_receiveFromMon, (void(*)(void*)) & Tasks::ReceiveFromMonTask, this)) {
  144. cerr << "Error task start: " << strerror(-err) << endl << flush;
  145. exit(EXIT_FAILURE);
  146. }/**/
  147. /**/if (err = rt_task_start(&th_openComRobot, (void(*)(void*)) & Tasks::OpenComRobot, this)) {
  148. cerr << "Error task start: " << strerror(-err) << endl << flush;
  149. exit(EXIT_FAILURE);
  150. }/**/
  151. if (err = rt_task_start(&th_startRobot, (void(*)(void*)) & Tasks::StartRobotTask, this)) {
  152. cerr << "Error task start: " << strerror(-err) << endl << flush;
  153. exit(EXIT_FAILURE);
  154. }
  155. if (err = rt_task_start(&th_move, (void(*)(void*)) & Tasks::MoveTask, this)) {
  156. cerr << "Error task start: " << strerror(-err) << endl << flush;
  157. exit(EXIT_FAILURE);
  158. }
  159. cout << "Tasks launched" << endl << flush;
  160. }
  161. /**
  162. * @brief Arrêt des tâches
  163. */
  164. void Tasks::Stop() {
  165. monitor.Close();
  166. robot.Close();
  167. }
  168. /**
  169. */
  170. void Tasks::Join() {
  171. cout << "Tasks synchronized" << endl << flush;
  172. rt_sem_broadcast(&sem_barrier);
  173. pause();
  174. }
  175. /**
  176. * @brief Thread handling server communication with the monitor.
  177. */
  178. void Tasks::ServerTask(void *arg) {
  179. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  180. // Synchronization barrier (waiting that all tasks are started)
  181. rt_sem_p(&sem_barrier, TM_INFINITE);
  182. rt_mutex_acquire(&mutex_monitor, TM_INFINITE);
  183. int status = monitor.Open(SERVER_PORT);
  184. rt_mutex_release(&mutex_monitor);
  185. cout << "Open server on port " << (SERVER_PORT) << " (" << status << ")" << endl;
  186. if (status < 0) throw std::runtime_error {
  187. "Unable to start server on port " + std::to_string(SERVER_PORT)
  188. };
  189. monitor.AcceptClient(); // Wait the monitor client
  190. cout << "Rock'n'Roll baby, client accepted!" << endl << flush;
  191. rt_sem_broadcast(&sem_serverOk);
  192. }
  193. /**
  194. * @brief Thread sending data to monitor.
  195. */
  196. void Tasks::SendToMonTask(void* arg) {
  197. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  198. // Synchronization barrier (waiting that all tasks are starting)
  199. rt_sem_p(&sem_barrier, TM_INFINITE);
  200. rt_sem_p(&sem_serverOk, TM_INFINITE);
  201. while (1) {
  202. cout << "wait msg to send" << endl << flush;
  203. Message *msg = ReadInQueue(&q_messageToMon);
  204. cout << "Send msg to mon: " << msg->ToString() << endl << flush;
  205. rt_mutex_acquire(&mutex_monitor, TM_INFINITE);
  206. monitor.Write(msg);
  207. rt_mutex_release(&mutex_monitor);
  208. }
  209. }
  210. /**
  211. * @brief Thread receiving data from monitor.
  212. */
  213. void Tasks::ReceiveFromMonTask(void *arg) {
  214. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  215. // Synchronization barrier (waiting that all tasks are starting)
  216. rt_sem_p(&sem_barrier, TM_INFINITE);
  217. rt_sem_p(&sem_serverOk, TM_INFINITE);
  218. cout << "Received message from monitor activated" << endl << flush;
  219. while (1) {
  220. Message *msgRcv;
  221. msgRcv = monitor.Read();
  222. cout << "Rcv <= " << msgRcv->ToString() << endl << flush;
  223. if (msgRcv->CompareID(MESSAGE_MONITOR_LOST)) {
  224. delete(msgRcv);
  225. exit(-1);
  226. } else if (msgRcv->CompareID(MESSAGE_ROBOT_COM_OPEN)) {
  227. rt_sem_v(&sem_openComRobot);
  228. } else if (msgRcv->CompareID(MESSAGE_ROBOT_START_WITHOUT_WD)) {
  229. rt_sem_v(&sem_startRobot);
  230. } else if (msgRcv->CompareID(MESSAGE_ROBOT_GO_FORWARD) ||
  231. msgRcv->CompareID(MESSAGE_ROBOT_GO_BACKWARD) ||
  232. msgRcv->CompareID(MESSAGE_ROBOT_GO_LEFT) ||
  233. msgRcv->CompareID(MESSAGE_ROBOT_GO_RIGHT) ||
  234. msgRcv->CompareID(MESSAGE_ROBOT_STOP)) {
  235. rt_mutex_acquire(&mutex_move, TM_INFINITE);
  236. move = msgRcv->GetID();
  237. rt_mutex_release(&mutex_move);
  238. }
  239. delete msgRcv; // mus be deleted manually, no consumer
  240. }
  241. }
  242. /**
  243. * @brief Thread opening communication with the robot.
  244. */
  245. void Tasks::OpenComRobot(void *arg) {
  246. int status;
  247. int err;
  248. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  249. // Synchronization barrier (waiting that all tasks are starting)
  250. rt_sem_p(&sem_barrier, TM_INFINITE);
  251. while (1) {
  252. rt_sem_p(&sem_openComRobot, TM_INFINITE);
  253. cout << "Open serial com (";
  254. rt_mutex_acquire(&mutex_robot, TM_INFINITE);
  255. status = robot.Open();
  256. rt_mutex_release(&mutex_robot);
  257. cout << status;
  258. cout << ")" << endl << flush;
  259. Message * msgSend;
  260. if (status < 0) {
  261. msgSend = new Message(MESSAGE_ANSWER_NACK);
  262. } else {
  263. msgSend = new Message(MESSAGE_ANSWER_ACK);
  264. }
  265. WriteInQueue(&q_messageToMon, msgSend);
  266. }
  267. }
  268. /**
  269. * @brief Thread starting the communication with the robot.
  270. */
  271. void Tasks::StartRobotTask(void *arg) {
  272. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  273. // Synchronization barrier (waiting that all tasks are starting)
  274. rt_sem_p(&sem_barrier, TM_INFINITE);
  275. while (1) {
  276. Message * msgSend;
  277. rt_sem_p(&sem_startRobot, TM_INFINITE);
  278. cout << "Start robot without watchdog (";
  279. rt_mutex_acquire(&mutex_robot, TM_INFINITE);
  280. msgSend = robot.Write(robot.StartWithoutWD());
  281. rt_mutex_release(&mutex_robot);
  282. cout << msgSend->GetID();
  283. cout << ")" << endl;
  284. cout << "Movement answer: " << msgSend->ToString() << endl << flush;
  285. WriteInQueue(&q_messageToMon, msgSend);
  286. if (msgSend->GetID() == MESSAGE_ANSWER_ACK) {
  287. rt_mutex_acquire(&mutex_robotStarted, TM_INFINITE);
  288. robotStarted = 1;
  289. rt_mutex_release(&mutex_robotStarted);
  290. }
  291. }
  292. }
  293. /**
  294. * @brief Thread handling control of the robot.
  295. */
  296. void Tasks::MoveTask(void *arg) {
  297. int rs;
  298. int cpMove;
  299. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  300. // Synchronization barrier (waiting that all tasks are starting)
  301. rt_sem_p(&sem_barrier, TM_INFINITE);
  302. rt_task_set_periodic(NULL, TM_NOW, 1000000000);
  303. while (1) {
  304. rt_task_wait_period(NULL);
  305. cout << "Periodic movement update";
  306. rt_mutex_acquire(&mutex_robotStarted, TM_INFINITE);
  307. rs = robotStarted;
  308. rt_mutex_release(&mutex_robotStarted);
  309. if (rs == 1) {
  310. rt_mutex_acquire(&mutex_move, TM_INFINITE);
  311. cpMove = move;
  312. rt_mutex_release(&mutex_move);
  313. cout << " move: " << cpMove;
  314. rt_mutex_acquire(&mutex_robot, TM_INFINITE);
  315. robot.Write(new Message((MessageID)cpMove));
  316. rt_mutex_release(&mutex_robot);
  317. }
  318. cout << endl << flush;
  319. }
  320. }
  321. /**
  322. * Write a message in a given queue
  323. * @param queue Queue identifier
  324. * @param msg Message to be stored
  325. */
  326. void Tasks::WriteInQueue(RT_QUEUE *queue, Message *msg) {
  327. int err;
  328. if ((err = rt_queue_write(queue, (const void *) &msg, sizeof ((const void *) &msg), Q_NORMAL)) < 0) {
  329. cerr << "Write in queue failed: " << strerror(-err) << endl << flush;
  330. throw std::runtime_error{"Error in write in queue"};
  331. }
  332. }
  333. /**
  334. * Read a message from a given queue, block if empty
  335. * @param queue Queue identifier
  336. * @return Message read
  337. */
  338. Message *Tasks::ReadInQueue(RT_QUEUE *queue) {
  339. int err;
  340. Message *msg;
  341. if ((err = rt_queue_read(queue, &msg, sizeof ((void*) &msg), TM_INFINITE)) < 0) {
  342. cout << "Read in queue failed: " << strerror(-err) << endl << flush;
  343. throw std::runtime_error{"Error in read in queue"};
  344. }/** else {
  345. cout << "@msg :" << msg << endl << flush;
  346. } /**/
  347. return msg;
  348. }