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 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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. int status;
  180. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  181. // Synchronization barrier (waiting that all tasks are started)
  182. rt_sem_p(&sem_barrier, TM_INFINITE);
  183. /**************************************************************************************/
  184. /* The task server starts here */
  185. /**************************************************************************************/
  186. rt_mutex_acquire(&mutex_monitor, TM_INFINITE);
  187. status = monitor.Open(SERVER_PORT);
  188. rt_mutex_release(&mutex_monitor);
  189. cout << "Open server on port " << (SERVER_PORT) << " (" << status << ")" << endl;
  190. if (status < 0) throw std::runtime_error {
  191. "Unable to start server on port " + std::to_string(SERVER_PORT)
  192. };
  193. monitor.AcceptClient(); // Wait the monitor client
  194. cout << "Rock'n'Roll baby, client accepted!" << endl << flush;
  195. rt_sem_broadcast(&sem_serverOk);
  196. }
  197. /**
  198. * @brief Thread sending data to monitor.
  199. */
  200. void Tasks::SendToMonTask(void* arg) {
  201. Message *msg;
  202. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  203. // Synchronization barrier (waiting that all tasks are starting)
  204. rt_sem_p(&sem_barrier, TM_INFINITE);
  205. /**************************************************************************************/
  206. /* The task sendToMon starts here */
  207. /**************************************************************************************/
  208. rt_sem_p(&sem_serverOk, TM_INFINITE);
  209. while (1) {
  210. cout << "wait msg to send" << endl << flush;
  211. msg = ReadInQueue(&q_messageToMon);
  212. cout << "Send msg to mon: " << msg->ToString() << endl << flush;
  213. rt_mutex_acquire(&mutex_monitor, TM_INFINITE);
  214. monitor.Write(msg); // The message is deleted with the Write
  215. rt_mutex_release(&mutex_monitor);
  216. }
  217. }
  218. /**
  219. * @brief Thread receiving data from monitor.
  220. */
  221. void Tasks::ReceiveFromMonTask(void *arg) {
  222. Message *msgRcv;
  223. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  224. // Synchronization barrier (waiting that all tasks are starting)
  225. rt_sem_p(&sem_barrier, TM_INFINITE);
  226. /**************************************************************************************/
  227. /* The task receiveFromMon starts here */
  228. /**************************************************************************************/
  229. rt_sem_p(&sem_serverOk, TM_INFINITE);
  230. cout << "Received message from monitor activated" << endl << flush;
  231. while (1) {
  232. msgRcv = monitor.Read();
  233. cout << "Rcv <= " << msgRcv->ToString() << endl << flush;
  234. if (msgRcv->CompareID(MESSAGE_MONITOR_LOST)) {
  235. delete(msgRcv);
  236. exit(-1);
  237. } else if (msgRcv->CompareID(MESSAGE_ROBOT_COM_OPEN)) {
  238. rt_sem_v(&sem_openComRobot);
  239. } else if (msgRcv->CompareID(MESSAGE_ROBOT_START_WITHOUT_WD)) {
  240. rt_sem_v(&sem_startRobot);
  241. } else if (msgRcv->CompareID(MESSAGE_ROBOT_GO_FORWARD) ||
  242. msgRcv->CompareID(MESSAGE_ROBOT_GO_BACKWARD) ||
  243. msgRcv->CompareID(MESSAGE_ROBOT_GO_LEFT) ||
  244. msgRcv->CompareID(MESSAGE_ROBOT_GO_RIGHT) ||
  245. msgRcv->CompareID(MESSAGE_ROBOT_STOP)) {
  246. rt_mutex_acquire(&mutex_move, TM_INFINITE);
  247. move = msgRcv->GetID();
  248. rt_mutex_release(&mutex_move);
  249. }
  250. delete(msgRcv); // mus be deleted manually, no consumer
  251. }
  252. }
  253. /**
  254. * @brief Thread opening communication with the robot.
  255. */
  256. void Tasks::OpenComRobot(void *arg) {
  257. int status;
  258. int err;
  259. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  260. // Synchronization barrier (waiting that all tasks are starting)
  261. rt_sem_p(&sem_barrier, TM_INFINITE);
  262. /**************************************************************************************/
  263. /* The task openComRobot starts here */
  264. /**************************************************************************************/
  265. while (1) {
  266. rt_sem_p(&sem_openComRobot, TM_INFINITE);
  267. cout << "Open serial com (";
  268. rt_mutex_acquire(&mutex_robot, TM_INFINITE);
  269. status = robot.Open();
  270. rt_mutex_release(&mutex_robot);
  271. cout << status;
  272. cout << ")" << endl << flush;
  273. Message * msgSend;
  274. if (status < 0) {
  275. msgSend = new Message(MESSAGE_ANSWER_NACK);
  276. } else {
  277. msgSend = new Message(MESSAGE_ANSWER_ACK);
  278. }
  279. WriteInQueue(&q_messageToMon, msgSend); // msgSend will be deleted by sendToMon
  280. }
  281. }
  282. /**
  283. * @brief Thread starting the communication with the robot.
  284. */
  285. void Tasks::StartRobotTask(void *arg) {
  286. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  287. // Synchronization barrier (waiting that all tasks are starting)
  288. rt_sem_p(&sem_barrier, TM_INFINITE);
  289. /**************************************************************************************/
  290. /* The task startRobot starts here */
  291. /**************************************************************************************/
  292. while (1) {
  293. Message * msgSend;
  294. rt_sem_p(&sem_startRobot, TM_INFINITE);
  295. cout << "Start robot without watchdog (";
  296. rt_mutex_acquire(&mutex_robot, TM_INFINITE);
  297. msgSend = robot.Write(robot.StartWithoutWD());
  298. rt_mutex_release(&mutex_robot);
  299. cout << msgSend->GetID();
  300. cout << ")" << endl;
  301. cout << "Movement answer: " << msgSend->ToString() << endl << flush;
  302. WriteInQueue(&q_messageToMon, msgSend); // msgSend will be deleted by sendToMon
  303. if (msgSend->GetID() == MESSAGE_ANSWER_ACK) {
  304. rt_mutex_acquire(&mutex_robotStarted, TM_INFINITE);
  305. robotStarted = 1;
  306. rt_mutex_release(&mutex_robotStarted);
  307. }
  308. }
  309. }
  310. /**
  311. * @brief Thread handling control of the robot.
  312. */
  313. void Tasks::MoveTask(void *arg) {
  314. int rs;
  315. int cpMove;
  316. cout << "Start " << __PRETTY_FUNCTION__ << endl << flush;
  317. // Synchronization barrier (waiting that all tasks are starting)
  318. rt_sem_p(&sem_barrier, TM_INFINITE);
  319. /**************************************************************************************/
  320. /* The task starts here */
  321. /**************************************************************************************/
  322. rt_task_set_periodic(NULL, TM_NOW, 100000000);
  323. while (1) {
  324. rt_task_wait_period(NULL);
  325. cout << "Periodic movement update";
  326. rt_mutex_acquire(&mutex_robotStarted, TM_INFINITE);
  327. rs = robotStarted;
  328. rt_mutex_release(&mutex_robotStarted);
  329. if (rs == 1) {
  330. rt_mutex_acquire(&mutex_move, TM_INFINITE);
  331. cpMove = move;
  332. rt_mutex_release(&mutex_move);
  333. cout << " move: " << cpMove;
  334. rt_mutex_acquire(&mutex_robot, TM_INFINITE);
  335. robot.Write(new Message((MessageID)cpMove));
  336. rt_mutex_release(&mutex_robot);
  337. }
  338. cout << endl << flush;
  339. }
  340. }
  341. /**
  342. * Write a message in a given queue
  343. * @param queue Queue identifier
  344. * @param msg Message to be stored
  345. */
  346. void Tasks::WriteInQueue(RT_QUEUE *queue, Message *msg) {
  347. int err;
  348. if ((err = rt_queue_write(queue, (const void *) &msg, sizeof ((const void *) &msg), Q_NORMAL)) < 0) {
  349. cerr << "Write in queue failed: " << strerror(-err) << endl << flush;
  350. throw std::runtime_error{"Error in write in queue"};
  351. }
  352. }
  353. /**
  354. * Read a message from a given queue, block if empty
  355. * @param queue Queue identifier
  356. * @return Message read
  357. */
  358. Message *Tasks::ReadInQueue(RT_QUEUE *queue) {
  359. int err;
  360. Message *msg;
  361. if ((err = rt_queue_read(queue, &msg, sizeof ((void*) &msg), TM_INFINITE)) < 0) {
  362. cout << "Read in queue failed: " << strerror(-err) << endl << flush;
  363. throw std::runtime_error{"Error in read in queue"};
  364. }/** else {
  365. cout << "@msg :" << msg << endl << flush;
  366. } /**/
  367. return msg;
  368. }