/* * 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" static void Configuring_Entry(StateMachineContext_T *context); static void Configuring_Do(StateMachineContext_T *context); static void Configuring_Exit(StateMachineContext_T *context); #define MAX_MENU_DEPTH 10 static MenuItem_T const *CurrentMenuItem; static uint8_t MenuItemHistoryIndex = 0; static MenuItem_T const *MenuItemHistory[MAX_MENU_DEPTH]; static const uint16_t LONG_PRESS_FOR_READY_in_ms = 5000; static const char *KLOG_TAG = "STATE_CONFIGURING"; //! Activities for the **Configuring** state. const StateActivity_T STATE_CONFIGURING_Activities = { .Entry = Configuring_Entry, .Do = Configuring_Do, .Exit = Configuring_Exit}; //! Sets up the Configuring state. /*! * \param context Context in which this state is being run. */ static void Configuring_Entry(StateMachineContext_T *context) { LOG("Entering the Configuring state."); NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_MENU, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); BLE_UpdateHelloPacket(); if (BLE_ScanAndAdvertise() != SYSTEMK_RESULT_SUCCESS) { KLOG_ERROR(KLOG_TAG, "Couldn't start BLE!"); } // Reset the menu. CurrentMenuItem = RootMenu; MenuItemHistory[MenuItemHistoryIndex] = CurrentMenuItem; } //! Executes the Configuring state. /*! * \param context Context in which this state is being run. */ static void Configuring_Do(StateMachineContext_T *context) { portBASE_TYPE xStatus; static KEvent_T Event; xStatus = Receive_KEvent(&Event); if (xStatus == pdPASS) { switch (Event.ID) { case KEVENT_MENU_ENTER: if (CurrentMenuItem->OnFocus != NULL) { CurrentMenuItem->OnFocus(true); } break; case KEVENT_MENU_SELECT: { if (CurrentMenuItem->OnSelect != NULL) { MenuItem_T const *menuItem = CurrentMenuItem->OnSelect(); // Check to see if we have entered a submenu. if (menuItem != NULL) { // Save off the old menu item, so we can get back to it later. MenuItemHistoryIndex++; MenuItemHistory[MenuItemHistoryIndex] = menuItem; CurrentMenuItem = menuItem; if (CurrentMenuItem->OnFocus != NULL) { CurrentMenuItem->OnFocus(true); } } } } break; case KEVENT_MENU_BACK: if (MenuItemHistoryIndex > 0) { // Go up a menu. MenuItemHistoryIndex--; CurrentMenuItem = MenuItemHistory[MenuItemHistoryIndex]; if (CurrentMenuItem->OnFocus != NULL) { CurrentMenuItem->OnFocus(true); } } break; case KEVENT_MENU_UP: { if (CurrentMenuItem->OnIncrement != NULL) { CurrentMenuItem->OnIncrement(); } } break; case KEVENT_MENU_DOWN: { if (CurrentMenuItem->OnDecrement != NULL) { CurrentMenuItem->OnDecrement(); } } break; case KEVENT_MENU_EXIT: while (MenuItemHistoryIndex > 0) { // Go up a menu. MenuItemHistoryIndex--; CurrentMenuItem = MenuItemHistory[MenuItemHistoryIndex]; if (CurrentMenuItem->OnFocus != NULL) { CurrentMenuItem->OnFocus(true); } } BLE_UpdateHelloPacket(); break; case KEVENT_TRIGGER_SWITCH_RELEASED: { uint32_t duration_of_press_in_ms = (uint32_t)Event.Data; if (duration_of_press_in_ms > LONG_PRESS_FOR_READY_in_ms) { Transition_For_Event(context, STATE_READY, &Event); } } break; case KEVENT_ACCESSORY_SWITCH_PRESSED: { uint8_t Team_ID; (void)SETTINGS_get_uint8_t(SYSTEMK_SETTING_TEAMID, &Team_ID); Team_ID++; if (Team_ID > BASIC_TEAMS_MAXIMUM) { Team_ID = BASIC_TEAMS_MINIMUM; } if (Set_Team_With_Audio_Feedback(Team_ID) != SYSTEMK_RESULT_SUCCESS) { KLOG_WARN(KLOG_TAG, "Failed to increment team!"); } BLE_UpdateHelloPacket(); } break; case KEVENT_PLAY_PRESSED_ON_REMOTE: Transition_For_Event(context, STATE_READY, &Event); break; case KEVENT_REPROGRAM: Transition_For_Event(context, STATE_REPROGRAMMING, &Event); break; default: // All other events are ignored in this state. ProcessUnhandledEvent(&Event); break; } } } //! Cleans up the Configuring state. /*! * \param context Context in which this state is being run. */ static void Configuring_Exit(StateMachineContext_T *context) { // Save any changes that were made to NVM. if (SETTINGS_Save() != SYSTEMK_RESULT_SUCCESS) { KLOG_ERROR(KLOG_TAG, "Couldn't save the settings to NVM!"); } NeoPixelsAction_T neopixels_action = {.ID = NEOPIXELS_ALL_OFF, .Prominence = NEOPIXELS_FOREGROUND, .Data = (void *)0x00}; xQueueSend(xQueueNeoPixels, &neopixels_action, 0); }