From 85f92ab4a9f8c45406364e80732977e4ad4695e3 Mon Sep 17 00:00:00 2001
From: Fabian Reister <fabian.reister@kit.edu>
Date: Fri, 7 Jan 2022 11:43:50 +0100
Subject: [PATCH] waitforstop with timeout

---
 source/armarx/navigation/client/Navigator.cpp | 51 +++++++++++++++++--
 source/armarx/navigation/client/Navigator.h   |  2 +-
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/source/armarx/navigation/client/Navigator.cpp b/source/armarx/navigation/client/Navigator.cpp
index 9780c8c0..6054d098 100644
--- a/source/armarx/navigation/client/Navigator.cpp
+++ b/source/armarx/navigation/client/Navigator.cpp
@@ -1,8 +1,12 @@
 #include "Navigator.h"
 
 #include <algorithm>
+#include <chrono>
+#include <future>
 
+#include "ArmarXCore/core/exceptions/LocalException.h"
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+#include <ArmarXCore/core/logging/Logging.h>
 #include <ArmarXCore/util/CPPUtility/trace.h>
 
 #include <armarx/navigation/client/PathBuilder.h>
@@ -114,14 +118,55 @@ namespace armarx::navigation::client
 
 
     StopEvent
-    Navigator::waitForStop()
+    Navigator::waitForStop(const std::int64_t timeoutMs)
     {
         ARMARX_TRACE;
-        std::unique_lock l{stoppedInfo.m};
-        stoppedInfo.cv.wait(l, [&i = stoppedInfo] { return i.event.has_value(); });
+
+        std::future<void> future = std::async(
+            std::launch::async,
+            [&]()
+            {
+                std::unique_lock l{stoppedInfo.m};
+                stoppedInfo.cv.wait(l, [&i = stoppedInfo] { return i.event.has_value(); });
+            });
+
+
+        if (timeoutMs > 0)
+        {
+            ARMARX_INFO << "future.wait()";
+            auto status = future.wait_for(std::chrono::milliseconds(timeoutMs));
+            ARMARX_INFO << "done";
+
+            switch (status)
+            {
+                case std::future_status::ready:
+                    ARMARX_INFO << "waitForStop: terminated on goal reached";
+                    break;
+                case std::future_status::timeout:
+                    ARMARX_INFO << "waitForStop: terminated due to timeout";
+                    ARMARX_INFO << "Stopping robot due to timeout";
+                    stop();
+
+                    throw LocalException("Navigator::waitForStop: timeout");
+                    break;
+                case std::future_status::deferred:
+                    ARMARX_INFO << "waitForStop: deferred";
+                    break;
+            }
+        }
+        else
+        {
+            ARMARX_INFO << "future.wait()";
+            future.wait();
+            ARMARX_INFO << "done";
+        }
+
+        // only due to timeout, stoppedInfo.event should be nullopt
+        ARMARX_CHECK(stoppedInfo.event.has_value());
 
         StopEvent e = stoppedInfo.event.value();
         stoppedInfo.event.reset();
+
         return e;
     }
 
diff --git a/source/armarx/navigation/client/Navigator.h b/source/armarx/navigation/client/Navigator.h
index 77547742..836ebffb 100644
--- a/source/armarx/navigation/client/Navigator.h
+++ b/source/armarx/navigation/client/Navigator.h
@@ -143,7 +143,7 @@ namespace armarx::navigation::client
 
         void onWaypointReached(const std::function<void(int)>& callback);
 
-        StopEvent waitForStop();
+        StopEvent waitForStop(std::int64_t timeoutMs = -1);
 
     protected:
     private:
-- 
GitLab