A simple, generic, header-only state machine implementation for C++.

Overview

Finite State Machine for C++

A simple, generic, header-only state machine implementation for C++.

Documentation

Please see the documentation in fsm.h for detailed documentation about the implemented features and semantics.

Some more information about this component can also be found on our website. See article 1 for the motivation, and article 2 for the implementation.

Usage

The implementation is contained in a single header file, fsm.h. Simply copy the file to a convenient place in your project and include it.

Example

As an example, consider the state machine below. It starts in state A. When it receives the exec trigger, it checks that the count variable is 1, increments it, and changes to state B.

       +------+  Exec[count=1] / count++    +------+
  o--->|  A   |---------------------------->|  B   |
       +------+                             +------+

The implementation of this state machine is done in a declarative way.

int count = 1;
enum class States { A, B };
enum class Triggers { Exec };
FSM::Fsm<States, States::A, Triggers> fsm;
fsm.add_transitions({
//  from state ,to state  ,triggers        ,guard                    ,action
  { States::A  ,States::B ,Triggers::Exec  ,[&]{return count == 1;}  ,[&]{count++;} },
});
fsm.execute(Triggers::Exec);
assert(count == 2);
assert(fsm.state() == States::B);

See the tests for more examples.

Stability

The implementation is already in use in different commercial applications. We have not found any issues so far. Please report any problems you find.

Tests

Tests can be run with

cd tests
g++ -std=c++11 -Wall -o tests fsm_test.cpp
./tests

Contributions

Contributions are welcome. Please use the Github issue tracker.

Comments
  • Move error code changing below guard check.

    Move error code changing below guard check.

    I thought that it isn't correct to return Fsm_Success when the action wasn't executed and the state hasn't changed.

    I'd make this method without err_code var:

    	Fsm_Errors execute(Trigger trigger)
    	{
    		const auto state_transitions = m_transitions.find(m_cs);
    		if(state_transitions == m_transitions.end()) {
    			return Fsm_NoMatchingTrigger; // No transition from current state found.
    		}
    
    		// iterate the transitions
    		const transition_elem_t& active_transitions = state_transitions->second;
    		for(const auto& transition : active_transitions) {
    			// Check if trigger matches.
    			if(trigger != transition.trigger) continue;
    			// Check if guard exists and returns true.
    			if(transition.guard && !transition.guard()) continue;
    			
    			// Now we have to take the action and set the new state.
    			// Then we are done.
    
    			// Check if action exists and execute it.
    			if(transition.action != 0) {
    				transition.action(); // execute action
    			}
    			m_cs = transition.to_state;
    			if(m_debug_fn) {
    				m_debug_fn(transition.from_state, transition.to_state, trigger);
    			}
    			return Fsm_Success;
    		}
    
    		return Fsm_NoMatchingTrigger;
    	}
    
    opened by golxzn 7
  • Move error code changing belowe guard check

    Move error code changing belowe guard check

    This pull request refers to the #5 old issue. In the last issue #5, the decision was made to add a new value to enum Fsm_Errors and rename it to Fsm_Status, so this pm does exactly it

    @eglimi, please, check the file fsm_test.cpp cuz I changed the test case "Test guards". I did it for supporting new return code from execute method

    opened by golxzn 3
  • Add entry and exit activities

    Add entry and exit activities

    Hello, I tried your fsm and I like the simplicity and the clean readable way of defining states and transitions. I was missing the entry/exit activities and tried to implement them.

    ...
      F::activityMap activities =
      {
        {States::A,
            {[]{std::cout << "State A entered" << std::endl;},  //entry
            []{std::cout << "State A exited" << std::endl;}}    //exit
        },
      };
    
      F fsm;
      fsm.add_transitions(transitions);
      fsm.add_activities(activities);
    ...
    

    I am attaching the file with the implementation. If this is in line with your roadmap you could add the changes in the repo. This is kind of proof of concept so you can implement it in a different way.

    fsm.zip

    opened by slavslavov 1
  • Removed use of alternative “not” operator.

    Removed use of alternative “not” operator.

    The alternative boolean tokens aren't well supported in Visual Studio, requiring either to compile without extensions ("/Za") or to include the header, which implements them as macros, which wreaks havoc with inline asm.

    opened by eigenwhat 0
  • Some weird behavior in execute method

    Some weird behavior in execute method

    Hi, @eglimi I noticed that we cannot use more transactions than one like that:

    FSM::Fsm<States, States::Initial, Triggers> fsm;
    fsm.add_transactions({
      { States::Initial, States::A, Triggers::ToA, nullptr, action0 },
      { States::A      , States::B, Triggers::ToB, nullptr, action1 },
      { States::B      , States::B, Triggers::ToB, nullptr, special },
    });
    fsm.execute(Triggers::ToA); // ok
    fsm.execute(Triggers::ToB); // will be executed only the action1 and special action will be ignored. 
    

    But, if we add a guard to the second transaction, then if the guard will return false, the special action will be executed:

    FSM::Fsm<States, States::Initial, Triggers> fsm;
    fsm.add_transactions({
      { States::Initial, States::A, Triggers::ToA, nullptr, action0 },
      { States::A      , States::B, Triggers::ToB, []{ return false; }, action1 },
      { States::B      , States::B, Triggers::ToB, nullptr, special },
    });
    fsm.execute(Triggers::ToA); // ok
    fsm.execute(Triggers::ToB); // will be executed special action 
    

    So, we can solve this cringe in two different ways:

    1. Return a list of Fsm_Status;
    2. Break the for a loop by a guard.

    Both of these solutions look like a crutch

    I think I have to make a new issue about this situation because my changes do nothing for this bug. 🗿

    Originally posted by @GRPilot in https://github.com/eglimi/cppfsm/issues/5#issuecomment-1023980882

    opened by golxzn 1
  • declare transitions in constructor

    declare transitions in constructor

    mirroring the add_transitions functions behaviors in constructor you can declare a FMS with all needed information in a single line (e.g. member initializer list)

    opened by mellotanica 0
Owner
Michael Egli
Mostly working on embedded devices for control applications in modern C++. Also interested in Elixir (and BEAM VM) and Rust.
Michael Egli
Professor Terence Parr has taught us how to create a virtual machine Now it is time to pwn virtual machine

My First real world CTF Simple Virtual Machine Challenge description Professor Terence Parr has taught us how to create a virtual machine Now it is ti

null 1 Feb 17, 2022
A simple Z-Machine implementation in a single C file. Now with online multiplayer! :)

This is an implementation of Infocom's Z-Machine. The Z-Machine is a virtual machine that's something like a high-level CPU. To keep their games portable and easier to write, Infocom's games all use this fake processor and ship with a platform-specific Z-Machine "emulator" ... so a game could run wherever someone had implemented the Z-Machine.

Ryan C. Gordon 86 Aug 25, 2022
Header-only VMWare Backdoor API Implementation & Effortless VMX Patcher for Custom Guest-to-Host RPCs

VmxHijack Header-only VMWare Backdoor API Implementation & Effortless VMX Patcher for Custom Guest-to-Host RPCs Sample // --- RPC Server Code (VmxHija

null 27 Sep 9, 2022
minimal but extensible header only implementation of photon mapping in C++

photon_mapping minimal but extensible header only implementation of photon mapping in C++. Features Direct illumination with explicit light sampling I

yumcyawiz 66 Nov 20, 2022
Header only implementation of Progressive Photon Mapping: A Probabilistic Approach(PPMAPA) in C++.

ppmapa Header only implementation of Progressive Photon Mapping: A Probabilistic Approach(PPMAPA) in C++. In this reformulation of (stochastic) progre

yumcyawiz 8 Jul 20, 2022
Simple header only pattern matching for c++14

Simple, Extensible C++ Pattern Matching Library I have recently been looking at Haskell and Rust. One of the things I wanted in C++ from those languag

John Bandela 207 Nov 22, 2022
🛠️ A simple ECS library made for learning purposes (header-only)

Met ECS A simple Entity Component System library made for learning purposes. It is header-only, so just have to copy the content of the src folder and

Guillaume Haerinck 15 Mar 26, 2022
Tightly coupled GNSS-Visual-Inertial system for locally smooth and globally consistent state estimation in complex environment.

GVINS GVINS: Tightly Coupled GNSS-Visual-Inertial Fusion for Smooth and Consistent State Estimation. paper link Authors: Shaozu CAO, Xiuyuan LU and Sh

HKUST Aerial Robotics Group 572 Nov 27, 2022
Automatic differentiation with weighted finite-state transducers.

GTN: Automatic Differentiation with WFSTs Quickstart | Installation | Documentation What is GTN? GTN is a framework for automatic differentiation with

null 98 Oct 30, 2022
Cobalt Strike Beacon Object File (BOF) that takes the name of of a PE file as an argument and spawns the process in a suspended state

Beacon Object File (BOF) that spawns an arbitrary process from beacons memory. Supports Parent Process ID (PPID) spoofing & blocking non-MS signed DLLs from loading into the processes memory (some EDR DLLs).

boku 348 Nov 15, 2022
EarlyBird process hollowing technique (BOF) - Spawns a process in a suspended state, inject shellcode, hijack main thread with APC, and execute shellcode

HOLLOW - Cobalt Strike BOF Authors: Bobby Cooke (@0xBoku) Justin Hamilton (@JTHam0) Octavio Paguaga (@OakTree__) Matt Kingstone (@n00bRage) Beacon Obj

Bobby Cooke 201 Nov 12, 2022
Universal State Monitor software for home automation input devices

Universal State Monitor Copyright 2019-2021 SuperHouse Automation Pty Ltd www.superhouse.tv A binary state monitor for DIY home automation projects. T

SuperHouse Automation 3 Aug 24, 2021
A kata to practice refactoring to the State Pattern

A kata to practice refactoring to the State Pattern

Barney Dellar 2 May 16, 2022
Hook up the OnePlus6(T) tri-state key in PostmarketOS!

OnePlus 6(T) tri-state key support in PostmarketOS As the name suggest, the goal of this little project is to hook up the OnePlus6(T) tri-state key in

Michele Perrone 7 Nov 14, 2021
RRxIO - Robust Radar Visual/Thermal Inertial Odometry: Robust and accurate state estimation even in challenging visual conditions.

RRxIO - Robust Radar Visual/Thermal Inertial Odometry RRxIO offers robust and accurate state estimation even in challenging visual conditions. RRxIO c

Christopher Doer 61 Nov 11, 2022
Monitor based on perf_event: split-lock, irq-off, profile, task-state, watchdog, kmemleak, kvm-exit, mpdelay

基于perf的监控框架 基于libperf和libtraceevent库实现简单的监控框架,提供比perf更灵活的特性。 数据不落盘。 数据过滤,基于tracepoint的过滤机制,减少数据量。 数据实时处理并输出。不需要存盘后再处理。 基于perf_event_open系统调用。 虽然比perf更

null 19 Nov 20, 2022
Convenient generic print() for C

generic-print Convenient generic print() for C inspired by Python/JavaScript and other high-level languages. Still using printf("%i\n", result) for de

exebook 304 Nov 19, 2022
Port of my M5Stack Core 2 audio monitor project to generic ESP32s with TFT screens

ESP32 Audio Monitor This is a port of this project to work with any ESP32 device with a TFT display. You can watch a video explainer here (YouTube) wh

atomic14 47 Nov 9, 2022
ASMotor is a portable and generic assembler engine and development system written in ANSI C99

ASMotor is a portable and generic assembler engine and development system written in ANSI C99 and licensed under the GNU Public License v3. The package consists of the assembler, the librarian and the linker. It can be used as either a cross or native development system.

null 42 Nov 18, 2022