/* * 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 . */ /* Include Files */ #include "SystemK.h" const StateActivity_T STATE_DEFAULT_Activities = { .Entry = NULL, .Do = NULL, .Exit = NULL }; //! Activities for the top-level state machine. /*! * This array is indexed by #StateID_T (except there is no entry for * #STATE_OUT_OF_RANGE or #STATE_NONE), and the order of activities * must match the order of the enumeration. */ static const StateActivity_T * Activities[] = { &STATE_DEFAULT_Activities, &STATE_INITIALIZING_Activities, &STATE_REPROGRAMMING_Activities, &STATE_CONFIGURING_Activities, &STATE_READY_Activities, &STATE_STARTING_GAME__INSTIGATING_Activities, &STATE_STARTING_GAME__RESPONDING_Activities, &STATE_STARTING_GAME__COUNTING_DOWN_Activities, &STATE_PLAYING__INTERACTING_Activities, &STATE_PLAYING__TAGGED_OUT_Activities, &STATE_WRAPPING_UP_Activities }; //! Context in which the top-level state machine is run. static StateMachineContext_T Context = { .States = { .Previous_State = STATE_NONE, .Current_State = STATE_NONE, .Next_State = STATE_INITIALIZING }, .Time_At_State_Entry_In_Ticks = 0, }; TaskHandle_t State_Machine_Task_Handle; void State_Machine_Task(void * pvParameters) { while (true) { // Handle state changes. if (Context.States.Next_State != Context.States.Current_State) { // Exit the current state. if (Context.States.Current_State < STATE_IS_OUT_OF_RANGE) { if (Activities[Context.States.Current_State]->Exit != NULL) { Activities[Context.States.Current_State]->Exit(&Context); } } // Save off the time of the state change. Context.Time_At_State_Entry_In_Ticks = xTaskGetTickCount(); // Update the current state. Context.States.Previous_State = Context.States.Current_State; Context.States.Current_State = Context.States.Next_State; if (Context.States.Current_State < STATE_IS_OUT_OF_RANGE) { // Enter the current state. if (Activities[Context.States.Current_State]->Entry != NULL) { Activities[Context.States.Current_State]->Entry(&Context); } } } if (Context.States.Current_State < STATE_IS_OUT_OF_RANGE) { // Execute the current state. if (Activities[Context.States.Current_State]->Do != NULL) { Activities[Context.States.Current_State]->Do(&Context); } } vTaskDelay(1); } } void ProcessUnhandledEvent(KEvent_T * Event) { switch (Event->ID) { case KEVENT_TAG_RECEIVED: FreeDecodedPacketBuffer(Event->Data); break; case KEVENT_COMMAND_RECEIVED: FreeDecodedPacketBuffer(Event->Data); break; case KEVENT_BLE_PACKET_RECEIVED: BLE_FreePacketBuffer(Event->Data); break; default: // All other events can be safely ignored. break; } }