{"id":18240666,"url":"https://github.com/endurodave/c_statemachine","last_synced_at":"2025-04-05T10:08:43.920Z","repository":{"id":113549575,"uuid":"163698699","full_name":"endurodave/C_StateMachine","owner":"endurodave","description":"State Machine Design in C","archived":false,"fork":false,"pushed_at":"2025-02-18T15:58:25.000Z","size":156,"stargazers_count":135,"open_issues_count":1,"forks_count":32,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-05T10:08:38.924Z","etag":null,"topics":["c-language","cross-platform","embedded-c","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":"2018-12-31T21:37:08.000Z","updated_at":"2025-03-31T12:48:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"71940a41-804d-47cc-ac46-3a3211d5bc08","html_url":"https://github.com/endurodave/C_StateMachine","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_StateMachine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_StateMachine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_StateMachine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/endurodave%2FC_StateMachine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/endurodave","download_url":"https://codeload.github.com/endurodave/C_StateMachine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247318744,"owners_count":20919484,"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":["c-language","cross-platform","embedded-c","embedded-systems","finite-state-machine","state-machine"],"created_at":"2024-11-05T05:04:15.066Z","updated_at":"2025-04-05T10:08:43.891Z","avatar_url":"https://github.com/endurodave.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"![License MIT](https://img.shields.io/github/license/BehaviorTree/BehaviorTree.CPP?color=blue)\n[![conan Ubuntu](https://github.com/endurodave/C_StateMachine/actions/workflows/cmake_ubuntu.yml/badge.svg)](https://github.com/endurodave/C_StateMachine/actions/workflows/cmake_ubuntu.yml)\n[![conan Ubuntu](https://github.com/endurodave/C_StateMachine/actions/workflows/cmake_clang.yml/badge.svg)](https://github.com/endurodave/C_StateMachine/actions/workflows/cmake_clang.yml)\n[![conan Windows](https://github.com/endurodave/C_StateMachine/actions/workflows/cmake_windows.yml/badge.svg)](https://github.com/endurodave/C_StateMachine/actions/workflows/cmake_windows.yml)\n\n# State Machine Design in C\n\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- [Project Build](#project-build)\n  - [Windows Visual Studio](#windows-visual-studio)\n  - [Linux Make](#linux-make)\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 module](#statemachine-module)\n- [Motor example](#motor-example)\n  - [External events](#external-events)\n  - [State enumerations](#state-enumerations)\n  - [State functions](#state-functions)\n  - [State map](#state-map)\n  - [State machine objects](#state-machine-objects)\n  - [Transition map](#transition-map)\n  - [New state machine steps](#new-state-machine-steps)\n- [State engine](#state-engine)\n- [Generating events](#generating-events)\n- [No heap usage](#no-heap-usage)\n- [CentrifugeTest example](#centrifugetest-example)\n- [Multithread safety](#multithread-safety)\n- [Conclusion](#conclusion)\n- [References](#references)\n\n# Preface\n\nOriginally published on CodeProject at: \u003ca href=\"https://www.codeproject.com/Articles/1275479/State-Machine-Design-in-C\"\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\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## Related repositories\n\n\u003cul\u003e\n    \u003cli\u003e\u003ca href=\"https://github.com/endurodave/C_StateMachineWithThreads\"\u003eC Language State Machine with Threads\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/C_Allocator\"\u003eA Fixed Block Allocator in C\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachine\"\u003eState Machine Design in C++\u003c/a\u003e - by David Lafreniere\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.\u003c/p\u003e\n\n\u003cp\u003eSometimes C is the right tool for the job. This article provides an alternate C language state machine implementation based on the ideas presented within the article \u0026ldquo;\u003cem\u003eState Machine Design in C++\u003c/em\u003e\u0026rdquo;. The design is suitable for any platform, embedded or PC, with any C compiler. This state machine has the following features:\u003c/p\u003e\n\n\u003cul\u003e\n\t\u003cli\u003e\u003cstrong\u003eC language\u003c/strong\u003e \u0026ndash; state machine written in C\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eCompact \u003c/strong\u003e\u0026ndash; consumes a minimum amount of resources.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eObjects\u003c/strong\u003e\u0026nbsp;\u0026ndash; support\u0026nbsp;multiple instantiations of a\u0026nbsp;single state machine type.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eTransition tables\u003c/strong\u003e \u0026ndash; transition tables precisely control state transition behavior.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eEvents \u003c/strong\u003e\u0026ndash; every event is a simple function with any argument types.\u003c/li\u003e\n\t\u003cli\u003e\u003cstrong\u003eState action\u003c/strong\u003e \u0026ndash; every state action is a separate 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\u0026nbsp;\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\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\u003eError checking\u003c/strong\u003e \u0026ndash; compile time and runtime checks catch mistakes early.\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/ul\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.\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.\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\n    case ST_STOP:\n       // do something in the stop state\n       break;\n\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# Project Build\n\n\u003ca href=\"https://www.cmake.org\"\u003eCMake\u003c/a\u003e is used to create the build files. CMake is free and open-source software. Windows, Linux and other toolchains are supported. Example CMake console commands executed inside the project root directory: \n\n## Windows Visual Studio\n\n\u003ccode\u003ecmake -G \"Visual Studio 17 2022\" -A Win32 -B Build -S .\u003c/code\u003e\n\nAfter executed, open the Visual Studio project from within the \u003ccode\u003eBuild\u003c/code\u003e directory.\n\n## Linux Make\n\n\u003ccode\u003ecmake -G \"Unix Makefiles\" -B Build -S .\u003c/code\u003e\n\nAfter executed, build the software from within the Build directory using the command \u003ccode\u003emake\u003c/code\u003e. Run the console app using \u003ccode\u003e./C_StateMachineApp\u003c/code\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.\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 module, these two events, or functions, are considered external events. To a client using our code, however, these are just plain functions.\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 instance can set the initial state when defined. 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 module. 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\u003e\u003cimg alt=\"\" src=\"Motor.png\" /\u003e\u003c/p\u003e\n\n\u003cdiv class=\"Caption\"\u003eFigure 1: Motor state diagram\u003c/div\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 module. 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 module\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 state machine instance. See source code function \u003ccode\u003e_SM_ExternalEvent()\u003c/code\u003e comments for where the locks go.\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. Event data is a single \u003ccode\u003econst\u003c/code\u003e or non-\u003ccode\u003econst \u003c/code\u003epointer to any built-in or user-defined data type.\u003c/p\u003e\n\n\u003cp\u003eOnce 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 dynamically created via \u003ccode\u003eSM_XAlloc()\u003c/code\u003e. \u0026nbsp;The state machine engine automatically frees allocated event data using \u003ccode\u003eSM_XFree()\u003c/code\u003e.\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 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 module\n\n\u003cp\u003eThe state machine source code is contained within the \u003cstrong\u003eStateMachine.c\u003c/strong\u003e and \u003cstrong\u003eStateMachine.h\u003c/strong\u003e files. The code below shows the partial header. The \u003cstrong\u003e\u003ccode\u003eStateMachine\u003c/code\u003e \u003c/strong\u003eheader contains various preprocessor multiline macros to ease implementation of a state machine.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nenum { EVENT_IGNORED = 0xFE, CANNOT_HAPPEN = 0xFF };\n\ntypedef void NoEventData;\n\n// State machine constant data\ntypedef struct\n{\n    const CHAR* name;\n    const BYTE maxStates;\n    const struct SM_StateStruct* stateMap;\n    const struct SM_StateStructEx* stateMapEx;\n} SM_StateMachineConst;\n\n// State machine instance data\ntypedef struct \n{\n    const CHAR* name;\n    void* pInstance;\n    BYTE newState;\n    BYTE currentState;\n    BOOL eventGenerated;\n    void* pEventData;\n} SM_StateMachine;\n\n// Generic state function signatures\ntypedef void (*SM_StateFunc)(SM_StateMachine* self, void* pEventData);\ntypedef BOOL (*SM_GuardFunc)(SM_StateMachine* self, void* pEventData);\ntypedef void (*SM_EntryFunc)(SM_StateMachine* self, void* pEventData);\ntypedef void (*SM_ExitFunc)(SM_StateMachine* self);\n\ntypedef struct SM_StateStruct\n{\n    SM_StateFunc pStateFunc;\n} SM_StateStruct;\n\ntypedef struct SM_StateStructEx\n{\n    SM_StateFunc pStateFunc;\n    SM_GuardFunc pGuardFunc;\n    SM_EntryFunc pEntryFunc;\n    SM_ExitFunc pExitFunc;\n} SM_StateStructEx;\n\n// Public functions\n#define SM_Event(_smName_, _eventFunc_, _eventData_) \\\n    _eventFunc_(\u0026amp;_smName_##Obj, _eventData_)\n\n// Protected functions\n#define SM_InternalEvent(_newState_, _eventData_) \\\n    _SM_InternalEvent(self, _newState_, _eventData_)\n#define SM_GetInstance(_instance_) \\\n    (_instance_*)(self-\u0026gt;pInstance);\n\n// Private functions\nvoid _SM_ExternalEvent(SM_StateMachine* self, const SM_StateMachineConst* selfConst, BYTE newState, void* pEventData);\nvoid _SM_InternalEvent(SM_StateMachine* self, BYTE newState, void* pEventData);\nvoid _SM_StateEngine(SM_StateMachine* self, const SM_StateMachineConst* selfConst);\nvoid _SM_StateEngineEx(SM_StateMachine* self, const SM_StateMachineConst* selfConst);\n\n#define SM_DECLARE(_smName_) \\\n    extern SM_StateMachine _smName_##Obj; \n\n#define SM_DEFINE(_smName_, _instance_) \\\n    SM_StateMachine _smName_##Obj = { #_smName_, _instance_, \\\n        0, 0, 0, 0 }; \n\n#define EVENT_DECLARE(_eventFunc_, _eventData_) \\\n    void _eventFunc_(SM_StateMachine* self, _eventData_* pEventData);\n\n#define EVENT_DEFINE(_eventFunc_, _eventData_) \\\n    void _eventFunc_(SM_StateMachine* self, _eventData_* pEventData)\n\n#define STATE_DECLARE(_stateFunc_, _eventData_) \\\n    static void ST_##_stateFunc_(SM_StateMachine* self, _eventData_* pEventData);\n\n#define STATE_DEFINE(_stateFunc_, _eventData_) \\\n    static void ST_##_stateFunc_(SM_StateMachine* self, _eventData_* pEventData)\n\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSM_Event()\u003c/code\u003e macro is used to generate external events whereas \u003ccode\u003eSM_InternalEvent()\u003c/code\u003e generates an internal event during state function execution. \u003ccode\u003eSM_GetInstance()\u003c/code\u003e obtains a pointer to the current state machine object.\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eSM_DECLARE \u003c/code\u003eand \u003ccode\u003eSM_DEFINE\u003c/code\u003e are used to create a state machine instance. \u003ccode\u003eEVENT_DECLARE\u003c/code\u003e and \u003ccode\u003eEVENT_DEFINE\u003c/code\u003e create external event functions. And finally, \u003ccode\u003eSTATE_DECLARE\u003c/code\u003e and \u003ccode\u003eSTATE_DEFINE\u003c/code\u003e create state functions.\u003c/p\u003e\n\n# Motor example\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\u003eMotor\u003c/code\u003e header interface is shown below:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n#include \u0026quot;StateMachine.h\u0026quot;\n\n// Motor object structure\ntypedef struct\n{\n    INT currentSpeed;\n} Motor;\n\n// Event data structure\ntypedef struct\n{\n    INT speed;\n} MotorData;\n\n// State machine event functions\nEVENT_DECLARE(MTR_SetSpeed, MotorData)\nEVENT_DECLARE(MTR_Halt, NoEventData)\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eMotor\u003c/code\u003e source file uses macros to simplify usage by hiding the required state machine machinery.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// State enumeration order must match the order of state\n// method entries in the state map\nenum States\n{\n    ST_IDLE,\n    ST_STOP,\n    ST_START,\n    ST_CHANGE_SPEED,\n    ST_MAX_STATES\n};\n\n// State machine state functions\nSTATE_DECLARE(Idle, NoEventData)\nSTATE_DECLARE(Stop, NoEventData)\nSTATE_DECLARE(Start, MotorData)\nSTATE_DECLARE(ChangeSpeed, MotorData)\n\n// State map to define state function order\nBEGIN_STATE_MAP(Motor)\n    STATE_MAP_ENTRY(ST_Idle)\n    STATE_MAP_ENTRY(ST_Stop)\n    STATE_MAP_ENTRY(ST_Start)\n    STATE_MAP_ENTRY(ST_ChangeSpeed)\nEND_STATE_MAP(Motor)\n\n// Set motor speed external event\nEVENT_DEFINE(MTR_SetSpeed, MotorData)\n{\n    // Given the SetSpeed event, transition to a new state based upon \n    // the current state of the state machine\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_ChangeSpeed\n    END_TRANSITION_MAP(Motor, pEventData)\n}\n\n// Halt motor external event\nEVENT_DEFINE(MTR_Halt, NoEventData)\n{\n    // Given the Halt event, transition to a new state based upon \n    // the current state of the state machine\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_ChangeSpeed\n    END_TRANSITION_MAP(Motor, pEventData)\n}\u003c/pre\u003e\n\n## External events\n\n\u003cp\u003e\u003ccode\u003eMTR_SetSpeed \u003c/code\u003eand \u003ccode\u003eMTR_Halt\u003c/code\u003e are considered external events into the \u003ccode\u003eMotor\u003c/code\u003e state machine. \u003ccode\u003eMTR_SetSpeed \u003c/code\u003etakes a pointer to \u003ccode\u003eMotorData\u003c/code\u003e event data, containing the motor speed. This data structure will be freed using \u003ccode\u003eSM_XFree()\u003c/code\u003e upon completion of the state processing, so it is imperative that it be created using \u003ccode\u003eSM_XAlloc()\u003c/code\u003e before the function call is made.\u003c/p\u003e\n\n## State enumerations\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\u003e provides these enumerations, which are used later for indexing into the transition map and state map lookup tables.\u003c/p\u003e\n\n## State functions\n\n\u003cp\u003eState functions implement each state \u0026mdash; one state function per state-machine state. \u003ccode\u003eSTATE_DECLARE \u003c/code\u003eis used to declare the state function interface and \u003ccode\u003eSTATE_DEFINE \u003c/code\u003edefines the implementation.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// State machine sits here when motor is not running\nSTATE_DEFINE(Idle, NoEventData)\n{\n    printf(\u0026quot;%s ST_Idle\\n\u0026quot;, self-\u0026gt;name);\n}\n\n// Stop the motor \nSTATE_DEFINE(Stop, NoEventData)\n{\n    // Get pointer to the instance data and update currentSpeed\n    Motor* pInstance = SM_GetInstance(Motor);\n    pInstance-\u0026gt;currentSpeed = 0;\n\n    // Perform the stop motor processing here\n    printf(\u0026quot;%s ST_Stop: %d\\n\u0026quot;, self-\u0026gt;name, pInstance-\u0026gt;currentSpeed);\n\n    // Transition to ST_Idle via an internal event\n    SM_InternalEvent(ST_IDLE, NULL);\n}\n\n// Start the motor going\nSTATE_DEFINE(Start, MotorData)\n{\n    ASSERT_TRUE(pEventData);\n\n    // Get pointer to the instance data and update currentSpeed\n    Motor* pInstance = SM_GetInstance(Motor);\n    pInstance-\u0026gt;currentSpeed = pEventData-\u0026gt;speed;\n\n    // Set initial motor speed processing here\n    printf(\u0026quot;%s ST_Start: %d\\n\u0026quot;, self-\u0026gt;name, pInstance-\u0026gt;currentSpeed);\n}\n\n// Changes the motor speed once the motor is moving\nSTATE_DEFINE(ChangeSpeed, MotorData)\n{\n    ASSERT_TRUE(pEventData);\n\n    // Get pointer to the instance data and update currentSpeed\n    Motor* pInstance = SM_GetInstance(Motor);\n    pInstance-\u0026gt;currentSpeed = pEventData-\u0026gt;speed;\n\n    // Perform the change motor speed here\n    printf(\u0026quot;%s ST_ChangeSpeed: %d\\n\u0026quot;, self-\u0026gt;name, pInstance-\u0026gt;currentSpeed);\n}\n\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eSTATE_DECLARE\u003c/code\u003e and \u003ccode\u003eSTATE_DEFINE\u003c/code\u003e use two arguments. The first argument is the state function name. The second argument is the event data type. If no event data is required, use \u003ccode\u003eNoEventData\u003c/code\u003e. Macros are also available for creating guard, exit and entry actions which are explained later in the article.\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSM_GetInstance()\u003c/code\u003e macro obtains an instance to the state machine object. The argument to the macro is the state machine name.\u003c/p\u003e\n\n\u003cp\u003eIn this implementation, all state machine functions must adhere to these signatures, which are as follows:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// Generic state function signatures\ntypedef void (*SM_StateFunc)(SM_StateMachine* self, void* pEventData);\ntypedef BOOL (*SM_GuardFunc)(SM_StateMachine* self, void* pEventData);\ntypedef void (*SM_EntryFunc)(SM_StateMachine* self, void* pEventData);\ntypedef void (*SM_ExitFunc)(SM_StateMachine* self);\n\u003c/pre\u003e\n\n\u003cp\u003eEach \u003ccode\u003eSM_StateFunc \u003c/code\u003eaccepts a pointer to a \u003ccode\u003eSM_StateMachine\u003c/code\u003e object and event data. If \u003ccode\u003eNoEventData \u003c/code\u003eis used, the \u003ccode\u003epEventData \u003c/code\u003eargument will be \u003ccode\u003eNULL\u003c/code\u003e. Otherwise, the \u003ccode\u003epEventData\u003c/code\u003e argument is of the type specified in \u003ccode\u003eSTATE_DEFINE\u003c/code\u003e.\u003c/p\u003e\n\n\u003cp\u003eIn \u003ccode\u003eMotor\u003c/code\u003e\u0026rsquo;s \u003ccode\u003eStart\u003c/code\u003e state function, the \u003ccode\u003eSTATE_DEFINE(Start, MotorData)\u0026nbsp;\u003c/code\u003emacro expands to:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid ST_Start(SM_StateMachine* self, MotorData* pEventData)\u003c/pre\u003e\n\n\u003cp\u003eNotice that every state function has \u003ccode\u003eself \u003c/code\u003eand\u0026nbsp;\u003ccode\u003epEventData \u003c/code\u003earguments. \u003ccode\u003eself \u003c/code\u003eis a pointer to the state machine object and \u003ccode\u003epEventData \u003c/code\u003eis the event data. Also note that the macro prepends \u0026ldquo;ST_\u0026rdquo; to the state name to create the function \u003ccode\u003eST_Start()\u003c/code\u003e.\u003c/p\u003e\n\n\u003cp\u003eSimilarly, the \u003ccode\u003eStop \u003c/code\u003estate function \u003ccode\u003eSTATE_DEFINE(Stop, NoEventData)\u003c/code\u003e is expands to:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nvoid ST_Stop(SM_StateMachine* self, void* pEventData)\u003c/pre\u003e\n\n\u003cp\u003e\u003ccode\u003eStop \u003c/code\u003edoesn\u0026#39;t accept event data so the \u003ccode\u003epEventData \u003c/code\u003eargument is \u003ccode\u003evoid*\u003c/code\u003e.\u0026nbsp;\u003c/p\u003e\n\n\u003cp\u003eThree characters are added to each state/guard/entry/exit function automatically within the macros. For instance, if declaring a function using \u003ccode\u003eSTATE_DEFINE(Idle, NoEventData)\u003c/code\u003e the actual state function name is called \u003ccode\u003eST_Idle()\u003c/code\u003e.\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\u003e\u003ccode\u003eSM_GuardFunc \u003c/code\u003eand \u003ccode\u003eSM_Entry \u003c/code\u003efunction \u003ccode\u003etypedef\u003c/code\u003e\u0026rsquo;s also accept event data. \u003ccode\u003eSM_ExitFunc \u003c/code\u003eis unique in that no event data is allowed.\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\u003ecurrentState\u003c/code\u003e variable to a specific state function. For instance, if \u003ccode\u003ecurrentState \u003c/code\u003eis 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\u003cdiv\u003e\n\u003cpre\u003e\nBEGIN_STATE_MAP\nSTATE_MAP_ENTRY\nEND_STATE_MAP\u003c/pre\u003e\n\u003c/div\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(Motor)\n    STATE_MAP_ENTRY(ST_Idle)\n    STATE_MAP_ENTRY(ST_Stop)\n    STATE_MAP_ENTRY(ST_Start)\n    STATE_MAP_ENTRY(ST_ChangeSpeed)\nEND_STATE_MAP\n\u003c/pre\u003e\n\n\u003cp\u003eAlternatively, guard/entry/exit features require utilizing the \u003ccode\u003e_EX\u003c/code\u003e (extended) version of the macros.\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.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// State map to define state function order\nBEGIN_STATE_MAP_EX(CentrifugeTest)\n    STATE_MAP_ENTRY_ALL_EX(ST_Idle, 0, EN_Idle, 0)\n    STATE_MAP_ENTRY_EX(ST_Completed)\n    STATE_MAP_ENTRY_EX(ST_Failed)\n    STATE_MAP_ENTRY_ALL_EX(ST_StartTest, GD_StartTest, 0, 0)\n    STATE_MAP_ENTRY_EX(ST_Acceleration)\n    STATE_MAP_ENTRY_ALL_EX(ST_WaitForAcceleration, 0, 0, EX_WaitForAcceleration)\n    STATE_MAP_ENTRY_EX(ST_Deceleration)\n    STATE_MAP_ENTRY_ALL_EX(ST_WaitForDeceleration, 0, 0, EX_WaitForDeceleration)\nEND_STATE_MAP_EX(CentrifugeTest)\u003c/pre\u003e\n\n\u003cp\u003eDon\u0026rsquo;t forget to add the prepended characters (ST_, GD_, EN_ or EX_) for each function.\u003c/p\u003e\n\n## State machine objects\n\n\u003cp\u003eIn C++, objects are integral to the language. Using C, you have to work a bit harder to accomplish similar behavior. This C language state machine supports multiple state machine objects (or instances) instead of having\u0026nbsp;a single, static state machine implementation.\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSM_StateMachine \u003c/code\u003edata structure stores state machine instance data; one object per state machine instance. The\u0026nbsp;\u003ccode\u003eSM_StateMachineConst \u003c/code\u003edata structure stores constant data; one constant object per state machine type.\u003c/p\u003e\n\n\u003cp\u003eThe state machine is defined using \u003ccode\u003eSM_DEFINE \u003c/code\u003emacro. The first argument is the state machine name. The second argument is a pointer to a user defined state machine structure, or \u003ccode\u003eNULL \u003c/code\u003eif no user object.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n#define SM_DEFINE(_smName_, _instance_) \\\n    SM_StateMachine _smName_##Obj = { #_smName_, _instance_, \\\n        0, 0, 0, 0 };\u003c/pre\u003e\n\n\u003cp\u003eIn this example, the state machine name is \u003ccode\u003eMotor\u003c/code\u003e and two objects and two state machines are created.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// Define motor objects\nstatic Motor motorObj1;\nstatic Motor motorObj2;\n\n// Define two public Motor state machine instances\nSM_DEFINE(Motor1SM, \u0026amp;motorObj1)\nSM_DEFINE(Motor2SM, \u0026amp;motorObj2)\u003c/pre\u003e\n\n\u003cp\u003eEach motor object handles state execution independent of the other. The \u003ccode\u003eMotor \u003c/code\u003estructure is used to store state machine instance-specific data. Within a state function, use \u003ccode\u003eSM_GetInstance()\u003c/code\u003e\u0026nbsp;to obtain\u0026nbsp;a pointer to the \u003ccode\u003eMotor \u003c/code\u003eobject at runtime.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// Get pointer to the instance data and update currentSpeed\nMotor* pInstance = SM_GetInstance(Motor);\npInstance-\u0026gt;currentSpeed = pEventData-\u0026gt;speed;\n\u003c/pre\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\u003ecurrentState \u003c/code\u003evariable to a state enum constant. Every external event function 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\n\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eMTR_Halt \u003c/code\u003eevent function in \u003ccode\u003eMotor \u003c/code\u003edefines the transition map as:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// Halt motor external event\nEVENT_DEFINE(MTR_Halt, NoEventData)\n{\n    // Given the Halt event, transition to a new state based upon \n    // the current state of the state machine\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_ChangeSpeed\n    END_TRANSITION_MAP(Motor, pEventData)\n}\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\u003e that 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 transition map entries. The location of each entry matches the order of state functions defined within the state map. Thus, the first entry within the \u003ccode\u003eMTR_Halt\u003c/code\u003e function indicates an \u003ccode\u003eEVENT_IGNORED \u003c/code\u003eas shown below.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nTRANSITION_MAP_ENTRY (EVENT_IGNORED)\u0026nbsp;\u0026nbsp;\u0026nbsp; \u003ci\u003e// ST_Idle\u003c/i\u003e\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\u003cdiv\u003e\n\u003cpre\u003e\nTRANSITION_MAP_ENTRY (ST_STOP)\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; \u003cem\u003e// ST_Start\u003c/em\u003e\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003eThis indicates \u0026quot;If a Halt event occurs while current is state Start, then transition to state Stop.\u0026quot;\u003c/p\u003e\n\n\u003cp\u003e\u003ccode\u003eEND_TRANSITION_MAP \u003c/code\u003eterminates the map. The first argument to this macro is the state machine name. The second argument is the event data.\u003c/p\u003e\n\n\u003cp\u003eThe \u003ccode\u003eC_ASSERT()\u003c/code\u003e macro is used within \u003ccode\u003eEND_TRANSITION_MAP\u003c/code\u003e. If there is a mismatch between the number of state machine states and the number of transition map entries, a compile time error is generated.\u003c/p\u003e\n\n## New state machine steps\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\u003eCreate a \u003ccode\u003eStates \u003c/code\u003eenumeration with one entry per state function.\u003c/li\u003e\n\t\u003cli\u003eDefine state functions.\u003c/li\u003e\n\t\u003cli\u003eDefine event functions.\u003c/li\u003e\n\t\u003cli\u003eCreate one state map lookup table using the \u003ccode\u003eSTATE_MAP\u003c/code\u003e macros.\u003c/li\u003e\n\t\u003cli\u003eCreate one transition map lookup table for each external event function using the \u003ccode\u003eTRANSITION_MAP \u003c/code\u003emacros.\u003c/li\u003e\n\u003c/ol\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\u003eSM_StateStruct\u003c/code\u003e instances indexed by the \u003ccode\u003ecurrentState \u003c/code\u003evariable. When the \u003ccode\u003e_SM_StateEngine()\u003c/code\u003e function executes, it looks up the correct state function within the \u003ccode\u003eSM_StateStruct \u003c/code\u003earray. After the state function has a chance to execute, it frees the event data, if any, before checking to see if any internal events were generated via \u003ccode\u003eSM_InternalEvent()\u003c/code\u003e.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// The state engine executes the state machine states\nvoid _SM_StateEngine(SM_StateMachine* self, SM_StateMachineConst* selfConst)\n{\n\u0026nbsp; \u0026nbsp; void* pDataTemp = NULL;\n\n\u0026nbsp; \u0026nbsp; ASSERT_TRUE(self);\n\u0026nbsp; \u0026nbsp; ASSERT_TRUE(selfConst);\n\n\u0026nbsp; \u0026nbsp; // While events are being generated keep executing states\n\u0026nbsp; \u0026nbsp; while (self-\u0026gt;eventGenerated)\n\u0026nbsp; \u0026nbsp; {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Error check that the new state is valid before proceeding\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; ASSERT_TRUE(self-\u0026gt;newState \u0026lt; selfConst-\u0026gt;maxStates);\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Get the pointers from the state map\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; SM_StateFunc state = selfConst-\u0026gt;stateMap[self-\u0026gt;newState].pStateFunc;\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Copy of event data pointer\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; pDataTemp = self-\u0026gt;pEventData;\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Event data used up, reset the pointer\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; self-\u0026gt;pEventData = NULL;\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Event used up, reset the flag\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; self-\u0026gt;eventGenerated = FALSE;\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Switch to the new current state\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; self-\u0026gt;currentState = self-\u0026gt;newState;\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // Execute the state action passing in event data\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; ASSERT_TRUE(state != NULL);\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; state(self, pDataTemp);\n\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; // If event data was used, then delete it\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; if (pDataTemp)\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; {\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; SM_XFree(pDataTemp);\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; pDataTemp = NULL;\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; }\n\u0026nbsp; \u0026nbsp; }\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\u003e_SM_StateEngine()\u003c/code\u003e engine implements only #1 and #5 below. The extended \u003ccode\u003e_SM_StateEngineEx()\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.\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.\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.\u003c/li\u003e\n\t\u003cli\u003eCall the state action function for the new state. The new state is now the current state.\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 dynamically creating the event data structure using \u003ccode\u003eSM_XAlloc()\u003c/code\u003e, assigning the structure member variables, and calling the external event function using the \u003ccode\u003eSM_Event()\u003c/code\u003e macro. The following code fragment shows how a synchronous call is made.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nMotorData* data;\n \n// Create event data\ndata = SM_XAlloc(sizeof(MotorData));\ndata-\u0026gt;speed = 100;\n\n// Call MTR_SetSpeed event function to start motor\nSM_Event(Motor1SM, MTR_SetSpeed, data);\n\u003c/pre\u003e\n\n\u003cp\u003eThe \u003ccode\u003eSM_Event()\u003c/code\u003e first argument is the state machine name. The second argument is the event function to invoke. The third argument is the event data, or \u003ccode\u003eNULL \u003c/code\u003eif no data.\u003c/p\u003e\n\n\u003cp\u003eTo generate an internal event from within a state function, call \u003ccode\u003eSM_InternalEvent()\u003c/code\u003e. If the destination doesn\u0026#39;t accept event data, then the last argument is \u003ccode\u003eNULL\u003c/code\u003e. Otherwise, create the event data using \u003ccode\u003eSM_XAlloc()\u003c/code\u003e.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nSM_InternalEvent(ST_IDLE, NULL);\u003c/pre\u003e\n\n\u003cp\u003eIn the example above, once the state function completes execution the state machine will transition to the \u003ccode\u003eST_Idle\u003c/code\u003e 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;    \ndata = SM_XAlloc(sizeof(MotorData));\ndata-\u0026gt;speed = 100;\nSM_InternalEvent(ST_CHANGE_SPEED, data);\n\u003c/pre\u003e\n\n# No heap usage\n\n\u003cp\u003eAll state machine event data must be dynamically created. However, on some systems using the heap is undesirable. The included \u003ccode\u003ex_allocator\u003c/code\u003e module is a fixed block memory allocator that eliminates heap usage. Define \u003ccode\u003eUSE_SM_ALLOCATOR \u003c/code\u003ewithin \u003cstrong\u003eStateMachine.c\u003c/strong\u003e to use the fixed block allocator. See the \u003cstrong\u003eReferences\u003c/strong\u003e section below for\u0026nbsp;\u003ccode\u003ex_allocator\u003c/code\u003e information.\u003c/p\u003e\n\n# CentrifugeTest example\n\n\u003cp\u003eThe \u003ccode\u003eCentrifugeTest \u003c/code\u003eexample shows how an extended state machine is created using guard, entry and exit actions. The state diagram is shown below.\u003c/p\u003e\n\n\u003cp\u003e\u003cimg alt=\"\" src=\"CentrifugeTest.png\" style=\"height: 736px; width: 500px\" /\u003e\u003c/p\u003e\n\n\u003cdiv class=\"Caption\"\u003eFigure 2: CentrifugeTest state diagram\u003c/div\u003e\n\n\u003cp\u003eA \u003ccode\u003eCentrifgeTest \u003c/code\u003eobject and state machine is created. The only difference here is that the state machine is a singleton, meaning the object is private and only one instance of \u003ccode\u003eCentrifugeTest \u003c/code\u003ecan be created. This is unlike the \u003ccode\u003eMotor \u003c/code\u003estate machine where multiple instances are allowed.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// CentrifugeTest object structure\ntypedef struct\n{\n    INT speed;\n    BOOL pollActive;\n} CentrifugeTest;\n\n// Define private instance of motor state machine\nCentrifugeTest centrifugeTestObj;\nSM_DEFINE(CentrifugeTestSM, \u0026amp;centrifugeTestObj)\n\u003c/pre\u003e\n\n\u003cp\u003eThe extended state machine uses \u003ccode\u003eENTRY_DECLARE\u003c/code\u003e, \u003ccode\u003eGUARD_DECLARE\u003c/code\u003e and \u003ccode\u003eEXIT_DECLARE \u003c/code\u003emacros.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// State enumeration order must match the order of state\n// method entries in the state map\nenum States\n{\n    ST_IDLE,\n    ST_COMPLETED,\n    ST_FAILED,\n    ST_START_TEST,\n    ST_ACCELERATION,\n    ST_WAIT_FOR_ACCELERATION,\n    ST_DECELERATION,\n    ST_WAIT_FOR_DECELERATION,\n    ST_MAX_STATES\n};\n\n// State machine state functions\nSTATE_DECLARE(Idle, NoEventData)\nENTRY_DECLARE(Idle, NoEventData)\nSTATE_DECLARE(Completed, NoEventData)\nSTATE_DECLARE(Failed, NoEventData)\nSTATE_DECLARE(StartTest, NoEventData)\nGUARD_DECLARE(StartTest, NoEventData)\nSTATE_DECLARE(Acceleration, NoEventData)\nSTATE_DECLARE(WaitForAcceleration, NoEventData)\nEXIT_DECLARE(WaitForAcceleration)\nSTATE_DECLARE(Deceleration, NoEventData)\nSTATE_DECLARE(WaitForDeceleration, NoEventData)\nEXIT_DECLARE(WaitForDeceleration)\n\n// State map to define state function order\nBEGIN_STATE_MAP_EX(CentrifugeTest)\n    STATE_MAP_ENTRY_ALL_EX(ST_Idle, 0, EN_Idle, 0)\n    STATE_MAP_ENTRY_EX(ST_Completed)\n    STATE_MAP_ENTRY_EX(ST_Failed)\n    STATE_MAP_ENTRY_ALL_EX(ST_StartTest, GD_StartTest, 0, 0)\n    STATE_MAP_ENTRY_EX(ST_Acceleration)\n    STATE_MAP_ENTRY_ALL_EX(ST_WaitForAcceleration, 0, 0, EX_WaitForAcceleration)\n    STATE_MAP_ENTRY_EX(ST_Deceleration)\n    STATE_MAP_ENTRY_ALL_EX(ST_WaitForDeceleration, 0, 0, EX_WaitForDeceleration)\nEND_STATE_MAP_EX(CentrifugeTest)\n\u003c/pre\u003e\n\n\u003cp\u003eNotice the \u003ccode\u003e_EX\u003c/code\u003e extended state map macros so the guard/entry/exit features are supported. Each guard/entry/exit \u003ccode\u003eDECLARE \u003c/code\u003emacro must be matched with the \u003ccode\u003eDEFINE\u003c/code\u003e. For instance, a guard condition for the \u003ccode\u003eStartTest \u003c/code\u003estate function is declared as:\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\nGUARD_DECLARE(StartTest, 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\u003eotherwise.\u003c/p\u003e\n\n\u003cpre lang=\"c++\"\u003e\n// Guard condition to determine whether StartTest state is executed.\nGUARD_DEFINE(StartTest, NoEventData)\n{\n    printf(\u0026quot;%s GD_StartTest\\n\u0026quot;, self-\u0026gt;name);\n    if (centrifugeTestObj.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}\n\u003c/pre\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\u003emodule can use locks within the \u003ccode\u003e_SM_ExternalEvent()\u003c/code\u003e\u0026nbsp;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\u0026nbsp;\u003cem\u003eand\u003c/em\u003e mutiple threads are able to access a single state machine instance. 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\u003eobjects from executing. 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\u003cul\u003e\n\u003c/ul\u003e\n\n# Conclusion\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 \u003ccode\u003eswitch\u003c/code\u003e 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\u003eThis C language version is a close translation of the\u0026nbsp;C++ implementation I\u0026rsquo;ve used for many years on different projects. Consider the C++ implementation within the \u003cstrong\u003eReferences \u003c/strong\u003esection if using C++.\u003c/p\u003e\n\n# References\n\n\u003cul\u003e\n    \u003cli\u003e\u003ca href=\"https://github.com/endurodave/C_StateMachineWithThreads\"\u003eC Language State Machine with Threads\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\t\u003cli\u003e\u003ca href=\"https://github.com/endurodave/C_Allocator\"\u003eA Fixed Block Allocator in C\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"https://github.com/endurodave/StateMachine\"\u003eState Machine Design in C++\u003c/a\u003e - by David Lafreniere\u003c/li\u003e\n\u003c/ul\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fc_statemachine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fendurodave%2Fc_statemachine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fendurodave%2Fc_statemachine/lists"}