diff --git a/.vscode/settings.json b/.vscode/settings.json
index fa393981b857a5dbcae6300ee78bf8cd29a623cb..b3baa6327cc1535e08f7028de062bb24db44cb80 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -115,7 +115,8 @@
                 "polynomials": "cpp",
                 "autodiff": "cpp",
                 "sparseextra": "cpp",
-                "specialfunctions": "cpp"
+                "specialfunctions": "cpp",
+                "csetjmp": "cpp"
         },
         "cSpell.words": [
                 "abom",
diff --git a/src/shared/events/FSM.h b/src/shared/events/FSM.h
index 35a3626beabe70990d4d6978b1e096c6a55ddc28..8a9887476a419316e54baba0b73d74b172811bec 100644
--- a/src/shared/events/FSM.h
+++ b/src/shared/events/FSM.h
@@ -23,9 +23,13 @@
 #pragma once
 
 #include <events/Event.h>
+#include <events/EventBroker.h>
 #include <events/EventHandler.h>
 #include <utils/collections/SyncQueue.h>
 
+#include <chrono>
+#include <csetjmp>
+
 #include "ActiveObject.h"
 
 namespace Boardcore
@@ -51,12 +55,18 @@ public:
     bool testState(void (T::*testState)(const Event&));
 
 protected:
+    void run() override;
     void handleEvent(const Event& e) override;
 
+    void waitEvent(Event events);
+    void waitFor(std::chrono::milliseconds time);
+
 private:
     void (T::*state)(const Event&);
     Event specialEvent;
 
+    std::jmp_buf runLoop;
+
 protected:
     // Async continuation support
     uint16_t asyncDelayedEventId;
@@ -84,6 +94,9 @@ void FSM<T>::transition(void (T::*nextState)(const Event&))
     state        = nextState;
     specialEvent = EV_ENTRY;
     (static_cast<T*>(this)->*state)(specialEvent);
+
+    // TODO: explain
+    longjmp(runLoop, 1);
 }
 
 template <class T>
@@ -92,12 +105,47 @@ bool FSM<T>::testState(void (T::*testState)(const Event&))
     return (this->state == testState);
 }
 
+template <class T>
+void FSM<T>::run()
+{
+    // TODO: explain
+    setjmp(runLoop);
+
+    while (!shouldStop())
+    {
+        Event e = eventList.get();
+        handleEvent(e);
+    }
+}
+
 template <class T>
 void FSM<T>::handleEvent(const Event& e)
 {
     (static_cast<T*>(this)->*state)(e);
 }
 
+template <class T>
+void FSM<T>::waitEvent(Event event)
+{
+    while (!shouldStop())
+    {
+        Event e = eventList.get();
+
+        if (e == event)
+            // The event we were waiting for has arrived
+            return;
+
+        handleEvent(e);
+    }
+}
+
+template <class T>
+void FSM<T>::waitFor(std::chrono::milliseconds time)
+{
+    EventBroker::getInstance().postDelayed(EV_ASYNC_CONTINUE, 0, time.count());
+    waitEvent(EV_ASYNC_CONTINUE);
+}
+
 /**
  * @brief Asynchronous continuation support.
  *