Embedded Template Library 1.0
Loading...
Searching...
No Matches
fsm_generator.h
1/******************************************************************************
2The MIT License(MIT)
3
4Embedded Template Library.
5https://github.com/ETLCPP/etl
6https://www.etlcpp.com
7
8Copyright(c) 2017 John Wellbelove
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files(the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions :
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27******************************************************************************/
28
29/*[[[cog
30import cog
31cog.outl("#if 0")
32]]]*/
33/*[[[end]]]*/
34#error THIS HEADER IS A GENERATOR. DO NOT INCLUDE.
35/*[[[cog
36import cog
37cog.outl("#endif")
38]]]*/
39/*[[[end]]]*/
40
41/*[[[cog
42import cog
43cog.outl("//***************************************************************************")
44cog.outl("// THIS FILE HAS BEEN AUTO GENERATED. DO NOT EDIT THIS FILE.")
45cog.outl("//***************************************************************************")
46]]]*/
47/*[[[end]]]*/
48
49//***************************************************************************
50// To generate to header file, run this at the command line.
51// Note: You will need Python and COG installed.
52//
53// cog -d -e -ofsm.h -DHandlers=<n> fsm_generator.h
54// Where <n> is the number of messages to support.
55//
56// e.g.
57// To generate handlers for up to 16 events...
58// cog -d -e -ofsm.h -DHandlers=16 fsm_generator.h
59//
60// See generate.bat
61//***************************************************************************
62
63#ifndef ETL_FSM_INCLUDED
64#define ETL_FSM_INCLUDED
65
66#include "platform.h"
67#include "array.h"
68#include "nullptr.h"
69#include "error_handler.h"
70#include "exception.h"
71#include "user_type.h"
72#include "message_router.h"
73#include "integral_limits.h"
74#include "largest.h"
75#if ETL_USING_CPP11
76 #include "tuple.h"
77#endif
78
79#include <stdint.h>
80
81#include "private/minmax_push.h"
82
83namespace etl
84{
85 class fsm;
86 class hfsm;
87
89#if !defined(ETL_FSM_STATE_ID_TYPE)
90 typedef uint_least8_t fsm_state_id_t;
91#else
92 typedef ETL_FSM_STATE_ID_TYPE fsm_state_id_t;
93#endif
94
95 // For internal FSM use.
96 typedef typename etl::larger_type<etl::message_id_t>::type fsm_internal_id_t;
97
98#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
99 template <typename, typename, etl::fsm_state_id_t, typename...>
100 class fsm_state;
101#else
102 /*[[[cog
103 import cog
104 cog.outl("template <typename, typename, etl::fsm_state_id_t,")
105 cog.out(" ")
106 for n in range(1, int(Handlers)):
107 cog.out("typename, ")
108 if n % 4 == 0:
109 cog.outl("")
110 cog.out(" ")
111 cog.outl("typename>")
112 cog.outl("class fsm_state;")
113 ]]]*/
114 /*[[[end]]]*/
115#endif
116
117 //***************************************************************************
119 //***************************************************************************
120 class fsm_exception : public etl::exception
121 {
122 public:
123
124 fsm_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
125 : etl::exception(reason_, file_name_, line_number_)
126 {
127 }
128 };
129
130 //***************************************************************************
132 //***************************************************************************
133 class fsm_null_state_exception : public etl::fsm_exception
134 {
135 public:
136
137 fsm_null_state_exception(string_type file_name_, numeric_type line_number_)
138 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:null state", ETL_FSM_FILE_ID"A"), file_name_, line_number_)
139 {
140 }
141 };
142
143 //***************************************************************************
145 //***************************************************************************
146 class fsm_state_id_exception : public etl::fsm_exception
147 {
148 public:
149
150 fsm_state_id_exception(string_type file_name_, numeric_type line_number_)
151 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state id", ETL_FSM_FILE_ID"B"), file_name_, line_number_)
152 {
153 }
154 };
155
156 //***************************************************************************
158 //***************************************************************************
159 class fsm_state_list_exception : public etl::fsm_exception
160 {
161 public:
162
163 fsm_state_list_exception(string_type file_name_, numeric_type line_number_)
164 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list", ETL_FSM_FILE_ID"C"), file_name_, line_number_)
165 {
166 }
167 };
168
169 //***************************************************************************
171 //***************************************************************************
172 class fsm_state_list_order_exception : public etl::fsm_exception
173 {
174 public:
175
176 fsm_state_list_order_exception(string_type file_name_, numeric_type line_number_)
177 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:state list order", ETL_FSM_FILE_ID"D"), file_name_, line_number_)
178 {
179 }
180 };
181
182 //***************************************************************************
184 //***************************************************************************
185 class fsm_not_started : public etl::fsm_exception
186 {
187 public:
188 fsm_not_started(string_type file_name_, numeric_type line_number_)
189 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:not started", ETL_FSM_FILE_ID"F"), file_name_, line_number_)
190 {
191 }
192 };
193
194 //***************************************************************************
197 //***************************************************************************
198 class fsm_reentrant_transition_forbidden : public etl::fsm_exception
199 {
200 public:
201 fsm_reentrant_transition_forbidden(string_type file_name_, numeric_type line_number_)
202 : etl::fsm_exception(ETL_ERROR_TEXT("fsm:reentrant calls to start/receive/etc. forbidden", ETL_FSM_FILE_ID"G"), file_name_, line_number_)
203 {
204 }
205 };
206
207 namespace private_fsm
208 {
209 template <typename T = void>
210 class ifsm_state_helper
211 {
212 public:
213
214 // Pass this whenever no state change is desired.
215 // The highest unsigned value of fsm_state_id_t.
216 static ETL_CONSTANT fsm_state_id_t No_State_Change = etl::integral_limits<fsm_state_id_t>::max;
217
218 // Pass this when this event also needs to be passed to the parent.
219 static ETL_CONSTANT fsm_state_id_t Pass_To_Parent = No_State_Change - 1U;
220
221 // Pass this when this event should trigger a self transition.
222 static ETL_CONSTANT fsm_state_id_t Self_Transition = No_State_Change - 2U;
223 };
224
225 template <typename T>
226 ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::No_State_Change;
227
228 template <typename T>
229 ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::Pass_To_Parent;
230
231 template <typename T>
232 ETL_CONSTANT fsm_state_id_t ifsm_state_helper<T>::Self_Transition;
233
234 // Compile-time: TState::ID must equal its index in the type list (0..N-1)
235 template <size_t Id, typename...> struct check_ids : etl::true_type
236 {
237 };
238
239 template <size_t Id, typename TState0, typename... TRest>
240 struct check_ids<Id, TState0, TRest...>
241 : etl::integral_constant<bool, (TState0::STATE_ID == Id) && private_fsm::check_ids<Id + 1, TRest...>::value>
242 {
243 };
244
245 //***************************************************************************
249 //***************************************************************************
250 class fsm_reentrancy_guard
251 {
252 public:
253 //*******************************************
256 //*******************************************
257 fsm_reentrancy_guard(bool& transition_guard_flag)
258 : is_locked(transition_guard_flag)
259 {
261 is_locked = true;
262 }
263
264 //*******************************************
267 //*******************************************
269 {
270 is_locked = false;
271 }
272
273 private:
274 // Reference to the flag signifying a lock on the state machine.
275 bool& is_locked;
276
277 // Copy & move semantics disabled since this is a guard.
279 fsm_reentrancy_guard& operator= (fsm_reentrancy_guard const&) ETL_DELETE;
280#if ETL_USING_CPP11
282 fsm_reentrancy_guard& operator= (fsm_reentrancy_guard&&) ETL_DELETE;
283#endif
284 };
285 }
286
287 class ifsm_state;
288
289#if ETL_USING_CPP11
290 //***************************************************************************
292 //***************************************************************************
293 template <typename... TStates>
294 class fsm_state_pack
295 {
296 public:
297
298 friend class etl::fsm;
299
300 ETL_STATIC_ASSERT((private_fsm::check_ids<0, TStates...>::value), "State IDs must be 0..N-1 and in order");
301 ETL_STATIC_ASSERT(sizeof...(TStates) > 0, "At least one state is required");
302 ETL_STATIC_ASSERT(sizeof...(TStates) < private_fsm::ifsm_state_helper<>::No_State_Change, "State IDs mst be less than ifsm_state::No_State_Change");
303
304 //*********************************
305 // The number of states.
306 //*********************************
307 static ETL_CONSTEXPR size_t size()
308 {
309 return sizeof...(TStates);
310 }
311
312 //*********************************
314 //*********************************
315 template <typename TState>
316 TState& get()
317 {
318 return etl::get<TState>(storage);
319 }
320
321 //*********************************
323 //*********************************
324 template <typename TState>
325 const TState& get() const
326 {
327 return etl::get<TState>(storage);
328 }
329
330 private:
331
332 //*********************************
334 //*********************************
335 etl::ifsm_state** get_state_list()
336 {
337 return &states[0];
338 }
339
341 etl::tuple<TStates...> storage{};
342
344 etl::ifsm_state* states[sizeof...(TStates)]{ &etl::get<TStates>(storage)... };
345 };
346#endif
347
348 //***************************************************************************
350 //***************************************************************************
352 {
353 public:
354
356 friend class etl::fsm;
357 friend class etl::hfsm;
358
359 using private_fsm::ifsm_state_helper<>::No_State_Change;
360 using private_fsm::ifsm_state_helper<>::Pass_To_Parent;
361 using private_fsm::ifsm_state_helper<>::Self_Transition;
362
363#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
364 template <typename, typename, etl::fsm_state_id_t, typename...>
365 friend class fsm_state;
366#else
367 /*[[[cog
368 import cog
369 cog.outl(" template <typename, typename, etl::fsm_state_id_t,")
370 cog.out(" ")
371 for n in range(1, int(Handlers)):
372 cog.out("typename, ")
373 if n % 4 == 0:
374 cog.outl("")
375 cog.out(" ")
376 cog.outl("typename>")
377 ]]]*/
378 /*[[[end]]]*/
379 friend class etl::fsm_state;
380#endif
381
382 //*******************************************
384 //*******************************************
386 {
387 return state_id;
388 }
389
390 //*******************************************
393 //*******************************************
395 {
396 ETL_ASSERT(state.p_parent == ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
397 state.p_parent = this;
398
399 if (p_default_child == ETL_NULLPTR)
400 {
401 p_default_child = &state;
402 }
403 }
404
405 //*******************************************
408 //*******************************************
409 template <typename TSize>
410 void set_child_states(etl::ifsm_state** state_list, TSize size)
411 {
412 p_active_child = ETL_NULLPTR;
413 p_default_child = ETL_NULLPTR;
414
415 for (TSize i = 0; i < size; ++i)
416 {
417 ETL_ASSERT(state_list[i] != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
418 add_child_state(*state_list[i]);
419 }
420 }
421
422 protected:
423
424 //*******************************************
426 //*******************************************
428 : state_id(state_id_),
429 p_context(ETL_NULLPTR),
430 p_parent(ETL_NULLPTR),
431 p_active_child(ETL_NULLPTR),
432 p_default_child(ETL_NULLPTR)
433 {
434 }
435
436 //*******************************************
438 //*******************************************
439 virtual ~ifsm_state()
440 {
441 }
442
443 //*******************************************
444 etl::fsm& get_fsm_context() const
445 {
446 return *p_context;
447 }
448
449 private:
450
451 virtual fsm_state_id_t process_event(const etl::imessage& message) = 0;
452
453 virtual fsm_state_id_t on_enter_state() { return No_State_Change; } // By default, do nothing.
454 virtual void on_exit_state() {} // By default, do nothing.
455
456 //*******************************************
457 void set_fsm_context(etl::fsm& context)
458 {
459 p_context = &context;
460 }
461
462 // The state id.
463 const etl::fsm_state_id_t state_id;
464
465 // A pointer to the FSM context.
466 etl::fsm* p_context;
467
468 // A pointer to the parent.
469 ifsm_state* p_parent;
470
471 // A pointer to the active child.
472 ifsm_state* p_active_child;
473
474 // A pointer to the default active child.
475 ifsm_state* p_default_child;
476
477 // Disabled.
478 ifsm_state(const ifsm_state&) ETL_DELETE;
479 ifsm_state& operator =(const ifsm_state&) ETL_DELETE;
480 };
481
482 //***************************************************************************
484 //***************************************************************************
485 class fsm : public etl::imessage_router
486 {
487 public:
488
489 friend class etl::hfsm;
490 using imessage_router::receive;
491
492 //*******************************************
494 //*******************************************
495 fsm(etl::message_router_id_t id)
496 : imessage_router(id)
497 , p_state(ETL_NULLPTR)
498 , state_list(ETL_NULLPTR)
499 , number_of_states(0U)
500 , is_processing_state_change(false)
501 {
502 }
503
504 //*******************************************
507 //*******************************************
508 template <typename TSize>
509 void set_states(etl::ifsm_state** p_states, TSize size)
510 {
511 state_list = p_states;
512 number_of_states = etl::fsm_state_id_t(size);
513
514 ETL_ASSERT(number_of_states > 0, ETL_ERROR(etl::fsm_state_list_exception));
515 ETL_ASSERT(number_of_states < ifsm_state::No_State_Change, ETL_ERROR(etl::fsm_state_list_exception));
516
517 for (etl::fsm_state_id_t i = 0; i < size; ++i)
518 {
519 ETL_ASSERT(state_list[i] != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
520 ETL_ASSERT(state_list[i]->get_state_id() == i, ETL_ERROR(etl::fsm_state_list_order_exception));
521 state_list[i]->set_fsm_context(*this);
522 }
523 }
524
525#if ETL_USING_CPP11
526 //*******************************************
529 //*******************************************
530 template <typename... TStates>
531 void set_states(etl::fsm_state_pack<TStates...>& state_pack)
532 {
533 state_list = state_pack.get_state_list();
534 number_of_states = etl::fsm_state_id_t(state_pack.size());
535
536 for (etl::fsm_state_id_t i = 0; i < number_of_states; ++i)
537 {
538 state_list[i]->set_fsm_context(*this);
539 }
540 }
541#endif
542
543 //*******************************************
548 //*******************************************
549 virtual void start(bool call_on_enter_state = true)
550 {
551 private_fsm::fsm_reentrancy_guard transition_lock(is_processing_state_change);
552
553 // Can only be started once.
554 if (!is_started())
555 {
556 p_state = state_list[0];
557 ETL_ASSERT(p_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
558
559 if (call_on_enter_state)
560 {
561 etl::fsm_state_id_t next_state_id;
562 etl::ifsm_state* p_last_state;
563
564 do
565 {
566 p_last_state = p_state;
567 next_state_id = p_state->on_enter_state();
568 if (next_state_id != ifsm_state::No_State_Change)
569 {
570 ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception));
571 p_state = state_list[next_state_id];
572 }
573 } while (p_last_state != p_state);
574 }
575 }
576 }
577
578 //*******************************************
580 //*******************************************
581 void receive(const etl::imessage& message) ETL_OVERRIDE
582 {
583 private_fsm::fsm_reentrancy_guard transition_lock(is_processing_state_change);
584
585 if (is_started())
586 {
587 etl::fsm_state_id_t next_state_id = p_state->process_event(message);
588
589 process_state_change(next_state_id);
590 }
591 else
592 {
593 ETL_ASSERT_FAIL(ETL_ERROR(etl::fsm_not_started));
594 }
595 }
596
597 //*******************************************
599 //*******************************************
601 {
602 private_fsm::fsm_reentrancy_guard transition_lock(is_processing_state_change);
603
604 if (is_started())
605 {
606 return process_state_change(new_state_id);
607 }
608 else
609 {
610 return ifsm_state::No_State_Change;
611 }
612 }
613
614 using imessage_router::accepts;
615
616 //*******************************************
619 //*******************************************
620 bool accepts(etl::message_id_t) const ETL_OVERRIDE
621 {
622 return true;
623 }
624
625 //*******************************************
627 //*******************************************
629 {
630 ETL_ASSERT(p_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
631 return p_state->get_state_id();
632 }
633
634 //*******************************************
636 //*******************************************
638 {
639 ETL_ASSERT(p_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
640 return *p_state;
641 }
642
643 //*******************************************
645 //*******************************************
646 const ifsm_state& get_state() const
647 {
648 ETL_ASSERT(p_state != ETL_NULLPTR, ETL_ERROR(etl::fsm_null_state_exception));
649 return *p_state;
650 }
651
652 //*******************************************
654 //*******************************************
655 bool is_started() const
656 {
657 return p_state != ETL_NULLPTR;
658 }
659
660 //*******************************************
663 //*******************************************
664 virtual void reset(bool call_on_exit_state = false)
665 {
666 private_fsm::fsm_reentrancy_guard transition_lock(is_processing_state_change);
667
668 if (is_started() && call_on_exit_state)
669 {
670 p_state->on_exit_state();
671 }
672
673 p_state = ETL_NULLPTR;
674 }
675
676 //********************************************
677 ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE
678 {
679 return false;
680 }
681
682 //********************************************
683 bool is_producer() const ETL_OVERRIDE
684 {
685 return true;
686 }
687
688 //********************************************
689 bool is_consumer() const ETL_OVERRIDE
690 {
691 return true;
692 }
693
694 private:
695
696 //********************************************
697 bool have_changed_state(etl::fsm_state_id_t next_state_id) const
698 {
699 return (next_state_id != p_state->get_state_id()) &&
700 (next_state_id != ifsm_state::No_State_Change) &&
701 (next_state_id != ifsm_state::Self_Transition);
702 }
703
704 //********************************************
705 bool is_self_transition(etl::fsm_state_id_t next_state_id) const
706 {
707 return (next_state_id == ifsm_state::Self_Transition);
708 }
709
710 //*******************************************
712 //*******************************************
713 virtual etl::fsm_state_id_t process_state_change(etl::fsm_state_id_t next_state_id)
714 {
715 if (is_self_transition(next_state_id))
716 {
717 p_state->on_exit_state();
718 next_state_id = p_state->on_enter_state();
719 }
720
721 if (have_changed_state(next_state_id))
722 {
723 ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
724 etl::ifsm_state* p_next_state = state_list[next_state_id];
725
726 do
727 {
728 p_state->on_exit_state();
729 p_state = p_next_state;
730
731 next_state_id = p_state->on_enter_state();
732
733 if (have_changed_state(next_state_id))
734 {
735 ETL_ASSERT_OR_RETURN_VALUE(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception), p_state->get_state_id());
736 p_next_state = state_list[next_state_id];
737 }
738 } while (p_next_state != p_state); // Have we changed state again?
739 }
740
741 return p_state->get_state_id();
742 }
743
744 etl::ifsm_state* p_state;
745 etl::ifsm_state** state_list;
746 etl::fsm_state_id_t number_of_states;
747 bool is_processing_state_change;
748 };
749
750 //*************************************************************************************************
751 // For C++17 and above.
752 //*************************************************************************************************
753#if ETL_USING_CPP17 && !defined(ETL_FSM_FORCE_CPP03_IMPLEMENTATION) // For C++17 and above
754 //***************************************************************************
755 // The definition for all types.
756 //***************************************************************************
757 template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
758 class fsm_state : public ifsm_state
759 {
760 public:
761
762 static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;
763
764 fsm_state()
765 : ifsm_state(STATE_ID)
766 {
767 }
768
769 protected:
770
771 ~fsm_state()
772 {
773 }
774
775 TContext& get_fsm_context() const
776 {
777 return static_cast<TContext&>(ifsm_state::get_fsm_context());
778 }
779
780 private:
781
782 //********************************************
783 struct result_t
784 {
785 bool was_handled;
786 etl::fsm_state_id_t state_id;
787 };
788
789 //********************************************
790 etl::fsm_state_id_t process_event(const etl::imessage& message)
791 {
792 etl::fsm_state_id_t new_state_id;
793
794 const bool was_handled = (process_event_type<TMessageTypes>(message, new_state_id) || ...);
795
796 if (!was_handled || (new_state_id == Pass_To_Parent))
797 {
798 new_state_id = (p_parent != nullptr) ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);
799 }
800
801 return new_state_id;
802 }
803
804 //********************************************
805 template <typename TMessage>
806 bool process_event_type(const etl::imessage& msg, etl::fsm_state_id_t& new_state_id)
807 {
808 if (TMessage::ID == msg.get_message_id())
809 {
810 new_state_id = static_cast<TDerived*>(this)->on_event(static_cast<const TMessage&>(msg));
811 return true;
812 }
813 else
814 {
815 return false;
816 }
817 }
818 };
819
821 template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, typename... TMessageTypes>
822 ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, TMessageTypes...>::STATE_ID;
823
824#else
825//*************************************************************************************************
826// For C++14 and below.
827//*************************************************************************************************
828 /*[[[cog
829 import cog
830 ################################################
831 # The first definition for all of the events.
832 ################################################
833 cog.outl("//***************************************************************************")
834 cog.outl("// The definition for all %s message types." % Handlers)
835 cog.outl("//***************************************************************************")
836 cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
837 cog.out(" ")
838 for n in range(1, int(Handlers)):
839 cog.out("typename T%s = void, " % n)
840 if n % 4 == 0:
841 cog.outl("")
842 cog.out(" ")
843 cog.outl("typename T%s = void>" % Handlers)
844 cog.outl("class fsm_state : public ifsm_state")
845 cog.outl("{")
846 cog.outl("public:")
847 cog.outl("")
848 cog.outl(" static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;")
849 cog.outl("")
850 cog.outl(" fsm_state()")
851 cog.outl(" : ifsm_state(STATE_ID)")
852 cog.outl(" {")
853 cog.outl(" }")
854 cog.outl("")
855 cog.outl("protected:")
856 cog.outl("")
857 cog.outl(" ~fsm_state()")
858 cog.outl(" {")
859 cog.outl(" }")
860 cog.outl("")
861 cog.outl(" TContext& get_fsm_context() const")
862 cog.outl(" {")
863 cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());")
864 cog.outl(" }")
865 cog.outl("")
866 cog.outl("private:")
867 cog.outl("")
868 cog.outl(" etl::fsm_state_id_t process_event(const etl::imessage& message)")
869 cog.outl(" {")
870 cog.outl(" etl::fsm_state_id_t new_state_id;")
871 cog.outl(" etl::message_id_t event_id = message.get_message_id();")
872 cog.outl("")
873 cog.outl(" switch (event_id)")
874 cog.outl(" {")
875 for n in range(1, int(Handlers) + 1):
876 cog.out(" case T%d::ID:" % n)
877 cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(static_cast<const T%d&>(message));" % n)
878 cog.outl(" break;")
879 cog.out(" default:")
880 cog.out(" new_state_id = p_parent ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);")
881 cog.outl(" break;")
882 cog.outl(" }")
883 cog.outl("")
884 cog.outl(" return (new_state_id != Pass_To_Parent) ? new_state_id : (p_parent ? p_parent->process_event(message) : No_State_Change);")
885 cog.outl(" }")
886 cog.outl("};")
887
888 ####################################
889 # All of the other specialisations.
890 ####################################
891 for n in range(int(Handlers) - 1, 0, -1):
892 cog.outl("")
893 cog.outl("//***************************************************************************")
894 if n == 1:
895 cog.outl("// Specialisation for %d message type." % n)
896 else:
897 cog.outl("// Specialisation for %d message types." % n)
898 cog.outl("//***************************************************************************")
899 cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
900 cog.out(" ")
901 for t in range(1, n):
902 cog.out("typename T%d, " % t)
903 if t % 4 == 0:
904 cog.outl("")
905 cog.out(" ")
906 cog.outl("typename T%d>" % n)
907 cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
908 for t in range(1, n + 1):
909 cog.out("T%d, " % t)
910 if t % 16 == 0:
911 cog.outl("")
912 cog.out(" ")
913 for t in range(n + 1, int(Handlers)):
914 cog.out("void, ")
915 if t % 16 == 0:
916 cog.outl("")
917 cog.out(" ")
918 cog.outl("void> : public ifsm_state")
919 cog.outl("{")
920 cog.outl("public:")
921 cog.outl("")
922 cog.outl(" static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;")
923 cog.outl("")
924 cog.outl(" fsm_state()")
925 cog.outl(" : ifsm_state(STATE_ID)")
926 cog.outl(" {")
927 cog.outl(" }")
928 cog.outl("")
929 cog.outl("protected:")
930 cog.outl("")
931 cog.outl(" ~fsm_state()")
932 cog.outl(" {")
933 cog.outl(" }")
934 cog.outl("")
935 cog.outl(" TContext& get_fsm_context() const")
936 cog.outl(" {")
937 cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());")
938 cog.outl(" }")
939 cog.outl("")
940 cog.outl("private:")
941 cog.outl("")
942 cog.outl(" etl::fsm_state_id_t process_event(const etl::imessage& message)")
943 cog.outl(" {")
944 cog.outl(" etl::fsm_state_id_t new_state_id;")
945 cog.outl(" etl::message_id_t event_id = message.get_message_id();")
946 cog.outl("")
947 cog.outl(" switch (event_id)")
948 cog.outl(" {")
949 for n in range(1, n + 1):
950 cog.out(" case T%d::ID:" % n)
951 cog.out(" new_state_id = static_cast<TDerived*>(this)->on_event(static_cast<const T%d&>(message));" % n)
952 cog.outl(" break;")
953 cog.out(" default:")
954 cog.out(" new_state_id = p_parent ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);")
955 cog.outl(" break;")
956 cog.outl(" }")
957 cog.outl("")
958 cog.outl(" return (new_state_id != Pass_To_Parent) ? new_state_id : (p_parent ? p_parent->process_event(message) : No_State_Change);")
959 cog.outl(" }")
960 cog.outl("};")
961 ####################################
962 # Specialisation for zero messages.
963 ####################################
964 cog.outl("")
965 cog.outl("//***************************************************************************")
966 cog.outl("// Specialisation for 0 message types.")
967 cog.outl("//***************************************************************************")
968 cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_>")
969 cog.out("class fsm_state<TContext, TDerived, STATE_ID_, ")
970 for t in range(1, int(Handlers)):
971 cog.out("void, ")
972 if t % 16 == 0:
973 cog.outl("")
974 cog.out(" ")
975 cog.outl("void> : public ifsm_state")
976 cog.outl("{")
977 cog.outl("public:")
978 cog.outl("")
979 cog.outl(" static ETL_CONSTANT etl::fsm_state_id_t STATE_ID = STATE_ID_;")
980 cog.outl("")
981 cog.outl(" fsm_state()")
982 cog.outl(" : ifsm_state(STATE_ID)")
983 cog.outl(" {")
984 cog.outl(" }")
985 cog.outl("")
986 cog.outl("protected:")
987 cog.outl("")
988 cog.outl(" ~fsm_state()")
989 cog.outl(" {")
990 cog.outl(" }")
991 cog.outl("")
992 cog.outl(" TContext& get_fsm_context() const")
993 cog.outl(" {")
994 cog.outl(" return static_cast<TContext&>(ifsm_state::get_fsm_context());")
995 cog.outl(" }")
996 cog.outl("private:")
997 cog.outl("")
998 cog.outl(" etl::fsm_state_id_t process_event(const etl::imessage& message)")
999 cog.outl(" {")
1000 cog.outl(" return p_parent ? p_parent->process_event(message) : static_cast<TDerived*>(this)->on_event_unknown(message);")
1001 cog.outl(" }")
1002 cog.outl("};")
1003
1004 cog.outl("")
1005 cog.outl("template <typename TContext, typename TDerived, etl::fsm_state_id_t STATE_ID_, ")
1006 cog.out(" ")
1007 for n in range(1, int(Handlers)):
1008 cog.out("typename T%s, " % n)
1009 if n % 4 == 0:
1010 cog.outl("")
1011 cog.out(" ")
1012 cog.outl("typename T%s>" % Handlers)
1013 cog.out("ETL_CONSTANT etl::fsm_state_id_t fsm_state<TContext, TDerived, STATE_ID_, ")
1014 for n in range(1, int(Handlers)):
1015 cog.out("T%s, " % n)
1016 cog.outl("T%s>::STATE_ID;" % Handlers)
1017 ]]]*/
1018 /*[[[end]]]*/
1019#endif
1020}
1021
1022#include "private/minmax_pop.h"
1023
1024#endif
Base exception class for FSM.
Definition fsm.h:102
Exception for message received but not started.
Definition fsm.h:167
Exception for null state pointer.
Definition fsm.h:115
Exception for call to receive/start/etc. while receive/start/etc. is already happening....
Definition fsm.h:180
Exception for invalid state id.
Definition fsm.h:128
Exception for incompatible state list.
Definition fsm.h:141
Exception for incompatible order state list.
Definition fsm.h:154
Definition fsm.h:811
The FSM class.
Definition fsm.h:460
etl::fsm_state_id_t get_state_id() const
Gets the current state id.
Definition fsm.h:602
void receive(const etl::imessage &message) ETL_OVERRIDE
Top level message handler for the FSM.
Definition fsm_generator.h:581
virtual void start(bool call_on_enter_state=true)
Starts the FSM. Can only be called once. Subsequent calls will do nothing.
Definition fsm_generator.h:549
fsm(etl::message_router_id_t id)
Constructor.
Definition fsm_generator.h:495
virtual void reset(bool call_on_exit_state=false)
Reset the FSM to pre-started state.
Definition fsm_generator.h:664
bool accepts(etl::message_id_t) const ETL_OVERRIDE
Does this FSM accept the message id? Yes, it accepts everything!
Definition fsm_generator.h:620
etl::fsm_state_id_t transition_to(etl::fsm_state_id_t new_state_id)
Invoke a state transition.
Definition fsm_generator.h:600
void set_states(etl::ifsm_state **p_states, TSize size)
Set the states for the FSM From a pointer to etl::ifsm_state and size.
Definition fsm_generator.h:509
const ifsm_state & get_state() const
Gets a const reference to the current state interface.
Definition fsm_generator.h:646
ifsm_state & get_state()
Gets a reference to the current state interface.
Definition fsm_generator.h:637
bool is_started() const
Checks if the FSM has been started.
Definition fsm.h:629
Definition hfsm.h:42
Interface class for FSM states.
Definition fsm.h:333
void add_child_state(etl::ifsm_state &state)
Adds a child to this state. Only of use when part of an HFSM.
Definition fsm_generator.h:394
void set_child_states(etl::ifsm_state **state_list, TSize size)
Adds a list of child states. Only of use when part of an HFSM.
Definition fsm_generator.h:410
etl::fsm_state_id_t get_state_id() const
Gets the id for this state.
Definition fsm_generator.h:385
ifsm_state(etl::fsm_state_id_t state_id_)
Constructor.
Definition fsm_generator.h:427
virtual ~ifsm_state()
Destructor.
Definition fsm_generator.h:439
friend class etl::fsm
Allows ifsm_state functions to be private.
Definition fsm.h:337
Definition message.h:73
Definition message.h:91
RAII detection mechanism to catch reentrant calls to methods that might transition the state machine ...
Definition fsm.h:232
~fsm_reentrancy_guard() ETL_NOEXCEPT
Destructor. Releases lock on reentrancy.
Definition fsm_generator.h:268
fsm_reentrancy_guard(bool &transition_guard_flag)
Constructor. Checks if another method has locked reentrancy.
Definition fsm_generator.h:257
#define ETL_ASSERT(b, e)
Definition error_handler.h:356
Definition exception.h:47
bitset_ext
Definition absolute.h:39
uint_least8_t message_id_t
Allow alternative type for message id.
Definition message_types.h:40
ETL_CONSTEXPR TContainer::size_type size(const TContainer &container)
Definition iterator.h:1187
T & get(array< T, Size > &a)
Definition array.h:1216
uint_least8_t fsm_state_id_t
Allow alternative type for state id.
Definition fsm.h:78