... | ... | @@ -54,7 +54,7 @@ By handling these two events, actions to be performed on entry/exit from a state |
|
|
|
|
|
You can find the complete implementation of the FSM class in `src/shared/events/FSM.h`.
|
|
|
|
|
|
## Example
|
|
|
## Example 1
|
|
|
This example implements the following very simple finite state machine behavior:
|
|
|
|
|
|

|
... | ... | @@ -220,9 +220,148 @@ int main() |
|
|
|
|
|
#### Output
|
|
|
|
|
|
```sh
|
|
|
```
|
|
|
0.12> S1: EV_1
|
|
|
0.22> S1: EV_2 ---> S2
|
|
|
0.32> S2: EV_2
|
|
|
1.42> S2: EV_1 ---> S1
|
|
|
```
|
|
|
|
|
|
## Example 2 - Timeouts
|
|
|
There exist situations in which we want to trigger a transition from a state to another after a timeout elapses.
|
|
|
This can be done via delayed events.
|
|
|
|
|
|
#### MyFSM.h
|
|
|
```cpp
|
|
|
#pragma once
|
|
|
|
|
|
#include "events/HSM.h"
|
|
|
#include "events/EventBroker.h"
|
|
|
|
|
|
enum ExampleEvents : uint8_t
|
|
|
{
|
|
|
EV_1 = EV_FIRST_SIGNAL,
|
|
|
EV_2
|
|
|
};
|
|
|
|
|
|
enum ExampleTopics : uint8_t
|
|
|
{
|
|
|
TOPIC_1
|
|
|
};
|
|
|
|
|
|
class MyFSM : public FSM<MyFSM>
|
|
|
{
|
|
|
public:
|
|
|
MyFSM() : FSM(&MyFSM::state_S1)
|
|
|
{
|
|
|
sEventBroker->subscribe(this, TOPIC_1);
|
|
|
}
|
|
|
|
|
|
~MyFSM()
|
|
|
{
|
|
|
sEventBroker->unsubscribe(this);
|
|
|
}
|
|
|
|
|
|
void state_S1(const Event& ev)
|
|
|
{
|
|
|
switch (ev.sig)
|
|
|
{
|
|
|
case EV_ENTRY:
|
|
|
case EV_EXIT:
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
case EV_1:
|
|
|
{
|
|
|
TRACE("S1 : EV_1 (start timer, post delayed EV_2) \n");
|
|
|
const unsigned int TIMEOUT = 1000; // in milliseconds
|
|
|
// post delayed event and store the event id
|
|
|
delayed_event_id =
|
|
|
sEventBroker->postDelayed<TIMEOUT>({EV_2}, TOPIC_1);
|
|
|
break;
|
|
|
}
|
|
|
case EV_2:
|
|
|
{
|
|
|
TRACE("S1 : EV_2 (timeout) ---> S2 \n");
|
|
|
transition(&MyFSM::state_S2);
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
last_event = ev.sig;
|
|
|
}
|
|
|
|
|
|
void state_S2(const Event& ev)
|
|
|
{
|
|
|
switch (ev.sig)
|
|
|
{
|
|
|
case EV_ENTRY:
|
|
|
{
|
|
|
TRACE("S2 : EV_ENTRY (remove delayed EV_2) \n");
|
|
|
// if it's not needed, remove the delayed event
|
|
|
sEventBroker->removeDelayed(delayed_event_id);
|
|
|
break;
|
|
|
}
|
|
|
case EV_EXIT:
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
|
{
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
last_event = ev.sig;
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
uint8_t delayed_event_id = 0;
|
|
|
uint8_t last_event = 0;
|
|
|
};
|
|
|
```
|
|
|
#### test-fsm.cpp
|
|
|
```cpp
|
|
|
#include <Common.h>
|
|
|
#include "MyFSM.h"
|
|
|
|
|
|
using namespace miosix;
|
|
|
|
|
|
int main()
|
|
|
{
|
|
|
EventBroker* broker = EventBroker::getInstance(); // singleton object
|
|
|
broker->start();
|
|
|
|
|
|
MyFSM fsm;
|
|
|
|
|
|
if (fsm.start())
|
|
|
{
|
|
|
// trigger post ov delayed event (timer)
|
|
|
// when the timer elapsed EV_2 is posted
|
|
|
// and the FSM moves to state S2
|
|
|
broker->post(Event{EV_1}, TOPIC_1);
|
|
|
|
|
|
// wait for the delayed event to be posted
|
|
|
// before stopping the active objects
|
|
|
Thread::sleep(2000);
|
|
|
|
|
|
fsm.stop();
|
|
|
broker->stop();
|
|
|
}
|
|
|
else {
|
|
|
TRACE("Failed to start MyFSM\n");
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
```
|
|
|
#### Output
|
|
|
```
|
|
|
0.12> S1 : EV_1 (start timer, post delayed EV_2)
|
|
|
1.15> S1 : EV_2 (timeout) ---> S2
|
|
|
1.17> S2 : EV_ENTRY (remove delayed EV_2)
|
|
|
``` |
|
|
\ No newline at end of file |