LCOV - code coverage report
Current view: top level - src/Kinematics - ObjectMoveHandler.cpp (source / functions) Hit Total Coverage
Test: HLR Lines: 101 101 100.0 %
Date: 2018-01-10 11:15:40 Functions: 12 12 100.0 %

          Line data    Source code
       1             : #include "ObjectMoveHandler.hpp"
       2             : 
       3             : #include <chrono>
       4             : #include <cstdint>
       5             : 
       6             : namespace HLR
       7             : {
       8             : namespace Kinematics
       9             : {
      10             : // also defined in ROS msg
      11             : const static uint8_t msg_ok = 0;
      12             : const static uint8_t msg_state = 1;
      13             : 
      14           2 : ObjectMoveHandler::ObjectMoveHandler()
      15             : {
      16             :     // bind topics and services
      17           2 :     progress_pub = nh.advertise<HLR::Progress>("move_progress", 1000);
      18           4 :     service_move_start = nh.advertiseService(
      19           2 :         "move_start", &ObjectMoveHandler::object_move_start, this);
      20           4 :     service_move_cancel = nh.advertiseService(
      21           2 :         "move_cancel", &ObjectMoveHandler::object_move_cancel, this);
      22           4 :     service_move_continue = nh.advertiseService(
      23           2 :         "move_continue", &ObjectMoveHandler::object_move_continue, this);
      24           4 :     service_move_stop = nh.advertiseService(
      25           2 :         "move_stop", &ObjectMoveHandler::object_move_stop, this);
      26             : 
      27             :     // spawn worker thread
      28           4 :     worker_thread = std::thread([this] { object_move_worker(); });
      29           2 : }
      30             : 
      31           5 : ObjectMoveHandler::~ObjectMoveHandler()
      32             : {
      33             :     // stop worker thread
      34           2 :     worker_state_m.lock();
      35           2 :     worker_state = State::exit;
      36           2 :     worker_state_m.unlock();
      37           2 :     queue_m.lock();
      38           2 :     cv.notify_all();
      39           2 :     queue_m.unlock();
      40           2 :     worker_thread.join();
      41           3 : }
      42             : 
      43           2 : void ObjectMoveHandler::object_move_worker()
      44             : {
      45             :     State state;
      46           2 :     const std::chrono::milliseconds sleep_for(200);
      47           4 :     std::unique_lock<std::mutex> cv_lock(queue_m, std::defer_lock);
      48             : 
      49             :     while (true)
      50             :     {
      51           5 :         worker_state_m.lock();
      52           5 :         worker_state = State::idle;
      53           5 :         worker_state_m.unlock();
      54             : 
      55             :         // wait for a cup to be queued or exit when requested
      56           5 :         cv_lock.lock();
      57          28 :         cv.wait(cv_lock, [this] {
      58          16 :             std::lock_guard<std::mutex> l(worker_state_m);
      59           8 :             if (worker_state == State::exit)
      60             :             {
      61           1 :                 return true;
      62             :             }
      63             : 
      64           7 :             return !queue.empty();
      65             :         });
      66           5 :         cv_lock.unlock();
      67             : 
      68             :         // exit when requested, reset state otherwise
      69           5 :         worker_state_m.lock();
      70           5 :         if (worker_state == State::exit)
      71             :         {
      72           1 :             worker_state_m.unlock();
      73           1 :             return;
      74             :         }
      75           4 :         worker_state = State::cont;
      76           4 :         worker_state_m.unlock();
      77             : 
      78             :         // pop the cup
      79           4 :         queue_m.lock();
      80           4 :         queue.pop();
      81           4 :         queue_m.unlock();
      82             : 
      83           4 :         progress.progress = 0;
      84           4 :         progress_pub.publish(progress);
      85             : 
      86          91 :         do
      87             :         {
      88             :             // exit when requested, handle external state changes
      89          95 :             worker_state_m.lock();
      90          95 :             if (worker_state == State::exit)
      91             :             {
      92           1 :                 worker_state_m.unlock();
      93           1 :                 return;
      94             :             }
      95          94 :             state = worker_state;
      96          94 :             worker_state_m.unlock();
      97             : 
      98          94 :             switch (state)
      99             :             {
     100          58 :                 case State::cont:
     101             :                     // ROS' internal type causes issues with Wconversion
     102             :                     // 0 <= progress <= 100 so this is safe
     103          58 :                     progress.progress =
     104          58 :                         static_cast<uint8_t>(progress.progress + 5);
     105          58 :                     progress_pub.publish(progress);
     106          58 :                     break;
     107             : 
     108           4 :                 case State::exit:
     109             :                 case State::idle:
     110             :                 case State::stop:
     111           4 :                     break;
     112             : 
     113          32 :                 case State::cancel:
     114             :                     // ROS' internal type causes issues with Wconversion
     115             :                     // 0 <= progress <= 100 so this is safe
     116          32 :                     progress.progress =
     117          32 :                         static_cast<uint8_t>(progress.progress - 5);
     118          32 :                     progress_pub.publish(progress);
     119          32 :                     break;
     120             :             }
     121             : 
     122             :             // simulate the arm actually moving by sleeping a bit
     123             :             // also prevents async service/topic handling bugs during tests
     124          94 :             std::this_thread::sleep_for(sleep_for);
     125          94 :         } while (progress.progress < 100
     126          94 :                  && !(state == State::cancel && progress.progress == 0));
     127           3 :     }
     128             : }
     129             : 
     130           4 : bool ObjectMoveHandler::object_move_start(HLR::ObjectMove::Request& req,
     131             :                                           HLR::ObjectMove::Response& res)
     132             : {
     133           4 :     queue_m.lock();
     134           4 :     queue.emplace(req.request);
     135           4 :     cv.notify_one();
     136           4 :     queue_m.unlock();
     137             : 
     138           4 :     res.response = msg_ok;
     139           4 :     return true;
     140             : }
     141             : 
     142           7 : bool ObjectMoveHandler::object_move_cancel(
     143             :     HLR::ObjectMove::Request& req[[maybe_unused]],
     144             :     HLR::ObjectMove::Response& res)
     145             : {
     146          14 :     std::lock_guard<std::mutex> l(worker_state_m);
     147             : 
     148           7 :     if (worker_state != State::stop)
     149             :     {
     150           5 :         res.response = msg_state;
     151           5 :         return false;
     152             :     }
     153           2 :     worker_state = State::cancel;
     154             : 
     155           2 :     res.response = msg_ok;
     156           2 :     return true;
     157             : }
     158             : 
     159           7 : bool ObjectMoveHandler::object_move_continue(
     160             :     HLR::ObjectMove::Request& req[[maybe_unused]],
     161             :     HLR::ObjectMove::Response& res)
     162             : {
     163          14 :     std::lock_guard<std::mutex> l(worker_state_m);
     164             : 
     165           7 :     if (worker_state != State::stop)
     166             :     {
     167           5 :         res.response = msg_state;
     168           5 :         return false;
     169             :     }
     170           2 :     worker_state = State::cont;
     171             : 
     172           2 :     res.response = msg_ok;
     173           2 :     return true;
     174             : }
     175             : 
     176           9 : bool ObjectMoveHandler::object_move_stop(
     177             :     HLR::ObjectMove::Request& req[[maybe_unused]],
     178             :     HLR::ObjectMove::Response& res)
     179             : {
     180          18 :     std::lock_guard<std::mutex> l(worker_state_m);
     181             : 
     182           9 :     if (worker_state != State::cont)
     183             :     {
     184           5 :         res.response = msg_state;
     185           5 :         return false;
     186             :     }
     187           4 :     worker_state = State::stop;
     188             : 
     189           4 :     res.response = msg_ok;
     190           4 :     return true;
     191             : }
     192             : 
     193             : } // namespace Kinematics
     194           3 : } // namespace HLR

Generated by: LCOV version 1.12