From fde252908e1d3e016e2cf74b950cef09f634d306 Mon Sep 17 00:00:00 2001 From: VPavlusha Date: Thu, 13 Apr 2023 18:16:17 +0300 Subject: [PATCH] Release #2 --- .gitignore | 5 +++ CMakeLists.txt | 11 +++++- README.md | 68 ++++++++++++++++++++------------ include/finite_state_machine.h | 26 +----------- include/finite_state_machine.hpp | 48 ++++++---------------- src/finite_state_machine.c | 51 ++++++++++++++++++++++++ src/finite_state_machine.cpp | 56 ++++++++++++++++++++++++++ 7 files changed, 178 insertions(+), 87 deletions(-) create mode 100644 .gitignore create mode 100644 src/finite_state_machine.c create mode 100644 src/finite_state_machine.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ace975 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +# Build results +build/ + +# VSCode +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt index 55afde2..9809025 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,15 +8,22 @@ else() add_compile_options(-Wall -Wextra -pedantic -Werror) endif() +set (SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set (INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) set (EXAMPLES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/examples) project(fsm_example_c) set(CMAKE_CXX_STANDARD 98) -add_executable(${PROJECT_NAME} ${EXAMPLES_DIR}/example.c ${INCLUDE_DIR}/finite_state_machine.h) +add_executable(${PROJECT_NAME} + ${SRC_DIR}/finite_state_machine.c + ${EXAMPLES_DIR}/example.c +) target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIR}) project(fsm_example_cpp) set(CMAKE_CXX_STANDARD 11) -add_executable(${PROJECT_NAME} ${EXAMPLES_DIR}/example.cpp ${INCLUDE_DIR}/finite_state_machine.hpp) +add_executable(${PROJECT_NAME} + ${SRC_DIR}/finite_state_machine.cpp + ${EXAMPLES_DIR}/example.cpp +) target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIR}) diff --git a/README.md b/README.md index 0547cac..f55baff 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,12 @@ [![CMake](https://github.com/VPavlusha/FSM/actions/workflows/cmake.yml/badge.svg)](https://github.com/VPavlusha/FSM/actions/workflows/cmake.yml) [![cpp-linter](https://github.com/VPavlusha/FSM/actions/workflows/cpp-linter.yml/badge.svg)](https://github.com/VPavlusha/FSM/actions/workflows/cpp-linter.yml) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/VPavlusha/FSM?label=Release&logo=github)](https://github.com/VPavlusha/FSM/releases) +[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) +[![Made in Ukraine](https://img.shields.io/badge/Made_in-Ukraine-ffd700.svg?labelColor=0057b7)](https://stand-with-ukraine.pp.ua) --- # FSM - Finite State Machine -A static (no dynamic allocations) Finite State Machine (FSM) header-only C/C++ library.
+A static (no dynamic allocations) Finite State Machine (FSM) C/C++ library.
Based on: https://github.com/AstarLight/FSM-framework #### Table of Contents @@ -14,16 +16,16 @@ Based on: https://github.com/AstarLight/FSM-framework  [3. Basic Usage in C](#3-basic-usage-in-c)  [4. Basic Usage in C++](#4-basic-usage-in-c)  [5. Examples](#5-examples) - [6. Installation](#6-installation) - [7. Requirement](#7-requirement) - [8. Build Procedure](#8-build-procedure) - [9. License](#9-license) + [6. Requirement](#6-requirement) + [7. Build Procedure by CMake (Unix)](#7-build-procedure-by-cmake-unix) + [8. Build Procedure by CMake (Windows)](#8-build-procedure-by-cmake-windows) + [9. Contributing](#9-contributing) + [10. License](#10-license) ## 1. Features - **Permissive** MIT License. - **C and C++ languages** – state machine is written both in C and C++ languages. - **Compact** – consumes a minimum amount of resources. - - **Header-only library** – no special installation steps are needed. - **Fully static** – no dynamic memory allocations. - **Objects** – support multiple FSM instantiations of a single state machine type. - **Transition table** – transition table precisely controls state transition behavior. @@ -32,7 +34,6 @@ Based on: https://github.com/AstarLight/FSM-framework - **Error checking** – runtime checks catch mistakes early. ## 2. State Transition Table - Finite State Machine The state diagram shown in the figure can be described via a state transition table. This table has four columns and as many rows as needed. Each row describes a transition from the **Present State** to the **Next State**. The transition is triggered by the **Event** (a combination of one or more event flags). The **Action** describes all the actions associated with the transition. @@ -100,7 +101,7 @@ int main() #include "finite_state_machine.hpp" // 2. Create enumeration for FSM states: -enum FSM_States : int { +enum FSM_States: int { STATE_0, STATE_1, STATE_2, @@ -146,32 +147,49 @@ int main() ``` ## 5. Examples -This project includes several [`examples`](https://github.com/VPavlusha/FSM/tree/main/examples) that showcase the functionality of the FSM library. These examples provide a practical demonstration of how to use the FSM API to implement finite state machines in your own applications. +This project includes several [examples](https://github.com/VPavlusha/FSM/tree/main/examples) that showcase the functionality of the FSM library. These examples provide a practical demonstration of how to use the FSM API to implement finite state machines in your own applications. + +## 6. Requirement +For the build process: + - **cmake** + - **make** + - **gcc** -## 6. Installation -FSM is a header-only library, no special installation steps are needed. Just point your compiler to the [`include`](https://github.com/VPavlusha/FSM/tree/main/include) directory. +For the documentation generation: + - **doxygen** -## 7. Requirement -For the build process : - - cmake - - make - - gcc +## 7. Build Procedure by CMake (Unix) +``` +git clone https://github.com/VPavlusha/FSM.git +cd fsm +mkdir build && cd build +cmake .. # Default to Unix Makefiles +make +``` +Once this completes, everything will be under **`build/`**: + - **fsm_example_c** + - **fsm_example_cpp** -For the documentation generation : - - doxygen +Run these files to try how FSM works. -## 8. Build Procedure +## 8. Build Procedure by CMake (Windows) ``` git clone https://github.com/VPavlusha/FSM.git cd fsm mkdir build && cd build -cmake .. -G "Unix Makefiles" && make +cmake .. -G "Unix Makefiles" # Or use any generator you want to use. Run cmake --help for a list +make ``` +Once this completes, everything will be under **`build/`**: + - **fsm_example_c.exe** + - **fsm_example_cpp.exe** + +Run these files to try how FSM works. -## 9. License -FSM is the [Open Source] software. It may be used for any purpose, -including commercial purposes, at absolutely no cost. It is -distributed under the terms of the [MIT license]. +## 9. Contributing +Contributions to the FSM project are welcome. If you find a bug or have a feature request, please submit an issue on the project's GitHub page. If you'd like to contribute code, please submit a pull request. - [Open Source]: http://www.opensource.org/docs/definition.html +## 10. License +The FSM project is licensed under the MIT License. See the [MIT license] file for more information. + [MIT license]: http://www.opensource.org/licenses/mit-license.html diff --git a/include/finite_state_machine.h b/include/finite_state_machine.h index 2b524f2..8733be5 100644 --- a/include/finite_state_machine.h +++ b/include/finite_state_machine.h @@ -31,7 +31,7 @@ */ #include -#include +#include typedef bool (*FSM_Event_t)(void); typedef void (*FSM_Action_t)(void); @@ -76,28 +76,6 @@ typedef struct { * \return FSM_SUCCESS On success. * \return FSM_ARGUMENT_NOT_VALID If an argument is a NULL pointer. */ -FSM_ReturnCode_t FSM_Kernel(FSM_t *const fsm) -{ - if (fsm == NULL) { - return FSM_ARGUMENT_NOT_VALID; - } - - for (size_t row = 0; row < fsm->fsm_table_size / sizeof(FSM_TableRow_t); ++row) { - if (fsm->fsm_table[row].present_state == fsm->current_state) { - if (fsm->fsm_table[row].event != NULL) { - if (fsm->fsm_table[row].event()) { - if (fsm->fsm_table[row].action != NULL) { - fsm->fsm_table[row].action(); - } - fsm->current_state = fsm->fsm_table[row].next_state; - break; - } - } else { - return FSM_ARGUMENT_NOT_VALID; - } - } - } - return FSM_SUCCESS; -} +FSM_ReturnCode_t FSM_Kernel(FSM_t *const fsm); #endif // FINITE_STATE_MACHINE_H_ diff --git a/include/finite_state_machine.hpp b/include/finite_state_machine.hpp index 19dcdb9..2c34118 100644 --- a/include/finite_state_machine.hpp +++ b/include/finite_state_machine.hpp @@ -81,7 +81,19 @@ class FSM { FSM &operator=(FSM &&) = delete; ~FSM() = default; + /** + * \brief Get FSM current state. + * + * \return FSM_State_t The FSM current state. + */ FSM_State_t FSM_GetCurrentState() const noexcept; + + /** + * \brief FSM kernel task running on background. + * + * \return FSM_SUCCESS On success. + * \return FSM_ARGUMENT_NOT_VALID If an argument is a nullptr pointer. + */ FSM_ReturnCode_t FSM_Kernel() noexcept; private: @@ -90,42 +102,6 @@ class FSM { FSM_State_t current_state_; }; -/** - * \brief Get FSM current state. - * - * \return FSM_State_t The FSM current state. - */ -FSM_State_t FSM::FSM_GetCurrentState() const noexcept -{ - return current_state_; -} - -/** - * \brief FSM kernel task running on background. - * - * \return FSM_SUCCESS On success. - * \return FSM_ARGUMENT_NOT_VALID If an argument is a nullptr pointer. - */ -FSM_ReturnCode_t FSM::FSM_Kernel() noexcept -{ - for (size_t row = 0; row < fsm_table_size_ / sizeof(FSM_TableRow_t); ++row) { - if (fsm_table_[row].present_state == current_state_) { - if (fsm_table_[row].event != nullptr) { - if (fsm_table_[row].event()) { - if (fsm_table_[row].action != nullptr) { - fsm_table_[row].action(); - } - current_state_ = fsm_table_[row].next_state; - break; - } - } else { - return FSM_ReturnCode_t::FSM_ARGUMENT_NOT_VALID; - } - } - } - return FSM_ReturnCode_t::FSM_SUCCESS; -} - } // namespace fsm #endif // FINITE_STATE_MACHINE_HPP_ diff --git a/src/finite_state_machine.c b/src/finite_state_machine.c new file mode 100644 index 0000000..c6957c0 --- /dev/null +++ b/src/finite_state_machine.c @@ -0,0 +1,51 @@ +/* + * MIT License + * + * Copyright (c) 2022 Volodymyr Pavlusha + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "finite_state_machine.h" + +#include + +FSM_ReturnCode_t FSM_Kernel(FSM_t *const fsm) +{ + if (fsm == NULL) { + return FSM_ARGUMENT_NOT_VALID; + } + + for (size_t row = 0; row < fsm->fsm_table_size / sizeof(FSM_TableRow_t); ++row) { + if (fsm->fsm_table[row].present_state == fsm->current_state) { + if (fsm->fsm_table[row].event != NULL) { + if (fsm->fsm_table[row].event()) { + if (fsm->fsm_table[row].action != NULL) { + fsm->fsm_table[row].action(); + } + fsm->current_state = fsm->fsm_table[row].next_state; + break; + } + } else { + return FSM_ARGUMENT_NOT_VALID; + } + } + } + return FSM_SUCCESS; +} diff --git a/src/finite_state_machine.cpp b/src/finite_state_machine.cpp new file mode 100644 index 0000000..c338dc9 --- /dev/null +++ b/src/finite_state_machine.cpp @@ -0,0 +1,56 @@ +/* + * MIT License + * + * Copyright (c) 2022 Volodymyr Pavlusha + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include + +namespace fsm { + +FSM_State_t FSM::FSM_GetCurrentState() const noexcept +{ + return current_state_; +} + +FSM_ReturnCode_t FSM::FSM_Kernel() noexcept +{ + for (size_t row = 0; row < fsm_table_size_ / sizeof(FSM_TableRow_t); ++row) { + if (fsm_table_[row].present_state == current_state_) { + if (fsm_table_[row].event != nullptr) { + if (fsm_table_[row].event()) { + if (fsm_table_[row].action != nullptr) { + fsm_table_[row].action(); + } + current_state_ = fsm_table_[row].next_state; + break; + } + } else { + return FSM_ReturnCode_t::FSM_ARGUMENT_NOT_VALID; + } + } + } + return FSM_ReturnCode_t::FSM_SUCCESS; +} + +} // namespace fsm