tsm  0.1.0
tsm_impl.h
Go to the documentation of this file.
1 #pragma once
2 #include <functional>
3 #include <tuple>
4 #include <type_traits>
5 #include <utility>
6 #include <variant>
7 
8 #ifdef __FREE_RTOS__
9 #include "FreeRTOS.h"
10 #include "semphr.h"
11 #include "task.h"
12 #else
13 #include <condition_variable>
14 #include <mutex>
15 #include <thread>
16 #endif // __FREE_RTOS__
17 
18 #ifdef __linux__
19 #include <sched.h>
20 #include <sys/mman.h>
21 #include <time.h>
22 #endif
23 namespace tsm {
24 
25 // Apply a wrapper to a tuple of types
26 template<template<class> class Wrapper, typename Tuple>
28 
29 template<template<class> class Wrapper, typename... Ts>
30 struct wrap_type_impl<Wrapper, std::tuple<Ts...>> {
31  using type = std::tuple<typename Wrapper<Ts>::type...>;
32 };
33 
34 template<template<class> class Wrapper, typename Tuple>
36 
37 // Append unique type to a tuple
38 template<typename T, typename Tuple>
40 
41 template<typename T>
42 struct append_unique_impl<T, std::tuple<>> {
43  using type = std::tuple<T>;
44 };
45 
46 template<typename T, typename... Ts>
47 struct append_unique_impl<T, std::tuple<Ts...>> {
48  // Add T to the tuple if it is not found among Ts..., otherwise, leave as
49  // is.
50  using type = std::conditional_t<!(std::is_same_v<T, Ts> || ...),
51  std::tuple<Ts..., T>,
52  std::tuple<Ts...>>;
53 };
54 
55 template<typename T, typename Tuple>
57 
58 // Remove duplicates from a tuple
59 // Base case for empty tuple, just provides a type 'type' equal to Us
60 template<typename Ts, typename Us>
62 
63 // Recursive case: tries to append T to Us if it's not already there and
64 // recurses with rest of Ts
65 template<typename... Us>
66 struct unique_tuple_impl<std::tuple<>, std::tuple<Us...>> {
67  using type = std::tuple<Us...>;
68 };
69 
70 // Recursive case: tries to append T to Us if it's not already there and
71 // recurses with rest of Ts
72 template<typename T, typename... Ts, typename... Us>
73 struct unique_tuple_impl<std::tuple<T, Ts...>, std::tuple<Us...>> {
74  using type =
75  typename unique_tuple_impl<std::tuple<Ts...>,
76  append_unique<T, std::tuple<Us...>>>::type;
77 };
78 
79 // Public interface, defaults to starting with an empty unique set (Us)
80 template<typename Ts, typename Us = std::tuple<>>
81 struct unique_tuple {
83 };
84 
85 template<typename Ts>
87 
88 // Rename tuple to variant
89 template<typename Tuple>
91 
92 template<typename... Ts>
93 struct tuple_to_variant_impl<std::tuple<Ts...>> {
94  using type = std::variant<Ts...>;
95 };
96 
97 // Pull out the Ts... from a tuple and create a std::
98 template<typename Tuple>
100 
101 // Event
102 struct Event {};
103 
104 template<typename T>
106  using type = T;
107 };
108 
109 // Transition
110 // Dummy action and guard - hopefully, these will be optimized away
111 
112 template<typename From, typename Event, typename To>
114  using from = From;
115  using event = Event;
116  using to = To;
117 };
118 
119 template<typename From,
120  typename Event,
121  typename To,
122  typename Action = void (*)(),
123  typename Guard = bool (*)()>
125  using action = Action;
126  using guard = Guard;
127  Action action_{}; // for lambdas
128  Guard guard_{};
129 };
130 
132  int ticks_;
133 };
134 
135 template<typename From,
136  typename To,
137  typename Guard = bool (*)(void),
138  typename Action = void (*)(void)>
141 
142 // get_states from TransitionTable
143 template<typename Tuple, typename... Ts>
145 
146 // Base case: No more transitions to process, just return the accumulated
147 // states.
148 template<typename Tuple>
149 struct get_states_impl<Tuple> {
150  using type = Tuple;
151 };
152 
153 // Recursive case: Process the first Transition, then recurse on the rest.
154 template<typename Tuple, typename First, typename... Rest>
155 struct get_states_impl<Tuple, First, Rest...> {
156  // Accumulate 'from' state
158  // Accumulate 'to' state
160 
161  // Recurse with the updated tuple and the remaining transitions
162  using type = typename get_states_impl<to_states, Rest...>::type;
163 };
164 
165 template<typename... Ts>
166 struct get_states;
167 
168 template<typename... Ts>
169 struct get_states<std::tuple<Ts...>> {
170  using type = typename get_states_impl<std::tuple<>, Ts...>::type;
171 };
172 
173 template<typename... Ts>
174 using get_states_t = typename get_states<Ts...>::type;
175 
176 // TransitionMap
177 
178 // Forward declaration for transition_map_helper with a default index parameter
179 // starting from 0
180 template<typename From,
181  typename Event,
182  typename TransitionsTuple,
183  size_t Index = 0,
184  typename = void>
186 
187 // Helper trait to check if a transition matches 'From' and 'Event'
188 template<typename Transition, typename From, typename Event>
189 struct is_transition_match : std::false_type {};
190 
191 template<typename From,
192  typename Event,
193  typename To,
194  typename Action,
195  typename Guard>
196 struct is_transition_match<Transition<From, Event, To, Action, Guard>,
197  From,
198  Event> : std::true_type {};
199 
200 // Iteration through the transitions
201 template<typename From, typename Event, typename... Transitions, size_t Index>
203  From,
204  Event,
205  std::tuple<Transitions...>,
206  Index,
207  std::enable_if_t<(Index < sizeof...(Transitions))>> {
209  std::tuple_element_t<Index, std::tuple<Transitions...>>;
210  static constexpr bool match =
212 
213  using type = typename std::conditional_t<
214  match,
216  typename transition_map_helper<From,
217  Event,
218  std::tuple<Transitions...>,
219  Index + 1>::type>;
220 };
221 
222 // Base case: Reached the end of the tuple without finding a match
223 template<typename From, typename Event, typename... Transitions, size_t Index>
225  From,
226  Event,
227  std::tuple<Transitions...>,
228  Index,
229  std::enable_if_t<!(Index < sizeof...(Transitions))>> {
230  using type = void; // Return void if no transition matches
231 };
232 
233 // Wrapper to start the search
234 template<typename From, typename Event, typename Transitions>
237 };
238 
239 // find transition
240 template<typename From, typename Event, typename Transitions>
243 
244 // variable template to check for the existence of a valid transition
245 template<typename State, typename Event, typename Transitions>
246 inline constexpr bool has_valid_transition_v =
247  !std::is_same_v<typename TransitionMap<State, Event, Transitions>::type,
248  void>;
249 
250 // SFINAE test for exit method
251 template<typename T, typename Event, typename = void>
252 struct has_exit : std::false_type {};
253 
254 template<typename T, typename Event>
255 struct has_exit<T,
256  Event,
257  std::void_t<std::disjunction<
258  std::is_invocable<decltype(&T::exit), T>,
259  std::is_invocable<decltype(&T::exit), T, T&>,
260  std::is_invocable<decltype(&T::exit), T, Event>>>>
261  : std::true_type {};
262 
263 template<typename T, typename Event>
264 inline constexpr bool has_exit_v = has_exit<T, Event>::value;
265 
266 // SFINAE test for entry method
267 template<typename T, typename Event, typename = void>
268 struct has_entry : std::false_type {};
269 
270 template<typename T, typename Event>
271 struct has_entry<T,
272  Event,
273  std::void_t<std::disjunction<
274  std::is_invocable<decltype(&T::entry), T>,
275  std::is_invocable<decltype(&T::entry), T&>,
276  std::is_invocable<decltype(&T::entry), T, Event>>>>
277  : std::true_type {};
278 
279 template<typename T, typename Event>
280 inline constexpr bool has_entry_v = has_entry<T, Event>::value;
281 
282 // SFINAE test for guard method
283 template<typename T, typename Event, typename = void>
284 struct has_guard : std::false_type {};
285 
286 template<typename T, typename Event>
287 struct has_guard<T,
288  Event,
289  std::void_t<std::disjunction<
290  std::is_invocable<decltype(&T::guard), T>,
291  std::is_invocable<decltype(&T::guard), T&>,
292  std::is_invocable<decltype(&T::guard), T, Event>>>>
293  : std::true_type {};
294 
295 template<typename T, typename Event>
296 inline constexpr bool has_guard_v = has_guard<T, Event>::value;
297 
298 // SFINAE test for action method
299 template<typename T, typename Event, typename = void>
300 struct has_action : std::false_type {};
301 
302 template<typename T, typename Event>
303 struct has_action<T,
304  Event,
305  std::void_t<std::disjunction<
306  std::is_invocable<decltype(&T::action), T>,
307  std::is_invocable<decltype(&T::action), T&>,
308  std::is_invocable<decltype(&T::action), T, Event>>>>
309  : std::true_type {};
310 
311 template<typename T, typename Event>
313 
314 // Trait to check for the presence of T::transitions
315 template<typename, typename = std::void_t<>>
316 struct has_transitions : std::false_type {};
317 
318 template<typename T>
319 struct has_transitions<T, std::void_t<typename T::transitions>>
320  : std::true_type {};
321 
322 template<typename T>
324 
325 template<typename T>
327 
328 // Define a trait to check for the presence of State::handle method for a given
329 // Event and Context
330 template<typename State,
331  typename Event,
332  typename Context,
333  typename = std::void_t<>>
334 struct has_handle_method : std::false_type {};
335 
336 template<typename State, typename Event, typename Context>
338  State,
339  Event,
340  Context,
341  std::void_t<decltype(std::declval<State>().handle(std::declval<Context&>(),
342  std::declval<Event>()))>>
343  : std::true_type {};
344 
345 // Helper variable template
346 template<typename State, typename Event, typename Context>
347 inline constexpr bool has_handle_method_v =
349 
350 // Trait to check for the presence of T::is_hsm
351 template<typename, typename = std::void_t<>>
352 struct is_hsm_trait : std::false_type {};
353 
354 template<typename T>
355 struct is_hsm_trait<T, std::void_t<decltype(T::is_hsm)>> : std::true_type {};
356 
357 template<typename T>
359 
360 template<typename T>
361 inline constexpr bool is_hsm_trait_v = is_hsm_trait<T>::value;
362 
363 // Define a helper to check for 'from' and 'to' types in transitions,
364 template<typename T>
365 inline constexpr bool is_state_trait_v =
366  std::conjunction_v<has_transitions<T>, std::negation<is_hsm_trait<T>>>;
367 
368 template<typename T, typename = void>
369 struct is_clocked_hsm : std::false_type {};
370 
371 template<typename T>
372 struct is_clocked_hsm<T, std::void_t<decltype(T::is_clocked_hsm)>>
373  : std::true_type {};
374 
375 template<typename T>
377 
378 // Hsm
379 template<typename T, typename transitions = typename T::transitions>
380 struct Hsm : T {
381  static constexpr bool is_hsm = true;
383  using HsmType = type; // alias for policy classes
384  using initial_state = typename std::tuple_element_t<0, transitions>::from;
386 
387  Hsm()
388  : current_state_(&std::get<initial_state>(states_)) {}
389 
390  // for rvalue reference and copy
391  template<typename Event>
392  bool handle(Event&& e) {
393  // using Event = std::decay_t<Evt>;
394  // Event e = std::forward<Evt>(event);
395  return std::visit(
396  [this, &e](auto* state) {
397  using State = std::decay_t<decltype(*state)>;
398  // check Event is same as decayed e
399  bool handled = false;
400  // if current_state is a state machine, call handle on it
401  if constexpr (is_hsm_trait_t<State>::value) {
402  handled = state->handle(std::forward<Event>(e));
403  }
404  if (!handled) {
405  // Does State implement handle for Event?
406  if constexpr (has_valid_transition_v<State,
407  std::decay_t<Event>,
408  transitions>) {
409  using transition = find_transition_t<State,
410  std::decay_t<Event>,
411  transitions>;
412  this->handle_transition<transition>(
413  state, static_cast<Event&&>(e));
414  handled = true;
415  }
416  }
417  return handled;
418  },
420  }
421 
422  template<typename Event, typename State>
423  void entry(Event&& e, State* state) noexcept {
424  if constexpr (has_entry_v<State, Event>) {
425  if constexpr (std::is_invocable_v<decltype(&State::entry),
426  State*,
427  T&,
428  decltype(e)>) {
429  state->entry(static_cast<T&>(*this), std::forward<Event>(e));
430  } else if constexpr (std::is_invocable_v<decltype(&State::entry),
431  State*,
432  T&>) {
433  state->entry(static_cast<T&>(*this));
434  } else if constexpr (std::is_invocable_v<decltype(&State::entry),
435  State*>) {
436  state->entry();
437  }
438  }
439  }
440 
441  template<typename Event, typename State>
442  void exit(Event&& e, State* state) noexcept {
443  if constexpr (has_exit_v<State, Event>) {
444  if constexpr (std::is_invocable_v<decltype(&State::exit),
445  State*,
446  T&,
447  decltype(e)>) {
448  state->exit(static_cast<T&>(*this), std::forward<Event>(e));
449  } else if constexpr (std::is_invocable_v<decltype(&State::exit),
450  State*,
451  T&>) {
452  state->exit(static_cast<T&>(*this));
453  } else if constexpr (std::is_invocable_v<decltype(&State::exit),
454  State*>) {
455  state->exit();
456  }
457  }
458  }
459  // Check Guard
460  template<typename Tn,
461  typename Event = typename Tn::event,
462  typename State = typename Tn::from>
463  bool check_guard(Event&& e, State* state) {
464  if constexpr (has_guard_v<State, Event>) {
465  if constexpr (std::is_invocable_v<decltype(&State::guard),
466  State*,
467  T&,
468  decltype(e)>) {
469  return state->guard(static_cast<T&>(*this),
470  std::forward<Event>(e));
471  } else if constexpr (std::is_invocable_v<decltype(&State::guard),
472  State*,
473  T&>) {
474  return state->guard(static_cast<T&>(*this));
475  } else if constexpr (std::is_invocable_v<decltype(&State::guard),
476  State*>) {
477  return state->guard();
478  }
479  }
480  return true;
481  }
482 
483  // Perform action
484  template<typename Tn,
485  typename Event = typename Tn::event,
486  typename State = typename Tn::from>
487  void perform_action(Event&& e, State* state) {
488  if constexpr (has_action_v<State, Event>) {
489  if constexpr (std::is_invocable_v<decltype(&State::action),
490  State*,
491  T&,
492  decltype(e)>) {
493  state->action(static_cast<T&>(*this), std::forward<Event>(e));
494  } else if constexpr (std::is_invocable_v<decltype(&State::action),
495  State*,
496  T&>) {
497  state->action(static_cast<T&>(*this));
498  } else if constexpr (std::is_invocable_v<decltype(&State::action),
499  State*>) {
500  state->action();
501  }
502  }
503  }
504 
505  template<typename transition,
506  typename State = typename transition::from,
507  typename Event = typename transition::event>
508  std::enable_if_t<!has_handle_method_v<State, Event, T>, void>
509  handle_transition(typename transition::from* state, Event&& e) {
510  // Assume TransitionMap provides the matching transition
511  if (!this->check_guard<transition>(std::forward<Event>(e), state)) {
512  return;
513  }
514 
515  this->template exit<Event, State>(std::forward<Event>(e), state);
516 
517  // Optional Action
518  this->perform_action<transition>(std::forward<Event>(e), state);
519 
520  using to = typename transition::to;
521 
522  // switch to the new state
523  current_state_ = &std::get<to>(states_);
524 
525  this->template entry<Event, to>(std::forward<Event>(e),
526  *std::get_if<to*>(&current_state_));
527  }
528 
529  template<typename transition,
530  typename State = typename transition::from,
531  typename Event = typename transition::event>
532  std::enable_if_t<has_handle_method_v<State, Event, T>, void>
533  handle_transition(State* state, Event&& e) {
534 
535  // A true gives permission to transition
536  if (!state->handle(static_cast<T&>(*this), std::forward<Event>(e))) {
537  return;
538  }
539 
540  using to = typename transition::to;
541 
542  // switch to the new state
543  current_state_ = &std::get<to>(states_);
544 
545  this->template entry<Event, to>(std::forward<Event>(e),
546  *std::get_if<to*>(&current_state_));
547  }
548 
549  template<typename State>
550  void current_state() {
551  current_state_ = &std::get<State>(states_);
552  }
553 
555  transitions transitions_;
557 };
558 
559 template<typename T, typename = void>
560 struct make_hsm;
561 
562 template<typename T>
563 struct make_hsm<T, std::enable_if_t<!is_state_trait_v<T>>> {
564  using type = T;
565 };
566 
567 template<typename T>
568 using make_hsm_t = typename make_hsm<T>::type;
569 
570 // Recursively wrap states in HSMs if they are state traits
571 template<typename T>
573  using from = typename T::from;
574  using event = typename T::event;
575  using to = typename T::to;
576  using action = typename T::action;
577  using guard = typename T::guard;
578 
579  using wrap_from =
580  std::conditional_t<is_state_trait_v<from>, make_hsm_t<from>, from>;
581  using wrap_to =
582  std::conditional_t<is_state_trait_v<to>, make_hsm_t<to>, to>;
583 
585 };
586 
587 template<typename T>
589 
590 template<typename... Ts>
592 
593 template<typename... Ts>
594 struct wrap_transitions<std::tuple<Ts...>> {
595  using type = std::tuple<wrap_transition_t<Ts>...>;
596 };
597 
598 template<typename... Ts>
599 using wrap_transitions_t = typename wrap_transitions<Ts...>::type;
600 
601 // Clocked HSM - react to events after a certain time period
602 // This is a wrapper around HSM that adds a tick method to the HSM
603 template<typename T, template<typename> class Policy = make_hsm_t>
604 struct ClockedHsm : Policy<T> {
606  using HsmType = typename Policy<T>::type;
607 
608  constexpr static bool is_clocked_hsm = true;
609 
610  bool tick() { return this->handle(tick_event_); }
611 
612  template<typename Event>
613  bool handle(Event e = Event()) {
614  return HsmType::handle(e);
615  }
616 
619  return HsmType::handle(e);
620  }
622 };
623 
624 // Define the wrapper for state traits to convert them into HSMs including their
625 // transitions
626 template<typename T>
627 struct make_hsm<T, std::enable_if_t<is_state_trait_v<T>>> {
628  // shadow the transitions with the wrapped transitions
630 
632 };
633 
634 // Orthogonal HSM
635 template<typename... Hsms>
637  static constexpr bool is_hsm = true;
638  using type = OrthogonalExecutionPolicy<Hsms...>;
639 
640  template<typename Event>
641  void entry(Event e = Event()) {
642  std::apply([e](auto&... hsm) { (hsm.entry(e), ...); }, hsms_);
643  }
644 
645  template<typename Event>
646  void exit(Event e = Event()) {
647  std::apply([e](auto&... hsm) { (hsm.exit(e), ...); }, hsms_);
648  }
649 
650  template<typename Event>
651  bool handle(Event e = Event()) {
652  return std::apply([e](auto&... hsm) { return (hsm.handle(e) && ...); },
653  hsms_);
654  }
655 
656  std::tuple<Hsms...> hsms_;
657 };
658 
659 // A thread safe event queue. Any thread can call add_event if it has a pointer
660 // to the event queue. The call to nextEvent is a blocking call
661 template<typename Event, typename LockType, typename ConditionVarType>
662 struct EventQueueT {
663  using EventType = Event;
664 
665  virtual ~EventQueueT() { stop(); }
666 
667  public:
668  // Block until you get an event
670  std::unique_lock<LockType> lock(eventQueueMutex_);
671  cvEventAvailable_.wait(
672  lock, [this] { return (!this->empty() || this->interrupt_); });
673  if (interrupt_) {
674  return Event();
675  }
676  const Event e = std::move(front());
677  pop_front();
678  return e;
679  }
680 
681  void add_event(Event&& e) {
682  if (interrupt_) {
683  return;
684  }
685  std::lock_guard<LockType> lock(eventQueueMutex_);
686  push_back(std::forward<Event>(e));
687  cvEventAvailable_.notify_all();
688  }
689 
690  void stop() {
691  interrupt_ = true;
692  cvEventAvailable_.notify_all();
693  // Log the events that are going to get dumped if the queue is not
694  // empty
695  }
696 
697  bool interrupted() { return interrupt_; }
698 
699  protected:
700  bool empty() { return push_index_ == pop_index_; }
701 
702  Event const& front() { return data_[pop_index_]; }
703 
704  void pop_front() {
705  if (!empty()) {
706  pop_index_ = (pop_index_ + 1) % data_.size();
707  }
708  }
709 
710  bool push_back(Event const& e) {
711  if ((push_index_ + 1) % data_.size() != pop_index_) {
712  data_[push_index_] = e;
713  push_index_ = (push_index_ + 1) % data_.size();
714  return true;
715  }
716  return false;
717  }
718 
719  private:
720  LockType eventQueueMutex_;
721  ConditionVarType cvEventAvailable_;
722  bool interrupt_{};
723  size_t push_index_{ 0 };
724  size_t pop_index_{ 0 };
725  std::array<Event, 50> data_;
726 };
727 
728 #ifdef __FREE_RTOS__
729 constexpr int MaxEvents = 10; // Define your own queue size
730 
732  public:
734  // Create the FreeRTOS mutex
735  this->mutex = xSemaphoreCreateMutex();
736  }
737 
739  // Delete the FreeRTOS mutex
740  vSemaphoreDelete(this->mutex);
741  }
742 
743  void lock() {
744  // Wait forever for the mutex to become available
745  xSemaphoreTake(this->mutex, portMAX_DELAY);
746  }
747 
748  bool try_lock() {
749  // Try to take the mutex without blocking
750  return xSemaphoreTake(this->mutex, 0) == pdTRUE;
751  }
752 
753  void unlock() {
754  // Release the mutex
755  xSemaphoreGive(this->mutex);
756  }
757 
758  // Return the native handle of the mutex
759  SemaphoreHandle_t native_handle() { return this->mutex; }
760 
761  private:
762  SemaphoreHandle_t mutex;
763 };
764 
766  public:
768  : semaphore_(xSemaphoreCreateBinary())
769  , waitersCount_(0) {
770  // Ensure the semaphore is in a non-signalled state initially.
771  xSemaphoreTake(semaphore_, 0);
772  }
773 
774  ~FreeRTOSConditionVariable() { vSemaphoreDelete(semaphore_); }
775 
776  template<typename Lock>
777  void wait(Lock& lock) {
778  // Increment the count of waiters.
779  UBaseType_t oldISRState = taskENTER_CRITICAL_FROM_ISR();
780  ++waitersCount_;
781  taskEXIT_CRITICAL_FROM_ISR(oldISRState);
782 
783  // Unlock the external mutex and wait for notification.
784  lock.unlock();
785  xSemaphoreTake(semaphore_, portMAX_DELAY);
786 
787  // Decrement the count of waiters.
788  oldISRState = taskENTER_CRITICAL_FROM_ISR();
789  --waitersCount_;
790  taskEXIT_CRITICAL_FROM_ISR(oldISRState);
791 
792  // Re-acquire the mutex before exiting.
793  lock.lock();
794  }
795 
796  void notify_one() {
797  if (waitersCount_ > 0) { // Check if there are any waiters.
798  xSemaphoreGive(semaphore_); // Wake up one waiter.
799  }
800  }
801 
802  void notify_all() {
803  while (waitersCount_ > 0) { // Keep waking all waiters.
804  xSemaphoreGive(semaphore_);
805  // Small delay to allow other tasks to respond to the semaphore.
806  vTaskDelay(pdMS_TO_TICKS(10));
807  }
808  }
809 
810  private:
811  SemaphoreHandle_t semaphore_;
812  volatile UBaseType_t waitersCount_;
813 };
814 
815 // C++ 11 compatible clock with FreeRTOS tick count.
817  using duration = std::chrono::milliseconds;
818  using period = duration::period;
819  using rep = duration::rep;
820  using time_point = std::chrono::time_point<FreeRTOSClock>;
821 
822  static constexpr bool is_steady = true;
823 
824  static time_point now() noexcept {
825  TickType_t ticks = xTaskGetTickCount();
826  // Convert ticks to milliseconds (note: configTICK_RATE_HZ is the number
827  // of ticks per second)
828  auto durationSinceEpoch =
829  std::chrono::milliseconds(ticks * (1000 / configTICK_RATE_HZ));
830  return time_point(duration(durationSinceEpoch));
831  }
832 };
833 
834 template<typename Event>
836 
837 template<typename HsmType, typename Events>
839  public:
841  // using EventQueue = FreeRTOSEventQueue<Event>; // Adapted for FreeRTOS
843 
846  interrupt_ = pdFALSE;
847  xTaskCreate(reinterpret_cast<TaskFunction_t>(taskCallback),
848  "ThreadedPolicyTask",
849  configMINIMAL_STACK_SIZE,
850  this,
851  tskIDLE_PRIORITY,
852  &smTaskHandle);
853  }
854 
856  interrupt_ = pdTRUE;
857  // Proper FreeRTOS task deletion if needed, ensuring clean-up.
858  if (smTaskHandle != nullptr) {
859  vTaskDelete(smTaskHandle);
860  smTaskHandle = nullptr;
861  }
862  }
863 
864  void send_event(const Event& event) { eventQueue.add_event(event); }
865 
866  protected:
868  TaskHandle_t smTaskHandle{};
870  BaseType_t interrupt_;
871 
872  static void StepTask(void* pvParameters) {
873  auto* policy = static_cast<ThreadedExecutionPolicy*>(pvParameters);
874  policy->step();
875  }
876 
877  void step() {
878  while (!interrupt_) {
879  processEvent();
880  }
881  }
882 
883  void process_event() {
884  Event const& nextEvent = eventQueue.next_event();
885  if (!eventQueue.interrupted()) {
886  std::visit([this](auto const& e) { return this->handle(e); },
887  nextEvent);
888  }
889  }
890 };
891 
892 #else // __FREE_RTOS__ is not defined
893 
894 template<typename Event>
895 using EventQueue = EventQueueT<Event, std::mutex, std::condition_variable_any>;
896 
897 // C++ 11 compatible accurate clock (nanosecond precision). This is a drop-in
898 // replacement for Clock types in std::chrono
899 struct AccurateClock {
900  using duration = std::chrono::nanoseconds;
901  using period = duration::period;
902  using rep = duration::rep;
903  using time_point = std::chrono::time_point<AccurateClock>;
904 
905  static constexpr bool is_steady = true;
906 
907  static time_point now() noexcept {
908  struct timespec ts;
909  clock_gettime(CLOCK_MONOTONIC, &ts);
910  auto durationSinceEpoch = std::chrono::seconds(ts.tv_sec) +
911  std::chrono::nanoseconds(ts.tv_nsec);
912  return time_point(duration(durationSinceEpoch));
913  }
914 };
915 
916 #endif
917 
918 // Forward declarations
919 template<typename HsmType, typename = void>
921 
922 template<typename Transition>
924 
925 template<typename TransitionsTuple>
927 
928 // Specialize for transitions tuple
929 template<typename... Transitions>
930 struct aggregate_events<std::tuple<Transitions...>> {
931  using type = decltype(std::tuple_cat(
933 };
934 
935 // Base case for empty tuple
936 template<>
937 struct aggregate_events<std::tuple<>> {
938  using type = std::tuple<>;
939 };
940 
941 // Extract events from a single transition
942 template<typename Transition>
944  using Event = std::tuple<typename Transition::event>;
945  using FromEvents =
947  using ToEvents =
949  using type = decltype(std::tuple_cat(Event{}, FromEvents{}, ToEvents{}));
950 };
951 
952 // Main structure for extracting events from an HSM
953 template<typename HsmType>
954 struct get_events_from_hsm<HsmType,
955  std::enable_if_t<has_transitions_v<HsmType>>> {
956  using Transitions = typename HsmType::transitions;
958 };
959 
960 // Fallback for non-HSM types
961 template<typename HsmType>
962 struct get_events_from_hsm<HsmType,
963  std::enable_if_t<!has_transitions_v<HsmType>>> {
964  using type = std::tuple<>;
965 };
966 
967 // Helper alias
968 template<typename HsmType>
971 
972 // Single threaded execution policy
973 template<typename Context, template<typename> class Policy = make_hsm_t>
974 struct SingleThreadedExecutionPolicy : Policy<Context> {
976  using HsmType = typename Policy<Context>::type;
978 
979  bool step() {
980  // This is a blocking wait
981  Event const& nextEvent = eventQueue_.next_event();
982  // go down the Hsm hierarchy to handle the event as that is the
983  // "most active state"
984  return std::visit(
985  [this](auto&& e) -> bool { return HsmType::handle(e); }, nextEvent);
986  }
987 
988  void send_event(Event&& event) {
989  eventQueue_.add_event(std::forward<Event>(event));
990  }
991 
992  private:
993  EventQueue<Event> eventQueue_;
994  bool interrupt_{};
995 };
996 
997 // Asynchronous execution policy
998 template<typename Context, template<typename> class Policy = make_hsm_t>
999 struct ThreadedExecutionPolicy : Policy<Context> {
1001  using HsmType = typename Policy<Context>::type;
1003 
1004  void start() {
1005  smThread_ = std::thread([this] {
1006  while (!interrupt_) {
1007  this->process_event();
1008  }
1009  });
1010  }
1011 
1012  void stop() {
1013  eventQueue_.stop();
1014  interrupt_ = true;
1015  if (smThread_.joinable()) {
1016  smThread_.join();
1017  }
1018  }
1019 
1021 
1022  void send_event(Event&& event) {
1023  eventQueue_.add_event(std::forward<Event>(event));
1024  }
1025 
1026  protected:
1027  std::thread smThread_;
1029  bool interrupt_{};
1030 
1031  void process_event() {
1032  // This is a blocking wait
1033  Event const& nextEvent = eventQueue_.next_event();
1034  if (!eventQueue_.interrupted()) {
1035  std::visit([this](auto const& e) { return this->handle(e); },
1036  nextEvent);
1037  }
1038  }
1039 };
1040 
1047 template<typename LockType, typename ConditionVarType>
1049  void notify() {
1050  std::unique_lock<std::mutex> lock(smBusyMutex_);
1051  notified_ = true;
1052  cv_.notify_all();
1053  }
1054 
1055  void wait() {
1056  std::unique_lock<std::mutex> lock(smBusyMutex_);
1057  cv_.wait(lock, [this] { return this->notified_ == true; });
1058  notified_ = false;
1059  }
1060 
1061  private:
1062  LockType smBusyMutex_;
1063  ConditionVarType cv_;
1064  bool notified_{};
1065 };
1066 
1067 // Preserving for historical reasons
1069  void add_callback(std::function<void()>&& cb) {
1070  if (cb != nullptr) {
1071  cbs_.push_back(cb);
1072  }
1073  }
1074 
1075  void notify() {
1076  for (auto const& cb : cbs_) {
1077  cb();
1078  }
1079  }
1080 
1081  private:
1082  std::vector<std::function<void()>> cbs_;
1083 };
1084 
1085 #ifdef __FREE_RTOS__
1088 #else
1090 #endif
1091 
1098 template<typename Observer,
1099  typename Context,
1100  template<typename> class Policy = ThreadedExecutionPolicy>
1102  : public Policy<Context>
1103  , public Observer {
1105  using HsmType = typename Policy<Context>::type;
1106  using HsmType::interrupt_;
1107  using HsmType::process_event;
1108  using HsmType::smThread_;
1109 
1110  void start() {
1111  smThread_ = std::thread([this] {
1112  while (!interrupt_) {
1113  Observer::notify();
1114  process_event();
1115  }
1116  });
1117  }
1118  virtual ~ThreadedExecWithObserver() = default;
1119 };
1120 
1125 template<typename Context>
1128 
1130 template<typename Clock = std::chrono::steady_clock,
1131  typename Duration = typename Clock::duration>
1132 struct Timer {
1133  using ClockType = Clock;
1134  using DurationType = Duration;
1135  void start() {
1136  start_time_ = Clock::now();
1137  started_ = true;
1138  }
1139 
1140  Duration elapsed() const {
1141  if (!started_) {
1142  return Duration(0);
1143  }
1144  auto now = Clock::now();
1145  auto interval = now - start_time_;
1146  return std::chrono::duration_cast<Duration>(interval);
1147  }
1148 
1149  template<typename ToDuration = Duration>
1150  Duration elapsed(ToDuration since) const {
1151  auto now = Clock::now();
1152  if constexpr (std::is_same<ToDuration, Duration>::value) {
1153  return std::chrono::duration_cast<Duration>(now - since);
1154  } else {
1155  return std::chrono::duration_cast<ToDuration>(now - since);
1156  }
1157  }
1158  // template function to convert to a different Duration
1159  template<typename ToDuration>
1160  ToDuration elapsed() const {
1161  return std::chrono::duration_cast<ToDuration>(elapsed());
1162  }
1163 
1164  bool started() const { return started_; }
1165  void reset() { start_time_ = Clock::now(); }
1166  void stop() { started_ = false; }
1167 
1168  protected:
1169  typename Clock::time_point start_time_;
1170  bool started_{ false };
1171 };
1172 
1173 // useful for profiling
1174 template<typename Clock = std::chrono::steady_clock,
1175  typename Duration = typename Clock::duration>
1176 struct IntervalTimer : public Timer<Clock, Duration> {
1177  // Return the interval since the previous call to this function, typecast
1178  // to the Duration type
1179  Duration interval() {
1180  if (!this->started()) {
1181  this->start();
1182  return Duration(0);
1183  }
1184  auto now = Clock::now();
1185  auto interval = now - this->start_time_;
1186  this->start_time_ = now;
1187  return std::chrono::duration_cast<Duration>(interval);
1188  }
1189 };
1190 
1191 #ifdef __linux__
1192 // Periodic Timer
1193 // Lock up the calling thread for a period of time. Accuracy is determined by
1194 // real-time scheduler settings and OS scheduling policies
1195 template<typename Clock = AccurateClock,
1196  typename Duration = typename Clock::duration>
1197 struct PeriodicSleepTimer : public Timer<Clock, Duration> {
1198  PeriodicSleepTimer(Duration period = Duration(1))
1199  : period_(period) {}
1201 
1202  void wait() {
1203  // calculate time elapsed since last callback
1204  auto remaining = period_ - Timer<Clock, Duration>::elapsed();
1205  // nanosleep for remaining time
1206  // Convert duration to timespec
1207  struct timespec ts;
1208  ts.tv_sec =
1209  std::chrono::duration_cast<std::chrono::seconds>(remaining).count();
1210  ts.tv_nsec =
1211  std::chrono::duration_cast<std::chrono::nanoseconds>(remaining)
1212  .count();
1213  // remaining time if -1
1214  struct timespec remaining_ts;
1215  while (nanosleep(&ts, &remaining_ts) == EINTR) {
1216  ts = remaining_ts;
1217  }
1218  // ensure that callback finishes within the period
1220  }
1221 
1222  Duration get_period() const { return period_; }
1223 
1224  protected:
1225  Duration period_;
1226 };
1227 
1228 // Real-time execution policy
1231  RealtimeConfigurator(int priority, std::array<int, 4> affinity)
1232  : PROCESS_PRIORITY(priority)
1233  , CPU_AFFINITY(affinity) {}
1234 
1236  // Set thread to real-time priority
1237  struct sched_param param;
1238  param.sched_priority = PROCESS_PRIORITY - 3;
1239  if (pthread_setschedparam(pthread_self(), SCHED_RR, &param) != 0) {
1240  perror("pthread_setschedparam");
1241  }
1242 
1243  // Set CPU affinity
1244  cpu_set_t cpuset;
1245  CPU_ZERO(&cpuset);
1246  for (auto cpu : CPU_AFFINITY) {
1247  CPU_SET(cpu, &cpuset);
1248  }
1249 
1250  if (pthread_setaffinity_np(
1251  pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) {
1252  perror("sched_setaffinity");
1253  }
1254 
1255  // Lock memory
1256  if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
1257  perror("mlockall failed");
1258  }
1259  }
1260 
1261  template<typename Fn>
1262  std::thread real_time_thread(Fn fn) {
1263  return std::thread([this, fn] {
1264  this->config_realtime_thread();
1265  fn();
1266  });
1267  }
1268 
1269  std::thread make_real_time(std::thread&& t) {
1271  return std::move(t);
1272  }
1273 
1274  protected:
1275  int PROCESS_PRIORITY{ 98 };
1276  std::array<int, 4> CPU_AFFINITY{ 0, 1, 2, 3 };
1277 };
1278 
1279 // Real-time execution policy - set cpu isolation in grub
1280 template<typename Context,
1281  template<typename> class Policy = ThreadedExecutionPolicy>
1283  : Policy<Context>
1286  using HsmType = typename Policy<Context>::type;
1287  using HsmType::interrupt_;
1288  using HsmType::process_event;
1289  using HsmType::smThread_;
1290 
1291  void start() {
1293  while (!interrupt_) {
1294  process_event();
1295  }
1296  });
1297  }
1298 
1299  virtual ~RealtimeExecutionPolicy() = default;
1300 };
1301 
1302 // Periodic execution policy
1303 template<typename Context,
1304  template<typename> class Policy = ThreadedExecutionPolicy,
1305  typename PeriodicTimer = PeriodicSleepTimer<std::chrono::steady_clock,
1306  std::chrono::milliseconds>>
1308  : Policy<Context>
1309  , PeriodicTimer {
1311  using HsmType = typename Policy<Context>::type;
1312  using TimerType = PeriodicTimer;
1313  using HsmType::interrupt_;
1314  using HsmType::send_event;
1315 
1316  void start() {
1317  PeriodicTimer::start();
1319 
1320  eventThread_ = std::thread([this] {
1321  while (!interrupt_) {
1322  PeriodicTimer::wait();
1323  ++tick_event_.ticks_;
1324  this->send_event(tick_event_);
1325  }
1326  });
1327  }
1328 
1329  void stop() {
1331  if (eventThread_.joinable()) {
1332  eventThread_.join();
1333  }
1334  }
1336 
1337  int get_ticks() { return tick_event_.ticks_; }
1338 
1339  protected:
1340  std::thread eventThread_;
1342 };
1343 
1344 // Periodic Real-time execution policy
1345 template<typename Context,
1346  template<typename> class Policy = ThreadedExecutionPolicy,
1347  typename PeriodicTimer = PeriodicSleepTimer<std::chrono::steady_clock,
1348  std::chrono::milliseconds>>
1351  , Policy<Context>
1352  , PeriodicTimer {
1353  using type =
1355  using TimerType = PeriodicTimer;
1356  using HsmType = typename Policy<Context>::type;
1357  using HsmType::interrupt_;
1358  using HsmType::process_event;
1359  using HsmType::send_event;
1360  using HsmType::smThread_;
1361 
1362  void start() {
1363  PeriodicTimer::start();
1365  while (!interrupt_) {
1366  this->process_event();
1367  }
1368  });
1369 
1371  while (!interrupt_) {
1372  PeriodicTimer::wait();
1373  ++tick_event_.ticks_;
1374  this->send_event(tick_event_);
1375  }
1376  });
1377  }
1378 
1379  void stop() {
1381  if (eventThread_.joinable()) {
1382  eventThread_.join();
1383  }
1384  }
1386 
1387  int get_ticks() { return tick_event_.ticks_; }
1388 
1389  protected:
1390  std::thread eventThread_;
1392 };
1393 
1394 // Concurrent HSMs
1395 template<typename... Hsms>
1397  static constexpr bool is_hsm = true;
1399 
1400  template<typename Event>
1401  void entry(Event e = Event()) {
1402  std::apply([e](auto&... hsm) { (hsm.entry(e), ...); }, hsms_);
1403  }
1404 
1405  template<typename Event>
1406  void exit(Event&& e) {
1407  std::apply([e](auto&... hsm) { (hsm.exit(e), ...); }, hsms_);
1408  }
1409 
1410  template<typename Event>
1411  void send_event(Event&& e) {
1412  return std::apply(
1413  // send event to all HSMs
1414  [e](auto&... hsm) { (hsm.send_event(e), ...); },
1415  hsms_);
1416  }
1417 
1418  // assume hsms can be `tick`ed
1419 
1420  void tick() {
1421  std::apply([](auto&... hsm) { (hsm.tick(), ...); }, hsms_);
1422  }
1423 
1424  std::tuple<Hsms...> hsms_;
1425 };
1426 
1427 // Each HSM in the concurrent HSM is wrapped with a ThreadedExecutionPolicy
1428 template<template<typename> class Policy = ThreadedExecutionPolicy,
1429  typename... Ts>
1432 };
1433 
1434 template<template<typename> class Policy = ThreadedExecutionPolicy,
1435  typename... Ts>
1436 using make_concurrent_hsm_t = typename make_concurrent_hsm<Policy, Ts...>::type;
1437 
1438 #endif // __linux__
1439 
1440 } // namespace hsm
Definition: tsm_impl.h:765
void notify_all()
Definition: tsm_impl.h:802
void notify_one()
Definition: tsm_impl.h:796
FreeRTOSConditionVariable()
Definition: tsm_impl.h:767
void wait(Lock &lock)
Definition: tsm_impl.h:777
~FreeRTOSConditionVariable()
Definition: tsm_impl.h:774
Definition: tsm_impl.h:731
FreeRTOSMutex()
Definition: tsm_impl.h:733
void lock()
Definition: tsm_impl.h:743
void unlock()
Definition: tsm_impl.h:753
bool try_lock()
Definition: tsm_impl.h:748
~FreeRTOSMutex()
Definition: tsm_impl.h:738
SemaphoreHandle_t native_handle()
Definition: tsm_impl.h:759
Definition: tsm_impl.h:838
TaskHandle_t smTaskHandle
Definition: tsm_impl.h:868
std::thread smThread_
Definition: tsm_impl.h:1027
static void StepTask(void *pvParameters)
Definition: tsm_impl.h:872
ThreadedExecutionPolicy()
Definition: tsm_impl.h:844
TaskCallback taskCallback
Definition: tsm_impl.h:867
EventQueue eventQueue
Definition: tsm_impl.h:869
BaseType_t interrupt_
Definition: tsm_impl.h:870
void stop()
Definition: tsm_impl.h:1012
void process_event()
Definition: tsm_impl.h:883
void start()
Definition: tsm_impl.h:1004
void send_event(Event &&event)
Definition: tsm_impl.h:1022
void send_event(const Event &event)
Definition: tsm_impl.h:864
void step()
Definition: tsm_impl.h:877
virtual ~ThreadedExecutionPolicy()
Definition: tsm_impl.h:855
void(*)(ThreadedExecutionPolicy *) TaskCallback
Definition: tsm_impl.h:842
typename Policy< Context >::type HsmType
Definition: tsm_impl.h:1001
EventQueue< Event > eventQueue_
Definition: tsm_impl.h:1028
tuple_to_variant_t< Events > Event
Definition: tsm_impl.h:840
Definition: tsm.h:5
typename is_hsm_trait< T >::type is_hsm_trait_t
Definition: tsm_impl.h:358
typename wrap_transitions< Ts... >::type wrap_transitions_t
Definition: tsm_impl.h:599
constexpr bool has_guard_v
Definition: tsm_impl.h:296
typename append_unique_impl< T, Tuple >::type append_unique
Definition: tsm_impl.h:56
constexpr bool has_transitions_v
Definition: tsm_impl.h:326
constexpr bool has_entry_v
Definition: tsm_impl.h:280
typename wrap_type_impl< Wrapper, Tuple >::type wrap_type
Definition: tsm_impl.h:35
constexpr bool has_handle_method_v
Definition: tsm_impl.h:347
constexpr bool has_action_v
Definition: tsm_impl.h:312
typename unique_tuple< Ts >::type unique_tuple_t
Definition: tsm_impl.h:86
typename make_hsm< T >::type make_hsm_t
Definition: tsm_impl.h:568
typename has_transitions< T >::type has_transitions_t
Definition: tsm_impl.h:323
constexpr bool has_exit_v
Definition: tsm_impl.h:264
constexpr int MaxEvents
Definition: tsm_impl.h:729
constexpr bool is_clocked_hsm_v
Definition: tsm_impl.h:376
typename tuple_to_variant_impl< Tuple >::type tuple_to_variant_t
Definition: tsm_impl.h:99
typename get_states< Ts... >::type get_states_t
Definition: tsm_impl.h:174
constexpr bool is_hsm_trait_v
Definition: tsm_impl.h:361
typename wrap_transition< T >::type wrap_transition_t
Definition: tsm_impl.h:588
constexpr bool is_state_trait_v
Definition: tsm_impl.h:365
typename TransitionMap< From, Event, Transitions >::type find_transition_t
Definition: tsm_impl.h:242
unique_tuple_t< typename get_events_from_hsm< HsmType >::type > get_events_t
Definition: tsm_impl.h:970
constexpr bool has_valid_transition_v
Definition: tsm_impl.h:246
typename make_concurrent_hsm< Policy, Ts... >::type make_concurrent_hsm_t
Definition: tsm_impl.h:1436
Definition: tsm_impl.h:113
To to
Definition: tsm_impl.h:116
From from
Definition: tsm_impl.h:114
Definition: tsm_impl.h:1048
void notify()
Definition: tsm_impl.h:1049
void wait()
Definition: tsm_impl.h:1055
Definition: tsm_impl.h:1068
void add_callback(std::function< void()> &&cb)
Definition: tsm_impl.h:1069
void notify()
Definition: tsm_impl.h:1075
Definition: tsm_impl.h:131
int ticks_
Definition: tsm_impl.h:132
Definition: tsm_impl.h:604
bool handle(ClockTickEvent &e)
Definition: tsm_impl.h:617
bool handle(Event e=Event())
Definition: tsm_impl.h:613
bool tick()
Definition: tsm_impl.h:610
ClockTickEvent tick_event_
Definition: tsm_impl.h:621
typename Policy< T >::type HsmType
Definition: tsm_impl.h:606
Definition: tsm_impl.h:140
Definition: tsm_impl.h:1396
void tick()
Definition: tsm_impl.h:1420
void send_event(Event &&e)
Definition: tsm_impl.h:1411
void exit(Event &&e)
Definition: tsm_impl.h:1406
static constexpr bool is_hsm
Definition: tsm_impl.h:1397
std::tuple< Hsms... > hsms_
Definition: tsm_impl.h:1424
void entry(Event e=Event())
Definition: tsm_impl.h:1401
Definition: tsm_impl.h:662
Event const & front()
Definition: tsm_impl.h:702
virtual ~EventQueueT()
Definition: tsm_impl.h:665
bool empty()
Definition: tsm_impl.h:700
void add_event(Event &&e)
Definition: tsm_impl.h:681
Event next_event()
Definition: tsm_impl.h:669
void stop()
Definition: tsm_impl.h:690
bool interrupted()
Definition: tsm_impl.h:697
bool push_back(Event const &e)
Definition: tsm_impl.h:710
void pop_front()
Definition: tsm_impl.h:704
Definition: tsm_impl.h:102
Definition: tsm_impl.h:816
std::chrono::time_point< FreeRTOSClock > time_point
Definition: tsm_impl.h:820
static constexpr bool is_steady
Definition: tsm_impl.h:822
std::chrono::milliseconds duration
Definition: tsm_impl.h:817
duration::rep rep
Definition: tsm_impl.h:819
static time_point now() noexcept
Definition: tsm_impl.h:824
duration::period period
Definition: tsm_impl.h:818
Definition: tsm_impl.h:380
void entry(Event &&e, State *state) noexcept
Definition: tsm_impl.h:423
void current_state()
Definition: tsm_impl.h:550
States states_
Definition: tsm_impl.h:554
tuple_to_variant_t< wrap_type< std::add_pointer, States > > current_state_
Definition: tsm_impl.h:556
std::enable_if_t< has_handle_method_v< State, Event, T >, void > handle_transition(State *state, Event &&e)
Definition: tsm_impl.h:533
Hsm()
Definition: tsm_impl.h:387
bool check_guard(Event &&e, State *state)
Definition: tsm_impl.h:463
void exit(Event &&e, State *state) noexcept
Definition: tsm_impl.h:442
std::enable_if_t<!has_handle_method_v< State, Event, T >, void > handle_transition(typename transition::from *state, Event &&e)
Definition: tsm_impl.h:509
static constexpr bool is_hsm
Definition: tsm_impl.h:381
transitions transitions_
Definition: tsm_impl.h:555
void perform_action(Event &&e, State *state)
Definition: tsm_impl.h:487
Hsm< T, transitions > type
Definition: tsm_impl.h:382
get_states_t< transitions > States
Definition: tsm_impl.h:385
bool handle(Event &&e)
Definition: tsm_impl.h:392
typename std::tuple_element_t< 0, transitions >::from initial_state
Definition: tsm_impl.h:384
Definition: tsm_impl.h:1176
Duration interval()
Definition: tsm_impl.h:1179
Definition: tsm_impl.h:636
void entry(Event e=Event())
Definition: tsm_impl.h:641
void exit(Event e=Event())
Definition: tsm_impl.h:646
bool handle(Event e=Event())
Definition: tsm_impl.h:651
std::tuple< Hsms... > hsms_
Definition: tsm_impl.h:656
static constexpr bool is_hsm
Definition: tsm_impl.h:637
Definition: tsm_impl.h:1309
PeriodicTimer TimerType
Definition: tsm_impl.h:1312
std::thread eventThread_
Definition: tsm_impl.h:1340
ClockTickEvent tick_event_
Definition: tsm_impl.h:1341
virtual ~PeriodicExecutionPolicy()
Definition: tsm_impl.h:1335
int get_ticks()
Definition: tsm_impl.h:1337
void stop()
Definition: tsm_impl.h:1329
void start()
Definition: tsm_impl.h:1316
typename Policy< Context >::type HsmType
Definition: tsm_impl.h:1311
Definition: tsm_impl.h:1197
void start()
Definition: tsm_impl.h:1200
Duration get_period() const
Definition: tsm_impl.h:1222
void wait()
Definition: tsm_impl.h:1202
Duration period_
Definition: tsm_impl.h:1225
PeriodicSleepTimer(Duration period=Duration(1))
Definition: tsm_impl.h:1198
Definition: tsm_impl.h:1229
void config_realtime_thread()
Definition: tsm_impl.h:1235
std::thread make_real_time(std::thread &&t)
Definition: tsm_impl.h:1269
int PROCESS_PRIORITY
Definition: tsm_impl.h:1275
std::thread real_time_thread(Fn fn)
Definition: tsm_impl.h:1262
RealtimeConfigurator(int priority, std::array< int, 4 > affinity)
Definition: tsm_impl.h:1231
std::array< int, 4 > CPU_AFFINITY
Definition: tsm_impl.h:1276
Definition: tsm_impl.h:1284
virtual ~RealtimeExecutionPolicy()=default
typename Policy< Context >::type HsmType
Definition: tsm_impl.h:1286
void start()
Definition: tsm_impl.h:1291
Definition: tsm_impl.h:1352
void start()
Definition: tsm_impl.h:1362
virtual ~RealtimePeriodicExecutionPolicy()
Definition: tsm_impl.h:1385
typename Policy< Context >::type HsmType
Definition: tsm_impl.h:1356
void stop()
Definition: tsm_impl.h:1379
PeriodicTimer TimerType
Definition: tsm_impl.h:1355
int get_ticks()
Definition: tsm_impl.h:1387
ClockTickEvent tick_event_
Definition: tsm_impl.h:1391
std::thread eventThread_
Definition: tsm_impl.h:1390
Definition: tsm_impl.h:974
typename Policy< Context >::type HsmType
Definition: tsm_impl.h:976
tuple_to_variant_t< get_events_t< HsmType > > Event
Definition: tsm_impl.h:977
void send_event(Event &&event)
Definition: tsm_impl.h:988
bool step()
Definition: tsm_impl.h:979
Definition: tsm_impl.h:1103
virtual ~ThreadedExecWithObserver()=default
typename Policy< Context >::type HsmType
Definition: tsm_impl.h:1105
void start()
Definition: tsm_impl.h:1110
Helper to implement a Timed Execution Policy.
Definition: tsm_impl.h:1132
void stop()
Definition: tsm_impl.h:1166
void start()
Definition: tsm_impl.h:1135
Clock ClockType
Definition: tsm_impl.h:1133
Duration DurationType
Definition: tsm_impl.h:1134
Duration elapsed(ToDuration since) const
Definition: tsm_impl.h:1150
bool started_
Definition: tsm_impl.h:1170
void reset()
Definition: tsm_impl.h:1165
ToDuration elapsed() const
Definition: tsm_impl.h:1160
Clock::time_point start_time_
Definition: tsm_impl.h:1169
bool started() const
Definition: tsm_impl.h:1164
Duration elapsed() const
Definition: tsm_impl.h:1140
Definition: tsm_impl.h:235
typename transition_map_helper< From, Event, Transitions >::type type
Definition: tsm_impl.h:236
Definition: tsm_impl.h:124
Action action
Definition: tsm_impl.h:125
Guard guard
Definition: tsm_impl.h:126
decltype(std::tuple_cat(typename get_events_from_transition< Transitions >::type{}...)) type
Definition: tsm_impl.h:932
std::tuple<> type
Definition: tsm_impl.h:938
Definition: tsm_impl.h:926
std::conditional_t<!(std::is_same_v< T, Ts >||...), std::tuple< Ts..., T >, std::tuple< Ts... > > type
Definition: tsm_impl.h:52
std::tuple< T > type
Definition: tsm_impl.h:43
Definition: tsm_impl.h:39
typename HsmType::transitions Transitions
Definition: tsm_impl.h:956
typename aggregate_events< Transitions >::type type
Definition: tsm_impl.h:957
Definition: tsm_impl.h:920
Definition: tsm_impl.h:943
typename get_events_from_hsm< typename Transition::to >::type ToEvents
Definition: tsm_impl.h:948
typename get_events_from_hsm< typename Transition::from >::type FromEvents
Definition: tsm_impl.h:946
decltype(std::tuple_cat(Event{}, FromEvents{}, ToEvents{})) type
Definition: tsm_impl.h:949
std::tuple< typename Transition::event > Event
Definition: tsm_impl.h:944
typename get_states_impl< std::tuple<>, Ts... >::type type
Definition: tsm_impl.h:170
typename get_states_impl< to_states, Rest... >::type type
Definition: tsm_impl.h:162
append_unique< typename First::from, Tuple > from_states
Definition: tsm_impl.h:157
append_unique< typename First::to, from_states > to_states
Definition: tsm_impl.h:159
Tuple type
Definition: tsm_impl.h:150
Definition: tsm_impl.h:144
Definition: tsm_impl.h:166
Definition: tsm_impl.h:300
Definition: tsm_impl.h:268
Definition: tsm_impl.h:252
Definition: tsm_impl.h:284
Definition: tsm_impl.h:334
Definition: tsm_impl.h:316
Definition: tsm_impl.h:369
Definition: tsm_impl.h:352
Definition: tsm_impl.h:189
Definition: tsm_impl.h:1430
wrap_transitions_t< typename T::transitions > transitions
Definition: tsm_impl.h:629
Definition: tsm_impl.h:560
typename std::conditional_t< match, CurrentTransition, typename transition_map_helper< From, Event, std::tuple< Transitions... >, Index+1 >::type > type
Definition: tsm_impl.h:219
std::tuple_element_t< Index, std::tuple< Transitions... > > CurrentTransition
Definition: tsm_impl.h:209
Definition: tsm_impl.h:185
std::variant< Ts... > type
Definition: tsm_impl.h:94
Definition: tsm_impl.h:90
typename unique_tuple_impl< std::tuple< Ts... >, append_unique< T, std::tuple< Us... > >>::type type
Definition: tsm_impl.h:76
std::tuple< Us... > type
Definition: tsm_impl.h:67
Definition: tsm_impl.h:61
Definition: tsm_impl.h:81
typename unique_tuple_impl< Ts, Us >::type type
Definition: tsm_impl.h:82
Definition: tsm_impl.h:572
typename T::from from
Definition: tsm_impl.h:573
typename T::to to
Definition: tsm_impl.h:575
typename T::guard guard
Definition: tsm_impl.h:577
typename T::action action
Definition: tsm_impl.h:576
std::conditional_t< is_state_trait_v< from >, make_hsm_t< from >, from > wrap_from
Definition: tsm_impl.h:580
std::conditional_t< is_state_trait_v< to >, make_hsm_t< to >, to > wrap_to
Definition: tsm_impl.h:582
std::tuple< wrap_transition_t< Ts >... > type
Definition: tsm_impl.h:595
Definition: tsm_impl.h:591
std::tuple< typename Wrapper< Ts >::type... > type
Definition: tsm_impl.h:31
Definition: tsm_impl.h:27
Definition: tsm_impl.h:105
T type
Definition: tsm_impl.h:106