/* * This program source code file is part of SystemK, a library in the KTag project. * * 🛡️ 🃞 * * Copyright © 2016-2025 Joseph P. Kearney and the KTag developers. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * There should be a copy of the GNU Affero General Public License in the LICENSE * file in the root of this repository. If not, see . */ #ifndef STATE_MACHINE_H #define STATE_MACHINE_H #define LOG_STATE_MACHINE TRUE #ifdef LOG_STATE_MACHINE #define LOG(message) KLOG_INFO("STATE", message) #else // LOG_STATE_MACHINE #define LOG(message) #endif // LOG_STATE_MACHINE //! Names of the states and substates of the top-level state machine. /*! The enumerators are explicitly specified for (some of) these states * to aid in tracing and debugging (\see #LOG_STATE_MACHINE). */ typedef enum { STATE_INITIALIZING = 0, STATE_REPROGRAMMING = 1, STATE_CONFIGURING = 2, STATE_READY = 3, // Substates of STATE_STARTING_GAME STATE_STARTING_GAME__INSTIGATING = 4, STATE_STARTING_GAME__RESPONDING = 5, STATE_STARTING_GAME__COUNTING_DOWN = 6, // Substates of STATE_PLAYING STATE_PLAYING__INTERACTING = 7, STATE_PLAYING__TAGGED_OUT = 8, STATE_WRAPPING_UP = 9, // STATE_IS_OUT_OF_RANGE is one more than the last valid state. STATE_IS_OUT_OF_RANGE, STATE_NONE = 255 } StateID_T; //! State information used by the top-level state machine. typedef struct { //! Most recent state of the top-level state machine not currently executing. StateID_T Previous_State; //! Currently executing state of the top-level state machine. StateID_T Current_State; //! Requested state of the top-level state machine. StateID_T Next_State; } State_T; typedef struct { //! State information used by the top-level state machine. State_T States; //! The most recent event to have caused a state transition. /*! * This is used by state entry logic to determine, for example, * which substate should be entered. */ KEvent_T* Cause_Of_Transition; // Time (in RTOS ticks) when the current state was entered. TickType_t Time_At_State_Entry_In_Ticks; } StateMachineContext_T; //! Activity actions for a given state, following UML 2.5.1 State Diagrams. /*! * \see https://www.omg.org/spec/UML/2.5.1/PDF */ typedef struct { //! The function called when a state is entered. void (* const Entry)(StateMachineContext_T * context); //! The function called periodically while in a state. void (* const Do)(StateMachineContext_T * context); //! The function called when a state is exited. void (* const Exit)(StateMachineContext_T * context); } StateActivity_T; extern TaskHandle_t State_Machine_Task_Handle; void State_Machine_Task(void * pvParameters); void ProcessUnhandledEvent(KEvent_T * Event); void HandleBLEEventPacket(const BLE_EventPacket_T *const packet, StateMachineContext_T *context); inline void Transition_For_Event(StateMachineContext_T* context, StateID_T next_state, KEvent_T* event) { context->States.Next_State = next_state; context->Cause_Of_Transition = event; } inline uint32_t GetTimeInState_in_ms(StateMachineContext_T * context) { uint32_t result = (xTaskGetTickCount() - context->Time_At_State_Entry_In_Ticks) * portTICK_PERIOD_MS; return result; } StateMachineContext_T* GetContext(); #include "State_Configuring.h" #include "State_Ready.h" #include "State_Initializing.h" #include "Playing/State_Playing.h" #include "Starting_Game/State_Starting_Game.h" #include "State_Reprogramming.h" #include "State_Wrapping_Up.h" #endif // STATE_MACHINE_H