{"id":21274170,"url":"https://github.com/endurodave/statemachine","last_synced_at":"2025-04-05T01:06:28.954Z","repository":{"id":37752166,"uuid":"108659257","full_name":"endurodave/StateMachine","owner":"endurodave","description":"State Machine Design in C++","archived":false,"fork":false,"pushed_at":"2025-02-18T15:55:04.000Z","size":76,"stargazers_count":137,"open_issues_count":2,"forks_count":41,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-29T00:09:10.550Z","etag":null,"topics":["cpp","cross-platform","embedded-cpp","embedded-systems","finite-state-machine","state-machine"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/endurodave.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-28T15:10:24.000Z","updated_at":"2025-03-22T23:53:34.000Z","dependencies_parsed_at":"2024-11-03T19:17:33.207Z","dependency_job_id":"66abefaa-f32c-4803-b6d0-df4d6672cd4f","html_url":"https://github.com/endurodave/StateMachine","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FStateMachine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FStateMachine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FStateMachine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FStateMachine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/endurodave","download_url":"https://codeload.github.com/endurodave/StateMachine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271528,"owners_count":20911587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cross-platform","embedded-cpp","embedded-systems","finite-state-machine","state-machine"],"created_at":"2024-11-21T09:19:13.378Z","updated_at":"2025-04-05T01:06:28.936Z","avatar_url":"https://github.com/endurodave.png","language":"C++","readme":"![License MIT](https://img.shields.io/github/license/BehaviorTree/BehaviorTree.CPP?color=blue)\n[![conan Ubuntu](https://github.com/endurodave/StateMachine/actions/workflows/cmake_ubuntu.yml/badge.svg)](https://github.com/endurodave/StateMachine/actions/workflows/cmake_ubuntu.yml)\n[![conan Ubuntu](https://github.com/endurodave/StateMachine/actions/workflows/cmake_clang.yml/badge.svg)](https://github.com/endurodave/StateMachine/actions/workflows/cmake_clang.yml)\n[![conan Windows](https://github.com/endurodave/StateMachine/actions/workflows/cmake_windows.yml/badge.svg)](https://github.com/endurodave/StateMachine/actions/workflows/cmake_windows.yml)\n\n# State Machine Design in C++\nA compact C++ finite state machine (FSM) implementation that's easy to use on embedded and PC-based systems.\n\n# Table of Contents\n\n- [State Machine Design in C++](#state-machine-design-in-c)\n- [Table of Contents](#table-of-contents)\n- [Preface](#preface)\n  - [Related repositories](#related-repositories)\n- [Introduction](#introduction)\n  - [Background](#background)\n  - [Why use a state machine?](#why-use-a-state-machine)\n- [State machine design](#state-machine-design)\n  - [Internal and external events](#internal-and-external-events)\n  - [Event data](#event-data)\n  - [State transitions](#state-transitions)\n- [StateMachine class](#statemachine-class)\n- [Motor example](#motor-example)\n  - [State functions](#state-functions)\n  - [State map](#state-map)\n  - [Transition map](#transition-map)\n- [State engine](#state-engine)\n- [Generating events](#generating-events)\n  - [External event no heap data](#external-event-no-heap-data)\n  - [Hiding and eliminating heap usage](#hiding-and-eliminating-heap-usage)\n- [State machine inheritance](#state-machine-inheritance)\n  - [Base class external event functions](#base-class-external-event-functions)\n- [State function inheritance](#state-function-inheritance)\n- [StateMachine compact class](#statemachine-compact-class)\n- [Multithread safety](#multithread-safety)\n- [Alternatives](#alternatives)\n- [Benefits](#benefits)\n- [References](#references)\n\n\n# Preface\n\nOriginally published on CodeProject at: \u003ca href=\"https://www.codeproject.com/Articles/1087619/State-Machine-Design-in-Cplusplus\"\u003e\u003cstrong\u003eState Machine Design in C++\u003c/strong\u003e\u003c/a\u003e\n\nBased on original design published in C\\C++ Users Journal (Dr. Dobb's) at: \u003ca href=\"http://www.drdobbs.com/cpp/state-machine-design-in-c/184401236\"\u003e\u003cstrong\u003eState Machine Design in C++\u003c/strong\u003e\u003c/a\u003e\n\n## Related repositories\n\nSee related compact state machine Git project \u003ca href=\"https://github.com/endurodave/StateMachineCompact\"\u003e\u003cstrong\u003ehere\u003c/strong\u003e\u003c/a\u003e.\n\n\u003cp\u003e\u003ca href=\"https://www.cmake.org/\"\u003eCMake\u003c/a\u003e\u0026nbsp;is used to create the build files. CMake is free and open-source software. Windows, Linux and other toolchains are supported. See the \u003cstrong\u003eCMakeLists.txt \u003c/strong\u003efile for more information.\u003c/p\u003e\n\n\u003cp\u003eSee other related GitHub repositories:\u003c/p\u003e\n\n\u003cul\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/C_StateMachine\"\u003eState Machine Design in C\u003c/a\u003e - A compact C finite state machine (FSM) implementation.\u003c/li\u003e\n   \t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachineCompact\"\u003eState Machine Design in C++ (Compact)\u003c/a\u003e - A compact C++ finite state machine (FSM) implementation.\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"https://github.com/endurodave/AsyncStateMachine\"\u003eAsynchronous State Machine in C++\u003c/a\u003e - An asynchronous C++ state machine implemented using an asynchronous delegate library.\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachineWithThreads\"\u003eC++ State Machine with Threads\u003c/a\u003e - A framework combining C++ state machines and multicast asynchronous callbacks.\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachineWithDelegates\"\u003eC++ State Machine with Asynchronous Multicast Delegates\u003c/a\u003e - A framework combining C++ state machines with asynchronous multicast delegates.\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachineWithModernDelegates\"\u003eC++ State Machine with Modern Asynchronous Multicast Delegates\u003c/a\u003e - A framework combining C++ state machines with modern asynchronous multicast delegates.\u003c/li\u003e\n\u003c/ul\u003e\n\n# Introduction\n\n\u003cp\u003eIn 2000, I wrote an article entitled \u0026quot;\u003cem\u003eState Machine Design in C++\u003c/em\u003e\u0026quot; for C/C++ Users Journal (R.I.P.). Interestingly, that old article is still available and (at the time of writing this article) the #1 hit on Google when searching for C++ state machine. The article was written over 15 years ago, but I continue to use the basic idea on numerous projects. It\u0026#39;s compact, easy to understand and, in most cases, has just enough features to accomplish what I need.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThis article provides a new implementation with updated features at the slight expense of a bit more code. I\u0026#39;ll also correct the errors in the original implementation because if you\u0026#39;re really tight on storage it\u0026rsquo;s still be a viable solution. Both designs are table driven suitable for any platform, embedded or PC, with any C++ compiler.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eWhy another state machine design? Certainly by now there\u0026#39;s an existing implementation out there that can be used, right? Maybe. On occasion, I\u0026#39;ll try a new state machine and find it doesn\u0026#39;t fit my needs for one reason or another. For me, the problem usually boils down to one or more of the following:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003cstrong\u003eToo large\u003c/strong\u003e \u0026ndash; the resulting implementation takes too much code space to justify on an embedded platform.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eToo complex\u003c/strong\u003e \u0026ndash; excessive templates or requires adoption of a complete framework to use the state machine.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eNo compiler support \u003c/strong\u003e\u0026ndash; relies upon new C++ language features not supported by the compiler.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eHigh learning curve\u003c/strong\u003e \u0026ndash; some require quite a lot of effort in this regard.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eDifficult syntax \u003c/strong\u003e\u0026ndash; non-intuitive state machine expression with hard to diagnose compiler errors.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eExternal libraries\u003c/strong\u003e \u0026ndash; relies upon external libraries that add size or aren\u0026#39;t supported on the platform.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eToo many features \u003c/strong\u003e\u0026ndash; full UML compliance isn\u0026#39;t required and therefore exceeds the basic needs of the problem at hand.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eNo event data\u003c/strong\u003e \u0026ndash; can\u0026#39;t send unique event data to a state function.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eCentral event handler \u003c/strong\u003e\u0026ndash; a single event handling function and a switch statement handles events for each class.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eNo type safety \u003c/strong\u003e\u0026ndash; requires manual typecasting the event data based on an enumeration.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eLimited transition rules \u003c/strong\u003e\u0026ndash; no support for event ignored and can\u0026#39;t happen event transitions.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eNo thread-safety \u003c/strong\u003e\u0026ndash; the code is not thread-safe.\u0026nbsp;\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eDon\u0026#39;t get me wrong, some implementations are quite impressive and suitable for many different projects. Every design has certain tradeoffs and this one is no different. Only you can decide if this one meets your needs or not. I\u0026#39;ll try to get you bootstrapped as quickly as possible through this article and sample code. This state machine has the following features:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003cstrong\u003eCompact\u003c/strong\u003e \u0026ndash; the StateMachine class is not a template \u0026ndash; only 448 bytes of code on Windows. Templates are used sparingly.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eTransition tables\u003c/strong\u003e \u0026ndash; transition tables precisely control state transition behavior.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eEvents \u003c/strong\u003e\u0026ndash; every event is a simple public instance member function with any argument types.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eState action\u003c/strong\u003e \u0026ndash; every state action is a separate instance member function with a single, unique event data argument if desired.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eGuards/entry/exit actions\u003c/strong\u003e \u0026ndash; optionally a state machine can use guard conditions and separate entry/exit action functions for each state.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eState machine inheritance \u003c/strong\u003e\u0026ndash; supports inheriting states from a base state machine class.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eState function inheritance \u003c/strong\u003e\u0026ndash; supports overriding a state function within a derived class.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eMacros \u003c/strong\u003e\u0026ndash; optional multiline macro support simplifies usage by automating the code \u0026quot;machinery\u0026quot;.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eType safe \u003c/strong\u003e\u0026ndash; compile time checks catch mistakes early. Runtime checks for the other cases.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eThread-safe \u003c/strong\u003e\u0026ndash; adding software locks to make the code thread-safe is easy.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eThis state machine design is not trying to achieve a full UML feature set. It is also not a Hierarchical State Machine (HSM). Instead, its goal is to be relatively compact, portable, and easy to use traditional Finite State Machine (FSM) with just enough unique features to solve many different problems.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThe article is not a tutorial on the best design decomposition practices for software state machines. I\u0026#39;ll be focusing on state machine code and simple examples with just enough complexity to facilitate understanding the features and usage.\u0026nbsp;\u003c/p\u003e\n\n## Background\n\n\u003cp\u003eA common design technique in the repertoire of most programmers is the venerable finite state machine (FSM). Designers use this programming construct to break complex problems into manageable states and state transitions. There are innumerable ways to implement a state machine.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eA switch statement provides one of the easiest to implement and most common version of a state machine. Here, each case within the switch statement becomes a state, implemented something like:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nswitch (currentState) {\n   case ST_IDLE:\n       // do something in the idle state\n       break;\n    case ST_STOP:\n       // do something in the stop state\n       break;\n    // etc...\n}\u003c/pre\u003e\n\n\u003cp\u003eThis method is certainly appropriate for solving many different design problems. When employed on an event driven, multithreaded project, however, state machines of this form can be quite limiting.\u003c/p\u003e\n\n\u003cp\u003eThe first problem revolves around controlling what state transitions are valid and which ones are invalid. There is no way to enforce the state transition rules. Any transition is allowed at any time, which is not particularly desirable. For most designs, only a few transition patterns are valid. Ideally, the software design should enforce these predefined state sequences and prevent the unwanted transitions. Another problem arises when trying to send data to a specific state. Since the entire state machine is located within a single function, sending additional data to any given state proves difficult. And lastly these designs are rarely suitable for use in a multithreaded system. The designer must ensure the state machine is called from a single thread of control.\u003c/p\u003e\n\n## Why use a state machine?\n\n\u003cp\u003eImplementing code using a state machine is an extremely handy design technique for solving complex engineering problems. State machines break down the design into a series of steps, or what are called states in state-machine lingo. Each state performs some narrowly defined task. Events, on the other hand, are the stimuli, which cause the state machine to move, or transition, between states.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eTo take a simple example, which I will use throughout this article, let\u0026#39;s say we are designing motor-control software. We want to start and stop the motor, as well as change the motor\u0026#39;s speed. Simple enough. The motor control events to be exposed to the client software will be as follows:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003cstrong\u003eSet Speed\u003c/strong\u003e \u0026ndash; sets the motor going at a specific speed.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eHalt \u003c/strong\u003e\u0026ndash; stops the motor.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eThese events provide the ability to start the motor at whatever speed desired, which also implies changing the speed of an already moving motor. Or we can stop the motor altogether. To the motor-control class, these two events, or functions, are considered external events. To a client using our code, however, these are just plain functions within a class.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThese events are not state machine states. The steps required to handle these two events are different. In this case the states are:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003e\u003cstrong\u003eIdle \u003c/strong\u003e\u0026mdash; the motor is not spinning but is at rest.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cul\u003e\n\t\u003cli\u003eDo nothing.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003col start=\"2\"\u003e\n\t\u003cli\u003e\u003cstrong\u003eStart \u003c/strong\u003e\u0026mdash; starts the motor from a dead stop.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cul\u003e\n\t\u003cli\u003eTurn on motor power.\u003c/li\u003e\n\t\u003cli\u003eSet motor speed.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003col start=\"3\"\u003e\n\t\u003cli\u003e\u003cstrong\u003eChange Speed \u003c/strong\u003e\u0026mdash; adjust the speed of an already moving motor.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cul\u003e\n\t\u003cli\u003eChange motor speed.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003col start=\"4\"\u003e\n\t\u003cli\u003e\u003cstrong\u003eStop \u003c/strong\u003e\u0026mdash; stop a moving motor.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cul\u003e\n\t\u003cli\u003eTurn off motor power.\u003c/li\u003e\n\t\u003cli\u003eGo to the Idle state.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eAs can be seen, breaking the motor control into discreet states, as opposed to having one monolithic function, we can more easily manage the rules of how to operate the motor.\u003c/p\u003e\n\n\u003cp\u003eEvery state machine has the concept of a \u0026quot;current state.\u0026quot; This is the state the state machine currently occupies. At any given moment in time, the state machine can be in only a single state. Every instance of a particular state machine class can set the initial state during construction. That initial state, however, does not execute during object creation. Only an event sent to the state machine causes a state function to execute.\u003c/p\u003e\n\n\u003cp\u003eTo graphically illustrate the states and events, we use a state diagram. Figure 1 below shows the state transitions for the motor control class. A box denotes a state and a connecting arrow indicates the event transitions. Arrows with the event name listed are external events, whereas unadorned lines are considered internal events. (I cover the differences between internal and external events later in the article.)\u003c/p\u003e\n\n\u003cp style=\"text-align: center\"\u003e\u003cimg alt=\"\" src=\"Motor.png\" /\u003e\u003cbr /\u003e\n\u0026nbsp;\u003cbr /\u003e\n\u003cstrong\u003eFigure 1: Motor state diagram\u0026nbsp;\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp\u003eAs you can see, when an event comes in the state transition that occurs depends on state machine\u0026#39;s current state. When a SetSpeed event comes in, for instance, and the motor is in the Idle state, it transitions to the Start state. However, that same SetSpeed event generated while the current state is Start transitions the motor to the ChangeSpeed state. You can also see that not all state transitions are valid. For instance, the motor can\u0026#39;t transition from ChangeSpeed to Idle without first going through the Stop state.\u003c/p\u003e\n\n\u003cp\u003eIn short, using a state machine captures and enforces complex interactions, which might otherwise be difficult to convey and implement.\u003c/p\u003e\n\n# State machine design\n\n## Internal and external events\n\n\u003cp\u003eAs I mentioned earlier, an event is the stimulus that causes a state machine to transition between states. For instance, a button press could be an event. Events can be broken out into two categories: external and internal. The external event, at its most basic level, is a function call into a state-machine object. These functions are public and are called from the outside or from code external to the state-machine object. Any thread or task within a system can generate an external event. If the external event function call causes a state transition to occur, the state will execute synchronously within the caller\u0026#39;s thread of control. An internal event, on the other hand, is self-generated by the state machine itself during state execution.\u003c/p\u003e\n\n\u003cp\u003eA typical scenario consists of an external event being generated, which, again, boils down to a function call into the class\u0026#39;s public interface. Based upon the event being generated and the state machine\u0026#39;s current state, a lookup is performed to determine if a transition is required. If so, the state machine transitions to the new state and the code for that state executes. At the end of the state function, a check is performed to determine whether an internal event was generated. If so, another transition is performed and the new state gets a chance to execute. This process continues until the state machine is no longer generating internal events, at which time the original external event function call returns. The external event and all internal events, if any, execute within the caller\u0026#39;s thread of control.\u003c/p\u003e\n\n\u003cp\u003eOnce the external event starts the state machine executing, it cannot be interrupted by another external event until the external event and all internal events have completed execution if locks are used. This run to completion model provides a multithread-safe environment for the state transitions. Semaphores or mutexes can be used in the state machine engine to block other threads that might be trying to be simultaneously access the same object. See source code function \u003ccode\u003eExternalEvent()\u003c/code\u003e comments for where the locks go.\u0026nbsp;\u003c/p\u003e\n\n## Event data\n\n\u003cp\u003eWhen an event is generated, it can optionally attach event data to be used by the state function during execution. Once the state has completed execution, the event data is considered used up and must be deleted. Therefore, any event data sent to a state machine must be created on the heap, via operator new, so that the state machine can delete it once used. In addition, for our particular implementation the event data must inherit from the \u003ccode\u003eEventData \u003c/code\u003ebase class. This gives the state machine engine a common base class for which to delete all event data.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nclass EventData \n{\npublic:\n    virtual ~EventData() {}\n};\u003c/pre\u003e\n\n\u003cp\u003eThe state machine implementation now has a build option that removes the requirement to create external event data on the heap. See the \u003cstrong\u003eExternal event no heap data\u003c/strong\u003e\u0026nbsp;section for details.\u0026nbsp;\u003c/p\u003e\n\n## State transitions\n\n\u003cp\u003eWhen an external event is generated, a lookup is performed to determine the state transition course of action. There are three possible outcomes to an event: new state, event ignored, or cannot happen. A new state causes a transition to a new state where it is allowed to execute. Transitions to the existing state are also possible, which means the current state is re-executed. For an ignored event, no state executes. However, the event data, if any, is deleted. The last possibility, cannot happen, is reserved for situations where the event is not valid given the current state of the state machine. If this occurs, the software faults.\u003c/p\u003e\n\n\u003cp\u003eIn this implementation, internal events are not required to perform a validating transition lookup. The state transition is assumed to be valid. You could check for both valid internal and external event transitions, but in practice, this just takes more storage space and generates busywork for very little benefit. The real need for validating transitions lies in the asynchronous, external events where a client can cause an event to occur at an inappropriate time. Once the state machine is executing, it cannot be interrupted. It is under the control of the class\u0026#39;s private implementation, thereby making transition checks unnecessary. This gives the designer the freedom to change states, via internal events, without the burden of updating transition tables.\u003c/p\u003e\n\n# StateMachine class\n\n\u003cp\u003eTwo base classes are necessary when creating your own state machine: \u003ccode\u003eStateMachine \u003c/code\u003eand \u003ccode\u003eEventData\u003c/code\u003e. A class inherits from \u003ccode\u003eStateMachine \u003c/code\u003eto obtain the necessary mechanisms to support state transitions and event handling. The \u003ccode\u003eStateMachine \u003c/code\u003eheader also contains various preprocessor multiline macros to ease implementation of the state machine (explained later in the article). To send unique data to the state functions, the structure must inherit from the \u003ccode\u003eEventData \u003c/code\u003ebase class.\u003c/p\u003e\n\n\u003cp\u003eThe state machine source code is contained within the StateMachine.cpp and StateMachine.h files (see attached \u003cem\u003eStateMachine.zip\u003c/em\u003e). The code below shows the class declaration.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nclass StateMachine \n{\npublic:\n    enum { EVENT_IGNORED = 0xFE, CANNOT_HAPPEN };\n\n    StateMachine(BYTE maxStates, BYTE initialState = 0);\n    virtual ~StateMachine() {}\n\n    BYTE GetCurrentState() { return m_currentState; }\n    \nprotected:\n    void ExternalEvent(BYTE newState, const EventData* pData = NULL);\n    void InternalEvent(BYTE newState, const EventData* pData = NULL);\n    \nprivate:\n    const BYTE MAX_STATES;\n    BYTE m_currentState;\n    BYTE m_newState;\n    BOOL m_eventGenerated;\n    const EventData* m_pEventData;\n\n    virtual const StateMapRow* GetStateMap() = 0;\n    virtual const StateMapRowEx* GetStateMapEx() = 0;\n    \n    void SetCurrentState(BYTE newState) { m_currentState = newState; }\n\n    void StateEngine(void);     \n    void StateEngine(const StateMapRow* const pStateMap);\n    void StateEngine(const StateMapRowEx* const pStateMapEx);\n};\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eStateMachine \u003c/code\u003eis the base class used for handling events and state transitions. The interface is contained within four functions:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid ExternalEvent(BYTE newState, const EventData* pData = NULL);\nvoid InternalEvent(BYTE newState, const EventData* pData = NULL);\nvirtual const StateMapRow* GetStateMap() = 0;\nvirtual const StateMapRowEx* GetStateMapEx() = 0;\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eExternalEvent()\u003c/code\u003e generates an external event to the state machine using as arguments the new state and a pointer to an EventData object, if any. The \u003ccode\u003eInternalEvent() \u003c/code\u003efunction generates internal events using the same set of arguments.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003eGetStateMap() \u003c/code\u003eand \u003ccode\u003eGetStateMapEx() \u003c/code\u003efunctions return an array of \u003ccode\u003eStateMapRow \u003c/code\u003eor \u003ccode\u003eStateMapRowEx \u003c/code\u003einstances which will be retrieved by the state engine when appropriate. The inheriting class must return an array with one of these functions. If the state machine only has state functions, \u003ccode\u003eGetStateMap()\u003c/code\u003e is used. If guard/entry/exit features are required, the \u003ccode\u003eGetStateMapEx() i\u003c/code\u003es used. The other unused version must return \u003ccode\u003eNULL\u003c/code\u003e. However, multiline macros are provided to implement these functions for us, as I will demonstrate shortly.\u003c/p\u003e\n\n# Motor example\n\n\u003cp\u003e\u003ccode\u003eMotor \u003c/code\u003eand \u003ccode\u003eMotorNM \u003c/code\u003eclasses are examples of how to use \u003ccode\u003eStateMachine\u003c/code\u003e. \u003ccode\u003eMotorNM \u003c/code\u003e(No Macros) exactly matches the \u003ccode\u003eMotor\u003c/code\u003e design without relying upon macros. This allows viewing all the macro-expanded code for ease of understanding. However, once up to speed I find that the macros greatly simplify usage by hiding the required source machinery.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003eMotorNM \u003c/code\u003eclass declaration shown below contains no macros:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nclass MotorNMData : public EventData\n{\npublic:\n    INT speed;\n};\n\n// Motor class with no macros\nclass MotorNM : public StateMachine\n{\npublic:\n    MotorNM();\n\n    // External events taken by this state machine\n    void SetSpeed(MotorNMData* data);\n    void Halt();\n\nprivate:\n    INT m_currentSpeed; \n\n    // State enumeration order must match the order of state method entries\n    // in the state map.\n    enum States\n    {\n        ST_IDLE,\n        ST_STOP,\n        ST_START,\n        ST_CHANGE_SPEED,\n        ST_MAX_STATES\n    };\n\n    // Define the state machine state functions with event data type\n    void ST_Idle(const NoEventData*);\n    StateAction\u0026lt;MotorNM, NoEventData, \u0026amp;MotorNM::ST_Idle\u0026gt; Idle;\n\n    void ST_Stop(const NoEventData*);\n    StateAction\u0026lt;MotorNM, NoEventData, \u0026amp;MotorNM::ST_Stop\u0026gt; Stop;\n\n    void ST_Start(const MotorNMData*);\n    StateAction\u0026lt;MotorNM, MotorNMData, \u0026amp;MotorNM::ST_Start\u0026gt; Start;\n\n    void ST_ChangeSpeed(const MotorNMData*);\n    StateAction\u0026lt;MotorNM, MotorNMData, \u0026amp;MotorNM::ST_ChangeSpeed\u0026gt; ChangeSpeed;\n\n    // State map to define state object order. Each state map entry defines a\n    // state object.\nprivate:\n    virtual const StateMapRowEx* GetStateMapEx() { return NULL; }\n    virtual const StateMapRow* GetStateMap() {\n        static const StateMapRow STATE_MAP[] = { \n            \u0026amp;Idle,\n            \u0026amp;Stop,\n            \u0026amp;Start,\n            \u0026amp;ChangeSpeed,\n        }; \n        C_ASSERT((sizeof(STATE_MAP)/sizeof(StateMapRow)) == ST_MAX_STATES); \n        return \u0026amp;STATE_MAP[0]; }\n};\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eMotor \u003c/code\u003eclass uses macros for comparison:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nclass MotorData : public EventData\n{\npublic:\n    INT speed;\n};\n\n// Motor class using macro support\nclass Motor : public StateMachine\n{\npublic:\n    Motor();\n\n    // External events taken by this state machine\n    void SetSpeed(MotorData* data);\n    void Halt();\n\nprivate:\n    INT m_currentSpeed; \n\n    // State enumeration order must match the order of state method entries\n    // in the state map.\n    enum States\n    {\n        ST_IDLE,\n        ST_STOP,\n        ST_START,\n        ST_CHANGE_SPEED,\n        ST_MAX_STATES\n    };\n\n    // Define the state machine state functions with event data type\n    STATE_DECLARE(Motor,     Idle,            NoEventData)\n    STATE_DECLARE(Motor,     Stop,            NoEventData)\n    STATE_DECLARE(Motor,     Start,           MotorData)\n    STATE_DECLARE(Motor,     ChangeSpeed,     MotorData)\n\n    // State map to define state object order. Each state map entry defines a\n    // state object.\n    BEGIN_STATE_MAP\n        STATE_MAP_ENTRY(\u0026amp;Idle)\n        STATE_MAP_ENTRY(\u0026amp;Stop)\n        STATE_MAP_ENTRY(\u0026amp;Start)\n        STATE_MAP_ENTRY(\u0026amp;ChangeSpeed)\n    END_STATE_MAP    \n};\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eMotor \u003c/code\u003eimplements our hypothetical motor-control state machine, where clients can start the motor, at a specific speed, and stop the motor. The\u003ccode\u003e SetSpeed()\u003c/code\u003e and \u003ccode\u003eHalt() \u003c/code\u003epublic functions are considered external events into the \u003ccode\u003eMotor \u003c/code\u003estate machine. \u003ccode\u003eSetSpeed()\u003c/code\u003e takes event data, which contains the motor speed. This data structure will be deleted upon completion of the state processing, so it is imperative that the structure inherit from \u003ccode\u003eEventData \u003c/code\u003eand be created using \u003ccode\u003eoperator new \u003c/code\u003ebefore the function call is made.\u003c/p\u003e\n\n\u003cp\u003eWhen the \u003ccode\u003eMotor \u003c/code\u003eclass is created, its initial state is Idle. The first call to \u003ccode\u003eSetSpeed() \u003c/code\u003etransitions the state machine to the Start state, where the motor is initially set into motion. Subsequent \u003ccode\u003eSetSpeed()\u003c/code\u003e events transition to the ChangeSpeed state, where the speed of an already moving motor is adjusted. The \u003ccode\u003eHalt() \u003c/code\u003eevent transitions to Stop, where, during state execution, an internal event is generated to transition back to the Idle state.\u003c/p\u003e\n\n\u003cp\u003eCreating a new state machine requires a few basic high-level steps:\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003eInherit from the \u003ccode\u003eStateMachine \u003c/code\u003ebase class.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003eCreate a \u003ccode\u003eStates \u003c/code\u003eenumeration with one entry per state function.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003eCreate state functions using the \u003ccode\u003eSTATE \u003c/code\u003emacros.\u003c/li\u003e\n\t\u003cli\u003eOptionally create guard/entry/exit functions for each state using the \u003ccode\u003eGUARD\u003c/code\u003e, \u003ccode\u003eENTRY \u003c/code\u003eand \u003ccode\u003eEXIT \u003c/code\u003emacros.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003eCreate one state map lookup table using the \u003ccode\u003eSTATE_MAP \u003c/code\u003emacros.\u003c/li\u003e\n\t\u003cli\u003eCreate one transition map lookup table for each external event using the \u003ccode\u003eTRANSITION_MAP\u003c/code\u003e macros.\u0026nbsp;\u003c/li\u003e\n\u003c/ol\u003e\n\n## State functions\n\n\u003cp\u003eState functions implement each state \u0026mdash; one state function per state-machine state. In this implementation, all state functions must adhere this state-function signature, which is as follows:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid \u0026lt;class\u0026gt;::\u0026lt;func\u0026gt;(const EventData*)\u003c/pre\u003e\n\n\u003cp\u003e\u0026lt;class\u0026gt; and \u0026lt;func\u0026gt; are not template parameters but just placeholders for the particular class and function name respectively. For example, you might choose a signature such as\u003ccode\u003e void Motor::ST_Start(const MotorData*)\u003c/code\u003e. The important thing here is that the function returns no data (has a \u003ccode\u003evoid \u003c/code\u003ereturn type) and that it has one input argument of type \u003ccode\u003eEventData*\u003c/code\u003e (or a derived class thereof).\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eDeclare state functions with the \u003ccode\u003eSTATE_DECLARE \u003c/code\u003emacro. The macro arguments are the state machine class name, state function name and event data type.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nSTATE_DECLARE(Motor,     Idle,            NoEventData)\nSTATE_DECLARE(Motor,     Stop,            NoEventData)\nSTATE_DECLARE(Motor,     Start,           MotorData)\nSTATE_DECLARE(Motor,     ChangeSpeed,     MotorData)\u003c/pre\u003e\n\n\u003cp\u003eExpanding the macros above yields:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid ST_Idle(const NoEventData*);\nStateAction\u0026lt;Motor, NoEventData, \u0026amp;Motor::ST_Idle\u0026gt; Idle;\n\nvoid ST_Stop(const NoEventData*);\nStateAction\u0026lt;Motor, NoEventData, \u0026amp;Motor::ST_Stop\u0026gt; Stop;\n\nvoid ST_Start(const MotorData*);\nStateAction\u0026lt;MotorNM, MotorData, \u0026amp;Motor::ST_Start\u0026gt; Start;\n\nvoid ST_ChangeSpeed(const MotorData*);\nStateAction\u0026lt;Motor, MotorData, \u0026amp;Motor::ST_ChangeSpeed\u0026gt; ChangeSpeed;\u003c/pre\u003e\n\n\u003cp\u003eNotice the multiline macros prepend \u0026quot;ST_\u0026quot; to each state function name. Three characters are added to each state/guard/entry/exit function automatically within the macro. For instance, if declaring a function using \u003ccode\u003eSTATE_DEFINE(Motor, Idle, NoEventData)\u003c/code\u003e the actual state function is called \u003ccode\u003eST_Idle()\u003c/code\u003e.\u0026nbsp;\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003eST_ - state function prepend characters\u003c/li\u003e\n\t\u003cli\u003eGD_ - guard function prepend characters\u003c/li\u003e\n\t\u003cli\u003eEN_ - entry function prepend characters\u003c/li\u003e\n\t\u003cli\u003eEX_ - exit function prepend characters\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eAfter a state function is declared, define a state function implementation with the \u003ccode\u003eSTATE_DEFINE \u003c/code\u003emacro. The arguments are the state machine class name, state function name, and event data type. The code to implement your state behavior goes inside the state function. Note, any state function code may call\u003ccode\u003e InternalEvent()\u003c/code\u003e to switch to another state. Guard/entry/exit functions cannot call \u003ccode\u003eInternalEvent() \u003c/code\u003eotherwise a runtime error will result.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nSTATE_DEFINE(Motor, Stop, NoEventData)\n{\n    cout \u0026lt;\u0026lt; \u0026quot;Motor::ST_Stop\u0026quot; \u0026lt;\u0026lt; endl;\n    m_currentSpeed = 0; \n\n    // perform the stop motor processing here\n    // transition to Idle via an internal event\n    InternalEvent(ST_IDLE);\n}\u003c/pre\u003e\n\n\u003cp\u003eExpanding the macro yields this state function definition.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid Motor::ST_Stop(const NoEventData* data)\n{\n    cout \u0026lt;\u0026lt; \u0026quot;Motor::ST_Stop\u0026quot; \u0026lt;\u0026lt; endl;\n    m_currentSpeed = 0; \n\n    // perform the stop motor processing here\n    // transition to Idle via an internal event\n    InternalEvent(ST_IDLE);\n}\u003c/pre\u003e\n\n\u003cp\u003eEach state function must have an enumeration associated with it. These enumerations are used to store the current state of the state machine. In \u003ccode\u003eMotor\u003c/code\u003e, \u003ccode\u003eStates \u003c/code\u003eprovides these enumerations, which are used later for indexing into the transition map and state map lookup tables.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nenum States\n{\n    ST_IDLE,\n    ST_STOP,\n    ST_START,\n    ST_CHANGE_SPEED,\n    ST_MAX_STATES\n};\u003c/pre\u003e\n\n\u003cp\u003eIt is important that the enumeration order match the order provided within the state map. This way, a state enumeration is tied to a particular state function call. \u003ccode\u003eEVENT_IGNORED\u003c/code\u003e and \u003ccode\u003eCANNOT_HAPPEN \u003c/code\u003eare two other constants used in conjunction with these state enumerations. \u003ccode\u003eEVENT_IGNORED \u003c/code\u003etells the state engine not to execute any state, just return and do nothing. \u003ccode\u003eCANNOT_HAPPEN \u003c/code\u003etells the state engine to fault. This abnormal catastrophic failure condition is never supposed to occur.\u003c/p\u003e\n\n## State map\n\n\u003cp\u003eThe state-machine engine knows which state function to call by using the state map. The state map maps the \u003ccode\u003em_currentState\u003c/code\u003e variable to a specific state function. For instance, if \u003ccode\u003em_currentState\u003c/code\u003e is 2, then the third state-map function pointer entry will be called (counting from zero). The state map table is created using these three macros:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nBEGIN_STATE_MAP\nSTATE_MAP_ENTRY\nEND_STATE_MAP\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eBEGIN_STATE_MAP \u003c/code\u003estarts the state map sequence. Each \u003ccode\u003eSTATE_MAP_ENTRY \u003c/code\u003ehas a state function name argument. \u003ccode\u003eEND_STATE_MAP \u003c/code\u003eterminates the map. The state map for \u003ccode\u003eMotor \u003c/code\u003eis shown below.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nBEGIN_STATE_MAP\n    STATE_MAP_ENTRY(\u0026amp;Idle)\n    STATE_MAP_ENTRY(\u0026amp;Stop)\n    STATE_MAP_ENTRY(\u0026amp;Start)\n    STATE_MAP_ENTRY(\u0026amp;ChangeSpeed)\nEND_STATE_MAP    \u003c/pre\u003e\n\n\u003cp\u003eThe completed state map just implements the pure virtual function \u003ccode\u003eGetStateMap()\u003c/code\u003e defined within the \u003ccode\u003eStateMachine \u003c/code\u003ebase class. Now the \u003ccode\u003eStateMachine \u003c/code\u003ebase class can get all the \u003ccode\u003eStateMapRow\u003c/code\u003e objects via this call. The macro-expanded code is shown below:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nprivate:\n    virtual const StateMapRowEx* GetStateMapEx() { return NULL; }\n    virtual const StateMapRow* GetStateMap() {\n        static const StateMapRow STATE_MAP[] = { \n            \u0026amp;Idle,\n            \u0026amp;Stop,\n            \u0026amp;Start,\n            \u0026amp;ChangeSpeed,\n        }; \n        C_ASSERT((sizeof(STATE_MAP)/sizeof(StateMapRow)) == ST_MAX_STATES); \n        return \u0026amp;STATE_MAP[0]; }\u003c/pre\u003e\n\n\u003cp\u003eNotice the \u003ccode\u003eC_ASSERT \u003c/code\u003emacro. It provides compile time protection against a state map having the wrong number of entries. Visual Studio gives an error of \u0026quot;error C2118: negative subscript\u0026quot;. Your compiler may give a different error message.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eAlternatively, guard/entry/exit features require utilizing the _EX (extended) version of the macros.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nBEGIN_STATE_MAP_EX\nSTATE_MAP_ENTRY_EX or STATE_MAP_ENTRY_ALL_EX \nEND_STATE_MAP_EX\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSTATE_MAP_ENTRY_ALL_EX \u003c/code\u003emacro has four arguments for the state action, guard condition, entry action and exit action in that order. The state action is mandatory but the other actions are optional. If a state doesn\u0026#39;t have an action, then use 0 for the argument. If a state doesn\u0026#39;t have any guard/entry/exit options, the \u003ccode\u003eSTATE_MAP_ENTRY_EX \u003c/code\u003emacro defaults all unused options to 0. The macro snippet below is for an advanced example presented later in the article.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nBEGIN_STATE_MAP_EX\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;Idle, 0, \u0026amp;EntryIdle, 0)\n    STATE_MAP_ENTRY_EX(\u0026amp;Completed)\n    STATE_MAP_ENTRY_EX(\u0026amp;Failed)\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;StartTest, \u0026amp;GuardStartTest, 0, 0)\n    STATE_MAP_ENTRY_EX(\u0026amp;Acceleration)\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;WaitForAcceleration, 0, 0, \u0026amp;ExitWaitForAcceleration)\n    STATE_MAP_ENTRY_EX(\u0026amp;Deceleration)\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;WaitForDeceleration, 0, 0, \u0026amp;ExitWaitForDeceleration)\nEND_STATE_MAP_EX\u003c/pre\u003e\n\n\u003cp\u003eEach entry within the transition map is a \u003ccode\u003eStateMapRow\u003c/code\u003e:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nstruct StateMapRow\n{\n    const StateBase* const State;\n};\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eStateBase \u003c/code\u003epointer has a pure virtual interface called by \u003ccode\u003eStateEngine()\u003c/code\u003e.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nclass StateBase\n{\npublic:\n    virtual void InvokeStateAction(StateMachine* sm, const EventData* data) const = 0;\n};\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eStateAction \u003c/code\u003ederives from \u003ccode\u003eStateBase \u003c/code\u003eand its sole responsibility is to implement \u003ccode\u003eInvokeStateAction()\u003c/code\u003e and cast the \u003ccode\u003eStateMachine \u003c/code\u003eand \u003ccode\u003eEventData \u003c/code\u003epointers to the correct derived class types, then call the state member function. Therefore, the state engine overhead to call each state function is one virtual function call, one \u003ccode\u003estatic_cast\u0026lt;\u0026gt; \u003c/code\u003eand one \u003ccode\u003edynamic_cast\u0026lt;\u0026gt;\u003c/code\u003e.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\ntemplate \u0026lt;class SM, class Data, void (SM::*Func)(const Data*)\u0026gt;\nclass StateAction : public StateBase\n{\npublic:\n    virtual void InvokeStateAction(StateMachine* sm, const EventData* data) const \n    {\n        // Downcast the state machine and event data to the correct derived type\n        SM* derivedSM = static_cast\u0026lt;SM*\u0026gt;(sm);\n\n        // Dynamic cast the data to the correct derived type        \n        const Data* derivedData = dynamic_cast\u0026lt;const Data*\u0026gt;(data);\n        ASSERT_TRUE(derivedData != NULL);\n\n        // Call the state function\n        (derivedSM-\u0026gt;*Func)(derivedData);\n    }\n};\u003c/pre\u003e\n\n\u003cp\u003eThe template arguments to \u003ccode\u003eStateAction\u0026lt;\u0026gt;\u003c/code\u003e are a state machine class (\u003ccode\u003eSM\u003c/code\u003e), an event data type (\u003ccode\u003eData\u003c/code\u003e) and a member function pointer to the state function (\u003ccode\u003eFunc\u003c/code\u003e).\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eGuardCondition\u0026lt;\u0026gt;\u003c/code\u003e, \u003ccode\u003eEntryAction\u0026lt;\u0026gt;\u003c/code\u003e and\u003ccode\u003e ExitAction\u0026lt;\u0026gt;\u003c/code\u003e classes also exist and their role is the same \u0026ndash; typecast state machine and event data then call the action member function. Minor variations exist with the template arguments. The \u003ccode\u003eGuardCondition\u0026lt;\u0026gt; \u003c/code\u003eclass \u003ccode\u003eFunc \u003c/code\u003etemplate parameter changes slightly and returns a \u003ccode\u003eBOOL\u003c/code\u003e. \u003ccode\u003eExitAction\u0026lt;\u0026gt;\u003c/code\u003e doesn\u0026#39;t have a \u003ccode\u003eData \u003c/code\u003etemplate argument.\u0026nbsp;\u003c/p\u003e\n\n## Transition map\n\n\u003cp\u003eThe last detail to attend to are the state transition rules. How does the state machine know what transitions should occur? The answer is the transition map. A transition map is lookup table that maps the \u003ccode\u003em_currentState \u003c/code\u003evariable to a state enum constant. Every external event has a transition map table created with three macros:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nBEGIN_TRANSITION_MAP\nTRANSITION_MAP_ENTRY\nEND_TRANSITION_MAP\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eHalt()\u003c/code\u003e event function in \u003ccode\u003eMotor \u003c/code\u003edefines the transition map as:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid Motor::Halt()\n{\n    BEGIN_TRANSITION_MAP                                      // - Current State -\n        TRANSITION_MAP_ENTRY (EVENT_IGNORED)                  // ST_IDLE\n        TRANSITION_MAP_ENTRY (CANNOT_HAPPEN)                  // ST_STOP\n        TRANSITION_MAP_ENTRY (ST_STOP)                        // ST_START\n        TRANSITION_MAP_ENTRY (ST_STOP)                        // ST_CHANGE_SPEED\n    END_TRANSITION_MAP(NULL)\n}\u003c/pre\u003e\n\n\u003cp\u003eThe macro-expanded code for \u003ccode\u003eHalt() \u003c/code\u003eis below. Again, notice the \u003ccode\u003eC_ASSERT\u003c/code\u003e macro providing compile time protection against an incorrect number of transition map entries.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid Motor::Halt()\n{\n    static const BYTE TRANSITIONS[] = {\n        EVENT_IGNORED,                    // ST_IDLE\n        CANNOT_HAPPEN,                    // ST_STOP\n        ST_STOP,                          // ST_START\n        ST_STOP,                          // ST_CHANGE_SPEED\n    };\n    ExternalEvent(TRANSITIONS[GetCurrentState()], NULL); \n    C_ASSERT((sizeof(TRANSITIONS)/sizeof(BYTE)) == ST_MAX_STATES);     \n}\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eBEGIN_TRANSITION_MAP\u003c/code\u003e starts the map. Each \u003ccode\u003eTRANSITION_MAP_ENTRY \u003c/code\u003ethat follows indicates what the state machine should do based upon the current state. The number of entries in each transition map table must match the number of state functions exactly. In our example, we have four state functions, so we need four entries. The location of each entry matches the order of state functions defined within the state map. Thus, the first entry within the \u003ccode\u003eHalt()\u003c/code\u003e function indicates an \u003ccode\u003eEVENT_IGNORED\u003c/code\u003e as shown below.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nTRANSITION_MAP_ENTRY (EVENT_IGNORED)    // ST_IDLE\u003c/pre\u003e\n\n\u003cp\u003eThis is interpreted as \u0026quot;If a Halt event occurs while the current state is state Idle, just ignore the event.\u0026quot;\u003c/p\u003e\n\n\u003cp\u003eSimilarly, the third entry in the map is:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nTRANSITION_MAP_ENTRY (ST_STOP)         // ST_START\u003c/pre\u003e\n\n\u003cp\u003eThis indicates \u0026quot;If a Halt event occurs while current is state Start, then transition to state Stop.\u0026quot;\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eEND_TRANSITION_MAP \u003c/code\u003eterminates the map. The argument to this end macro is the event data, if any. \u003ccode\u003eHalt()\u003c/code\u003e has no event data so the argument is \u003ccode\u003eNULL\u003c/code\u003e, but\u003ccode\u003e ChangeSpeed()\u003c/code\u003e has data so it is passed in here.\u003c/p\u003e\n\n# State engine\n\n\u003cp\u003eThe state engine executes the state functions based upon events generated. The transition map is an array of \u003ccode\u003eStateMapRow\u003c/code\u003e instances indexed by the \u003ccode\u003em_currentState \u003c/code\u003evariable. When the \u003ccode\u003eStateEngine()\u003c/code\u003e function executes, it looks up a \u003ccode\u003eStateMapRow \u003c/code\u003eor \u003ccode\u003eStateMapRowEx \u003c/code\u003earray by calling \u003ccode\u003eGetStateMap()\u003c/code\u003e or \u003ccode\u003eGetStateMapEx()\u003c/code\u003e:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid StateMachine::StateEngine(void)\n{\n    const StateMapRow* pStateMap = GetStateMap();\n    if (pStateMap != NULL)\n        StateEngine(pStateMap);\n    else\n    {\n        const StateMapRowEx* pStateMapEx = GetStateMapEx();\n        if (pStateMapEx != NULL)\n            StateEngine(pStateMapEx);\n        else\n            ASSERT();\n    }\n}\u003c/pre\u003e\n\n\u003cp\u003eIndexing into the \u003ccode\u003eStateMapRow \u003c/code\u003etable with a new state value a state functions is executed by calling \u003ccode\u003eInvokeStateAction()\u003c/code\u003e:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nconst StateBase* state = pStateMap[m_newState].State;\nstate-\u0026gt;InvokeStateAction(this, pDataTemp);\u003c/pre\u003e\n\n\u003cp\u003eAfter the state function has a chance to execute, it deletes the event data, if any, before checking to see if any internal events were generated. One entire state engine function is shown below. The other overloaded state engine function (see attached source code) handles state machines with a \u003ccode\u003eStateMapRowEx \u003c/code\u003etable containing the additional guard/entry/exit features.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid StateMachine::StateEngine(const StateMapRow* const pStateMap)\n{\n    const EventData* pDataTemp = NULL;    \n    \n    // While events are being generated keep executing states\n    while (m_eventGenerated)\n    {\n        // Error check that the new state is valid before proceeding\n        ASSERT_TRUE(m_newState \u0026lt; MAX_STATES);\n    \n        // Get the pointer from the state map\n        const StateBase* state = pStateMap[m_newState].State;\n            \n           // Copy of event data pointer\n        pDataTemp = m_pEventData;\n\n        // Event data used up, reset the pointer\n        m_pEventData = NULL;\n\n        // Event used up, reset the flag\n        m_eventGenerated = FALSE;\n\n        // Switch to the new current state\n        SetCurrentState(m_newState);\n\n        // Execute the state action passing in event data\n        ASSERT_TRUE(state != NULL);\n        state-\u0026gt;InvokeStateAction(this, pDataTemp);\n\n        // If event data was used, then delete it\n        if (pDataTemp)\n        {\n             delete pDataTemp;\n             pDataTemp = NULL;\n        }\n    }\n}\u003c/pre\u003e\n\n\u003cp\u003eThe state engine logic for guard, entry, state, and exit actions is expressed by the following sequence. The \u003ccode\u003eStateMapRow\u003c/code\u003e engine implements only #1 and #5 below. The extended \u003ccode\u003eStateMapRowEx\u003c/code\u003e engine uses the entire logic sequence.\u003c/p\u003e\n\n\u003col\u003e\n\t\u003cli\u003eEvaluate the state transition table. If \u003ccode\u003eEVENT_IGNORED\u003c/code\u003e, the event is ignored and the transition is not performed. If \u003ccode\u003eCANNOT_HAPPEN\u003c/code\u003e, the software faults. Otherwise, continue with next step.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003eIf a guard condition is defined execute the guard condition function. If the guard condition returns \u003ccode\u003eFALSE\u003c/code\u003e, the state transition is ignored and the state function is not called. If the guard returns \u003ccode\u003eTRUE\u003c/code\u003e, or if no guard condition exists, the state function will be executed.\u003c/li\u003e\n\t\u003cli\u003eIf transitioning to a new state and an exit action is defined for the current state, call the current state exit action function.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003eIf transitioning to a new state and an entry action is defined for the new state, call the new state entry action function.\u0026nbsp;\u003c/li\u003e\n\t\u003cli\u003eCall the state action function for the new state. The new state is now the current state.\u0026nbsp;\u003c/li\u003e\n\u003c/ol\u003e\n\n# Generating events\n\n\u003cp\u003eAt this point, we have a working state machine. Let\u0026#39;s see how to generate events to it. An external event is generated by creating the event data structure on the heap using new, assigning the structure member variables, and calling the external event function. The following code fragment shows how a synchronous call is made.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nMotorData* data = new MotorData();\ndata-\u0026gt;speed = 50;\nmotor.SetSpeed(data);\u003c/pre\u003e\n\n\u003cp\u003eTo generate an internal event from within a state function, call \u003ccode\u003eInternalEvent()\u003c/code\u003e. If the destination doesn\u0026#39;t accept event data, then the function is called with only the state you want to transition to:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nInternalEvent(ST_IDLE);\u003c/pre\u003e\n\n\u003cp\u003eIn the example above, once the state function completes execution the state machine will transition to the Idle state. If, on the other hand, event data needs to be sent to the destination state, then the data structure needs to be created on the heap and passed in as an argument:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nMotorData* data = new MotorData();\ndata-\u0026gt;speed = 100;\nInternalEvent(ST_CHANGE_SPEED, data);\u003c/pre\u003e\n\n## External event no heap data\n\n\u003cp\u003eThe state machine has the \u003ccode\u003eEXTERNAL_EVENT_NO_HEAP_DATA\u003c/code\u003e build option that changes the behavior of \u003ccode\u003eExternalEvent()\u003c/code\u003e. When defined, just pass in data on the stack instead of creating external event data on the heap as shown below. This option relieves the caller from having to remember to create event data structure dynamically.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nMotorData data;\ndata.speed = 100;\nmotor.SetSpeed(\u0026amp;data);\u003c/pre\u003e\n\n\u003cp\u003eThe option doesn\u0026#39;t effect internal events. \u003ccode\u003eInternalEvent()\u003c/code\u003e data, if any, must still be created on the heap.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nMotorData* data = new MotorData();\ndata-\u0026gt;speed = 100;\nInternalEvent(ST_CHANGE_SPEED, data);\u003c/pre\u003e\n\n## Hiding and eliminating heap usage\n\n\u003cp\u003eThe \u003ccode\u003eSetSpeed()\u003c/code\u003e function takes a \u003ccode\u003eMotorData \u003c/code\u003eargument that the client must create on the heap. Alternatively, the class can hide the heap usage from the caller. The change is as simple as creating the \u003ccode\u003eMotorData \u003c/code\u003einstance within the \u003ccode\u003eSetSpeed()\u003c/code\u003e function. This way, the caller isn\u0026rsquo;t required to create a dynamic instance:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid Motor::SetSpeed(INT speed)\n{\n    MotorData* data = new MotorData;\n    pData-\u0026gt;speed = speed;\n\n    BEGIN_TRANSITION_MAP                             // - Current State -\n        TRANSITION_MAP_ENTRY (ST_START)              // ST_IDLE\n        TRANSITION_MAP_ENTRY (CANNOT_HAPPEN)         // ST_STOP\n        TRANSITION_MAP_ENTRY (ST_CHANGE_SPEED)       // ST_START\n        TRANSITION_MAP_ENTRY (ST_CHANGE_SPEED)       // ST_CHANGE_SPEED\n    END_TRANSITION_MAP(data)\n}\u003c/pre\u003e\n\n\u003cp\u003eAlternatively, use the\u0026nbsp;\u003ccode\u003eEXTERNAL_EVENT_NO_HEAP_DATA\u003c/code\u003e build option and the caller is not required to create external event data on the heap.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eOn some systems, using the heap is undesirable. For those systems, I\u0026#39;ve included the \u003ccode\u003exallocator \u003c/code\u003efixed block allocator within the attached source code. It\u0026#39;s optional, but when used it creates memory blocks from static memory or previously recycled heap memory. A single \u003ccode\u003eXALLOCATOR \u003c/code\u003emacro in the \u003ccode\u003eEventData\u003c/code\u003e base class provides fixed block allocations for all \u003ccode\u003eEventData \u003c/code\u003eand derived classes.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n#include \u0026quot;xallocator.h\u0026quot;\nclass EventData\n{\npublic:\n    virtual ~EventData() {}\n    XALLOCATOR\n};\u003c/pre\u003e\n\n\u003cp\u003eFor more information on xallocator, see the article \u0026quot;\u003cstrong\u003e\u003ca href=\"http://www.codeproject.com/Articles/1084801/Replace-malloc-free-with-a-Fast-Fixed-Block-Memory\"\u003eReplace malloc/free with a Fast Fixed Block Memory Allocator\u003c/a\u003e\u003c/strong\u003e\u0026quot;.\u0026nbsp;\u003c/p\u003e\n\n# State machine inheritance\n\n\u003cp\u003eInheriting states allows common states to reside in a base class for sharing with inherited classes. \u003ccode\u003eStateMachine \u003c/code\u003esupports state machine inheritance with minimal effort. I\u0026rsquo;ll use an example to illustrate.\u003c/p\u003e\n\n\u003cp\u003eSome systems have a built in self-test mode where the software executes a series of test steps to determine if the system is operational. In this example, each self-test has common states to handle Idle, Completed and Failed states. Using inheritance, a base class contains the shared states. The classes \u003ccode\u003eSelfTest\u003c/code\u003e and \u003ccode\u003eCentrifugeTest \u003c/code\u003edemonstrate the concept. The state diagram is shown below.\u0026nbsp;\u003c/p\u003e\n\n\u003cp style=\"text-align: center\"\u003e\u003cimg alt=\"\" src=\"CentrifugeTest.png\" /\u003e\u003c/p\u003e\n\n\u003cp style=\"text-align: center\"\u003e\u003cstrong\u003eFigure 2: CentrifugeTest state diagram\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eSelfTest \u003c/code\u003edefines the following states:\u003c/p\u003e\n\n\u003col start=\"0\"\u003e\n\t\u003cli\u003eIdle\u003c/li\u003e\n\t\u003cli\u003eCompleted\u003c/li\u003e\n\t\u003cli\u003eFailed\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003e\u003ccode\u003eCentrifugeTest \u003c/code\u003einherits those states and creates new ones:\u003c/p\u003e\n\n\u003col start=\"3\"\u003e\n\t\u003cli\u003eStart Test\u003c/li\u003e\n\t\u003cli\u003eAcceleration\u003c/li\u003e\n\t\u003cli\u003eWait For Acceleration\u003c/li\u003e\n\t\u003cli\u003eDeceleration\u003c/li\u003e\n\t\u003cli\u003eWait For Deceleration\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSeftTest \u003c/code\u003ebase class defines the \u003ccode\u003eStates \u003c/code\u003eenumeration and states but not the state map. Only the most derived state machine class within the hierarchy defines a state map.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nenum States\n{\n    ST_IDLE,\n    ST_COMPLETED,\n    ST_FAILED,\n    ST_MAX_STATES\n};\n\n// Define the state machine states\nSTATE_DECLARE(SelfTest,     Idle,            NoEventData)\nENTRY_DECLARE(SelfTest,     EntryIdle,       NoEventData)\nSTATE_DECLARE(SelfTest,     Completed,       NoEventData)\nSTATE_DECLARE(SelfTest,     Failed,          NoEventData)\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eCentrifugeTest \u003c/code\u003eclass defines its state machine below. Take note of the \u0026quot;\u003ccode\u003eST_START_TEST = SelfTest::ST_MAX_STATES\u003c/code\u003e\u0026quot; enumeration entry. It is critical that the derived class continue numbering states where the base class left off.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nenum States\n{\n    // Continue state numbering using the last SelfTest::States enum value\n    ST_START_TEST = SelfTest::ST_MAX_STATES,    \n    ST_ACCELERATION,\n    ST_WAIT_FOR_ACCELERATION,\n    ST_DECELERATION,\n    ST_WAIT_FOR_DECELERATION,\n    ST_MAX_STATES\n};\n\n// Define the state machine state functions with event data type\nSTATE_DECLARE(CentrifugeTest,     Idle,                        NoEventData)\nSTATE_DECLARE(CentrifugeTest,     StartTest,                   NoEventData)\nGUARD_DECLARE(CentrifugeTest,     GuardStartTest,              NoEventData)\nSTATE_DECLARE(CentrifugeTest,     Acceleration,                NoEventData)\nSTATE_DECLARE(CentrifugeTest,     WaitForAcceleration,         NoEventData)\nEXIT_DECLARE(CentrifugeTest,      ExitWaitForAcceleration)\nSTATE_DECLARE(CentrifugeTest,     Deceleration,                NoEventData)\nSTATE_DECLARE(CentrifugeTest,     WaitForDeceleration,         NoEventData)\nEXIT_DECLARE(CentrifugeTest,      ExitWaitForDeceleration)\n\n// State map to define state object order. Each state map entry defines a\n// state object.\nBEGIN_STATE_MAP_EX\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;Idle, 0, \u0026amp;EntryIdle, 0)\n    STATE_MAP_ENTRY_EX(\u0026amp;Completed)\n    STATE_MAP_ENTRY_EX(\u0026amp;Failed)\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;StartTest, \u0026amp;GuardStartTest, 0, 0)\n    STATE_MAP_ENTRY_EX(\u0026amp;Acceleration)\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;WaitForAcceleration, 0, 0, \u0026amp;ExitWaitForAcceleration)\n    STATE_MAP_ENTRY_EX(\u0026amp;Deceleration)\n    STATE_MAP_ENTRY_ALL_EX(\u0026amp;WaitForDeceleration, 0, 0, \u0026amp;ExitWaitForDeceleration)\nEND_STATE_MAP_EX    \u003c/pre\u003e\n\n\u003cp\u003eThe state map contains entries for all states within the hierarchy, in this case \u003ccode\u003eSelfTest \u003c/code\u003eand \u003ccode\u003eCentrifugeTest\u003c/code\u003e. Notice the use of the _EX extended state map macros so that guard/entry/exit features are supported. For instance, a guard condition for the StartState is declared as:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nGUARD_DECLARE(CentrifugeTest, GuardStartTest, NoEventData)\u003c/pre\u003e\n\n\u003cp\u003eThe guard condition function returns \u003ccode\u003eTRUE \u003c/code\u003eif the state function is to be executed or \u003ccode\u003eFALSE\u003c/code\u003e otherwise.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nGUARD_DEFINE(CentrifugeTest, GuardStartTest, NoEventData)\n{\n    cout \u0026lt;\u0026lt; \u0026quot;CentrifugeTest::GuardStartTest\u0026quot; \u0026lt;\u0026lt; endl;\n    if (m_speed == 0)\n        return TRUE;    // Centrifuge stopped. OK to start test.\n    else\n        return FALSE;   // Centrifuge spinning. Can\u0026#39;t start test.\n}\u003c/pre\u003e\n\n## Base class external event functions\n\n\u003cp\u003eWhen using state machine inheritance, it\u0026rsquo;s not just the most-derived class that may define external event functions. The base and intermediary classes may also use transition maps. A parent state machine doesn\u0026rsquo;t have awareness of child classes. One or more subclass state machine hierarchical levels may exist each adding more states. Therefore parent classes of the most-derived state machine utilize a \u003cem\u003epartial\u003c/em\u003e transition map, that is, the state transition map only handles the states that are known to the parent class. Any events generated while the current state is outside the maximum parent state\u0026nbsp;enumeration range must be handled by the \u003ccode\u003eSUBCLASS_TRANSITION \u003c/code\u003emacro which is placed directly above the transition map as shown below.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid SelfTest::Cancel()\n{\n    SUBCLASS_TRANSITION (ST_FAILED)\n\n    BEGIN_TRANSITION_MAP                                    // - Current State -\n        TRANSITION_MAP_ENTRY (EVENT_IGNORED)                // ST_IDLE\n        TRANSITION_MAP_ENTRY (CANNOT_HAPPEN)                // ST_COMPLETED\n        TRANSITION_MAP_ENTRY (CANNOT_HAPPEN)                // ST_FAILED\n    END_TRANSITION_MAP(NULL)\n}\n\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSUBCLASS_TRANSITION \u003c/code\u003eexample above is read \u0026ldquo;If the Cancel event is generated when the state machine is \u003cem\u003enot\u003c/em\u003e in \u003ccode\u003eST_IDLE\u003c/code\u003e, \u003ccode\u003eST_COMPLETE\u003c/code\u003e, or \u003ccode\u003eST_FAILED \u003c/code\u003ethen transition to the \u003ccode\u003eST_FAILED \u003c/code\u003estate\u0026rdquo;. The macro preceding the transition map is the catch-all if the current state is beyond what is known by the current state machine hierarchy level. The expanded \u003ccode\u003eSUBCLASS_TRANSITION \u003c/code\u003emacro for the above example is shown below.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nif (GetCurrentState() \u0026gt;= ST_MAX_STATES \u0026amp;\u0026amp; \n    GetCurrentState() \u0026lt; GetMaxStates()) { \n     ExternalEvent(ST_FAILED); \n     return; }\n\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eGetCurrentState()\u003c/code\u003e returns the state machine current state. \u003ccode\u003eST_MAX_STATES \u003c/code\u003eis the maximum parent class \u003ccode\u003eState \u003c/code\u003eenum value. \u003ccode\u003eGetMaxStates()\u003c/code\u003e returns the maximum state value for the entire state machine up to the most-derived class. The expanded code shows that if the current state is higher than the maximum parent class state value (i.e. \u003ccode\u003eSelfTest::ST_MAX_STATES\u003c/code\u003e) but less than the entire state machine maximum state value (i.e. \u003ccode\u003eCentrifugeTest::ST_MAX_STATES\u003c/code\u003e), then transition to state Failed. In this way, transitions are uniformly handled if outside the range handled by the parent partial transition map. Otherwise, the partial transition map handles the state transition. \u003ccode\u003eEVENT_IGNORED \u003c/code\u003eand \u003ccode\u003eCANNOT_HAPPED \u003c/code\u003eare also valid \u003ccode\u003eSUBCLASS_TRANSITION\u003c/code\u003e arguments.\u003c/p\u003e\n\n\u003cp\u003eLet\u0026rsquo;s say the parent\u0026nbsp;\u003ccode\u003eSelfTest::Cancel()\u003c/code\u003e is unacceptable for some child classes. Just override or make the external event function \u003ccode\u003evirtual \u003c/code\u003eand use a full transition map within the derived \u003ccode\u003eCancel()\u003c/code\u003e function.\u003c/p\u003e\n\n\u003cp\u003eAlternative to a partial transition map, a parent class may generate external events manually without any macro support. To have external event functions within parent class hierarchy levels, use \u003ccode\u003eGetCurrentState()\u003c/code\u003e and \u003ccode\u003eExternalEvent()\u003c/code\u003e. The \u003ccode\u003eSelfTest \u003c/code\u003eclass has one external event function: \u003ccode\u003eCancel()\u003c/code\u003e. As shown in the code below, the state machine transitions to the Failed state if the current state is not Idle.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid SelfTest::Cancel()\n{\n    if (GetCurrentState() != ST_IDLE)\n        ExternalEvent(ST_FAILED);\n}\u003c/pre\u003e\n\n\u003cp\u003eThe state machine inheritance technique expressed here does not implement a Hierarchical State Machine (HSM). An HSM has different semantics and behaviors including, among other things, a hierarchical event processing model. This feature explained here offers code reuse by factoring common states into a base class, but the state machine is still considered a traditional FSM.\u003c/p\u003e\n\n# State function inheritance\n\n\u003cp\u003eState functions can be overridden in the derived class. The derived class may call the base implementation if so desired. In this case, \u003ccode\u003eSelfTest \u003c/code\u003edeclares and defines an Idle state:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nSTATE_DECLARE(SelfTest, Idle, NoEventData)\n\nSTATE_DEFINE(SelfTest,  Idle, NoEventData)\n{\n    cout \u0026lt;\u0026lt; \u0026quot;SelfTest::ST_Idle\u0026quot; \u0026lt;\u0026lt; endl;\n}\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eCentrifugeTest \u003c/code\u003ealso declares and defines the same Idle\u0026nbsp;state with the same event data type.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nSTATE_DECLARE(CentrifugeTest,  Idle, NoEventData)\n\nSTATE_DEFINE(CentrifugeTest,   Idle, NoEventData)\n{\n    cout \u0026lt;\u0026lt; \u0026quot;CentrifugeTest::ST_Idle\u0026quot; \u0026lt;\u0026lt; endl;\n\n    // Call base class Idle state\n    SelfTest::ST_Idle(data);    \n    StopPoll();\n}\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eCentrifugeTest::ST_Idle() \u003c/code\u003efunction calls the base implementation \u003ccode\u003eSelfTest::ST_Idle()\u003c/code\u003e. State function inheritance is a powerful mechanism to allow each level within the hierarchy to process the same event.\u003c/p\u003e\n\n\u003cp\u003eIn the same way a state function is overridden, a derived class may also override a guard/entry/exit function. Within the override, you decide whether to call the base implementation or not on a case-by-case basis.\u0026nbsp;\u003c/p\u003e\n\n# StateMachine compact class\n\n\u003cp\u003eIf the \u003ccode\u003eStateMachine \u003c/code\u003eimplementation is too large or too slow due to the virtual function and typecasting, then the compact version is available at the expense of no type checking of the member function pointers. The compact version is only 68 bytes (on Windows release build) vs. 448 bytes on the non-compact version. See \u003cem\u003eStateMachineCompact.zip\u003c/em\u003e for the source files.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eNotice that we have to use \u003ccode\u003ereinterpret_cast\u0026lt;\u0026gt;\u003c/code\u003e operator within the \u003ccode\u003eSTATE_MAP_ENTRY \u003c/code\u003emacro to cast the derived class member function pointer to a \u003ccode\u003eStateMachine \u003c/code\u003emember function pointer.\u0026nbsp;\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nreinterpret_cast\u0026lt;StateFunc\u0026gt;(stateFunc)\u003c/pre\u003e\n\n\u003cp\u003eIt is necessary to perform this upcast since the \u003ccode\u003eStateMachine\u003c/code\u003e base class has no idea what the derived class is. So, it is imperative that the entries provided to \u003ccode\u003eSTATE_MAP_ENTRY \u003c/code\u003eare really member functions of an inheriting class and that they conform to the state function signature discussed earlier (see State Functions section). Otherwise bad things will happen.\u003c/p\u003e\n\n\u003cp\u003eOn most projects, I\u0026rsquo;m not counting CPU instructions for the state execution and a few extra bytes of storage isn\u0026rsquo;t critical. The state machine portion of my projects have never been the bottleneck. So I prefer the enhanced error checking of the non-compact version.\u0026nbsp;\u003c/p\u003e\n\n# Multithread safety\n\n\u003cp\u003eTo prevent preemption by another thread when the state machine is in the process of execution, the \u003ccode\u003eStateMachine \u003c/code\u003eclass can use locks within the \u003ccode\u003eExternalEvent()\u003c/code\u003e function. Before the external event is allowed to execute, a semaphore can be locked. When the external event and all internal events have been processed, the software lock is released, allowing another external event to enter the state machine instance.\u003c/p\u003e\n\n\u003cp\u003eComments indicate where the lock and unlock should be placed if the application is multithreaded. Note that each \u003ccode\u003eStateMachine \u003c/code\u003eobject should have its own instance of a software lock. This prevents a single instance from locking and preventing all other \u003ccode\u003eStateMachine\u003c/code\u003e objects from executing. Note, software locks are only required if a \u003ccode\u003eStateMachine \u003c/code\u003einstance is called by multiple threads of control. If not, then locks are not required.\u003c/p\u003e\n\n\u003cp\u003eSee the article \u0026quot;\u003cstrong\u003e\u003ca href=\"http://www.codeproject.com/Articles/1156423/Cplusplus-State-Machine-with-Threads\"\u003eC++ State Machine with Threads\u003c/a\u003e\u003c/strong\u003e\u0026quot; for a complete multithreaded example\u0026nbsp;using the state machine presented here.\u003c/p\u003e\n\n# Alternatives\n\n\u003cp\u003eOccasionally you need something more powerful to capture the behavior of a system using events and states. The version presented here is a variation of a conventional FSM. A true Hierarchical State Machine (HSM), on the other hand, can significantly simplify the solution to certain types of problems. Many good HSM projects exist ready for you to explore. But sometimes a simple FSM is all that you need.\u0026nbsp;\u003c/p\u003e\n\n# Benefits\n\n\u003cp\u003eImplementing a state machine using this method as opposed to the old switch statement style may seem like extra effort. However, the payoff is in a more robust design that is capable of being employed uniformly over an entire multithreaded system. Having each state in its own function provides easier reading than a single huge switch statement, and allows unique event data to be sent to each state. In addition, validating state transitions prevents client misuse by eliminating the side effects caused by unwanted state transitions.\u003c/p\u003e\n\n\u003cp\u003eI\u0026rsquo;ve used variations of this code for self-test engines, a gesture recognition library, user interface wizards, and machine automation, among other projects. This implementation offers easy use for the inheriting classes. With the macros it lets you just \u0026quot;turn the crank\u0026quot; without much thought given to the underlying mechanics of how the state engine operates. This allows you more time to concentrate on more important things, like the design of the state transitions and state function implementation.\u003c/p\u003e\n\n# References\n\n\u003cul\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachineWithThreads\"\u003eC++ State Machine with Threads\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachineWithDelegates\"\u003eC++ State Machine with Delegates\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachineWithModernDelegates\"\u003eC++ State Machine with Modern Delegates\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://www.codeproject.com/Articles/1165243/Cplusplus-State-Machine-with-Asynchronous-Multicas\"\u003e\u003cstrong\u003eC++ State Machine with Asynchronous Multicast Delegates\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"http://www.codeproject.com/Articles/1084801/Replace-malloc-free-with-a-Fast-Fixed-Block-Memory\"\u003eReplace malloc/free with a Fast Fixed Block Memory Allocator\u003c/a\u003e\u0026nbsp;- by David Lafreniere\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"http://www.codeproject.com/Articles/1083210/An-Efficient-Cplusplus-Fixed-Block-Memory-Allocato\"\u003eAn Efficient C++ Fixed Block Memory Allocator\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\u003c/ul\u003e\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fstatemachine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fendurodave%2Fstatemachine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fstatemachine/lists"}