Git Product home page Git Product logo

tinyfsm's Introduction

TinyFSM

TinyFSM is a simple finite state machine library for C++, designed for optimal performance and low memory footprint. This makes it ideal for real-time operating systems. The concept is very simple, allowing the programmer to fully understand what is happening behind the scenes. It provides a straightforward way of mapping your state machine charts into source code.

TinyFSM basically wraps event dispatching into function calls, making event dispatching equally fast to calling (or even inlining) a function. Even in the worst case, dispatching leads to nothing more than a single vtable lookup and function call!

Key Features:

  • Entry/exit actions
  • Event actions
  • Transition functions
  • Transition conditions
  • Event payload (classes)
  • Inheritance of states and action functions

TinyFSM benefits from the C++11 template metaprogramming features like variadic templates, and does not depend on RTTI, exceptions or any external library.

Official home page: https://digint.ch/tinyfsm

Current version: 0.3.3

Installation

TinyFSM is a header-only library, no special installation steps are needed. Just point your compiler to the "include" directory.

Documentation

You can find the full documentation in the doc/ directory:

The docmentation is also available on the official home page.

Code examples

Donate

So TinyFSM has proven useful for you?

I will definitively continue to develop TinyFSM for free. If you want to support me with a donation, you are welcome to do so!

Donate

Development

The source code for TinyFSM is managed using Git:

git clone https://dev.tty0.ch/tinyfsm.git

Mirror on GitHub:

git clone https://github.com/digint/tinyfsm.git

If you would like to contribute or have found bugs, visit the TinyFSM project page on GitHub and use the issues tracker there.

Contact

For questions and suggestions regarding TinyFSM, success or failure stories, and any other kind of feedback, please feel free to contact the author (the email address can be found in the sources).

License

TinyFSM is Open Source software. It may be used for any purpose, including commercial purposes, at absolutely no cost. It is distributed under the terms of the MIT license.

tinyfsm's People

Contributors

digint avatar maxgerhardt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tinyfsm's Issues

Doesn't compile when debug information is enabled.

After enabling debug information:

#include <iostream>
#define DBG(str) do { std::cerr << str << std::endl; } while( false )
DBG("*** dbg_example *** " << __PRETTY_FUNCTION__);

the projects don't compile:

$ make
g++ -c -I ../../include -MMD -Os -std=c++11 -fno-exceptions -fno-rtti -Wall -Wextra -Wctor-dtor-privacy -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -pedantic -o motor.o motor.cpp
In file included from motor.cpp:1:
../../include/tinyfsm.hpp:46:19: error: expected unqualified-id before ‘do’
   46 |  #define DBG(str) do { std::cerr << str << std::endl; } while( false )
      |                   ^~
../../include/tinyfsm.hpp:47:2: note: in expansion of macro ‘DBG’
   47 |  DBG("*** dbg_example *** " << __PRETTY_FUNCTION__);
      |  ^~~
../../include/tinyfsm.hpp:46:57: error: expected unqualified-id before ‘while’
   46 |  #define DBG(str) do { std::cerr << str << std::endl; } while( false )
      |                                                         ^~~~~
../../include/tinyfsm.hpp:47:2: note: in expansion of macro ‘DBG’
   47 |  DBG("*** dbg_example *** " << __PRETTY_FUNCTION__);
      |  ^~~
make: *** [Makefile:90: motor.o] Error 1
$ 

Any hint?

How do you pass a SM to a function?

main()
{
MyStateMachine::start();

gatherInformation();

dispatcherAndDecisionMakingFunction(MyStateMachine );

}

Something like this is what I'd like to accomplish.

Security Disclosure Policy

Is there a security disclosure policy for tinyfsm?

If a vulnerability is found, is it posted anywhere?

State update loop

Might be a dumb question. But my understanding is that the react method of each state is used to update the current state.

Is there some way of including an update method that is called on each loop of the main program? Making it possible to perform an operation for the duration of the state?

transit<> shall be the last statement in react(), but isn't ...

The documentation says:

  1. Implement Actions and Event Reactions

In most cases, event reactions consist of one or more of the following steps:

Change some local data
Send events to other state machines
Transit to different state

Important: Make sure that the transit<>() function call is the last command executed within a reaction function!

However in elevator.cpp:

class Moving
: public Elevator
{
  void react(FloorSensor const & e) override {
    cout << "Reached floor " << e.floor << endl;

    int floor_expected = current_floor + Motor::getDirection();
    if(floor_expected != e.floor)
    {
      cout << "Floor sensor defect (expected " << floor_expected << ", got " << e.floor << ")" << endl;
      transit<Panic>(CallMaintenance);
    }

    current_floor = e.floor;
    if(e.floor == dest_floor)
      transit<Idle>();
  };
};

If the expected floor is not the reported floor it transits to Panic, still sets the current floor to the floor sensor information and might even transit to Idle.

Yeah I know it's more or less cosmetic, but to avoid to confuse newbies (like me) I'd suggest:

class Moving
: public Elevator
{
 void react(FloorSensor const & e) override {
   int floor_expected = current_floor + Motor::getDirection();
   if(floor_expected != e.floor)
   {
     cout << "Floor sensor defect (expected " << floor_expected << ", got " << e.floor << ")" << endl;
     transit<Panic>(CallMaintenance);
   }
  else
  {
     cout << "Reached floor " << e.floor << endl;
     current_floor = e.floor;
     if(e.floor == dest_floor)
       transit<Idle>();
  }
 };
};

Should FSM_INITIAL_STATE call entry?

Great project here. One thing I was a little confused about was why entry state isn't being called when setting initial state. I expected this because the pattern seems to be that entry is the first call to every state, but INIT seems to be exception. I updated the MACRO to work as expected, but is there a better way to do this? Or should it not be done at all?

Calling dispatch() and/or transit() from action function

In the comment for transit function there is a note: do not send events in action_function definisions.
As I understand, that limitation is bacause of order of operations inside transit() functions:

current_state_ptr->exit();
action_function();
current_state_ptr = &_state_instance<S>::value;
current_state_ptr->entry();

Any state change caused by action_function() will be overriden by the next line.

What if we rearrange operations so that action is last:

current_state_ptr->exit();
current_state_ptr = &_state_instance<S>::value;
current_state_ptr->entry();
action_function();

Now we can call all API functions without limitation. Any state change caused by action_function() will count as any other.
What do you think?

Not able to compile with IAR ARM v8.20.2

TinyFSM v.0.3.2 can't be compiled using IAR ARM compiler (V8.20.2):

image

The compiler seems to think that the derived state classes are unreleated to the base class. Using GCC the same code compiles and works fine without any warnings.

Adding a reinterpret_cast in line 137 allows compilation, but maybe there is a better solution/workaround for this?

current_state_ptr = reinterpret_cast<state_ptr_t>(&_state_instance<S>::value);

Thanks and best regards
Marvin

Any chance to pass an Action via an Event

Probably this is more a general C++ question than it is a tinyfsm one, but maybe some did this already.

I have an event called ShouldEstimateAndSend which transits to a new state on a few conditions. I'd like to have it call transit<NewState>(ShoudEstimateAndSend::action_function).
Using std::function would work, but this introduces some runtime overhead and pulls in exception handling which is not what I like on my embedded target. Using a template event class 'breaks' inheritance and would need a template react function as far as I can see?!

Can't wiggle my head around this.

non virtual destructor

Hi,
I like you take on a simple state machine. When building with -Wnon-virtual-dtor you got some warning. I would add
virtual ~MooreMachine() noexcept = default;
to the MooreMachine template.

There is some reason I am missing why it is not there?

How to separate state classes from the state machine class?

It's been quite some time since I've developed cpp but I'm stuck on trying to separate out the state classes from the State Machine Class's cpp file. No matter how I rearrange the code, I get an expected class-name before '{' token error defining the state class.

Using the Elevator example, let's say I wanted to pull out the Panic state class into it's own file. How would I do that?

If I put the panic class into panic.hpp and include it in Elevator.hpp, then I get

In file included from elevator.hpp:5,
                 from elevator.cpp:3:
panic.h:3:1: error: expected class-name before ‘{’ token
    3 | {

The doc states

Note that the "elevator" example source code does not declare the states separately, but rather defines the code directly in the declaration.

So my question would be, how would I declare the states separately?

Thanks!

Testing tinyFSM state machines with VectorCAST?

Does anyone have any experience testing tinyFSM state machines using a unit test tool like VectorCAST? For the application we are considering, we need to be able to provide events/stimulus and verify that each state handles the appropriate event and that transitions are executed correctly.

Any suggestions for setting up a state machine and unit test project to cover all possible events and state transitions would be greatly appreciated!

compile error using gcc 5.4.0 (ubuntu 16.04)

I get the following compile error for the (unmodified) elevator example:

g++ -c -I ../../include -MMD -Os -std=c++11 -fno-exceptions -fno-rtti -Wall -Wextra -Wctor-dtor-privacy -Wcast-align -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -pedantic -o motor.o motor.cpp
In file included from motor.cpp:1:0:
../../include/tinyfsm.hpp:235:63: error: specialization of ‘template static void tinyfsm::Fsm::set_initial_state()’ in different namespace [-fpermissive]
template<> void tinyfsm::Fsm< _FSM >::set_initial_state(void) {
^
motor.cpp:62:1: note: in expansion of macro ‘FSM_INITIAL_STATE’
FSM_INITIAL_STATE(Motor, Stopped)
^
../../include/tinyfsm.hpp:96:17: error: from definition of ‘template static void tinyfsm::Fsm::set_initial_state()’ [-fpermissive]
static void set_initial_state();
^
Makefile:90: recipe for target 'motor.o' failed
make: *** [motor.o] Error 1

Any hint appreciated, my C++ template skills seem quite a bit rusty?!

Events double dispatching support

What do you think about making Events to be double dispatch-able? For now it is necessary to explicitly specify event type when dispatching event, however since it is c++ library it can be useful to take advantage of polymorphic events.

Passing data into the State machine.

I was wondering how I might pass data into the state machine either during initialization or after it's been initialized.
I seen this question came up before but the author closed it without providing a solution and I can't find it in the examples provided.

Remove dependency on standard library

It would be nice if the stdfunctionality (currently only those 3 compile time checks) could be disabled using a define so that it would be easy to integrate tinyfsm into a microcontroller toolchain.

Alternatively, the is_same and result_of could be implemented independently.

Linking error

Hello,

I have some troubles using the fsm. When I compile the elevator example in the console using make everything compiles fine. When I make a new project in Qt Creator I get a linker error undefined reference to tinyfsm::Fsm::set_initial_state().
Can somebody tell what the reason is for this?

Thanks in advance
John

connecting IO class with Tiny FSM

Hi,
I am working on some project (studying C++). I have an IO class providing interface to send/receive (boost::asio async raw socket) with the following methods:

class IO {

     public:
         ...
       void do_receive()
        void do_send(char* data_, std::size_t length)
        ...

so there is object of that class:

IO s(io_context, argv[1]);

And I can send data to FSM passing buffer inside an Event but would like also to be able to generate packets outbound so from FSM. What way would you recommend to implement exchange with network ? Maybe you have some quick examples doing the same?

Template specialization fails in gcc < 7.0.0

Hi Axel,
I'm trying to compile the tinyfsm under ubuntu 16.04, my g++ version is 5.4.0. But when I run make under example, I get the following error:

In file included from motor.cpp:1:0:
../../include/tinyfsm.hpp:235:63: error: specialization of ‘template<class F> static void tinyfsm::Fsm<F>::set_initial_state()’ in different namespace [-fpermissive]
   template<> void tinyfsm::Fsm< _FSM >::set_initial_state(void) {     \
                                                               ^
motor.cpp:62:1: note: in expansion of macro ‘FSM_INITIAL_STATE’
 FSM_INITIAL_STATE(Motor, Stopped)
 ^
../../include/tinyfsm.hpp:96:17: error:   from definition of ‘template<class F> static void tinyfsm::Fsm<F>::set_initial_state()’ [-fpermissive]
     static void set_initial_state();
                 ^
Makefile:90: recipe for target 'motor.o' failed
make: *** [motor.o] Error 1

Would you help me to fix it ?
Thank you,
Husky

Transit only if not already in state

Would it make sense to add a transitIfNotIn method next to transit, that prevents calling entry and exit? Like so:

  template <typename S> void transit(void) {
    current_state_ptr->exit();
    current_state_ptr = &_state_instance<S>::value;
    current_state_ptr->entry();
  }

  template <typename S> void transitIfNotIn(void) {
    if (current_state_ptr == &_state_instance<S>::value)
      return;
    current_state_ptr->exit();
    current_state_ptr = &_state_instance<S>::value;
    current_state_ptr->entry();
  }

Example usage:

virtual void react(NoWifiEvent const &) { transitIfNotIn<LostWifiState>(); }

Unresolved external symbol tinyfsm::Fsm<...>::current_state

Hi Axel,
I'm trying to use tinyfsm in a Windows DLL, i.e. my concrete FSM is defined in DLL and referenced in an (unit test) executable that links this DLL's import library :

in DLL sources :
class __declspec (dllexport) AutopilotFSM : public tinyfsm::Fsm<AutopilotFSM> {...}

in executable sources :
class __declspec (dllimport) AutopilotFSM : public tinyfsm::Fsm<AutopilotFSM> {...}

It builds and runs OK, until I try to dispatch an event from the executable :
AutopilotFSMList::template dispatch<EventType>(event);

When I try to link the executable, I get a linker error below.
I've double-checked the DLL (with dependency walker), and current_state IS defined there.

error LNK2001: unresolved external symbol "private: static class AP::AutopilotFSM * tinyfsm::Fsm::current_state" (?current_state@?$Fsm@VAutopilotFSM@AP@@@tinyfsm@@0PAVAutopilotFSM@AP@@A)

Would you have any suggestions ?
Thanks,
Eugene

Handle multiple FSMs

I have the need to have, in parallel, several FSM that are exactly the same, but that will be in different states as they respond to a button, but that button is different for all of them.

Considering tinyfsm FSMs are not instances, what is the best way to handle this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.