Embedded Template Library 1.0
Loading...
Searching...
No Matches
state_chart.h
1/******************************************************************************
2The MIT License(MIT)
3
4Embedded Template Library.
5https://github.com/ETLCPP/etl
6https://www.etlcpp.com
7
8Copyright(c) 2018 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#ifndef ETL_STATE_CHART_INCLUDED
30#define ETL_STATE_CHART_INCLUDED
31
32#include "platform.h"
33#include "array.h"
34#include "array_view.h"
35#include "nullptr.h"
36#include "utility.h"
37
38#include <stdint.h>
39
40namespace etl
41{
42 //***************************************************************************
44 //***************************************************************************
45
47 {
48 typedef uint_least8_t state_id_t;
49 typedef uint_least8_t event_id_t;
50
51 //*************************************************************************
53 //*************************************************************************
54 template <typename TObject, typename TParameter = void>
55 struct transition
56 {
57 ETL_CONSTEXPR transition(const state_id_t current_state_id_, event_id_t event_id_, const state_id_t next_state_id_,
58 void (TObject::*const action_)(TParameter) = ETL_NULLPTR, bool (TObject::*const guard_)() = ETL_NULLPTR)
59 : current_state_id(current_state_id_)
60 , event_id(event_id_)
61 , next_state_id(next_state_id_)
62 , action(action_)
63 , guard(guard_)
64 , from_any_state(false)
65 {
66 }
67
68 ETL_CONSTEXPR transition(event_id_t event_id_, const state_id_t next_state_id_, void (TObject::*const action_)(TParameter) = ETL_NULLPTR,
69 bool (TObject::*const guard_)() = ETL_NULLPTR)
70 : current_state_id(0)
71 , event_id(event_id_)
72 , next_state_id(next_state_id_)
73 , action(action_)
74 , guard(guard_)
75 , from_any_state(true)
76 {
77 }
78
79 const state_id_t current_state_id;
80 const event_id_t event_id;
81 const state_id_t next_state_id;
82 void (TObject::*const action)(TParameter);
83 bool (TObject::*const guard)();
84 const bool from_any_state;
85 };
86
87 //*************************************************************************
90 //*************************************************************************
91 template <typename TObject>
92 struct transition<TObject, void>
93 {
94 ETL_CONSTEXPR transition(const state_id_t current_state_id_, event_id_t event_id_, const state_id_t next_state_id_,
95 void (TObject::*const action_)() = ETL_NULLPTR, bool (TObject::*const guard_)() = ETL_NULLPTR)
96 : current_state_id(current_state_id_)
97 , event_id(event_id_)
98 , next_state_id(next_state_id_)
99 , action(action_)
100 , guard(guard_)
101 , from_any_state(false)
102 {
103 }
104
105 ETL_CONSTEXPR transition(event_id_t event_id_, const state_id_t next_state_id_, void (TObject::*const action_)() = ETL_NULLPTR,
106 bool (TObject::*const guard_)() = ETL_NULLPTR)
107 : current_state_id(0)
108 , event_id(event_id_)
109 , next_state_id(next_state_id_)
110 , action(action_)
111 , guard(guard_)
112 , from_any_state(true)
113 {
114 }
115
116 const state_id_t current_state_id;
117 const event_id_t event_id;
118 const state_id_t next_state_id;
119 void (TObject::*const action)();
120 bool (TObject::*const guard)();
121 const bool from_any_state;
122 };
123
124 //*************************************************************************
126 //*************************************************************************
127 template <typename TObject>
128 struct state
129 {
130 ETL_CONSTEXPR state(const state_id_t state_id_, void (TObject::*const on_entry_)() = ETL_NULLPTR, void (TObject::*const on_exit_)() = ETL_NULLPTR)
131 : state_id(state_id_)
132 , on_entry(on_entry_)
133 , on_exit(on_exit_)
134 {
135 }
136
137 state_id_t state_id;
138 void (TObject::*const on_entry)();
139 void (TObject::*const on_exit)();
140 };
141 } // namespace state_chart_traits
142
143 //***************************************************************************
145 //***************************************************************************
146 template <typename TParameter>
147 class istate_chart
148 {
149 public:
150
151 typedef TParameter parameter_t;
152 typedef state_chart_traits::state_id_t state_id_t;
153 typedef state_chart_traits::event_id_t event_id_t;
154
155 istate_chart(state_id_t initial_state_id)
156 : current_state_id(initial_state_id)
157 {
158 }
159
160 virtual void start(bool on_entry_initial = true) = 0;
161 virtual void process_event(event_id_t, parameter_t) = 0;
162 virtual ~istate_chart() {}
163
164 //*************************************************************************
167 //*************************************************************************
168 state_id_t get_state_id() const
169 {
170 return current_state_id;
171 }
172
173 protected:
174
175 state_id_t current_state_id;
176 };
177
178 //***************************************************************************
180 //***************************************************************************
181 template <>
182 class istate_chart<void>
183 {
184 public:
185
186 typedef void parameter_t;
187 typedef state_chart_traits::state_id_t state_id_t;
188 typedef state_chart_traits::event_id_t event_id_t;
189
190 istate_chart(state_id_t initial_state_id)
191 : current_state_id(initial_state_id)
192 {
193 }
194
195 virtual void process_event(event_id_t) = 0;
196 virtual void start(bool on_entry_initial = true) = 0;
197 virtual ~istate_chart() {}
198
199 //*************************************************************************
202 //*************************************************************************
203 state_id_t get_state_id() const
204 {
205 return current_state_id;
206 }
207
208 protected:
209
210 state_id_t current_state_id;
211 };
212
213 //***************************************************************************
217 //***************************************************************************
218 template <typename TObject, TObject& TObject_Ref, const etl::state_chart_traits::transition<TObject, void>* Transition_Table_Begin,
219 size_t Transition_Table_Size, const etl::state_chart_traits::state<TObject>* State_Table_Begin, size_t State_Table_Size,
220 etl::state_chart_traits::state_id_t Initial_State>
221 class state_chart_ct : public istate_chart<void>
222 {
223 public:
224
225 typedef void parameter_t;
226 typedef state_chart_traits::state_id_t state_id_t;
227 typedef state_chart_traits::event_id_t event_id_t;
230
231 //*************************************************************************
233 //*************************************************************************
234 ETL_CONSTEXPR state_chart_ct()
235 : istate_chart<void>(Initial_State)
236 , started(false)
237 {
238 }
239
240 //*************************************************************************
243 //*************************************************************************
244 TObject& get_object()
245 {
246 return TObject_Ref;
247 }
248
249 //*************************************************************************
252 //*************************************************************************
253 const TObject& get_object() const
254 {
255 return TObject_Ref;
256 }
257
258 //*************************************************************************
260 //*************************************************************************
261 virtual void start(bool on_entry_initial = true) ETL_OVERRIDE
262 {
263 if (!started)
264 {
265 if (on_entry_initial)
266 {
267 // See if we have a state item for the initial state.
268 const state* s = find_state(this->current_state_id);
269
270 // If the initial state has an 'on_entry' then call it.
271 if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR))
272 {
273 (TObject_Ref.*(s->on_entry))();
274 }
275 }
276
277 started = true;
278 }
279 }
280
281 //*************************************************************************
286 //*************************************************************************
287 virtual void process_event(event_id_t event_id) ETL_OVERRIDE
288 {
289 if (started)
290 {
291 const transition* t = Transition_Table_Begin;
292
293 // Keep looping until we execute a transition or reach the end of the
294 // table.
295 while (t != (Transition_Table_Begin + Transition_Table_Size))
296 {
297 // Scan the transition table from the latest position.
298 t = etl::find_if(t, (Transition_Table_Begin + Transition_Table_Size), is_transition(event_id, this->current_state_id));
299
300 // Found an entry?
301 if (t != (Transition_Table_Begin + Transition_Table_Size))
302 {
303 // Shall we execute the transition?
304 if ((t->guard == ETL_NULLPTR) || ((TObject_Ref.*t->guard)()))
305 {
306 // Shall we execute the action?
307 if (t->action != ETL_NULLPTR)
308 {
309 (TObject_Ref.*t->action)();
310 }
311
312 // Changing state?
313 if (this->current_state_id != t->next_state_id)
314 {
315 const state* s;
316
317 // See if we have a state item for the current state.
318 s = find_state(this->current_state_id);
319
320 // If the current state has an 'on_exit' then call it.
321 if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_exit != ETL_NULLPTR))
322 {
323 (TObject_Ref.*(s->on_exit))();
324 }
325
326 this->current_state_id = t->next_state_id;
327
328 // See if we have a state item for the new state.
329 s = find_state(this->current_state_id);
330
331 // If the new state has an 'on_entry' then call it.
332 if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR))
333 {
334 (TObject_Ref.*(s->on_entry))();
335 }
336 }
337
338 t = (Transition_Table_Begin + Transition_Table_Size);
339 }
340 else
341 {
342 // Start the search from the next item in the table.
343 ++t;
344 }
345 }
346 }
347 }
348 }
349
350 private:
351
352 //*************************************************************************
355 //*************************************************************************
356 const state* find_state(state_id_t state_id)
357 {
358 return etl::find_if(State_Table_Begin, State_Table_Begin + State_Table_Size, is_state(state_id));
359 }
360
361 //*************************************************************************
362 struct is_transition
363 {
364 is_transition(event_id_t event_id_, state_id_t state_id_)
365 : event_id(event_id_)
366 , state_id(state_id_)
367 {
368 }
369
370 bool operator()(const transition& t) const
371 {
372 return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id));
373 }
374
375 const event_id_t event_id;
376 const state_id_t state_id;
377 };
378
379 //*************************************************************************
380 struct is_state
381 {
382 is_state(state_id_t state_id_)
383 : state_id(state_id_)
384 {
385 }
386
387 bool operator()(const state& s) const
388 {
389 return (s.state_id == state_id);
390 }
391
392 const state_id_t state_id;
393 };
394
395 // Disabled
396 state_chart_ct(const state_chart_ct&) ETL_DELETE;
397 state_chart_ct& operator=(const state_chart_ct&) ETL_DELETE;
398
399 bool started;
400 };
401
402 //***************************************************************************
406 //***************************************************************************
407 template <typename TObject, typename TParameter, TObject& TObject_Ref,
408 const etl::state_chart_traits::transition<TObject, TParameter>* Transition_Table_Begin, size_t Transition_Table_Size,
409 const etl::state_chart_traits::state<TObject>* State_Table_Begin, size_t State_Table_Size,
410 etl::state_chart_traits::state_id_t Initial_State>
411 class state_chart_ctp : public istate_chart<TParameter>
412 {
413 public:
414
415 typedef TParameter parameter_t;
416 typedef state_chart_traits::state_id_t state_id_t;
417 typedef state_chart_traits::event_id_t event_id_t;
420
421 //*************************************************************************
423 //*************************************************************************
424 ETL_CONSTEXPR state_chart_ctp()
425 : istate_chart<TParameter>(Initial_State)
426 , started(false)
427 {
428 }
429
430 //*************************************************************************
433 //*************************************************************************
434 TObject& get_object()
435 {
436 return TObject_Ref;
437 }
438
439 //*************************************************************************
442 //*************************************************************************
443 const TObject& get_object() const
444 {
445 return TObject_Ref;
446 }
447
448 //*************************************************************************
450 //*************************************************************************
451 virtual void start(bool on_entry_initial = true) ETL_OVERRIDE
452 {
453 if (!started)
454 {
455 if (on_entry_initial)
456 {
457 // See if we have a state item for the initial state.
458 const state* s = find_state(this->current_state_id);
459
460 // If the initial state has an 'on_entry' then call it.
461 if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR))
462 {
463 (TObject_Ref.*(s->on_entry))();
464 }
465 }
466
467 started = true;
468 }
469 }
470
471 //*************************************************************************
476 //*************************************************************************
477 virtual void process_event(event_id_t event_id, parameter_t data) ETL_OVERRIDE
478 {
479 if (started)
480 {
481 const transition* t = Transition_Table_Begin;
482
483 // Keep looping until we execute a transition or reach the end of the
484 // table.
485 while (t != (Transition_Table_Begin + Transition_Table_Size))
486 {
487 // Scan the transition table from the latest position.
488 t = etl::find_if(t, (Transition_Table_Begin + Transition_Table_Size), is_transition(event_id, this->current_state_id));
489
490 // Found an entry?
491 if (t != (Transition_Table_Begin + Transition_Table_Size))
492 {
493 // Shall we execute the transition?
494 if ((t->guard == ETL_NULLPTR) || ((TObject_Ref.*t->guard)()))
495 {
496 // Shall we execute the action?
497 if (t->action != ETL_NULLPTR)
498 {
499#if ETL_USING_CPP11
500 (TObject_Ref.*t->action)(etl::forward<parameter_t>(data));
501#else
502 (TObject_Ref.*t->action)(data);
503#endif
504 }
505
506 // Changing state?
507 if (this->current_state_id != t->next_state_id)
508 {
509 const state* s;
510
511 // See if we have a state item for the current state.
512 s = find_state(this->current_state_id);
513
514 // If the current state has an 'on_exit' then call it.
515 if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_exit != ETL_NULLPTR))
516 {
517 (TObject_Ref.*(s->on_exit))();
518 }
519
520 this->current_state_id = t->next_state_id;
521
522 // See if we have a state item for the new state.
523 s = find_state(this->current_state_id);
524
525 // If the new state has an 'on_entry' then call it.
526 if ((s != (State_Table_Begin + State_Table_Size)) && (s->on_entry != ETL_NULLPTR))
527 {
528 (TObject_Ref.*(s->on_entry))();
529 }
530 }
531
532 t = (Transition_Table_Begin + Transition_Table_Size);
533 }
534 else
535 {
536 // Start the search from the next item in the table.
537 ++t;
538 }
539 }
540 }
541 }
542 }
543
544 private:
545
546 //*************************************************************************
549 //*************************************************************************
550 const state* find_state(state_id_t state_id)
551 {
552 return etl::find_if(State_Table_Begin, State_Table_Begin + State_Table_Size, is_state(state_id));
553 }
554
555 //*************************************************************************
556 struct is_transition
557 {
558 is_transition(event_id_t event_id_, state_id_t state_id_)
559 : event_id(event_id_)
560 , state_id(state_id_)
561 {
562 }
563
564 bool operator()(const transition& t) const
565 {
566 return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id));
567 }
568
569 const event_id_t event_id;
570 const state_id_t state_id;
571 };
572
573 //*************************************************************************
574 struct is_state
575 {
576 is_state(state_id_t state_id_)
577 : state_id(state_id_)
578 {
579 }
580
581 bool operator()(const state& s) const
582 {
583 return (s.state_id == state_id);
584 }
585
586 const state_id_t state_id;
587 };
588
589 // Disabled
590 state_chart_ctp(const state_chart_ctp&) ETL_DELETE;
591 state_chart_ctp& operator=(const state_chart_ctp&) ETL_DELETE;
592
593 bool started;
594 };
595
596 //***************************************************************************
600 //***************************************************************************
601 template <typename TObject, typename TParameter = void>
602 class state_chart : public istate_chart<TParameter>
603 {
604 public:
605
606 typedef TParameter parameter_t;
607 typedef state_chart_traits::state_id_t state_id_t;
608 typedef state_chart_traits::event_id_t event_id_t;
611
612 //*************************************************************************
620 //*************************************************************************
621 ETL_CONSTEXPR state_chart(TObject& object_, const transition* transition_table_begin_, const transition* transition_table_end_,
622 const state* state_table_begin_, const state* state_table_end_, const state_id_t state_id_)
623 : istate_chart<TParameter>(state_id_)
624 , object(object_)
625 , transition_table_begin(transition_table_begin_)
626 , state_table_begin(state_table_begin_)
627 , transition_table_size(transition_table_end_ - transition_table_begin_)
628 , state_table_size(state_table_end_ - state_table_begin_)
629 , started(false)
630 {
631 }
632
633 //*************************************************************************
637 //*************************************************************************
638 void set_transition_table(const transition* transition_table_begin_, const transition* transition_table_end_)
639 {
640 transition_table_begin = transition_table_begin_;
641 transition_table_size = transition_table_end_ - transition_table_begin_;
642 }
643
644 //*************************************************************************
648 //*************************************************************************
649 void set_state_table(const state* state_table_begin_, const state* state_table_end_)
650 {
651 state_table_begin = state_table_begin_;
652 state_table_size = state_table_end_ - state_table_begin_;
653 }
654
655 //*************************************************************************
658 //*************************************************************************
659 TObject& get_object()
660 {
661 return object;
662 }
663
664 //*************************************************************************
667 //*************************************************************************
668 const TObject& get_object() const
669 {
670 return object;
671 }
672
673 //*************************************************************************
675 //*************************************************************************
676 virtual void start(bool on_entry_initial = true) ETL_OVERRIDE
677 {
678 if (!started)
679 {
680 if (on_entry_initial)
681 {
682 // See if we have a state item for the initial state.
683 const state* s = find_state(this->current_state_id);
684
685 // If the initial state has an 'on_entry' then call it.
686 if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR))
687 {
688 (object.*(s->on_entry))();
689 }
690 }
691
692 started = true;
693 }
694 }
695
696 //*************************************************************************
701 //*************************************************************************
702 void process_event(event_id_t event_id, parameter_t data) ETL_OVERRIDE
703 {
704 if (started)
705 {
706 const transition* t = transition_table_begin;
707
708 // Keep looping until we execute a transition or reach the end of the
709 // table.
710 while (t != transition_table_end())
711 {
712 // Scan the transition table from the latest position.
713 t = etl::find_if(t, transition_table_end(), is_transition(event_id, this->current_state_id));
714
715 // Found an entry?
716 if (t != transition_table_end())
717 {
718 // Shall we execute the transition?
719 if ((t->guard == ETL_NULLPTR) || ((object.*t->guard)()))
720 {
721 // Shall we execute the action?
722 if (t->action != ETL_NULLPTR)
723 {
724#if ETL_USING_CPP11
725 (object.*t->action)(etl::forward<parameter_t>(data));
726#else
727 (object.*t->action)(data);
728#endif
729 }
730
731 // Changing state?
732 if (this->current_state_id != t->next_state_id)
733 {
734 const state* s;
735
736 // See if we have a state item for the current state.
737 s = find_state(this->current_state_id);
738
739 // If the current state has an 'on_exit' then call it.
740 if ((s != state_table_end()) && (s->on_exit != ETL_NULLPTR))
741 {
742 (object.*(s->on_exit))();
743 }
744
745 this->current_state_id = t->next_state_id;
746
747 // See if we have a state item for the new state.
748 s = find_state(this->current_state_id);
749
750 // If the new state has an 'on_entry' then call it.
751 if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR))
752 {
753 (object.*(s->on_entry))();
754 }
755 }
756
757 t = transition_table_end();
758 }
759 else
760 {
761 // Start the search from the next item in the table.
762 ++t;
763 }
764 }
765 }
766 }
767 }
768
769 private:
770
771 //*************************************************************************
774 //*************************************************************************
775 const state* find_state(state_id_t state_id)
776 {
777 if (state_table_begin == ETL_NULLPTR)
778 {
779 return state_table_end();
780 }
781 else
782 {
783 return etl::find_if(state_table_begin, state_table_end(), is_state(state_id));
784 }
785 }
786
787 //*************************************************************************
788 const transition* transition_table_end() const
789 {
790 return transition_table_begin + transition_table_size;
791 }
792
793 //*************************************************************************
794 const state* state_table_end() const
795 {
796 return state_table_begin + state_table_size;
797 }
798
799 //*************************************************************************
800 struct is_transition
801 {
802 is_transition(event_id_t event_id_, state_id_t state_id_)
803 : event_id(event_id_)
804 , state_id(state_id_)
805 {
806 }
807
808 bool operator()(const transition& t) const
809 {
810 return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id));
811 }
812
813 const event_id_t event_id;
814 const state_id_t state_id;
815 };
816
817 //*************************************************************************
818 struct is_state
819 {
820 is_state(state_id_t state_id_)
821 : state_id(state_id_)
822 {
823 }
824
825 bool operator()(const state& s) const
826 {
827 return (s.state_id == state_id);
828 }
829
830 const state_id_t state_id;
831 };
832
833 // Disabled
834 state_chart(const state_chart&) ETL_DELETE;
835 state_chart& operator=(const state_chart&) ETL_DELETE;
836
837 TObject& object;
838 const transition* transition_table_begin;
839 const state* state_table_begin;
840 uint_least8_t transition_table_size;
841 uint_least8_t state_table_size;
842 bool started;
843 };
844
845 //***************************************************************************
849 //***************************************************************************
850 template <typename TObject>
851 class state_chart<TObject, void> : public istate_chart<void>
852 {
853 public:
854
855 typedef void parameter_t;
856 typedef state_chart_traits::state_id_t state_id_t;
857 typedef state_chart_traits::event_id_t event_id_t;
860
861 //*************************************************************************
869 //*************************************************************************
870 ETL_CONSTEXPR state_chart(TObject& object_, const transition* transition_table_begin_, const transition* transition_table_end_,
871 const state* state_table_begin_, const state* state_table_end_, const state_id_t state_id_)
872 : istate_chart<void>(state_id_)
873 , object(object_)
874 , transition_table_begin(transition_table_begin_)
875 , state_table_begin(state_table_begin_)
876 , transition_table_size(transition_table_end_ - transition_table_begin_)
877 , state_table_size(state_table_end_ - state_table_begin_)
878 , started(false)
879 {
880 }
881
882 //*************************************************************************
886 //*************************************************************************
887 void set_transition_table(const transition* transition_table_begin_, const transition* transition_table_end_)
888 {
889 transition_table_begin = transition_table_begin_;
890 transition_table_size = transition_table_end_ - transition_table_begin_;
891 }
892
893 //*************************************************************************
897 //*************************************************************************
898 void set_state_table(const state* state_table_begin_, const state* state_table_end_)
899 {
900 state_table_begin = state_table_begin_;
901 state_table_size = state_table_end_ - state_table_begin_;
902 }
903
904 //*************************************************************************
907 //*************************************************************************
908 TObject& get_object()
909 {
910 return object;
911 }
912
913 //*************************************************************************
916 //*************************************************************************
917 const TObject& get_object() const
918 {
919 return object;
920 }
921
922 //*************************************************************************
924 //*************************************************************************
925 virtual void start(bool on_entry_initial = true) ETL_OVERRIDE
926 {
927 if (!started)
928 {
929 if (on_entry_initial)
930 {
931 // See if we have a state item for the initial state.
932 const state* s = find_state(this->current_state_id);
933
934 // If the initial state has an 'on_entry' then call it.
935 if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR))
936 {
937 (object.*(s->on_entry))();
938 }
939 }
940
941 started = true;
942 }
943 }
944
945 //*************************************************************************
950 //*************************************************************************
951 void process_event(event_id_t event_id) ETL_OVERRIDE
952 {
953 if (started)
954 {
955 const transition* t = transition_table_begin;
956
957 // Keep looping until we execute a transition or reach the end of the
958 // table.
959 while (t != transition_table_end())
960 {
961 // Scan the transition table from the latest position.
962 t = etl::find_if(t, transition_table_end(), is_transition(event_id, this->current_state_id));
963
964 // Found an entry?
965 if (t != transition_table_end())
966 {
967 // Shall we execute the transition?
968 if ((t->guard == ETL_NULLPTR) || ((object.*t->guard)()))
969 {
970 // Shall we execute the action?
971 if (t->action != ETL_NULLPTR)
972 {
973 (object.*t->action)();
974 }
975
976 // Changing state?
977 if (this->current_state_id != t->next_state_id)
978 {
979 const state* s;
980
981 // See if we have a state item for the current state.
982 s = find_state(this->current_state_id);
983
984 // If the current state has an 'on_exit' then call it.
985 if ((s != state_table_end()) && (s->on_exit != ETL_NULLPTR))
986 {
987 (object.*(s->on_exit))();
988 }
989
990 this->current_state_id = t->next_state_id;
991
992 // See if we have a state item for the new state.
993 s = find_state(this->current_state_id);
994
995 // If the new state has an 'on_entry' then call it.
996 if ((s != state_table_end()) && (s->on_entry != ETL_NULLPTR))
997 {
998 (object.*(s->on_entry))();
999 }
1000 }
1001
1002 t = transition_table_end();
1003 }
1004 else
1005 {
1006 // Start the search from the next item in the table.
1007 ++t;
1008 }
1009 }
1010 }
1011 }
1012 }
1013
1014 private:
1015
1016 //*************************************************************************
1019 //*************************************************************************
1020 const state* find_state(state_id_t state_id)
1021 {
1022 if (state_table_begin == ETL_NULLPTR)
1023 {
1024 return state_table_end();
1025 }
1026 else
1027 {
1028 return etl::find_if(state_table_begin, state_table_end(), is_state(state_id));
1029 }
1030 }
1031
1032 //*************************************************************************
1033 const transition* transition_table_end() const
1034 {
1035 return transition_table_begin + transition_table_size;
1036 }
1037
1038 //*************************************************************************
1039 const state* state_table_end() const
1040 {
1041 return state_table_begin + state_table_size;
1042 }
1043
1044 //*************************************************************************
1045 struct is_transition
1046 {
1047 is_transition(event_id_t event_id_, state_id_t state_id_)
1048 : event_id(event_id_)
1049 , state_id(state_id_)
1050 {
1051 }
1052
1053 bool operator()(const transition& t) const
1054 {
1055 return (t.event_id == event_id) && (t.from_any_state || (t.current_state_id == state_id));
1056 }
1057
1058 const event_id_t event_id;
1059 const state_id_t state_id;
1060 };
1061
1062 //*************************************************************************
1063 struct is_state
1064 {
1065 is_state(state_id_t state_id_)
1066 : state_id(state_id_)
1067 {
1068 }
1069
1070 bool operator()(const state& s) const
1071 {
1072 return (s.state_id == state_id);
1073 }
1074
1075 const state_id_t state_id;
1076 };
1077
1078 // Disabled
1079 state_chart(const state_chart&) ETL_DELETE;
1080 state_chart& operator=(const state_chart&) ETL_DELETE;
1081
1082 TObject& object;
1083 const transition* transition_table_begin;
1084 const state* state_table_begin;
1085 uint_least8_t transition_table_size;
1086 uint_least8_t state_table_size;
1087 bool started;
1088 };
1089} // namespace etl
1090
1091#endif
state_id_t get_state_id() const
Definition state_chart.h:203
state_id_t current_state_id
The current state id.
Definition state_chart.h:210
state_id_t current_state_id
The current state id.
Definition state_chart.h:175
state_id_t get_state_id() const
Definition state_chart.h:168
ETL_CONSTEXPR state_chart(TObject &object_, const transition *transition_table_begin_, const transition *transition_table_end_, const state *state_table_begin_, const state *state_table_end_, const state_id_t state_id_)
Definition state_chart.h:870
virtual void start(bool on_entry_initial=true) ETL_OVERRIDE
Start the state chart.
Definition state_chart.h:925
void process_event(event_id_t event_id) ETL_OVERRIDE
Definition state_chart.h:951
TObject & get_object()
Definition state_chart.h:908
const TObject & get_object() const
Definition state_chart.h:917
void set_transition_table(const transition *transition_table_begin_, const transition *transition_table_end_)
Definition state_chart.h:887
void set_state_table(const state *state_table_begin_, const state *state_table_end_)
Definition state_chart.h:898
ETL_CONSTEXPR state_chart_ct()
Constructor.
Definition state_chart.h:234
const TObject & get_object() const
Definition state_chart.h:253
TObject & get_object()
Definition state_chart.h:244
virtual void start(bool on_entry_initial=true) ETL_OVERRIDE
Start the state chart.
Definition state_chart.h:261
virtual void process_event(event_id_t event_id) ETL_OVERRIDE
Definition state_chart.h:287
const TObject & get_object() const
Definition state_chart.h:443
TObject & get_object()
Definition state_chart.h:434
virtual void start(bool on_entry_initial=true) ETL_OVERRIDE
Start the state chart.
Definition state_chart.h:451
virtual void process_event(event_id_t event_id, parameter_t data) ETL_OVERRIDE
Definition state_chart.h:477
ETL_CONSTEXPR state_chart_ctp()
Constructor.
Definition state_chart.h:424
void process_event(event_id_t event_id, parameter_t data) ETL_OVERRIDE
Definition state_chart.h:702
ETL_CONSTEXPR state_chart(TObject &object_, const transition *transition_table_begin_, const transition *transition_table_end_, const state *state_table_begin_, const state *state_table_end_, const state_id_t state_id_)
Definition state_chart.h:621
TObject & get_object()
Definition state_chart.h:659
virtual void start(bool on_entry_initial=true) ETL_OVERRIDE
Start the state chart.
Definition state_chart.h:676
void set_transition_table(const transition *transition_table_begin_, const transition *transition_table_end_)
Definition state_chart.h:638
void set_state_table(const state *state_table_begin_, const state *state_table_end_)
Definition state_chart.h:649
const TObject & get_object() const
Definition state_chart.h:668
Simple Finite State Machine Types.
Definition state_chart.h:47
bitset_ext
Definition absolute.h:40
ETL_CONSTEXPR TContainer::pointer data(TContainer &container)
Definition iterator.h:1228
State definition.
Definition state_chart.h:129
Transition definition.
Definition state_chart.h:56