From 65d4ad1e256ea3b84745be0a0f5a64cba756122e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 30 Sep 2023 13:53:13 +0100 Subject: [PATCH 001/167] feat: WIP - Protobuf config, ConfiguratorBackend, remapping, persistence, huge refactor --- .clang-format | 3 + HAL/avr/avr_usb/src/core/KeyboardMode.cpp | 4 +- HAL/pico/include/core/KeyboardMode.hpp | 3 +- HAL/pico/src/comms/NintendoSwitchBackend.cpp | 6 +- HAL/pico/src/core/KeyboardMode.cpp | 6 +- config/mode_selection.hpp | 100 +++++-- config/pico/config.cpp | 261 ++++++++++++++++--- include/comms/ConfiguratorBackend.hpp | 27 ++ include/core/ControllerMode.hpp | 4 +- include/core/InputMode.hpp | 8 +- include/core/persistence.hpp | 21 ++ include/core/socd.hpp | 33 +-- include/core/state.hpp | 95 +++++-- include/input/GpioButtonInput.hpp | 4 +- include/input/SwitchMatrixInput.hpp | 10 +- include/modes/DefaultKeyboardMode.hpp | 3 +- include/modes/FgcMode.hpp | 3 +- include/modes/Melee18Button.hpp | 3 +- include/modes/Melee20Button.hpp | 5 +- include/modes/ProjectM.hpp | 3 +- include/modes/RivalsOfAether.hpp | 3 +- include/modes/Ultimate.hpp | 3 +- include/modes/extra/DarkSouls.hpp | 2 +- include/modes/extra/HollowKnight.hpp | 2 +- include/modes/extra/MKWii.hpp | 2 +- include/modes/extra/MultiVersus.hpp | 2 +- include/modes/extra/RocketLeague.hpp | 2 +- include/modes/extra/SaltAndSanctuary.hpp | 2 +- include/modes/extra/ShovelKnight.hpp | 2 +- include/modes/extra/ToughLoveArena.hpp | 2 +- include/modes/extra/Ultimate2.hpp | 2 +- platformio.ini | 18 ++ src/comms/ConfiguratorBackend.cpp | 135 ++++++++++ src/core/ControllerMode.cpp | 12 +- src/core/InputMode.cpp | 78 ++++-- src/core/persistence.cpp | 84 ++++++ src/core/socd.cpp | 94 ++++--- src/input/GpioButtonInput.cpp | 2 +- src/modes/DefaultKeyboardMode.cpp | 2 +- src/modes/FgcMode.cpp | 14 +- src/modes/Melee18Button.cpp | 11 +- src/modes/Melee20Button.cpp | 11 +- src/modes/ProjectM.cpp | 10 +- src/modes/RivalsOfAether.cpp | 10 +- src/modes/Ultimate.cpp | 10 +- src/modes/extra/DarkSouls.cpp | 10 +- src/modes/extra/HollowKnight.cpp | 10 +- src/modes/extra/MKWii.cpp | 10 +- src/modes/extra/MultiVersus.cpp | 10 +- src/modes/extra/RocketLeague.cpp | 10 +- src/modes/extra/SaltAndSanctuary.cpp | 10 +- src/modes/extra/ShovelKnight.cpp | 10 +- src/modes/extra/ToughLoveArena.cpp | 17 +- src/modes/extra/Ultimate2.cpp | 10 +- 54 files changed, 865 insertions(+), 349 deletions(-) create mode 100644 include/comms/ConfiguratorBackend.hpp create mode 100644 include/core/persistence.hpp create mode 100644 src/comms/ConfiguratorBackend.cpp create mode 100644 src/core/persistence.cpp diff --git a/.clang-format b/.clang-format index 7501bc99..32c2f383 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,4 @@ +--- DisableFormat: false AlignAfterOpenBracket: BlockIndent AlignArrayOfStructures: Left @@ -57,3 +58,5 @@ SpaceBeforeCtorInitializerColon: true SpacesInContainerLiterals: false TabWidth: 4 UseTab: Never +--- +Language: Proto \ No newline at end of file diff --git a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp index edf6435e..9aab88fc 100644 --- a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp @@ -12,7 +12,9 @@ KeyboardMode::~KeyboardMode() { } void KeyboardMode::SendReport(InputState &inputs) { - HandleSocd(inputs); + InputState remapped_inputs = inputs; + HandleRemap(inputs, remapped_inputs); + HandleSocd(remapped_inputs); UpdateKeys(inputs); _keyboard.sendReport(); } diff --git a/HAL/pico/include/core/KeyboardMode.hpp b/HAL/pico/include/core/KeyboardMode.hpp index e2d5e79f..19e83721 100644 --- a/HAL/pico/include/core/KeyboardMode.hpp +++ b/HAL/pico/include/core/KeyboardMode.hpp @@ -6,10 +6,11 @@ #include "core/state.hpp" #include +#include class KeyboardMode : public InputMode { public: - KeyboardMode(); + KeyboardMode(GameModeConfig &config); ~KeyboardMode(); void SendReport(InputState &inputs); diff --git a/HAL/pico/src/comms/NintendoSwitchBackend.cpp b/HAL/pico/src/comms/NintendoSwitchBackend.cpp index 3af69be8..3b8f4eba 100644 --- a/HAL/pico/src/comms/NintendoSwitchBackend.cpp +++ b/HAL/pico/src/comms/NintendoSwitchBackend.cpp @@ -48,9 +48,13 @@ HID_REPORT_SIZE ( 8 ) ,\ HID_REPORT_COUNT ( 4 ) ,\ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ - /* Some output from the host idk */ \ + /* Some random vendor input idk */ \ HID_USAGE_PAGE_N ( HID_USAGE_PAGE_VENDOR, 2 ) ,\ HID_USAGE ( 0x20 ) ,\ + HID_REPORT_COUNT ( 1 ) ,\ + HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ + /* Some output from the host idk */ \ + 0x0A, 0x21, 0x26, \ HID_REPORT_COUNT ( 8 ) ,\ HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\ HID_COLLECTION_END diff --git a/HAL/pico/src/core/KeyboardMode.cpp b/HAL/pico/src/core/KeyboardMode.cpp index c87acf7c..bff9e1a6 100644 --- a/HAL/pico/src/core/KeyboardMode.cpp +++ b/HAL/pico/src/core/KeyboardMode.cpp @@ -4,7 +4,7 @@ #include -KeyboardMode::KeyboardMode() { +KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) { _keyboard = new TUKeyboard(); _keyboard->begin(); } @@ -16,7 +16,9 @@ KeyboardMode::~KeyboardMode() { } void KeyboardMode::SendReport(InputState &inputs) { - HandleSocd(inputs); + InputState remapped_inputs = inputs; + HandleRemap(inputs, remapped_inputs); + HandleSocd(remapped_inputs); UpdateKeys(inputs); _keyboard->sendState(); } diff --git a/config/mode_selection.hpp b/config/mode_selection.hpp index 181b7fec..54ced0c3 100644 --- a/config/mode_selection.hpp +++ b/config/mode_selection.hpp @@ -9,6 +9,9 @@ #include "modes/RivalsOfAether.hpp" #include "modes/Ultimate.hpp" +#include + +extern Config config; extern KeyboardMode *current_kb_mode; void set_mode(CommunicationBackend *backend, ControllerMode *mode) { @@ -30,34 +33,93 @@ void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { backend->SetGameMode(nullptr); } -void select_mode(CommunicationBackend *backend) { - InputState &inputs = backend->GetInputs(); - if (inputs.mod_x && !inputs.mod_y && inputs.start) { - if (inputs.l) { - set_mode( - backend, - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); - } else if (inputs.left) { +void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config) { + switch (mode_config.mode_id) { + case MODE_MELEE: + set_mode(backend, new Melee20Button(mode_config, { .crouch_walk_os = false })); + break; + case MODE_PROJECT_M: set_mode( backend, new ProjectM( - socd::SOCD_2IP_NO_REAC, + mode_config, { .true_z_press = false, .ledgedash_max_jump_traj = true } ) ); - } else if (inputs.down) { - set_mode(backend, new Ultimate(socd::SOCD_2IP)); - } else if (inputs.right) { - set_mode(backend, new FgcMode(socd::SOCD_NEUTRAL, socd::SOCD_NEUTRAL)); - } else if (inputs.b) { - set_mode(backend, new RivalsOfAether(socd::SOCD_2IP)); + break; + case MODE_ULTIMATE: + set_mode(backend, new Ultimate(mode_config)); + break; + case MODE_FGC: + set_mode(backend, new FgcMode(mode_config)); + break; + case MODE_RIVALS_OF_AETHER: + set_mode(backend, new RivalsOfAether(mode_config)); + break; + case MODE_UNSPECIFIED: + default: + break; + } +} + +void set_mode(CommunicationBackend *backend, GameModeId mode_id) { + // In this overload we only know the mode id so we need to find a mode config that matches this + // ID. + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode = config.game_mode_configs[i]; + if (mode.mode_id == mode_id) { + set_mode(backend, mode); + return; } - } else if (inputs.mod_y && !inputs.mod_x && inputs.start) { - if (inputs.l) { - set_mode(backend, new DefaultKeyboardMode(socd::SOCD_2IP)); + } +} + +void select_mode(CommunicationBackend *backend) { + // TODO: Use a counter variable to only run the contents of this function every x iterations + // rather than on every single poll. + + InputState &inputs = backend->GetInputs(); + + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + // TODO: Cache gamemode activation binding masks globally so they aren't rebuilt in main + // loop. + // Build bit mask for checking for matching button hold. + uint64_t activation_binding_mask = + make_button_mask(mode_config.activation_binding, mode_config.activation_binding_count); + + if (all_buttons_held(inputs.buttons, activation_binding_mask)) { + set_mode(backend, mode_config); + return; } } + + // if (inputs.mod_x && !inputs.mod_y && inputs.start) { + // if (inputs.l) { + // set_mode( + // backend, + // new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) + // ); + // } else if (inputs.left) { + // set_mode( + // backend, + // new ProjectM( + // socd::SOCD_2IP_NO_REAC, + // { .true_z_press = false, .ledgedash_max_jump_traj = true } + // ) + // ); + // } else if (inputs.down) { + // set_mode(backend, new Ultimate(socd::SOCD_2IP)); + // } else if (inputs.right) { + // set_mode(backend, new FgcMode(socd::SOCD_NEUTRAL, socd::SOCD_NEUTRAL)); + // } else if (inputs.b) { + // set_mode(backend, new RivalsOfAether(socd::SOCD_2IP)); + // } + // } else if (inputs.mod_y && !inputs.mod_x && inputs.start) { + // if (inputs.l) { + // set_mode(backend, new DefaultKeyboardMode(socd::SOCD_2IP)); + // } + // } } #endif diff --git a/config/pico/config.cpp b/config/pico/config.cpp index bf4f4a50..72de616a 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -1,4 +1,5 @@ #include "comms/B0XXInputViewer.hpp" +#include "comms/ConfiguratorBackend.hpp" #include "comms/DInputBackend.hpp" #include "comms/GamecubeBackend.hpp" #include "comms/N64Backend.hpp" @@ -8,6 +9,7 @@ #include "core/CommunicationBackend.hpp" #include "core/InputMode.hpp" #include "core/KeyboardMode.hpp" +#include "core/persistence.hpp" #include "core/pinout.hpp" #include "core/socd.hpp" #include "core/state.hpp" @@ -17,40 +19,120 @@ #include "modes/Melee20Button.hpp" #include "stdlib.hpp" +#include +#include #include +Config config = { + .default_backend = COMMS_BACKEND_XINPUT, + .game_mode_configs_count = 4, + .game_mode_configs = { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_L }, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_LEFT }, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_DOWN }, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_MOD_X, .button_dir2 = BTN_C_UP, .socd_type = SOCD_DIR1_PRIORITY }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_MOD_X, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_RIGHT }, + }, + }, + .communication_backend_configs_count = 3, + .communication_backend_configs = { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_XINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 0, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 1, + .activation_binding = { BTN_Z }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_CONFIGURATOR, + .default_mode = MODE_UNSPECIFIED, + .activation_binding_count = 1, + .activation_binding = { BTN_C_DOWN }, + } + }, +}; CommunicationBackend **backends = nullptr; size_t backend_count; KeyboardMode *current_kb_mode = nullptr; GpioButtonMapping button_mappings[] = { - {&InputState::l, 5 }, - { &InputState::left, 4 }, - { &InputState::down, 3 }, - { &InputState::right, 2 }, - - { &InputState::mod_x, 6 }, - { &InputState::mod_y, 7 }, - - { &InputState::select, 10}, - { &InputState::start, 0 }, - { &InputState::home, 11}, - - { &InputState::c_left, 13}, - { &InputState::c_up, 12}, - { &InputState::c_down, 15}, - { &InputState::a, 14}, - { &InputState::c_right, 16}, - - { &InputState::b, 26}, - { &InputState::x, 21}, - { &InputState::z, 19}, - { &InputState::up, 17}, - - { &InputState::r, 27}, - { &InputState::y, 22}, - { &InputState::lightshield, 20}, - { &InputState::midshield, 18}, + {BTN_L, 5 }, + { BTN_LEFT, 4 }, + { BTN_DOWN, 3 }, + { BTN_RIGHT, 2 }, + + { BTN_MOD_X, 6 }, + { BTN_MOD_Y, 7 }, + + { BTN_SELECT, 10}, + { BTN_START, 0 }, + { BTN_HOME, 11}, + + { BTN_C_LEFT, 13}, + { BTN_C_UP, 12}, + { BTN_C_DOWN, 15}, + { BTN_A, 14}, + { BTN_C_RIGHT, 16}, + + { BTN_B, 26}, + { BTN_X, 21}, + { BTN_Z, 19}, + { BTN_UP, 17}, + + { BTN_R, 27}, + { BTN_Y, 22}, + { BTN_LIGHTSHIELD, 20}, + { BTN_MIDSHIELD, 18}, }; size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); @@ -62,6 +144,13 @@ const Pinout pinout = { .nunchuk_scl = -1, }; +void set_comms_backend( + CommunicationBackendId backend_id, + GameModeId mode_id, + InputSource **input_sources, + size_t input_source_count +); + void setup() { // Create GPIO input source and use it to read button states for checking button holds. GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); @@ -79,14 +168,124 @@ void setup() { gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); + EEPROM.begin(EEPROM_SIZE); + if (!persistence::load_config(config)) { + persistence::save_config(config); + } + // Create array of input sources to be used. static InputSource *input_sources[] = { gpio_input }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; + // Build bit mask for checking for matching button hold. + uint64_t button_hold_mask = make_button_mask( + backend_config.activation_binding, + backend_config.activation_binding_count + ); + + // Check if button hold matches. + if (all_buttons_held(button_holds.buttons, button_hold_mask)) { + set_comms_backend( + backend_config.backend_id, + backend_config.default_mode, + input_sources, + input_source_count + ); + return; + } + } + + // If no backend selected using button holds, run auto detection. ConnectedConsole console = detect_console(pinout.joybus_data); + CommunicationBackendId backend_id = COMMS_BACKEND_UNSPECIFIED; + switch (console) { + case ConnectedConsole::GAMECUBE: + backend_id = COMMS_BACKEND_GAMECUBE; + break; + case ConnectedConsole::N64: + backend_id = COMMS_BACKEND_N64; + break; + case ConnectedConsole::NONE: + default: + backend_id = config.default_backend; + } + + // No button hold was matched to a comms backend so we need to find a backend config that + // matches the detected console so we can check what the configured default gamemode is. + // Fall back to Melee mode if no other match found. + GameModeId mode_id = MODE_MELEE; + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; + if (backend_config.backend_id == backend_id) { + mode_id = backend_config.default_mode; + } + } + + set_comms_backend(backend_id, mode_id, input_sources, input_source_count); +} + +void set_comms_backend( + CommunicationBackendId backend_id, + GameModeId mode_id, + InputSource **input_sources, + size_t input_source_count +) { + if (mode_id == MODE_UNSPECIFIED) { + mode_id = MODE_MELEE; + } - /* Select communication backend. */ CommunicationBackend *primary_backend; + + switch (backend_id) { + case COMMS_BACKEND_DINPUT: + TUGamepad::registerDescriptor(); + TUKeyboard::registerDescriptor(); + primary_backend = new DInputBackend(input_sources, input_source_count); + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(input_sources, input_source_count) + }; + break; + case COMMS_BACKEND_XINPUT: + primary_backend = new XInputBackend(input_sources, input_source_count); + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(input_sources, input_source_count) + }; + break; + case COMMS_BACKEND_GAMECUBE: + primary_backend = + new GamecubeBackend(input_sources, input_source_count, pinout.joybus_data); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_N64: + primary_backend = new N64Backend(input_sources, input_source_count, pinout.joybus_data); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_NINTENDO_SWITCH: + NintendoSwitchBackend::RegisterDescriptor(); + primary_backend = new NintendoSwitchBackend(input_sources, input_source_count); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. + case COMMS_BACKEND_CONFIGURATOR: + default: + primary_backend = new ConfiguratorBackend(input_sources, input_source_count); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + } + + set_mode(primary_backend, mode_id); +} + +#ifdef DEFINITELY_NOT_DEFINED +void old_main_stuff() { + /* Select communication backend. */ if (console == ConnectedConsole::NONE) { if (button_holds.x) { // If no console detected and X is held on plugin then use Switch USB backend. @@ -96,7 +295,7 @@ void setup() { backends = new CommunicationBackend *[backend_count] { primary_backend }; // Default to Ultimate mode on Switch. - primary_backend->SetGameMode(new Ultimate(socd::SOCD_2IP)); + set_mode(primary_backend, new Ultimate(socd::SOCD_2IP)); return; } else if (button_holds.z) { // If no console detected and Z is held on plugin then use DInput backend. @@ -129,10 +328,12 @@ void setup() { } // Default to Melee mode. - primary_backend->SetGameMode( + set_mode( + primary_backend, new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) ); } +#endif void loop() { select_mode(backends[0]); diff --git a/include/comms/ConfiguratorBackend.hpp b/include/comms/ConfiguratorBackend.hpp new file mode 100644 index 00000000..30102db7 --- /dev/null +++ b/include/comms/ConfiguratorBackend.hpp @@ -0,0 +1,27 @@ +#ifndef _COMMS_CONFIGURATORBACKEND_HPP +#define _COMMS_CONFIGURATORBACKEND_HPP + +#include "cobs/Print.h" +#include "cobs/Stream.h" +#include "core/CommunicationBackend.hpp" + +#include + +class ConfiguratorBackend : public CommunicationBackend { + public: + ConfiguratorBackend(InputSource **input_sources, size_t input_source_count); + ~ConfiguratorBackend(); + void SendReport(); + + private: + packetio::COBSStream *_in; + packetio::COBSPrint *_out; + size_t ReadPacket(uint8_t *buffer, size_t max_len); + bool WritePacket(Command command_id, uint8_t *buffer, size_t len); + bool HandleUnknownCommand(Command command); + bool HandleGetDeviceInfo(); + bool HandleGetConfig(); + bool HandleSetConfig(uint8_t *buffer, size_t len); +}; + +#endif \ No newline at end of file diff --git a/include/core/ControllerMode.hpp b/include/core/ControllerMode.hpp index 05b776b0..41bfd39c 100644 --- a/include/core/ControllerMode.hpp +++ b/include/core/ControllerMode.hpp @@ -5,9 +5,11 @@ #include "core/socd.hpp" #include "core/state.hpp" +#include + class ControllerMode : public InputMode { public: - ControllerMode(); + ControllerMode(GameModeConfig &config); void UpdateOutputs(InputState &inputs, OutputState &outputs); void ResetDirections(); virtual void UpdateDirections( diff --git a/include/core/InputMode.hpp b/include/core/InputMode.hpp index 2be670c2..57196256 100644 --- a/include/core/InputMode.hpp +++ b/include/core/InputMode.hpp @@ -4,16 +4,18 @@ #include "socd.hpp" #include "state.hpp" +#include + class InputMode { public: - InputMode(); + InputMode(GameModeConfig &config); virtual ~InputMode(); protected: - socd::SocdPair *_socd_pairs = nullptr; - size_t _socd_pair_count = 0; + GameModeConfig &_config; virtual void HandleSocd(InputState &inputs); + virtual void HandleRemap(InputState &original_inputs, InputState &remapped_inputs); private: socd::SocdState *_socd_states = nullptr; diff --git a/include/core/persistence.hpp b/include/core/persistence.hpp new file mode 100644 index 00000000..f4a38588 --- /dev/null +++ b/include/core/persistence.hpp @@ -0,0 +1,21 @@ +#ifndef _CORE_PERSISTENCE_HPP +#define _CORE_PERSISTENCE_HPP + +#include +#include + +namespace persistence { + typedef struct _ConfigHeader { + size_t config_size = 0; + uint32_t config_crc = 0; + } ConfigHeader; + + bool save_config(Config &config); + bool load_config(Config &config); + size_t load_config_raw(uint8_t *buffer, size_t buffer_len); +} + +#define EEPROM_SIZE 4096 +#define CONFIG_OFFSET sizeof(persistence::ConfigHeader) + +#endif \ No newline at end of file diff --git a/include/core/socd.hpp b/include/core/socd.hpp index 78b6bddd..5d912b27 100644 --- a/include/core/socd.hpp +++ b/include/core/socd.hpp @@ -4,22 +4,9 @@ #include "state.hpp" #include "stdlib.hpp" -namespace socd { - typedef enum { - SOCD_NEUTRAL, - SOCD_2IP, - SOCD_2IP_NO_REAC, - SOCD_DIR1_PRIORITY, - SOCD_DIR2_PRIORITY, - SOCD_NONE, - } SocdType; - - typedef struct { - bool InputState::*input_dir1; - bool InputState::*input_dir2; - SocdType socd_type = SOCD_NEUTRAL; - } SocdPair; +#include +namespace socd { typedef struct { bool was_dir1 = false; bool was_dir2 = false; @@ -28,16 +15,22 @@ namespace socd { } SocdState; void second_input_priority_no_reactivation( - bool &input_dir1, - bool &input_dir2, + InputState &inputs, + Button button_dir1, + Button button_dir2, SocdState &socd_state ); - void second_input_priority(bool &input_dir1, bool &input_dir2, SocdState &socd_state); + void second_input_priority( + InputState &inputs, + Button button_dir1, + Button button_dir2, + SocdState &socd_state + ); - void neutral(bool &input_dir1, bool &input_dir2); + void neutral(InputState &inputs, Button button_dir1, Button button_dir2); - void dir1_priority(bool &input_dir1, bool &input_dir2); + void dir1_priority(InputState &inputs, Button button_dir1, Button button_dir2); } #endif diff --git a/include/core/state.hpp b/include/core/state.hpp index 5570e599..6fe0b35f 100644 --- a/include/core/state.hpp +++ b/include/core/state.hpp @@ -3,40 +3,83 @@ #include "stdlib.hpp" +#include + // Button state. -typedef struct inputstate { +typedef struct _InputState { // Rectangle inputs. - bool left = false; - bool right = false; - bool down = false; - bool up = false; - bool c_left = false; - bool c_right = false; - bool c_down = false; - bool c_up = false; - bool a = false; - bool b = false; - bool x = false; - bool y = false; - bool l = false; - bool r = false; - bool z = false; - bool lightshield = false; - bool midshield = false; - bool select = false; - bool start = false; - bool home = false; - bool mod_x = false; - bool mod_y = false; + union { + uint64_t buttons = 0; + + struct { + bool left : 1; + bool right : 1; + bool down : 1; + bool up : 1; + bool c_left : 1; + bool c_right : 1; + bool c_down : 1; + bool c_up : 1; + bool a : 1; + bool b : 1; + bool x : 1; + bool y : 1; + bool l : 1; + bool r : 1; + bool z : 1; + bool lightshield : 1; + bool midshield : 1; + bool select : 1; + bool start : 1; + bool home : 1; + bool mod_x : 1; + bool mod_y : 1; + }; + }; // Nunchuk inputs. - bool nunchuk_connected = false; + union { + uint8_t nunchuk_buttons = 0; + + struct { + bool nunchuk_connected : 1; + bool nunchuk_c : 1; + bool nunchuk_z : 1; + }; + }; + int8_t nunchuk_x = 0; int8_t nunchuk_y = 0; - bool nunchuk_c = false; - bool nunchuk_z = false; } InputState; +inline static void set_button(uint64_t &buttons, Button button_index, bool pressed) { + if (button_index == BTN_UNSPECIFIED) { + return; + } + Button button_index_adjusted = (Button)(button_index - 1); + buttons = (buttons & ~(1UL << button_index_adjusted)) | (pressed << button_index_adjusted); +} + +inline static bool get_button(uint64_t &buttons, Button button_index) { + if (button_index == BTN_UNSPECIFIED) { + return false; + } + return buttons & (1UL << (button_index - 1)); +} + +inline static uint64_t make_button_mask(Button *buttons, size_t buttons_count) { + uint64_t button_mask = 0; + for (size_t j = 0; j < buttons_count; j++) { + // TODO: Cache gamemode activation binding masks globally. + button_mask |= (1UL << (buttons[j] - 1)); + } + return button_mask; +} + +inline static bool all_buttons_held(uint64_t &buttons, uint64_t button_mask) { + return button_mask != 0 && (buttons & button_mask) == button_mask; +} + // State describing stick direction at the quadrant level. typedef struct { bool horizontal; diff --git a/include/input/GpioButtonInput.hpp b/include/input/GpioButtonInput.hpp index 4fefb4d6..eda1ad13 100644 --- a/include/input/GpioButtonInput.hpp +++ b/include/input/GpioButtonInput.hpp @@ -5,8 +5,10 @@ #include "core/state.hpp" #include "stdlib.hpp" +#include + typedef struct { - bool InputState::*button; + Button button; uint pin; } GpioButtonMapping; diff --git a/include/input/SwitchMatrixInput.hpp b/include/input/SwitchMatrixInput.hpp index 7da9f838..69023725 100644 --- a/include/input/SwitchMatrixInput.hpp +++ b/include/input/SwitchMatrixInput.hpp @@ -13,14 +13,12 @@ enum class DiodeDirection { COL2ROW, }; -typedef bool InputState::*SwitchMatrixElement; - template class SwitchMatrixInput : public InputSource { public: SwitchMatrixInput( uint row_pins[num_rows], uint col_pins[num_cols], - SwitchMatrixElement (&matrix)[num_rows][num_cols], + Button (&matrix)[num_rows][num_cols], DiodeDirection direction ) : _matrix(matrix) { @@ -66,10 +64,10 @@ template class SwitchMatrixInput : public Inp // Read each cell in the column/row. for (size_t j = 0; j < _num_inputs; j++) { - SwitchMatrixElement button = + Button button = _direction == DiodeDirection::ROW2COL ? _matrix[j][i] : _matrix[i][j]; if (button != nullptr) { - inputs.*button = !gpio::read_digital(_input_pins[j]); + set_button(inputs.buttons, button, !gpio::read_digital(_input_pins[j])); } } @@ -83,7 +81,7 @@ template class SwitchMatrixInput : public Inp size_t _num_inputs; uint *_output_pins; uint *_input_pins; - SwitchMatrixElement (&_matrix)[num_rows][num_cols]; + Button (&_matrix)[num_rows][num_cols]; DiodeDirection _direction; }; diff --git a/include/modes/DefaultKeyboardMode.hpp b/include/modes/DefaultKeyboardMode.hpp index 30de505f..189fcb7e 100644 --- a/include/modes/DefaultKeyboardMode.hpp +++ b/include/modes/DefaultKeyboardMode.hpp @@ -2,12 +2,11 @@ #define _MODES_DEFAULTKEYBOARDMODE_HPP #include "core/KeyboardMode.hpp" -#include "core/socd.hpp" #include "core/state.hpp" class DefaultKeyboardMode : public KeyboardMode { public: - DefaultKeyboardMode(socd::SocdType socd_type); + DefaultKeyboardMode(GameModeConfig &config); private: void UpdateKeys(InputState &inputs); diff --git a/include/modes/FgcMode.hpp b/include/modes/FgcMode.hpp index bc838827..281205dc 100644 --- a/include/modes/FgcMode.hpp +++ b/include/modes/FgcMode.hpp @@ -2,12 +2,11 @@ #define _MODES_FGCMODE_HPP #include "core/ControllerMode.hpp" -#include "core/socd.hpp" #include "core/state.hpp" class FgcMode : public ControllerMode { public: - FgcMode(socd::SocdType horizontal_socd, socd::SocdType vertical_socd); + FgcMode(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/Melee18Button.hpp b/include/modes/Melee18Button.hpp index 48843853..c7163a0a 100644 --- a/include/modes/Melee18Button.hpp +++ b/include/modes/Melee18Button.hpp @@ -2,7 +2,6 @@ #define _MODES_MELEE18BUTTON_HPP #include "core/ControllerMode.hpp" -#include "core/socd.hpp" #include "core/state.hpp" typedef struct { @@ -11,7 +10,7 @@ typedef struct { class Melee18Button : public ControllerMode { public: - Melee18Button(socd::SocdType socd_type, Melee18ButtonOptions options = {}); + Melee18Button(GameModeConfig &config, Melee18ButtonOptions options = {}); private: Melee18ButtonOptions _options; diff --git a/include/modes/Melee20Button.hpp b/include/modes/Melee20Button.hpp index 12be2801..46e0fd64 100644 --- a/include/modes/Melee20Button.hpp +++ b/include/modes/Melee20Button.hpp @@ -2,16 +2,17 @@ #define _MODES_MELEE20BUTTON_HPP #include "core/ControllerMode.hpp" -#include "core/socd.hpp" #include "core/state.hpp" +#include + typedef struct { bool crouch_walk_os = false; } Melee20ButtonOptions; class Melee20Button : public ControllerMode { public: - Melee20Button(socd::SocdType socd_type, Melee20ButtonOptions options = {}); + Melee20Button(GameModeConfig &config, Melee20ButtonOptions options = {}); protected: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/ProjectM.hpp b/include/modes/ProjectM.hpp index ec46038d..52d37db3 100644 --- a/include/modes/ProjectM.hpp +++ b/include/modes/ProjectM.hpp @@ -2,7 +2,6 @@ #define _MODES_PROJECTM_HPP #include "core/ControllerMode.hpp" -#include "core/socd.hpp" #include "core/state.hpp" typedef struct { @@ -12,7 +11,7 @@ typedef struct { class ProjectM : public ControllerMode { public: - ProjectM(socd::SocdType socd_type, ProjectMOptions options = {}); + ProjectM(GameModeConfig &config, ProjectMOptions options = {}); private: ProjectMOptions _options; diff --git a/include/modes/RivalsOfAether.hpp b/include/modes/RivalsOfAether.hpp index 62ddfb83..15a6e2b4 100644 --- a/include/modes/RivalsOfAether.hpp +++ b/include/modes/RivalsOfAether.hpp @@ -2,12 +2,11 @@ #define _MODES_RIVALSOFAETHER_HPP #include "core/ControllerMode.hpp" -#include "core/socd.hpp" #include "core/state.hpp" class RivalsOfAether : public ControllerMode { public: - RivalsOfAether(socd::SocdType socd_type); + RivalsOfAether(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/Ultimate.hpp b/include/modes/Ultimate.hpp index a49e225a..986f09c5 100644 --- a/include/modes/Ultimate.hpp +++ b/include/modes/Ultimate.hpp @@ -2,12 +2,11 @@ #define _MODES_ULTIMATE_HPP #include "core/ControllerMode.hpp" -#include "core/socd.hpp" #include "core/state.hpp" class Ultimate : public ControllerMode { public: - Ultimate(socd::SocdType socd_type); + Ultimate(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/DarkSouls.hpp b/include/modes/extra/DarkSouls.hpp index 65c04851..eda4e6b1 100644 --- a/include/modes/extra/DarkSouls.hpp +++ b/include/modes/extra/DarkSouls.hpp @@ -7,7 +7,7 @@ class DarkSouls : public ControllerMode { public: - DarkSouls(socd::SocdType socd_type); + DarkSouls(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/HollowKnight.hpp b/include/modes/extra/HollowKnight.hpp index 8a182ea4..7e03d8e1 100644 --- a/include/modes/extra/HollowKnight.hpp +++ b/include/modes/extra/HollowKnight.hpp @@ -8,7 +8,7 @@ class HollowKnight : public ControllerMode { public: - HollowKnight(socd::SocdType socd_type); + HollowKnight(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/MKWii.hpp b/include/modes/extra/MKWii.hpp index 3b165f1b..13766ed1 100644 --- a/include/modes/extra/MKWii.hpp +++ b/include/modes/extra/MKWii.hpp @@ -7,7 +7,7 @@ class MKWii : public ControllerMode { public: - MKWii(socd::SocdType socd_type); + MKWii(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/MultiVersus.hpp b/include/modes/extra/MultiVersus.hpp index 2f7c510c..f48353cf 100644 --- a/include/modes/extra/MultiVersus.hpp +++ b/include/modes/extra/MultiVersus.hpp @@ -7,7 +7,7 @@ class MultiVersus : public ControllerMode { public: - MultiVersus(socd::SocdType socd_type); + MultiVersus(GameModeConfig &config); protected: virtual void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/RocketLeague.hpp b/include/modes/extra/RocketLeague.hpp index 4891b833..0d229d0f 100644 --- a/include/modes/extra/RocketLeague.hpp +++ b/include/modes/extra/RocketLeague.hpp @@ -7,7 +7,7 @@ class RocketLeague : public ControllerMode { public: - RocketLeague(socd::SocdType socd_type); + RocketLeague(GameModeConfig &config); private: void HandleSocd(InputState &inputs); diff --git a/include/modes/extra/SaltAndSanctuary.hpp b/include/modes/extra/SaltAndSanctuary.hpp index 5ca60a3e..7e259362 100644 --- a/include/modes/extra/SaltAndSanctuary.hpp +++ b/include/modes/extra/SaltAndSanctuary.hpp @@ -7,7 +7,7 @@ class SaltAndSanctuary : public ControllerMode { public: - SaltAndSanctuary(socd::SocdType socd_type); + SaltAndSanctuary(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/ShovelKnight.hpp b/include/modes/extra/ShovelKnight.hpp index a9bec744..60822ba8 100644 --- a/include/modes/extra/ShovelKnight.hpp +++ b/include/modes/extra/ShovelKnight.hpp @@ -7,7 +7,7 @@ class ShovelKnight : public ControllerMode { public: - ShovelKnight(socd::SocdType socd_type); + ShovelKnight(GameModeConfig &config); private: virtual void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/ToughLoveArena.hpp b/include/modes/extra/ToughLoveArena.hpp index bb843ab5..2e02f463 100644 --- a/include/modes/extra/ToughLoveArena.hpp +++ b/include/modes/extra/ToughLoveArena.hpp @@ -7,7 +7,7 @@ class ToughLoveArena : public KeyboardMode { public: - ToughLoveArena(socd::SocdType socd_type); + ToughLoveArena(GameModeConfig &config); private: void UpdateKeys(InputState &inputs); diff --git a/include/modes/extra/Ultimate2.hpp b/include/modes/extra/Ultimate2.hpp index 3aff2506..8b5f0c3e 100644 --- a/include/modes/extra/Ultimate2.hpp +++ b/include/modes/extra/Ultimate2.hpp @@ -7,7 +7,7 @@ class Ultimate2 : public ControllerMode { public: - Ultimate2(socd::SocdType socd_type); + Ultimate2(GameModeConfig &config); private: void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); diff --git a/platformio.ini b/platformio.ini index 1a085212..4c620fee 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,16 +1,29 @@ [platformio] +name = HayBox default_envs = pico extra_configs = config/*/env.ini src_dir = ./ [env] build_type = release +custom_firmware_version = 3.0.0 lib_ldf_mode = chain+ build_flags = -I src/ -I include/ + -D 'DEVICE_NAME="${PIOENV}"' + -D 'FIRMWARE_NAME="${platformio.name}"' + -D 'FIRMWARE_VERSION="${this.custom_firmware_version}"' build_src_filter = + + - +custom_nanopb_protos = + +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> +lib_deps = + https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip + git+git@github.com:JonnyHaystack/HayBox-proto#33bdbc1 + eric-wieser/PacketIO@^0.3.0 + bakercp/CRC32@^2.0.0 [avr_base] platform = atmelavr @@ -18,6 +31,7 @@ framework = arduino build_unflags = -std=gnu++11 build_flags = + ${env.build_flags} -std=gnu++17 -Os -fdata-sections @@ -25,6 +39,10 @@ build_flags = -fno-sized-deallocation -Wl,--gc-sections -I HAL/avr/include + -D PB_BUFFER_ONLY + -D PB_WITHOUT_64BIT + -D PB_NO_ERRMSG + -D PB_CONVERT_DOUBLE_FLOAT build_src_filter = ${env.build_src_filter} + diff --git a/src/comms/ConfiguratorBackend.cpp b/src/comms/ConfiguratorBackend.cpp new file mode 100644 index 00000000..dfa9428a --- /dev/null +++ b/src/comms/ConfiguratorBackend.cpp @@ -0,0 +1,135 @@ +#include "comms/ConfiguratorBackend.hpp" + +#include "core/InputSource.hpp" +#include "core/persistence.hpp" +#include "serial.hpp" + +#include +#include + +ConfiguratorBackend::ConfiguratorBackend(InputSource **input_sources, size_t input_source_count) + : CommunicationBackend(input_sources, input_source_count) { + _in = new packetio::COBSStream(Serial); + _out = new packetio::COBSPrint(Serial); + serial::init(115200); +} + +ConfiguratorBackend::~ConfiguratorBackend() { + serial::close(); + delete _in; + delete _out; +} + +void ConfiguratorBackend::SendReport() { + uint8_t buffer[EEPROM_SIZE]; + size_t packet_len = ReadPacket(buffer, sizeof(buffer)); + Command command = (Command)buffer[0]; + switch (command) { + case CMD_GET_DEVICE_INFO: + HandleGetDeviceInfo(); + break; + case CMD_GET_CONFIG: + HandleGetConfig(); + break; + case CMD_SET_CONFIG: + HandleSetConfig(buffer, packet_len); + break; + case CMD_REBOOT_FIRMWARE: + watchdog_enable(1, 1); + while (1) { + tight_loop_contents(); + } + break; + case CMD_REBOOT_BOOTLOADER: + reset_usb_boot(0, 0); + break; + case CMD_UNSPECIFIED: + default: + HandleUnknownCommand(command); + break; + } +} + +size_t ConfiguratorBackend::ReadPacket(uint8_t *buffer, size_t max_len) { + size_t bytes_read = 0; + while (!Serial.available()) { + delay(1); + } + while (true) { + int result = _in->read(); + if (result == _in->EOF) { + continue; + } + if (result == _in->EOP) { + break; + } + buffer[bytes_read++] = result; + if (bytes_read >= max_len) { + _in->next(); + return bytes_read; + } + } + _in->next(); + + return bytes_read; +} + +bool ConfiguratorBackend::WritePacket(Command command_id, uint8_t *buffer, size_t len) { + _out->write((uint8_t)command_id); + for (size_t i = 0; i < len; i++) { + _out->write(buffer[i]); + } + return _out->end(); +} + +bool ConfiguratorBackend::HandleGetDeviceInfo() { + static const DeviceInfo device_info = { + FIRMWARE_NAME, + FIRMWARE_VERSION, + DEVICE_NAME, + }; + + uint8_t buffer[sizeof(DeviceInfo)]; + pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + + if (!pb_encode(&ostream, &DeviceInfo_msg, &device_info)) { + char errmsg[] = "Failed to encode device info"; + WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); + return false; + } + + return WritePacket(CMD_SET_DEVICE_INFO, buffer, ostream.bytes_written); +} + +bool ConfiguratorBackend::HandleGetConfig() { + uint8_t buffer[EEPROM_SIZE - CONFIG_OFFSET]; + size_t config_size = persistence::load_config_raw(buffer, sizeof(buffer)); + return WritePacket(CMD_SET_CONFIG, buffer, config_size); +} + +bool ConfiguratorBackend::HandleSetConfig(uint8_t *buffer, size_t len) { + Config config = Config_init_zero; + pb_istream_t istream = pb_istream_from_buffer(&buffer[1], len - 1); + + if (!pb_decode(&istream, &Config_msg, &config)) { + char errmsg[] = "Failed to decode config"; + WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); + return false; + } + + if (!persistence::save_config(config)) { + char errmsg[] = "Failed to save config to memory"; + WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); + return false; + } + + WritePacket(CMD_SUCCESS, nullptr, 0); + return true; +} + +bool ConfiguratorBackend::HandleUnknownCommand(Command command) { + char errmsg[50]; + size_t errmsg_len = + snprintf(errmsg, sizeof(errmsg), "Unknown command ID: %d", (uint8_t)command); + return WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); +} \ No newline at end of file diff --git a/src/core/ControllerMode.cpp b/src/core/ControllerMode.cpp index af203165..75ecb61b 100644 --- a/src/core/ControllerMode.cpp +++ b/src/core/ControllerMode.cpp @@ -1,14 +1,18 @@ #include "core/ControllerMode.hpp" -ControllerMode::ControllerMode() { +ControllerMode::ControllerMode(GameModeConfig &config) : InputMode(config) { // Set up initial state. ResetDirections(); } void ControllerMode::UpdateOutputs(InputState &inputs, OutputState &outputs) { - HandleSocd(inputs); - UpdateDigitalOutputs(inputs, outputs); - UpdateAnalogOutputs(inputs, outputs); + // Create a copy of the input state here so remapping can be many-to-one (many physical buttons + // to one activated button). + InputState remapped_inputs = inputs; + HandleRemap(inputs, remapped_inputs); + HandleSocd(remapped_inputs); + UpdateDigitalOutputs(remapped_inputs, outputs); + UpdateAnalogOutputs(remapped_inputs, outputs); } void ControllerMode::ResetDirections() { diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index 56afd594..1b5d270b 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -3,52 +3,78 @@ #include "core/socd.hpp" #include "core/state.hpp" -InputMode::InputMode() {} +InputMode::InputMode(GameModeConfig &config) : _config(config) { + _socd_states = new socd::SocdState[_config.socd_pairs_count]; +} InputMode::~InputMode() { - delete[] _socd_pairs; delete[] _socd_states; } void InputMode::HandleSocd(InputState &inputs) { - if (_socd_pairs == nullptr) { - return; - } - - // Initialize SOCD states if they aren't initialized. - if (_socd_states == nullptr) { - _socd_states = new socd::SocdState[_socd_pair_count]; - } - // Handle SOCD resolution for each SOCD button pair. - for (size_t i = 0; i < _socd_pair_count; i++) { - socd::SocdPair pair = _socd_pairs[i]; + for (size_t i = 0; i < _config.socd_pairs_count; i++) { + SocdPair &pair = _config.socd_pairs[i]; switch (pair.socd_type) { - case socd::SOCD_NEUTRAL: - socd::neutral(inputs.*(pair.input_dir1), inputs.*(pair.input_dir2)); + case SOCD_NEUTRAL: + socd::neutral(inputs, pair.button_dir1, pair.button_dir2); break; - case socd::SOCD_2IP: + case SOCD_2IP: socd::second_input_priority( - inputs.*(pair.input_dir1), - inputs.*(pair.input_dir2), + inputs, + pair.button_dir1, + pair.button_dir2, _socd_states[i] ); break; - case socd::SOCD_2IP_NO_REAC: + case SOCD_2IP_NO_REAC: socd::second_input_priority_no_reactivation( - inputs.*(pair.input_dir1), - inputs.*(pair.input_dir2), + inputs, + pair.button_dir1, + pair.button_dir2, _socd_states[i] ); break; - case socd::SOCD_DIR1_PRIORITY: - socd::dir1_priority(inputs.*(pair.input_dir1), inputs.*(pair.input_dir2)); + case SOCD_DIR1_PRIORITY: + socd::dir1_priority(inputs, pair.button_dir1, pair.button_dir2); break; - case socd::SOCD_DIR2_PRIORITY: - socd::dir1_priority(inputs.*(pair.input_dir2), inputs.*(pair.input_dir1)); + case SOCD_DIR2_PRIORITY: + socd::dir1_priority(inputs, pair.button_dir2, pair.button_dir1); break; - case socd::SOCD_NONE: + case SOCD_UNSPECIFIED: + default: break; } } } + +void InputMode::HandleRemap(InputState &original_inputs, InputState &remapped_inputs) { + // Keep track of which buttons have been remapped so that we can avoid conflicts for buttons + // that are remapped to multiple buttons and prevent macro remapping. + uint64_t physical_buttons_already_remapped = 0; + uint64_t buttons_already_mapped_to = 0; + for (size_t i = 0; i < _config.button_remapping_count; i++) { + ButtonRemap &remapping = _config.button_remapping[i]; + // If this physical button was already mapped to something else, ignore this remapping. This + // is to prevent creating macro behaviour through remapping. + if (get_button(physical_buttons_already_remapped, remapping.physical_button)) { + continue; + } + // If physical button has not been mapped to yet, set it to false. + if (!get_button(buttons_already_mapped_to, remapping.physical_button)) { + set_button(remapped_inputs.buttons, remapping.physical_button, false); + } + + // Either use the value of the physical button, or if the physical button is not pressed, + // but the target button has another physical button remapped to it, and is considered to be + // pressed, leave it as pressed. + bool should_be_pressed = get_button(original_inputs.buttons, remapping.physical_button) || + (get_button(buttons_already_mapped_to, remapping.activates) && + get_button(remapped_inputs.buttons, remapping.activates)); + set_button(remapped_inputs.buttons, remapping.activates, should_be_pressed); + + // Track which buttons have been mapped from/to. + set_button(physical_buttons_already_remapped, remapping.physical_button, true); + set_button(buttons_already_mapped_to, remapping.activates, true); + } +} diff --git a/src/core/persistence.cpp b/src/core/persistence.cpp new file mode 100644 index 00000000..1d28a416 --- /dev/null +++ b/src/core/persistence.cpp @@ -0,0 +1,84 @@ +#include "core/persistence.hpp" + +#include "stdlib.hpp" + +#include +#include +#include + +bool persistence::save_config(Config &config) { + uint8_t buffer[EEPROM_SIZE - CONFIG_OFFSET]; + + pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + + if (!pb_encode(&ostream, &Config_msg, &config)) { + return false; + } + + ConfigHeader header = { + .config_size = ostream.bytes_written, + .config_crc = CRC32::calculate(buffer, ostream.bytes_written), + }; + + // Store number of bytes of configuration data at offset 0. + EEPROM.put(0, header); + + // Store the rest of the data directly after that. + for (size_t i = 0; i < header.config_size; i++) { + EEPROM.write(CONFIG_OFFSET + i, buffer[i]); + } +#ifdef ARDUINO_PICO_REVISION + EEPROM.commit(); +#endif + + return true; +} + +bool persistence::load_config(Config &config) { + uint8_t buffer[EEPROM_SIZE - CONFIG_OFFSET]; + size_t config_size = load_config_raw(buffer, sizeof(buffer)); + + // No valid config found. + if (config_size == 0) { + return false; + } + + pb_istream_t istream = pb_istream_from_buffer(buffer, config_size); + + Config original = config; + + // Return true if successfully decoded. + if (pb_decode(&istream, &Config_msg, &config)) { + return true; + } + + // Otherwise reset back to original config. + config = original; + return false; +} + +size_t persistence::load_config_raw(uint8_t *buffer, size_t buffer_len) { + // Get config header containing CRC32 checksum and number of stored bytes of config data from + // offset 0 of EEPROM. + ConfigHeader header; + EEPROM.get(0, header); + + // Buffer can't be less than the size we expect to read. + if (buffer_len < header.config_size) { + return 0; + } + + // Read config data from EEPROM into the buffer. + size_t bytes_read; + for (bytes_read = 0; bytes_read < header.config_size; bytes_read++) { + buffer[bytes_read] = EEPROM.read(CONFIG_OFFSET + bytes_read); + } + + // If CRC32 checksum does not match, consider it as having failed to read. + if (CRC32::calculate(buffer, bytes_read) != header.config_crc) { + return 0; + } + + // Return the number of bytes of config data read. + return bytes_read; +} \ No newline at end of file diff --git a/src/core/socd.cpp b/src/core/socd.cpp index 504f3500..bf2ebe71 100644 --- a/src/core/socd.cpp +++ b/src/core/socd.cpp @@ -1,84 +1,94 @@ #include "core/socd.hpp" void socd::second_input_priority_no_reactivation( - bool &input_dir1, - bool &input_dir2, + InputState &inputs, + Button button_dir1, + Button button_dir2, SocdState &socd_state ) { - bool is_dir1 = false; - bool is_dir2 = false; - if (input_dir1 && input_dir2) { + bool result_dir1 = false; + bool result_dir2 = false; + bool dir1_pressed = get_button(inputs.buttons, button_dir1); + bool dir2_pressed = get_button(inputs.buttons, button_dir2); + if (dir1_pressed && dir2_pressed) { if (socd_state.was_dir2) { - is_dir1 = true; - is_dir2 = false; + result_dir1 = true; + result_dir2 = false; socd_state.lock_dir2 = true; } if (socd_state.was_dir1) { - is_dir1 = false; - is_dir2 = true; + result_dir1 = false; + result_dir2 = true; socd_state.lock_dir1 = true; } } - if (!input_dir1 && input_dir2 && !socd_state.lock_dir2) { - is_dir1 = false; - is_dir2 = true; + if (!dir1_pressed && dir2_pressed && !socd_state.lock_dir2) { + result_dir1 = false; + result_dir2 = true; socd_state.was_dir2 = true; socd_state.was_dir1 = false; socd_state.lock_dir1 = false; } - if (input_dir1 && !input_dir2 && !socd_state.lock_dir1) { - is_dir1 = true; - is_dir2 = false; + if (dir1_pressed && !dir2_pressed && !socd_state.lock_dir1) { + result_dir1 = true; + result_dir2 = false; socd_state.was_dir1 = true; socd_state.was_dir2 = false; socd_state.lock_dir2 = false; } - if (!input_dir1 && !input_dir2) { + if (!dir1_pressed && !dir2_pressed) { socd_state.was_dir2 = false; socd_state.was_dir1 = false; socd_state.lock_dir1 = false; socd_state.lock_dir2 = false; } - input_dir1 = is_dir1; - input_dir2 = is_dir2; + set_button(inputs.buttons, button_dir1, result_dir1); + set_button(inputs.buttons, button_dir2, result_dir2); } -void socd::second_input_priority(bool &input_dir1, bool &input_dir2, SocdState &socd_state) { - bool is_dir1 = false; - bool is_dir2 = false; - if (input_dir1 && socd_state.was_dir2) { - is_dir1 = true; - is_dir2 = false; +void socd::second_input_priority( + InputState &inputs, + Button button_dir1, + Button button_dir2, + SocdState &socd_state +) { + bool result_dir1 = false; + bool result_dir2 = false; + bool dir1_pressed = get_button(inputs.buttons, button_dir1); + bool dir2_pressed = get_button(inputs.buttons, button_dir2); + if (dir1_pressed && socd_state.was_dir2) { + result_dir1 = true; + result_dir2 = false; } - if (input_dir2 && socd_state.was_dir1) { - is_dir1 = false; - is_dir2 = true; + if (dir2_pressed && socd_state.was_dir1) { + result_dir1 = false; + result_dir2 = true; } - if (!input_dir1 && input_dir2) { - is_dir1 = false; - is_dir2 = true; + if (!dir1_pressed && dir2_pressed) { + result_dir1 = false; + result_dir2 = true; socd_state.was_dir2 = true; socd_state.was_dir1 = false; } - if (input_dir1 && !input_dir2) { - is_dir1 = true; - is_dir2 = false; + if (dir1_pressed && !dir2_pressed) { + result_dir1 = true; + result_dir2 = false; socd_state.was_dir1 = true; socd_state.was_dir2 = false; } - input_dir1 = is_dir1; - input_dir2 = is_dir2; + set_button(inputs.buttons, button_dir1, result_dir1); + set_button(inputs.buttons, button_dir2, result_dir2); } -void socd::neutral(bool &input_dir1, bool &input_dir2) { - if (input_dir1 && input_dir2) { - input_dir1 = false; - input_dir2 = false; +void socd::neutral(InputState &inputs, Button button_dir1, Button button_dir2) { + if (get_button(inputs.buttons, button_dir1) && get_button(inputs.buttons, button_dir2)) { + set_button(inputs.buttons, button_dir1, false); + set_button(inputs.buttons, button_dir2, false); } } -void socd::dir1_priority(bool &input_dir1, bool &input_dir2) { - if (input_dir1 && input_dir2) { - input_dir2 = false; +void socd::dir1_priority(InputState &inputs, Button button_dir1, Button button_dir2) { + if (get_button(inputs.buttons, button_dir1) && get_button(inputs.buttons, button_dir2)) { + set_button(inputs.buttons, button_dir2, false); } } diff --git a/src/input/GpioButtonInput.cpp b/src/input/GpioButtonInput.cpp index de65476f..96ec0242 100644 --- a/src/input/GpioButtonInput.cpp +++ b/src/input/GpioButtonInput.cpp @@ -20,6 +20,6 @@ InputScanSpeed GpioButtonInput::ScanSpeed() { void GpioButtonInput::UpdateInputs(InputState &inputs) { for (size_t i = 0; i < _button_count; i++) { GpioButtonMapping button_mapping = _button_mappings[i]; - inputs.*(button_mapping.button) = !gpio::read_digital(button_mapping.pin); + set_button(inputs.buttons, button_mapping.button, !gpio::read_digital(button_mapping.pin)); } } diff --git a/src/modes/DefaultKeyboardMode.cpp b/src/modes/DefaultKeyboardMode.cpp index 33960778..7dd3b3c4 100644 --- a/src/modes/DefaultKeyboardMode.cpp +++ b/src/modes/DefaultKeyboardMode.cpp @@ -3,7 +3,7 @@ #include "core/socd.hpp" #include "core/state.hpp" -DefaultKeyboardMode::DefaultKeyboardMode(socd::SocdType socd_type) {} +DefaultKeyboardMode::DefaultKeyboardMode(GameModeConfig &config) : KeyboardMode(config) {} void DefaultKeyboardMode::UpdateKeys(InputState &inputs) { Press(HID_KEY_A, inputs.l); diff --git a/src/modes/FgcMode.cpp b/src/modes/FgcMode.cpp index 4928a89e..529d68b1 100644 --- a/src/modes/FgcMode.cpp +++ b/src/modes/FgcMode.cpp @@ -1,18 +1,6 @@ #include "modes/FgcMode.hpp" -FgcMode::FgcMode(socd::SocdType horizontal_socd, socd::SocdType vertical_socd) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, horizontal_socd }, - /* Mod X override C-Up input if both are pressed. Without this, neutral SOCD doesn't work - properly if Down and both Up buttons are pressed, because it first resolves Down + Mod X - to set both as unpressed, and then it sees C-Up as pressed but not Down, so you get an up - input instead of neutral. */ - socd::SocdPair{ &InputState::mod_x, &InputState::c_up, socd::SOCD_DIR1_PRIORITY}, - socd::SocdPair{ &InputState::down, &InputState::mod_x, vertical_socd }, - socd::SocdPair{ &InputState::down, &InputState::c_up, vertical_socd }, - }; -} +FgcMode::FgcMode(GameModeConfig &config) : ControllerMode(config) {} void FgcMode::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { // Directions diff --git a/src/modes/Melee18Button.cpp b/src/modes/Melee18Button.cpp index d9ac9f60..21c701dd 100644 --- a/src/modes/Melee18Button.cpp +++ b/src/modes/Melee18Button.cpp @@ -4,15 +4,8 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee18Button::Melee18Button(socd::SocdType socd_type, Melee18ButtonOptions options) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::up, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; - +Melee18Button::Melee18Button(GameModeConfig &config, Melee18ButtonOptions options) + : ControllerMode(config) { _options = options; horizontal_socd = false; } diff --git a/src/modes/Melee20Button.cpp b/src/modes/Melee20Button.cpp index cfb47075..530ca515 100644 --- a/src/modes/Melee20Button.cpp +++ b/src/modes/Melee20Button.cpp @@ -4,15 +4,8 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee20Button::Melee20Button(socd::SocdType socd_type, Melee20ButtonOptions options) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::up, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; - +Melee20Button::Melee20Button(GameModeConfig &config, Melee20ButtonOptions options) + : ControllerMode(config) { _options = options; _horizontal_socd = false; } diff --git a/src/modes/ProjectM.cpp b/src/modes/ProjectM.cpp index 704ea041..e32789cd 100644 --- a/src/modes/ProjectM.cpp +++ b/src/modes/ProjectM.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -ProjectM::ProjectM(socd::SocdType socd_type, ProjectMOptions options) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::up, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; - +ProjectM::ProjectM(GameModeConfig &config, ProjectMOptions options) : ControllerMode(config) { _options = options; _horizontal_socd = false; } diff --git a/src/modes/RivalsOfAether.cpp b/src/modes/RivalsOfAether.cpp index b43aed8b..30d4d722 100644 --- a/src/modes/RivalsOfAether.cpp +++ b/src/modes/RivalsOfAether.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -RivalsOfAether::RivalsOfAether(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::up, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +RivalsOfAether::RivalsOfAether(GameModeConfig &config) : ControllerMode(config) {} void RivalsOfAether::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; diff --git a/src/modes/Ultimate.cpp b/src/modes/Ultimate.cpp index c23289ad..b4c242a4 100644 --- a/src/modes/Ultimate.cpp +++ b/src/modes/Ultimate.cpp @@ -5,15 +5,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate::Ultimate(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::up, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +Ultimate::Ultimate(GameModeConfig &config) : ControllerMode(config) {} void Ultimate::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; diff --git a/src/modes/extra/DarkSouls.cpp b/src/modes/extra/DarkSouls.cpp index 3e432120..d5e8ab43 100644 --- a/src/modes/extra/DarkSouls.cpp +++ b/src/modes/extra/DarkSouls.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -DarkSouls::DarkSouls(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::mod_x, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +DarkSouls::DarkSouls(GameModeConfig &config) : ControllerMode(config) {} void DarkSouls::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.y = inputs.y; diff --git a/src/modes/extra/HollowKnight.cpp b/src/modes/extra/HollowKnight.cpp index 5cd66e83..c45e322e 100644 --- a/src/modes/extra/HollowKnight.cpp +++ b/src/modes/extra/HollowKnight.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -HollowKnight::HollowKnight(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::mod_x, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +HollowKnight::HollowKnight(GameModeConfig &config) : ControllerMode(config) {} void HollowKnight::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; // Attack diff --git a/src/modes/extra/MKWii.cpp b/src/modes/extra/MKWii.cpp index 8bef561a..318f01c0 100644 --- a/src/modes/extra/MKWii.cpp +++ b/src/modes/extra/MKWii.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MKWii::MKWii(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::l, &InputState::down, socd_type}, - socd::SocdPair{ &InputState::l, &InputState::mod_x, socd_type}, - socd::SocdPair{ &InputState::l, &InputState::mod_y, socd_type}, - }; -} +MKWii::MKWii(GameModeConfig &config) : ControllerMode(config) {} void MKWii::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.a = inputs.b; diff --git a/src/modes/extra/MultiVersus.cpp b/src/modes/extra/MultiVersus.cpp index 83ffe989..f27af54e 100644 --- a/src/modes/extra/MultiVersus.cpp +++ b/src/modes/extra/MultiVersus.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MultiVersus::MultiVersus(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::up, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +MultiVersus::MultiVersus(GameModeConfig &config) : ControllerMode(config) {} void MultiVersus::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { // Bind X and Y to "jump" in-game. diff --git a/src/modes/extra/RocketLeague.cpp b/src/modes/extra/RocketLeague.cpp index e10299ec..1fd781ed 100644 --- a/src/modes/extra/RocketLeague.cpp +++ b/src/modes/extra/RocketLeague.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -RocketLeague::RocketLeague(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type }, - socd::SocdPair{ &InputState::down, &InputState::mod_x, socd::SOCD_DIR2_PRIORITY}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type }, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type }, - }; -} +RocketLeague::RocketLeague(GameModeConfig &config) : ControllerMode(config) {} void RocketLeague::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; diff --git a/src/modes/extra/SaltAndSanctuary.cpp b/src/modes/extra/SaltAndSanctuary.cpp index d1581817..2c792f3c 100644 --- a/src/modes/extra/SaltAndSanctuary.cpp +++ b/src/modes/extra/SaltAndSanctuary.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -SaltAndSanctuary::SaltAndSanctuary(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::mod_x, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +SaltAndSanctuary::SaltAndSanctuary(GameModeConfig &config) : ControllerMode(config) {} void SaltAndSanctuary::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.dpadRight = inputs.l; // Block diff --git a/src/modes/extra/ShovelKnight.cpp b/src/modes/extra/ShovelKnight.cpp index e956a7bf..138e78ef 100644 --- a/src/modes/extra/ShovelKnight.cpp +++ b/src/modes/extra/ShovelKnight.cpp @@ -4,15 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -ShovelKnight::ShovelKnight(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::mod_x, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +ShovelKnight::ShovelKnight(GameModeConfig &config) : ControllerMode(config) {} void ShovelKnight::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.dpadLeft = inputs.left; diff --git a/src/modes/extra/ToughLoveArena.cpp b/src/modes/extra/ToughLoveArena.cpp index e1d765d3..ad0b847d 100644 --- a/src/modes/extra/ToughLoveArena.cpp +++ b/src/modes/extra/ToughLoveArena.cpp @@ -1,16 +1,11 @@ #include "modes/extra/ToughLoveArena.hpp" -ToughLoveArena::ToughLoveArena(socd::SocdType socd_type) { - _socd_pair_count = 1; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - }; -} +ToughLoveArena::ToughLoveArena(GameModeConfig &config) : ControllerMode(config) {} void ToughLoveArena::UpdateKeys(InputState &inputs) { - Press('s', inputs.left); - Press('d', inputs.right); - Press('j', inputs.b); - Press('k', inputs.x); - Press('l', inputs.z); + Press(HID_KEY_S, inputs.left); + Press(HID_KEY_D, inputs.right); + Press(HID_KEY_J, inputs.b); + Press(HID_KEY_K, inputs.x); + Press(HID_KEY_L, inputs.z); } diff --git a/src/modes/extra/Ultimate2.cpp b/src/modes/extra/Ultimate2.cpp index 666dd94c..7d9c62cd 100644 --- a/src/modes/extra/Ultimate2.cpp +++ b/src/modes/extra/Ultimate2.cpp @@ -5,15 +5,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate2::Ultimate2(socd::SocdType socd_type) { - _socd_pair_count = 4; - _socd_pairs = new socd::SocdPair[_socd_pair_count]{ - socd::SocdPair{&InputState::left, &InputState::right, socd_type}, - socd::SocdPair{ &InputState::down, &InputState::up, socd_type}, - socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type}, - socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type}, - }; -} +Ultimate2::Ultimate2(GameModeConfig &config) : ControllerMode(config) {} void Ultimate2::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; From 64e9947cfef8223ffd2fa1d979d76f59bdb48764 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 3 Oct 2023 15:12:38 +0100 Subject: [PATCH 002/167] fix: remove large stack allocations to heap to prevent stack overflow --- config/pico/config.cpp | 67 +++---------------- include/comms/ConfiguratorBackend.hpp | 11 ++- include/core/Persistence.hpp | 27 ++++++++ include/core/persistence.hpp | 21 ------ platformio.ini | 8 ++- src/comms/ConfiguratorBackend.cpp | 38 +++++------ src/core/{persistence.cpp => Persistence.cpp} | 34 ++++++---- 7 files changed, 88 insertions(+), 118 deletions(-) create mode 100644 include/core/Persistence.hpp delete mode 100644 include/core/persistence.hpp rename src/core/{persistence.cpp => Persistence.cpp} (63%) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 72de616a..074dd896 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -9,7 +9,7 @@ #include "core/CommunicationBackend.hpp" #include "core/InputMode.hpp" #include "core/KeyboardMode.hpp" -#include "core/persistence.hpp" +#include "core/Persistence.hpp" #include "core/pinout.hpp" #include "core/socd.hpp" #include "core/state.hpp" @@ -21,7 +21,6 @@ #include #include -#include Config config = { .default_backend = COMMS_BACKEND_XINPUT, @@ -101,6 +100,7 @@ Config config = { } }, }; + CommunicationBackend **backends = nullptr; size_t backend_count; KeyboardMode *current_kb_mode = nullptr; @@ -160,7 +160,7 @@ void setup() { // Bootsel button hold as early as possible for safety. if (button_holds.start) { - reset_usb_boot(0, 0); + rp2040.rebootToBootloader(); } // Turn on LED to indicate firmware booted. @@ -168,10 +168,11 @@ void setup() { gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); - EEPROM.begin(EEPROM_SIZE); - if (!persistence::load_config(config)) { - persistence::save_config(config); + Persistence *persistence = new Persistence(); + if (!persistence->LoadConfig(config)) { + persistence->SaveConfig(config); } + delete persistence; // Create array of input sources to be used. static InputSource *input_sources[] = { gpio_input }; @@ -275,7 +276,7 @@ void set_comms_backend( case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. case COMMS_BACKEND_CONFIGURATOR: default: - primary_backend = new ConfiguratorBackend(input_sources, input_source_count); + primary_backend = new ConfiguratorBackend(input_sources, input_source_count, config); backend_count = 1; backends = new CommunicationBackend *[backend_count] { primary_backend }; } @@ -283,58 +284,6 @@ void set_comms_backend( set_mode(primary_backend, mode_id); } -#ifdef DEFINITELY_NOT_DEFINED -void old_main_stuff() { - /* Select communication backend. */ - if (console == ConnectedConsole::NONE) { - if (button_holds.x) { - // If no console detected and X is held on plugin then use Switch USB backend. - NintendoSwitchBackend::RegisterDescriptor(); - backend_count = 1; - primary_backend = new NintendoSwitchBackend(input_sources, input_source_count); - backends = new CommunicationBackend *[backend_count] { primary_backend }; - - // Default to Ultimate mode on Switch. - set_mode(primary_backend, new Ultimate(socd::SOCD_2IP)); - return; - } else if (button_holds.z) { - // If no console detected and Z is held on plugin then use DInput backend. - TUGamepad::registerDescriptor(); - TUKeyboard::registerDescriptor(); - backend_count = 2; - primary_backend = new DInputBackend(input_sources, input_source_count); - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - // Default to XInput mode if no console detected and no other mode forced. - backend_count = 2; - primary_backend = new XInputBackend(input_sources, input_source_count); - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } - } else { - if (console == ConnectedConsole::GAMECUBE) { - primary_backend = - new GamecubeBackend(input_sources, input_source_count, pinout.joybus_data); - } else if (console == ConnectedConsole::N64) { - primary_backend = new N64Backend(input_sources, input_source_count, pinout.joybus_data); - } - - // If console then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } - - // Default to Melee mode. - set_mode( - primary_backend, - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); -} -#endif - void loop() { select_mode(backends[0]); diff --git a/include/comms/ConfiguratorBackend.hpp b/include/comms/ConfiguratorBackend.hpp index 30102db7..8720abfd 100644 --- a/include/comms/ConfiguratorBackend.hpp +++ b/include/comms/ConfiguratorBackend.hpp @@ -4,24 +4,29 @@ #include "cobs/Print.h" #include "cobs/Stream.h" #include "core/CommunicationBackend.hpp" +#include "core/Persistence.hpp" #include class ConfiguratorBackend : public CommunicationBackend { public: - ConfiguratorBackend(InputSource **input_sources, size_t input_source_count); + ConfiguratorBackend(InputSource **input_sources, size_t input_source_count, Config &config); ~ConfiguratorBackend(); void SendReport(); private: - packetio::COBSStream *_in; - packetio::COBSPrint *_out; size_t ReadPacket(uint8_t *buffer, size_t max_len); bool WritePacket(Command command_id, uint8_t *buffer, size_t len); bool HandleUnknownCommand(Command command); bool HandleGetDeviceInfo(); bool HandleGetConfig(); bool HandleSetConfig(uint8_t *buffer, size_t len); + + packetio::COBSStream *_in; + packetio::COBSPrint *_out; + Persistence *_persistence; + uint8_t _cmd_buffer[Persistence::eeprom_size - Persistence::config_offset]; + Config &_config; }; #endif \ No newline at end of file diff --git a/include/core/Persistence.hpp b/include/core/Persistence.hpp new file mode 100644 index 00000000..6ee1c285 --- /dev/null +++ b/include/core/Persistence.hpp @@ -0,0 +1,27 @@ +#ifndef _CORE_PERSISTENCE_HPP +#define _CORE_PERSISTENCE_HPP + +#include + +class Persistence { + public: + typedef struct _ConfigHeader { + size_t config_size = 0; + uint32_t config_crc = 0; + } ConfigHeader; + + Persistence(); + ~Persistence(); + + bool SaveConfig(Config &config); + bool LoadConfig(Config &config); + size_t LoadConfigRaw(uint8_t *buffer, size_t buffer_len); + + static constexpr size_t eeprom_size = 4096; + static constexpr size_t config_offset = sizeof(ConfigHeader); + + private: + uint8_t _buffer[eeprom_size - config_offset]; +}; + +#endif \ No newline at end of file diff --git a/include/core/persistence.hpp b/include/core/persistence.hpp deleted file mode 100644 index f4a38588..00000000 --- a/include/core/persistence.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _CORE_PERSISTENCE_HPP -#define _CORE_PERSISTENCE_HPP - -#include -#include - -namespace persistence { - typedef struct _ConfigHeader { - size_t config_size = 0; - uint32_t config_crc = 0; - } ConfigHeader; - - bool save_config(Config &config); - bool load_config(Config &config); - size_t load_config_raw(uint8_t *buffer, size_t buffer_len); -} - -#define EEPROM_SIZE 4096 -#define CONFIG_OFFSET sizeof(persistence::ConfigHeader) - -#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 4c620fee..d4f0098a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,7 +16,6 @@ build_flags = -D 'FIRMWARE_VERSION="${this.custom_firmware_version}"' build_src_filter = + - - custom_nanopb_protos = +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> lib_deps = @@ -79,7 +78,9 @@ platform = https://github.com/maxgerhardt/platform-raspberrypi framework = arduino board = pico extra_scripts = pre:builder_scripts/arduino_pico.py -debug_tool = picoprobe +debug_tool = cmsis-dap +; upload_protocol = cmsis-dap +monitor_speed = 115200 board_build.core = earlephilhower board_build.f_cpu = 130000000L build_unflags = -Os @@ -88,11 +89,14 @@ build_flags = -D USE_TINYUSB -D CFG_TUSB_CONFIG_FILE=\"tusb_config_pico.h\" -D NDEBUG + -Wstack-usage=4096 -O3 -I HAL/pico/include build_src_filter = ${env.build_src_filter} + +platform_packages = + framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.0 lib_archive = no lib_deps = ${env.lib_deps} diff --git a/src/comms/ConfiguratorBackend.cpp b/src/comms/ConfiguratorBackend.cpp index dfa9428a..62259293 100644 --- a/src/comms/ConfiguratorBackend.cpp +++ b/src/comms/ConfiguratorBackend.cpp @@ -1,29 +1,34 @@ #include "comms/ConfiguratorBackend.hpp" #include "core/InputSource.hpp" -#include "core/persistence.hpp" #include "serial.hpp" #include #include -ConfiguratorBackend::ConfiguratorBackend(InputSource **input_sources, size_t input_source_count) - : CommunicationBackend(input_sources, input_source_count) { +ConfiguratorBackend::ConfiguratorBackend( + InputSource **input_sources, + size_t input_source_count, + Config &config +) + : CommunicationBackend(input_sources, input_source_count), + _config(config) { _in = new packetio::COBSStream(Serial); _out = new packetio::COBSPrint(Serial); serial::init(115200); + _persistence = new Persistence(); } ConfiguratorBackend::~ConfiguratorBackend() { serial::close(); + delete _persistence; delete _in; delete _out; } void ConfiguratorBackend::SendReport() { - uint8_t buffer[EEPROM_SIZE]; - size_t packet_len = ReadPacket(buffer, sizeof(buffer)); - Command command = (Command)buffer[0]; + size_t packet_len = ReadPacket(_cmd_buffer, sizeof(_cmd_buffer)); + Command command = (Command)_cmd_buffer[0]; switch (command) { case CMD_GET_DEVICE_INFO: HandleGetDeviceInfo(); @@ -32,16 +37,13 @@ void ConfiguratorBackend::SendReport() { HandleGetConfig(); break; case CMD_SET_CONFIG: - HandleSetConfig(buffer, packet_len); + HandleSetConfig(_cmd_buffer, packet_len); break; case CMD_REBOOT_FIRMWARE: - watchdog_enable(1, 1); - while (1) { - tight_loop_contents(); - } + rp2040.reboot(); break; case CMD_REBOOT_BOOTLOADER: - reset_usb_boot(0, 0); + rp2040.rebootToBootloader(); break; case CMD_UNSPECIFIED: default: @@ -92,7 +94,7 @@ bool ConfiguratorBackend::HandleGetDeviceInfo() { uint8_t buffer[sizeof(DeviceInfo)]; pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer)); - if (!pb_encode(&ostream, &DeviceInfo_msg, &device_info)) { + if (!pb_encode(&ostream, DeviceInfo_fields, &device_info)) { char errmsg[] = "Failed to encode device info"; WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); return false; @@ -102,22 +104,20 @@ bool ConfiguratorBackend::HandleGetDeviceInfo() { } bool ConfiguratorBackend::HandleGetConfig() { - uint8_t buffer[EEPROM_SIZE - CONFIG_OFFSET]; - size_t config_size = persistence::load_config_raw(buffer, sizeof(buffer)); - return WritePacket(CMD_SET_CONFIG, buffer, config_size); + size_t config_size = _persistence->LoadConfigRaw(_cmd_buffer, sizeof(_cmd_buffer)); + return WritePacket(CMD_SET_CONFIG, _cmd_buffer, config_size); } bool ConfiguratorBackend::HandleSetConfig(uint8_t *buffer, size_t len) { - Config config = Config_init_zero; pb_istream_t istream = pb_istream_from_buffer(&buffer[1], len - 1); - if (!pb_decode(&istream, &Config_msg, &config)) { + if (!pb_decode(&istream, Config_fields, &_config)) { char errmsg[] = "Failed to decode config"; WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); return false; } - if (!persistence::save_config(config)) { + if (!_persistence->SaveConfig(_config)) { char errmsg[] = "Failed to save config to memory"; WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); return false; diff --git a/src/core/persistence.cpp b/src/core/Persistence.cpp similarity index 63% rename from src/core/persistence.cpp rename to src/core/Persistence.cpp index 1d28a416..4801206d 100644 --- a/src/core/persistence.cpp +++ b/src/core/Persistence.cpp @@ -1,23 +1,30 @@ -#include "core/persistence.hpp" +#include "core/Persistence.hpp" #include "stdlib.hpp" +#include #include #include #include -bool persistence::save_config(Config &config) { - uint8_t buffer[EEPROM_SIZE - CONFIG_OFFSET]; +Persistence::Persistence() { + EEPROM.begin(eeprom_size); +} + +Persistence::~Persistence() { + EEPROM.end(); +} - pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer)); +bool Persistence::SaveConfig(Config &config) { + pb_ostream_t ostream = pb_ostream_from_buffer(_buffer, sizeof(_buffer)); - if (!pb_encode(&ostream, &Config_msg, &config)) { + if (!pb_encode(&ostream, Config_fields, &config)) { return false; } ConfigHeader header = { .config_size = ostream.bytes_written, - .config_crc = CRC32::calculate(buffer, ostream.bytes_written), + .config_crc = CRC32::calculate(_buffer, ostream.bytes_written), }; // Store number of bytes of configuration data at offset 0. @@ -25,7 +32,7 @@ bool persistence::save_config(Config &config) { // Store the rest of the data directly after that. for (size_t i = 0; i < header.config_size; i++) { - EEPROM.write(CONFIG_OFFSET + i, buffer[i]); + EEPROM.write(config_offset + i, _buffer[i]); } #ifdef ARDUINO_PICO_REVISION EEPROM.commit(); @@ -34,21 +41,20 @@ bool persistence::save_config(Config &config) { return true; } -bool persistence::load_config(Config &config) { - uint8_t buffer[EEPROM_SIZE - CONFIG_OFFSET]; - size_t config_size = load_config_raw(buffer, sizeof(buffer)); +bool Persistence::LoadConfig(Config &config) { + size_t config_size = LoadConfigRaw(_buffer, sizeof(_buffer)); // No valid config found. if (config_size == 0) { return false; } - pb_istream_t istream = pb_istream_from_buffer(buffer, config_size); + pb_istream_t istream = pb_istream_from_buffer(_buffer, config_size); Config original = config; // Return true if successfully decoded. - if (pb_decode(&istream, &Config_msg, &config)) { + if (pb_decode(&istream, Config_fields, &config)) { return true; } @@ -57,7 +63,7 @@ bool persistence::load_config(Config &config) { return false; } -size_t persistence::load_config_raw(uint8_t *buffer, size_t buffer_len) { +size_t Persistence::LoadConfigRaw(uint8_t *buffer, size_t buffer_len) { // Get config header containing CRC32 checksum and number of stored bytes of config data from // offset 0 of EEPROM. ConfigHeader header; @@ -71,7 +77,7 @@ size_t persistence::load_config_raw(uint8_t *buffer, size_t buffer_len) { // Read config data from EEPROM into the buffer. size_t bytes_read; for (bytes_read = 0; bytes_read < header.config_size; bytes_read++) { - buffer[bytes_read] = EEPROM.read(CONFIG_OFFSET + bytes_read); + buffer[bytes_read] = EEPROM.read(config_offset + bytes_read); } // If CRC32 checksum does not match, consider it as having failed to read. From a9d782ba5dc7849fe0c1fe74c2cad7edd37aaa98 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 3 Oct 2023 15:13:47 +0100 Subject: [PATCH 003/167] fix: prevent unmapping default activator when a new physical activator is mapped to an input --- src/core/InputMode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index 1b5d270b..4f751060 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -60,7 +60,8 @@ void InputMode::HandleRemap(InputState &original_inputs, InputState &remapped_in if (get_button(physical_buttons_already_remapped, remapping.physical_button)) { continue; } - // If physical button has not been mapped to yet, set it to false. + // If physical button has not been mapped to yet, set it to false. This too is intended to + // prevent creating macro behaviour through remapping. if (!get_button(buttons_already_mapped_to, remapping.physical_button)) { set_button(remapped_inputs.buttons, remapping.physical_button, false); } @@ -69,8 +70,7 @@ void InputMode::HandleRemap(InputState &original_inputs, InputState &remapped_in // but the target button has another physical button remapped to it, and is considered to be // pressed, leave it as pressed. bool should_be_pressed = get_button(original_inputs.buttons, remapping.physical_button) || - (get_button(buttons_already_mapped_to, remapping.activates) && - get_button(remapped_inputs.buttons, remapping.activates)); + get_button(remapped_inputs.buttons, remapping.activates); set_button(remapped_inputs.buttons, remapping.activates, should_be_pressed); // Track which buttons have been mapped from/to. From 39ec0c8c7175e9140f0f1e4f75de021c98dcd737 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 3 Oct 2023 15:14:15 +0100 Subject: [PATCH 004/167] fix: typo in ToughLoveArena mode --- src/modes/extra/ToughLoveArena.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modes/extra/ToughLoveArena.cpp b/src/modes/extra/ToughLoveArena.cpp index ad0b847d..3f12429b 100644 --- a/src/modes/extra/ToughLoveArena.cpp +++ b/src/modes/extra/ToughLoveArena.cpp @@ -1,6 +1,6 @@ #include "modes/extra/ToughLoveArena.hpp" -ToughLoveArena::ToughLoveArena(GameModeConfig &config) : ControllerMode(config) {} +ToughLoveArena::ToughLoveArena(GameModeConfig &config) : KeyboardMode(config) {} void ToughLoveArena::UpdateKeys(InputState &inputs) { Press(HID_KEY_S, inputs.left); From 8dc3cd255fafc1ec0f5e428a9219debddf9676df Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 3 Oct 2023 17:36:53 +0100 Subject: [PATCH 005/167] chore: remove commented out code --- config/mode_selection.hpp | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/config/mode_selection.hpp b/config/mode_selection.hpp index 54ced0c3..b8abcf1e 100644 --- a/config/mode_selection.hpp +++ b/config/mode_selection.hpp @@ -93,33 +93,6 @@ void select_mode(CommunicationBackend *backend) { return; } } - - // if (inputs.mod_x && !inputs.mod_y && inputs.start) { - // if (inputs.l) { - // set_mode( - // backend, - // new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - // ); - // } else if (inputs.left) { - // set_mode( - // backend, - // new ProjectM( - // socd::SOCD_2IP_NO_REAC, - // { .true_z_press = false, .ledgedash_max_jump_traj = true } - // ) - // ); - // } else if (inputs.down) { - // set_mode(backend, new Ultimate(socd::SOCD_2IP)); - // } else if (inputs.right) { - // set_mode(backend, new FgcMode(socd::SOCD_NEUTRAL, socd::SOCD_NEUTRAL)); - // } else if (inputs.b) { - // set_mode(backend, new RivalsOfAether(socd::SOCD_2IP)); - // } - // } else if (inputs.mod_y && !inputs.mod_x && inputs.start) { - // if (inputs.l) { - // set_mode(backend, new DefaultKeyboardMode(socd::SOCD_2IP)); - // } - // } } #endif From 6fb1efc03b856799d7276959267b6c09c4cbe2f1 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 6 Oct 2023 18:00:37 +0100 Subject: [PATCH 006/167] feat: add config utils --- include/core/config_utils.hpp | 18 ++++++++++++ src/core/config_utils.cpp | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 include/core/config_utils.hpp create mode 100644 src/core/config_utils.cpp diff --git a/include/core/config_utils.hpp b/include/core/config_utils.hpp new file mode 100644 index 00000000..ad235140 --- /dev/null +++ b/include/core/config_utils.hpp @@ -0,0 +1,18 @@ +#ifndef _CORE_CONFIG_UTILS_HPP +#define _CORE_CONFIG_UTILS_HPP + +#include "core/state.hpp" + +#include + +CommunicationBackendConfig backend_config_from_buttons( + const InputState &inputs, + const Config &config +); + +CommunicationBackendConfig backend_config_from_id( + CommunicationBackendId backend_id, + const Config &config +); + +#endif \ No newline at end of file diff --git a/src/core/config_utils.cpp b/src/core/config_utils.cpp new file mode 100644 index 00000000..42648c1e --- /dev/null +++ b/src/core/config_utils.cpp @@ -0,0 +1,52 @@ +#include "core/config_utils.hpp" + +#include "core/state.hpp" + +#include + +CommunicationBackendConfig backend_config_from_buttons( + const InputState &inputs, + const Config &config +) { + const CommunicationBackendConfig *backend_configs = config.communication_backend_configs; + size_t backend_configs_count = config.communication_backend_configs_count; + for (size_t i = 0; i < backend_configs_count; i++) { + const CommunicationBackendConfig &backend_config = backend_configs[i]; + // Build bit mask for checking for matching button hold. + uint64_t button_hold_mask = make_button_mask( + backend_config.activation_binding, + backend_config.activation_binding_count + ); + + // Check if button hold matches. + if (all_buttons_held(inputs.buttons, button_hold_mask)) { + return backend_config; + } + } + + return CommunicationBackendConfig{ + .backend_id = COMMS_BACKEND_UNSPECIFIED, + .default_mode = MODE_UNSPECIFIED, + }; +} + +CommunicationBackendConfig backend_config_from_id( + CommunicationBackendId backend_id, + const Config &config +) { + const CommunicationBackendConfig *backend_configs = config.communication_backend_configs; + size_t backend_configs_count = config.communication_backend_configs_count; + // Find the first backend config that matches the detected console so we can check what the + // configured default gamemode is. + for (size_t i = 0; i < backend_configs_count; i++) { + const CommunicationBackendConfig &backend_config = backend_configs[i]; + if (backend_config.backend_id == backend_id) { + return backend_config; + } + } + + return CommunicationBackendConfig{ + .backend_id = backend_id, + .default_mode = MODE_UNSPECIFIED, + }; +} \ No newline at end of file From fac53ac80bdc595b95342ea9d4ae434caa945bcf Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 6 Oct 2023 18:09:16 +0100 Subject: [PATCH 007/167] feat: updated mode selection code --- include/core/mode_selection.hpp | 23 ++++++++ src/core/mode_selection.cpp | 100 ++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 include/core/mode_selection.hpp create mode 100644 src/core/mode_selection.cpp diff --git a/include/core/mode_selection.hpp b/include/core/mode_selection.hpp new file mode 100644 index 00000000..97775470 --- /dev/null +++ b/include/core/mode_selection.hpp @@ -0,0 +1,23 @@ +#ifndef _CORE_MODE_SELECTION_HPP +#define _CORE_MODE_SELECTION_HPP + +#include "core/CommunicationBackend.hpp" +#include "core/ControllerMode.hpp" +#include "core/KeyboardMode.hpp" + +#include + +// extern Config config; +extern KeyboardMode *current_kb_mode; + +void set_mode(CommunicationBackend *backend, ControllerMode *mode); +void set_mode(CommunicationBackend *backend, KeyboardMode *mode); +void set_mode(CommunicationBackend *backend, const GameModeConfig &mode_config); +void set_mode(CommunicationBackend *backend, GameModeId mode_id); +void select_mode( + CommunicationBackend *backend, + const GameModeConfig *game_mode_configs, + const size_t game_mode_configs_count +); + +#endif diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp new file mode 100644 index 00000000..eb3073fb --- /dev/null +++ b/src/core/mode_selection.cpp @@ -0,0 +1,100 @@ +#include "core/mode_selection.hpp" + +#include "core/state.hpp" +#include "modes/DefaultKeyboardMode.hpp" +#include "modes/FgcMode.hpp" +#include "modes/Melee20Button.hpp" +#include "modes/ProjectM.hpp" +#include "modes/RivalsOfAether.hpp" +#include "modes/Ultimate.hpp" + +#include + +extern const Config config; + +uint64_t gamemode_activation_masks[sizeof(config.game_mode_configs) / sizeof(GameModeConfig)]; + +void set_mode(CommunicationBackend *backend, ControllerMode *mode) { + // Delete keyboard mode in case one is set, so we don't end up getting both controller and + // keyboard inputs. + delete current_kb_mode; + current_kb_mode = nullptr; + + // Set new controller mode. + backend->SetGameMode(mode); +} + +void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { + // Delete and reassign current keyboard mode. + delete current_kb_mode; + current_kb_mode = mode; + + // Unset the current controller mode so backend only gives neutral inputs. + backend->SetGameMode(nullptr); +} + +void set_mode(CommunicationBackend *backend, const GameModeConfig &mode_config) { + switch (mode_config.mode_id) { + case MODE_MELEE: + set_mode(backend, new Melee20Button(mode_config, { .crouch_walk_os = false })); + break; + case MODE_PROJECT_M: + set_mode( + backend, + new ProjectM( + mode_config, + { .true_z_press = false, .ledgedash_max_jump_traj = true } + ) + ); + break; + case MODE_ULTIMATE: + set_mode(backend, new Ultimate(mode_config)); + break; + case MODE_FGC: + set_mode(backend, new FgcMode(mode_config)); + break; + case MODE_RIVALS_OF_AETHER: + set_mode(backend, new RivalsOfAether(mode_config)); + break; + case MODE_UNSPECIFIED: + default: + break; + } +} + +void set_mode(CommunicationBackend *backend, GameModeId mode_id) { + // In this overload we only know the mode id so we need to find a mode config that matches this + // ID. + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + const GameModeConfig &mode = config.game_mode_configs[i]; + if (mode.mode_id == mode_id) { + set_mode(backend, mode); + return; + } + } +} + +void select_mode( + CommunicationBackend *backend, + const GameModeConfig *game_mode_configs, + const size_t game_mode_configs_count +) { + // TODO: Use a counter variable to only run the contents of this function every x iterations + // rather than on every single poll. + + InputState &inputs = backend->GetInputs(); + + for (size_t i = 0; i < game_mode_configs_count; i++) { + const GameModeConfig &mode_config = game_mode_configs[i]; + // TODO: Cache gamemode activation binding masks globally so they aren't rebuilt in main + // loop. + // Build bit mask for checking for matching button hold. + uint64_t activation_binding_mask = + make_button_mask(mode_config.activation_binding, mode_config.activation_binding_count); + + if (all_buttons_held(inputs.buttons, activation_binding_mask)) { + set_mode(backend, mode_config); + return; + } + } +} From 123a22c9c460ca54602c2be0f1109b6d9d200e05 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 8 Oct 2023 17:29:32 +0100 Subject: [PATCH 008/167] Lots of refactoring: use const where possible, split up backend initialization and console detection code per platform, lift input state up outside of backends --- .../avr_nousb/include/comms/backend_init.hpp | 33 +++++++ .../avr_nousb/include/core/KeyboardMode.hpp | 2 +- HAL/avr/avr_nousb/src/comms/backend_init.cpp | 81 ++++++++++++++++ .../avr_nousb/src/comms/console_detection.cpp | 5 + HAL/avr/avr_nousb/src/core/KeyboardMode.cpp | 2 +- .../avr_usb/include/comms/DInputBackend.hpp | 2 +- .../avr_usb/include/comms/backend_init.hpp | 35 +++++++ HAL/avr/avr_usb/include/core/KeyboardMode.hpp | 2 +- HAL/avr/avr_usb/src/comms/DInputBackend.cpp | 8 +- HAL/avr/avr_usb/src/comms/backend_init.cpp | 77 +++++++++++++++ .../avr_usb/src/comms/console_detection.cpp | 39 ++++++++ HAL/avr/avr_usb/src/core/KeyboardMode.cpp | 2 +- HAL/avr/include/comms/GamecubeBackend.hpp | 1 + HAL/avr/include/comms/N64Backend.hpp | 1 + HAL/avr/src/comms/GamecubeBackend.cpp | 3 +- HAL/avr/src/comms/N64Backend.cpp | 3 +- HAL/avr/src/reboot.cpp | 15 +++ HAL/pico/include/comms/DInputBackend.hpp | 2 +- HAL/pico/include/comms/GamecubeBackend.hpp | 1 + HAL/pico/include/comms/N64Backend.hpp | 1 + .../include/comms/NintendoSwitchBackend.hpp | 6 +- HAL/pico/include/comms/XInputBackend.hpp | 2 +- HAL/pico/include/comms/backend_init.hpp | 31 ++++++ HAL/pico/include/core/KeyboardMode.hpp | 2 +- HAL/pico/include/joybus_utils.hpp | 14 --- HAL/pico/src/comms/DInputBackend.cpp | 8 +- HAL/pico/src/comms/GamecubeBackend.cpp | 3 +- HAL/pico/src/comms/N64Backend.cpp | 3 +- HAL/pico/src/comms/NintendoSwitchBackend.cpp | 8 +- HAL/pico/src/comms/XInputBackend.cpp | 8 +- HAL/pico/src/comms/backend_init.cpp | 97 +++++++++++++++++++ HAL/pico/src/comms/console_detection.cpp | 25 +++++ HAL/pico/src/core/KeyboardMode.cpp | 2 +- HAL/pico/src/joybus_utils.cpp | 22 ----- HAL/pico/src/reboot.cpp | 11 +++ include/comms/B0XXInputViewer.hpp | 2 +- include/comms/ConfiguratorBackend.hpp | 7 +- include/comms/console_detection.hpp | 10 ++ include/core/CommunicationBackend.hpp | 8 +- include/core/ControllerMode.hpp | 8 +- include/core/InputMode.hpp | 6 +- include/core/config_utils.hpp | 6 +- include/core/mode_selection.hpp | 12 ++- include/core/state.hpp | 16 +-- include/input/GpioButtonInput.hpp | 4 +- include/modes/DefaultKeyboardMode.hpp | 2 +- include/modes/FgcMode.hpp | 6 +- include/modes/Melee18Button.hpp | 6 +- include/modes/Melee20Button.hpp | 6 +- include/modes/ProjectM.hpp | 6 +- include/modes/RivalsOfAether.hpp | 6 +- include/modes/Ultimate.hpp | 6 +- include/modes/extra/DarkSouls.hpp | 6 +- include/modes/extra/HollowKnight.hpp | 6 +- include/modes/extra/MKWii.hpp | 6 +- include/modes/extra/MultiVersus.hpp | 6 +- include/modes/extra/RocketLeague.hpp | 6 +- include/modes/extra/SaltAndSanctuary.hpp | 6 +- include/modes/extra/ShovelKnight.hpp | 6 +- include/modes/extra/ToughLoveArena.hpp | 2 +- include/modes/extra/Ultimate2.hpp | 6 +- include/reboot.hpp | 7 ++ src/core/CommunicationBackend.cpp | 7 +- src/core/ControllerMode.cpp | 4 +- src/core/InputMode.cpp | 8 +- src/core/config_utils.cpp | 10 +- src/modes/DefaultKeyboardMode.cpp | 2 +- src/modes/FgcMode.cpp | 6 +- src/modes/Melee18Button.cpp | 6 +- src/modes/Melee20Button.cpp | 6 +- src/modes/ProjectM.cpp | 6 +- src/modes/RivalsOfAether.cpp | 6 +- src/modes/Ultimate.cpp | 6 +- src/modes/extra/DarkSouls.cpp | 6 +- src/modes/extra/HollowKnight.cpp | 6 +- src/modes/extra/MKWii.cpp | 6 +- src/modes/extra/MultiVersus.cpp | 6 +- src/modes/extra/RocketLeague.cpp | 6 +- src/modes/extra/SaltAndSanctuary.cpp | 6 +- src/modes/extra/ShovelKnight.cpp | 6 +- src/modes/extra/ToughLoveArena.cpp | 2 +- src/modes/extra/Ultimate2.cpp | 6 +- 82 files changed, 663 insertions(+), 185 deletions(-) create mode 100644 HAL/avr/avr_nousb/include/comms/backend_init.hpp create mode 100644 HAL/avr/avr_nousb/src/comms/backend_init.cpp create mode 100644 HAL/avr/avr_nousb/src/comms/console_detection.cpp create mode 100644 HAL/avr/avr_usb/include/comms/backend_init.hpp create mode 100644 HAL/avr/avr_usb/src/comms/backend_init.cpp create mode 100644 HAL/avr/avr_usb/src/comms/console_detection.cpp create mode 100644 HAL/avr/src/reboot.cpp create mode 100644 HAL/pico/include/comms/backend_init.hpp delete mode 100644 HAL/pico/include/joybus_utils.hpp create mode 100644 HAL/pico/src/comms/backend_init.cpp create mode 100644 HAL/pico/src/comms/console_detection.cpp delete mode 100644 HAL/pico/src/joybus_utils.cpp create mode 100644 HAL/pico/src/reboot.cpp create mode 100644 include/comms/console_detection.hpp create mode 100644 include/reboot.hpp diff --git a/HAL/avr/avr_nousb/include/comms/backend_init.hpp b/HAL/avr/avr_nousb/include/comms/backend_init.hpp new file mode 100644 index 00000000..02099334 --- /dev/null +++ b/HAL/avr/avr_nousb/include/comms/backend_init.hpp @@ -0,0 +1,33 @@ +#ifndef _COMMS_BACKEND_INIT_HPP +#define _COMMS_BACKEND_INIT_HPP + +#include "core/CommunicationBackend.hpp" +#include "core/InputSource.hpp" +#include "core/pinout.hpp" +#include "core/state.hpp" + +#include + +/** + * @brief Initialize the backends array and return the number of elements in the array + * + * @param backends The reference to assign to the created backends array + * @param backend_config The selected backend config that we want to map to an array of + * communication backends + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param pinout Pinout struct used for GameCube/N64 communication backends + * @param config Reference to global config struct, to be used by ConfiguratorBackend + * @return size_t The number of backends in the array + */ +size_t initialize_backends( + CommunicationBackend **&backends, + const CommunicationBackendConfig &backend_config, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + const Pinout &pinout +); + +#endif \ No newline at end of file diff --git a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp index 7c0b7c8f..1a6e30ed 100644 --- a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp @@ -8,7 +8,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(); + KeyboardMode(const GameModeConfig &config); ~KeyboardMode(); void SendReport(InputState &inputs); diff --git a/HAL/avr/avr_nousb/src/comms/backend_init.cpp b/HAL/avr/avr_nousb/src/comms/backend_init.cpp new file mode 100644 index 00000000..57672542 --- /dev/null +++ b/HAL/avr/avr_nousb/src/comms/backend_init.cpp @@ -0,0 +1,81 @@ +#include "comms/B0XXInputViewer.hpp" +#include "comms/ConfiguratorBackend.hpp" +#include "comms/DInputBackend.hpp" +#include "comms/GamecubeBackend.hpp" +#include "comms/N64Backend.hpp" +#include "comms/NintendoSwitchBackend.hpp" +#include "comms/XInputBackend.hpp" +#include "comms/backend_init.hpp" +#include "core/CommunicationBackend.hpp" +#include "core/mode_selection.hpp" +#include "core/pinout.hpp" + +#include +#include +#include + +size_t initialize_backends( + CommunicationBackend **&backends, + const CommunicationBackendConfig &backend_config, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + const Pinout &pinout, + Config &config +) { + GameModeId mode_id = backend_config.default_mode; + if (backend_config.default_mode == MODE_UNSPECIFIED) { + mode_id = MODE_MELEE; + } + + CommunicationBackend *primary_backend; + size_t backend_count; + + switch (backend_config.backend_id) { + case COMMS_BACKEND_DINPUT: + TUGamepad::registerDescriptor(); + TUKeyboard::registerDescriptor(); + primary_backend = new DInputBackend(inputs, input_sources, input_source_count); + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) + }; + break; + case COMMS_BACKEND_XINPUT: + primary_backend = new XInputBackend(inputs, input_sources, input_source_count); + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) + }; + break; + case COMMS_BACKEND_GAMECUBE: + primary_backend = + new GamecubeBackend(inputs, input_sources, input_source_count, pinout.joybus_data); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_N64: + primary_backend = + new N64Backend(inputs, input_sources, input_source_count, pinout.joybus_data); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_NINTENDO_SWITCH: + NintendoSwitchBackend::RegisterDescriptor(); + primary_backend = new NintendoSwitchBackend(inputs, input_sources, input_source_count); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. + case COMMS_BACKEND_CONFIGURATOR: + default: + primary_backend = + new ConfiguratorBackend(inputs, input_sources, input_source_count, config); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + } + + set_mode(primary_backend, mode_id); + + return backend_count; +} \ No newline at end of file diff --git a/HAL/avr/avr_nousb/src/comms/console_detection.cpp b/HAL/avr/avr_nousb/src/comms/console_detection.cpp new file mode 100644 index 00000000..a679e359 --- /dev/null +++ b/HAL/avr/avr_nousb/src/comms/console_detection.cpp @@ -0,0 +1,5 @@ +#include "comms/console_detection.hpp" + +CommunicationBackendId detect_console(const Pinout &pinout) { + return COMMS_BACKEND_GAMECUBE; +} diff --git a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp index b7ce470d..6c9d77f2 100644 --- a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp @@ -2,7 +2,7 @@ #include "core/InputMode.hpp" -KeyboardMode::KeyboardMode() {} +KeyboardMode::KeyboardMode(const GameModeConfig &config) : InputMode(config) {} KeyboardMode::~KeyboardMode() {} diff --git a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp index 247eecde..0f980188 100644 --- a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp +++ b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp @@ -11,7 +11,7 @@ class DInputBackend : public CommunicationBackend { public: - DInputBackend(InputSource **input_sources, size_t input_source_count); + DInputBackend(InputState &inputs, InputSource **input_sources, size_t input_source_count); ~DInputBackend(); void SendReport(); diff --git a/HAL/avr/avr_usb/include/comms/backend_init.hpp b/HAL/avr/avr_usb/include/comms/backend_init.hpp new file mode 100644 index 00000000..34778cae --- /dev/null +++ b/HAL/avr/avr_usb/include/comms/backend_init.hpp @@ -0,0 +1,35 @@ +#ifndef _COMMS_BACKEND_INIT_HPP +#define _COMMS_BACKEND_INIT_HPP + +#include "core/CommunicationBackend.hpp" +#include "core/InputSource.hpp" +#include "core/pinout.hpp" +#include "core/state.hpp" + +#include + +/** + * @brief Initialize the backends array and return the number of elements in the array + * + * @param backends The reference to assign to the created backends array + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param backend_configs Array of backend configs to select from + * @param backend_configs_count Number of elements in the backend_configs array + * @param pinout Pinout struct used for GameCube/N64 communication backends + * @return size_t The number of backends in the array + */ +size_t initialize_backends( + CommunicationBackend **&backends, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count, + const GameModeConfig *game_mode_configs, + size_t game_mode_configs_count, + const Pinout &pinout +); + +#endif \ No newline at end of file diff --git a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp index bcdcf9c6..dbfb3ba4 100644 --- a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp @@ -9,7 +9,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(); + KeyboardMode(const GameModeConfig &config); ~KeyboardMode(); void SendReport(InputState &inputs); diff --git a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp index 6dbebf9a..cdf4e034 100644 --- a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp +++ b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp @@ -5,8 +5,12 @@ #include -DInputBackend::DInputBackend(InputSource **input_sources, size_t input_source_count) - : CommunicationBackend(input_sources, input_source_count) { +DInputBackend::DInputBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count +) + : CommunicationBackend(inputs, input_sources, input_source_count) { _joystick = new Joystick_( JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp new file mode 100644 index 00000000..7ecd11db --- /dev/null +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -0,0 +1,77 @@ +#include "comms/backend_init.hpp" + +#include "comms/B0XXInputViewer.hpp" +#include "comms/DInputBackend.hpp" +#include "comms/GamecubeBackend.hpp" +#include "comms/N64Backend.hpp" +#include "comms/console_detection.hpp" +#include "core/CommunicationBackend.hpp" +#include "core/config_utils.hpp" +#include "core/mode_selection.hpp" +#include "core/pinout.hpp" + +#include + +size_t initialize_backends( + CommunicationBackend **&backends, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count, + const GameModeConfig *game_mode_configs, + size_t game_mode_configs_count, + const Pinout &pinout +) { + CommunicationBackend *primary_backend; + + CommunicationBackendConfig backend_config = + backend_config_from_buttons(inputs, backend_configs, backend_configs_count); + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { + primary_backend = new DInputBackend(inputs, input_sources, input_source_count); + delay(500); + CommunicationBackendId detected_backend_id = detect_console(pinout); + backend_config = + backend_config_from_id(detected_backend_id, backend_configs, backend_configs_count); + } + + size_t backend_count; + + switch (backend_config.backend_id) { + case COMMS_BACKEND_GAMECUBE: + delete primary_backend; + primary_backend = new GamecubeBackend( + inputs, + input_sources, + input_source_count, + inputs.a ? 0 : 125, + pinout.joybus_data + ); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_N64: + delete primary_backend; + primary_backend = + new N64Backend(inputs, input_sources, input_source_count, 60, pinout.joybus_data); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_DINPUT: + default: + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) + }; + break; + } + + GameModeId mode_id = backend_config.default_mode; + if (backend_config.default_mode == MODE_UNSPECIFIED) { + mode_id = MODE_MELEE; + } + + set_mode(primary_backend, mode_id, game_mode_configs, game_mode_configs_count); + + return backend_count; +} \ No newline at end of file diff --git a/HAL/avr/avr_usb/src/comms/console_detection.cpp b/HAL/avr/avr_usb/src/comms/console_detection.cpp new file mode 100644 index 00000000..0d9d2ef9 --- /dev/null +++ b/HAL/avr/avr_usb/src/comms/console_detection.cpp @@ -0,0 +1,39 @@ +#include "comms/console_detection.hpp" + +#include "comms/DInputBackend.hpp" +#include "core/pinout.hpp" +#include "stdlib.hpp" + +#include + +// extern const Pinout pinout; + +/* +ConnectedConsole detect_console() { + // InputState inputs; + // CommunicationBackend *dinput = new DInputBackend(inputs, nullptr, 0); + Serial.begin(115200); + // delay(100); + delay(500); + bool usb_connected = UDADDR & _BV(ADDEN); + // USBD_Connected(); + // Serial.end(); + // delete dinput; + + if (usb_connected) { + return ConnectedConsole::NONE; + } + + return ConnectedConsole::GAMECUBE; +} +*/ + +CommunicationBackendId detect_console(const Pinout &pinout) { + bool usb_connected = UDADDR & _BV(ADDEN); + + if (usb_connected) { + return COMMS_BACKEND_DINPUT; + } + + return COMMS_BACKEND_GAMECUBE; +} \ No newline at end of file diff --git a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp index 9aab88fc..79135297 100644 --- a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp @@ -4,7 +4,7 @@ #include -KeyboardMode::KeyboardMode() {} +KeyboardMode::KeyboardMode(const GameModeConfig &config) : InputMode(config) {} KeyboardMode::~KeyboardMode() { _keyboard.releaseAll(); diff --git a/HAL/avr/include/comms/GamecubeBackend.hpp b/HAL/avr/include/comms/GamecubeBackend.hpp index 41da94f5..9544c068 100644 --- a/HAL/avr/include/comms/GamecubeBackend.hpp +++ b/HAL/avr/include/comms/GamecubeBackend.hpp @@ -9,6 +9,7 @@ class GamecubeBackend : public CommunicationBackend { public: GamecubeBackend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, int polling_rate, diff --git a/HAL/avr/include/comms/N64Backend.hpp b/HAL/avr/include/comms/N64Backend.hpp index 68324780..0326aaca 100644 --- a/HAL/avr/include/comms/N64Backend.hpp +++ b/HAL/avr/include/comms/N64Backend.hpp @@ -9,6 +9,7 @@ class N64Backend : public CommunicationBackend { public: N64Backend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, int polling_rate, diff --git a/HAL/avr/src/comms/GamecubeBackend.cpp b/HAL/avr/src/comms/GamecubeBackend.cpp index 4869e055..0b292863 100644 --- a/HAL/avr/src/comms/GamecubeBackend.cpp +++ b/HAL/avr/src/comms/GamecubeBackend.cpp @@ -6,12 +6,13 @@ #include GamecubeBackend::GamecubeBackend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, int polling_rate, int data_pin ) - : CommunicationBackend(input_sources, input_source_count) { + : CommunicationBackend(inputs, input_sources, input_source_count) { _gamecube = new CGamecubeConsole(data_pin); _data = defaultGamecubeData; diff --git a/HAL/avr/src/comms/N64Backend.cpp b/HAL/avr/src/comms/N64Backend.cpp index 0e6c84af..0817ffef 100644 --- a/HAL/avr/src/comms/N64Backend.cpp +++ b/HAL/avr/src/comms/N64Backend.cpp @@ -3,12 +3,13 @@ #include N64Backend::N64Backend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, int polling_rate, int data_pin ) - : CommunicationBackend(input_sources, input_source_count) { + : CommunicationBackend(inputs, input_sources, input_source_count) { _n64 = new CN64Console(data_pin); _data = defaultN64Data; diff --git a/HAL/avr/src/reboot.cpp b/HAL/avr/src/reboot.cpp new file mode 100644 index 00000000..b57cf9c3 --- /dev/null +++ b/HAL/avr/src/reboot.cpp @@ -0,0 +1,15 @@ +#include "reboot.hpp" + +#include "stdlib.hpp" + +void (*resetFunc)(void) = 0; + +void reboot_firmware() { + resetFunc(); +} + +void reboot_bootloader() { + while (true) { + delay(1); + } +} \ No newline at end of file diff --git a/HAL/pico/include/comms/DInputBackend.hpp b/HAL/pico/include/comms/DInputBackend.hpp index 08af6eb0..96281ec4 100644 --- a/HAL/pico/include/comms/DInputBackend.hpp +++ b/HAL/pico/include/comms/DInputBackend.hpp @@ -9,7 +9,7 @@ class DInputBackend : public CommunicationBackend { public: - DInputBackend(InputSource **input_sources, size_t input_source_count); + DInputBackend(InputState &inputs, InputSource **input_sources, size_t input_source_count); ~DInputBackend(); void SendReport(); diff --git a/HAL/pico/include/comms/GamecubeBackend.hpp b/HAL/pico/include/comms/GamecubeBackend.hpp index 742e030e..dac858f2 100644 --- a/HAL/pico/include/comms/GamecubeBackend.hpp +++ b/HAL/pico/include/comms/GamecubeBackend.hpp @@ -9,6 +9,7 @@ class GamecubeBackend : public CommunicationBackend { public: GamecubeBackend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, uint data_pin, diff --git a/HAL/pico/include/comms/N64Backend.hpp b/HAL/pico/include/comms/N64Backend.hpp index b9c9972e..0f4b7f64 100644 --- a/HAL/pico/include/comms/N64Backend.hpp +++ b/HAL/pico/include/comms/N64Backend.hpp @@ -9,6 +9,7 @@ class N64Backend : public CommunicationBackend { public: N64Backend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, uint data_pin, diff --git a/HAL/pico/include/comms/NintendoSwitchBackend.hpp b/HAL/pico/include/comms/NintendoSwitchBackend.hpp index 693d00bf..c8b5eed0 100644 --- a/HAL/pico/include/comms/NintendoSwitchBackend.hpp +++ b/HAL/pico/include/comms/NintendoSwitchBackend.hpp @@ -41,7 +41,11 @@ typedef struct __attribute__((packed, aligned(1))) { class NintendoSwitchBackend : public CommunicationBackend { public: - NintendoSwitchBackend(InputSource **input_sources, size_t input_source_count); + NintendoSwitchBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count + ); ~NintendoSwitchBackend(); static void RegisterDescriptor(); diff --git a/HAL/pico/include/comms/XInputBackend.hpp b/HAL/pico/include/comms/XInputBackend.hpp index 6dfefd79..f139323d 100644 --- a/HAL/pico/include/comms/XInputBackend.hpp +++ b/HAL/pico/include/comms/XInputBackend.hpp @@ -9,7 +9,7 @@ class XInputBackend : public CommunicationBackend { public: - XInputBackend(InputSource **input_sources, size_t input_source_count); + XInputBackend(InputState &inputs, InputSource **input_sources, size_t input_source_count); ~XInputBackend(); void SendReport(); diff --git a/HAL/pico/include/comms/backend_init.hpp b/HAL/pico/include/comms/backend_init.hpp new file mode 100644 index 00000000..e40017d4 --- /dev/null +++ b/HAL/pico/include/comms/backend_init.hpp @@ -0,0 +1,31 @@ +#ifndef _COMMS_BACKEND_INIT_HPP +#define _COMMS_BACKEND_INIT_HPP + +#include "core/CommunicationBackend.hpp" +#include "core/InputSource.hpp" +#include "core/pinout.hpp" +#include "core/state.hpp" + +#include + +/** + * @brief Initialize the backends array and return the number of elements in the array + * + * @param backends The reference to assign to the created backends array + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct + * @param pinout Pinout struct used for GameCube/N64 communication backends + * @return size_t The number of backends in the array + */ +size_t initialize_backends( + CommunicationBackend **&backends, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +); + +#endif \ No newline at end of file diff --git a/HAL/pico/include/core/KeyboardMode.hpp b/HAL/pico/include/core/KeyboardMode.hpp index 19e83721..3a51cbf4 100644 --- a/HAL/pico/include/core/KeyboardMode.hpp +++ b/HAL/pico/include/core/KeyboardMode.hpp @@ -10,7 +10,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(GameModeConfig &config); + KeyboardMode(const GameModeConfig &config); ~KeyboardMode(); void SendReport(InputState &inputs); diff --git a/HAL/pico/include/joybus_utils.hpp b/HAL/pico/include/joybus_utils.hpp deleted file mode 100644 index 2bb493c4..00000000 --- a/HAL/pico/include/joybus_utils.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _JOYBUS_UTILS_HPP -#define _JOYBUS_UTILS_HPP - -#include - -enum class ConnectedConsole { - GAMECUBE, - N64, - NONE, -}; - -ConnectedConsole detect_console(uint joybus_pin); - -#endif \ No newline at end of file diff --git a/HAL/pico/src/comms/DInputBackend.cpp b/HAL/pico/src/comms/DInputBackend.cpp index 5945e1e1..f141d03c 100644 --- a/HAL/pico/src/comms/DInputBackend.cpp +++ b/HAL/pico/src/comms/DInputBackend.cpp @@ -5,8 +5,12 @@ #include -DInputBackend::DInputBackend(InputSource **input_sources, size_t input_source_count) - : CommunicationBackend(input_sources, input_source_count) { +DInputBackend::DInputBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count +) + : CommunicationBackend(inputs, input_sources, input_source_count) { _gamepad = new TUGamepad(); _gamepad->begin(); diff --git a/HAL/pico/src/comms/GamecubeBackend.cpp b/HAL/pico/src/comms/GamecubeBackend.cpp index a5b1bdfb..43249488 100644 --- a/HAL/pico/src/comms/GamecubeBackend.cpp +++ b/HAL/pico/src/comms/GamecubeBackend.cpp @@ -7,6 +7,7 @@ #include GamecubeBackend::GamecubeBackend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, uint data_pin, @@ -14,7 +15,7 @@ GamecubeBackend::GamecubeBackend( int sm, int offset ) - : CommunicationBackend(input_sources, input_source_count) { + : CommunicationBackend(inputs, input_sources, input_source_count) { _gamecube = new GamecubeConsole(data_pin, pio, sm, offset); _report = default_gc_report; } diff --git a/HAL/pico/src/comms/N64Backend.cpp b/HAL/pico/src/comms/N64Backend.cpp index 58ed3030..8193c7b6 100644 --- a/HAL/pico/src/comms/N64Backend.cpp +++ b/HAL/pico/src/comms/N64Backend.cpp @@ -6,6 +6,7 @@ #include N64Backend::N64Backend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, uint data_pin, @@ -13,7 +14,7 @@ N64Backend::N64Backend( int sm, int offset ) - : CommunicationBackend(input_sources, input_source_count) { + : CommunicationBackend(inputs, input_sources, input_source_count) { _n64 = new N64Console(data_pin, pio, sm, offset); _report = default_n64_report; } diff --git a/HAL/pico/src/comms/NintendoSwitchBackend.cpp b/HAL/pico/src/comms/NintendoSwitchBackend.cpp index 3b8f4eba..0c92edae 100644 --- a/HAL/pico/src/comms/NintendoSwitchBackend.cpp +++ b/HAL/pico/src/comms/NintendoSwitchBackend.cpp @@ -63,8 +63,12 @@ uint8_t NintendoSwitchBackend::_descriptor[] = { HID_REPORT_DESC() }; -NintendoSwitchBackend::NintendoSwitchBackend(InputSource **input_sources, size_t input_source_count) - : CommunicationBackend(input_sources, input_source_count) { +NintendoSwitchBackend::NintendoSwitchBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count +) + : CommunicationBackend(inputs, input_sources, input_source_count) { USBDevice.setManufacturerDescriptor("HORI CO.,LTD."); USBDevice.setProductDescriptor("POKKEN CONTROLLER"); USBDevice.setSerialDescriptor("1.0"); diff --git a/HAL/pico/src/comms/XInputBackend.cpp b/HAL/pico/src/comms/XInputBackend.cpp index 55ab4ad7..d7ded9d2 100644 --- a/HAL/pico/src/comms/XInputBackend.cpp +++ b/HAL/pico/src/comms/XInputBackend.cpp @@ -5,8 +5,12 @@ #include -XInputBackend::XInputBackend(InputSource **input_sources, size_t input_source_count) - : CommunicationBackend(input_sources, input_source_count) { +XInputBackend::XInputBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count +) + : CommunicationBackend(inputs, input_sources, input_source_count) { Serial.end(); _xinput = new Adafruit_USBD_XInput(); _xinput->begin(); diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp new file mode 100644 index 00000000..6f84eb10 --- /dev/null +++ b/HAL/pico/src/comms/backend_init.cpp @@ -0,0 +1,97 @@ +#include "comms/backend_init.hpp" + +#include "comms/B0XXInputViewer.hpp" +#include "comms/ConfiguratorBackend.hpp" +#include "comms/DInputBackend.hpp" +#include "comms/GamecubeBackend.hpp" +#include "comms/N64Backend.hpp" +#include "comms/NintendoSwitchBackend.hpp" +#include "comms/XInputBackend.hpp" +#include "comms/console_detection.hpp" +#include "core/CommunicationBackend.hpp" +#include "core/config_utils.hpp" +#include "core/mode_selection.hpp" +#include "core/pinout.hpp" + +#include +#include +#include + +size_t initialize_backends( + CommunicationBackend **&backends, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + CommunicationBackendConfig backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { + CommunicationBackendId detected_backend_id = detect_console(pinout); + backend_config = backend_config_from_id( + detected_backend_id, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + } + + CommunicationBackend *primary_backend; + size_t backend_count; + + switch (backend_config.backend_id) { + case COMMS_BACKEND_DINPUT: + TUGamepad::registerDescriptor(); + TUKeyboard::registerDescriptor(); + primary_backend = new DInputBackend(inputs, input_sources, input_source_count); + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) + }; + break; + case COMMS_BACKEND_XINPUT: + primary_backend = new XInputBackend(inputs, input_sources, input_source_count); + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) + }; + break; + case COMMS_BACKEND_GAMECUBE: + primary_backend = + new GamecubeBackend(inputs, input_sources, input_source_count, pinout.joybus_data); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_N64: + primary_backend = + new N64Backend(inputs, input_sources, input_source_count, pinout.joybus_data); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_NINTENDO_SWITCH: + NintendoSwitchBackend::RegisterDescriptor(); + primary_backend = new NintendoSwitchBackend(inputs, input_sources, input_source_count); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; + case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. + case COMMS_BACKEND_CONFIGURATOR: + default: + primary_backend = + new ConfiguratorBackend(inputs, input_sources, input_source_count, config); + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + } + + GameModeId mode_id = backend_config.default_mode; + if (backend_config.default_mode == MODE_UNSPECIFIED) { + mode_id = MODE_MELEE; + } + + set_mode(primary_backend, mode_id); + + return backend_count; +} \ No newline at end of file diff --git a/HAL/pico/src/comms/console_detection.cpp b/HAL/pico/src/comms/console_detection.cpp new file mode 100644 index 00000000..9c9c003f --- /dev/null +++ b/HAL/pico/src/comms/console_detection.cpp @@ -0,0 +1,25 @@ +#include "comms/console_detection.hpp" + +#include "core/pinout.hpp" + +#include +#include +#include + +#define VBUS_SENSE_PIN 24 + +CommunicationBackendId detect_console(const Pinout &pinout) { + gpio_init(VBUS_SENSE_PIN); + gpio_set_dir(VBUS_SENSE_PIN, GPIO_IN); + bool vbus_powered = gpio_get(VBUS_SENSE_PIN); + + if (GamecubeConsole(pinout.joybus_data).Detect()) { + return COMMS_BACKEND_GAMECUBE; + } + // 5V is not connected when plugged into N64 so we check that first to save time. + if (!vbus_powered && N64Console(pinout.joybus_data).Detect()) { + return COMMS_BACKEND_N64; + } + + return COMMS_BACKEND_XINPUT; +} \ No newline at end of file diff --git a/HAL/pico/src/core/KeyboardMode.cpp b/HAL/pico/src/core/KeyboardMode.cpp index bff9e1a6..36a08257 100644 --- a/HAL/pico/src/core/KeyboardMode.cpp +++ b/HAL/pico/src/core/KeyboardMode.cpp @@ -4,7 +4,7 @@ #include -KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) { +KeyboardMode::KeyboardMode(const GameModeConfig &config) : InputMode(config) { _keyboard = new TUKeyboard(); _keyboard->begin(); } diff --git a/HAL/pico/src/joybus_utils.cpp b/HAL/pico/src/joybus_utils.cpp deleted file mode 100644 index d4e14f98..00000000 --- a/HAL/pico/src/joybus_utils.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "joybus_utils.hpp" - -#include -#include - -#define VBUS_SENSE_PIN 24 - -ConnectedConsole detect_console(uint joybus_pin) { - gpio_init(VBUS_SENSE_PIN); - gpio_set_dir(VBUS_SENSE_PIN, GPIO_IN); - bool vbus_powered = gpio_get(VBUS_SENSE_PIN); - - if (GamecubeConsole(joybus_pin).Detect()) { - return ConnectedConsole::GAMECUBE; - } - // 5V is not connected when plugged into N64 so we check that first to save time. - if (!vbus_powered && N64Console(joybus_pin).Detect()) { - return ConnectedConsole::N64; - } - - return ConnectedConsole::NONE; -} \ No newline at end of file diff --git a/HAL/pico/src/reboot.cpp b/HAL/pico/src/reboot.cpp new file mode 100644 index 00000000..796c7f4b --- /dev/null +++ b/HAL/pico/src/reboot.cpp @@ -0,0 +1,11 @@ +#include "reboot.hpp" + +#include "stdlib.hpp" + +void reboot_firmware() { + rp2040.reboot(); +} + +void reboot_bootloader() { + rp2040.rebootToBootloader(); +} \ No newline at end of file diff --git a/include/comms/B0XXInputViewer.hpp b/include/comms/B0XXInputViewer.hpp index b03f1fc5..47713956 100644 --- a/include/comms/B0XXInputViewer.hpp +++ b/include/comms/B0XXInputViewer.hpp @@ -12,7 +12,7 @@ enum reportState : byte { class B0XXInputViewer : public CommunicationBackend { public: - B0XXInputViewer(InputSource **input_sources, size_t input_source_count); + B0XXInputViewer(InputState &inputs, InputSource **input_sources, size_t input_source_count); ~B0XXInputViewer(); void SendReport(); diff --git a/include/comms/ConfiguratorBackend.hpp b/include/comms/ConfiguratorBackend.hpp index 8720abfd..25daeaaa 100644 --- a/include/comms/ConfiguratorBackend.hpp +++ b/include/comms/ConfiguratorBackend.hpp @@ -10,7 +10,12 @@ class ConfiguratorBackend : public CommunicationBackend { public: - ConfiguratorBackend(InputSource **input_sources, size_t input_source_count, Config &config); + ConfiguratorBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config + ); ~ConfiguratorBackend(); void SendReport(); diff --git a/include/comms/console_detection.hpp b/include/comms/console_detection.hpp new file mode 100644 index 00000000..9ddea46d --- /dev/null +++ b/include/comms/console_detection.hpp @@ -0,0 +1,10 @@ +#ifndef _COMMS_CONSOLE_DETECTION_HPP +#define _COMMS_CONSOLE_DETECTION_HPP + +#include "core/pinout.hpp" + +#include + +CommunicationBackendId detect_console(const Pinout &pinout); + +#endif \ No newline at end of file diff --git a/include/core/CommunicationBackend.hpp b/include/core/CommunicationBackend.hpp index 33fd56d0..f644c439 100644 --- a/include/core/CommunicationBackend.hpp +++ b/include/core/CommunicationBackend.hpp @@ -7,7 +7,11 @@ class CommunicationBackend { public: - CommunicationBackend(InputSource **input_sources, size_t input_source_count); + CommunicationBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count + ); virtual ~CommunicationBackend(){}; InputState &GetInputs(); @@ -20,7 +24,7 @@ class CommunicationBackend { virtual void SendReport() = 0; protected: - InputState _inputs; + InputState &_inputs; InputSource **_input_sources; size_t _input_source_count; diff --git a/include/core/ControllerMode.hpp b/include/core/ControllerMode.hpp index 41bfd39c..a8e2ff09 100644 --- a/include/core/ControllerMode.hpp +++ b/include/core/ControllerMode.hpp @@ -9,8 +9,8 @@ class ControllerMode : public InputMode { public: - ControllerMode(GameModeConfig &config); - void UpdateOutputs(InputState &inputs, OutputState &outputs); + ControllerMode(const GameModeConfig &config); + void UpdateOutputs(const InputState &inputs, OutputState &outputs); void ResetDirections(); virtual void UpdateDirections( bool lsLeft, @@ -31,8 +31,8 @@ class ControllerMode : public InputMode { StickDirections directions; private: - virtual void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) = 0; - virtual void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) = 0; + virtual void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) = 0; + virtual void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) = 0; }; #endif diff --git a/include/core/InputMode.hpp b/include/core/InputMode.hpp index 57196256..17e745d1 100644 --- a/include/core/InputMode.hpp +++ b/include/core/InputMode.hpp @@ -8,14 +8,14 @@ class InputMode { public: - InputMode(GameModeConfig &config); + InputMode(const GameModeConfig &config); virtual ~InputMode(); protected: - GameModeConfig &_config; + const GameModeConfig &_config; virtual void HandleSocd(InputState &inputs); - virtual void HandleRemap(InputState &original_inputs, InputState &remapped_inputs); + virtual void HandleRemap(const InputState &original_inputs, InputState &remapped_inputs); private: socd::SocdState *_socd_states = nullptr; diff --git a/include/core/config_utils.hpp b/include/core/config_utils.hpp index ad235140..643d6294 100644 --- a/include/core/config_utils.hpp +++ b/include/core/config_utils.hpp @@ -7,12 +7,14 @@ CommunicationBackendConfig backend_config_from_buttons( const InputState &inputs, - const Config &config + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count ); CommunicationBackendConfig backend_config_from_id( CommunicationBackendId backend_id, - const Config &config + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count ); #endif \ No newline at end of file diff --git a/include/core/mode_selection.hpp b/include/core/mode_selection.hpp index 97775470..7ad789b1 100644 --- a/include/core/mode_selection.hpp +++ b/include/core/mode_selection.hpp @@ -13,11 +13,17 @@ extern KeyboardMode *current_kb_mode; void set_mode(CommunicationBackend *backend, ControllerMode *mode); void set_mode(CommunicationBackend *backend, KeyboardMode *mode); void set_mode(CommunicationBackend *backend, const GameModeConfig &mode_config); -void set_mode(CommunicationBackend *backend, GameModeId mode_id); +void set_mode( + CommunicationBackend *backend, + GameModeId mode_id, + const GameModeConfig *mode_configs, + size_t mode_configs_count +); void select_mode( CommunicationBackend *backend, - const GameModeConfig *game_mode_configs, - const size_t game_mode_configs_count + const GameModeConfig *mode_configs, + size_t mode_configs_count ); +void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count); #endif diff --git a/include/core/state.hpp b/include/core/state.hpp index 6fe0b35f..d3f0054f 100644 --- a/include/core/state.hpp +++ b/include/core/state.hpp @@ -52,31 +52,31 @@ typedef struct _InputState { int8_t nunchuk_y = 0; } InputState; -inline static void set_button(uint64_t &buttons, Button button_index, bool pressed) { +inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { if (button_index == BTN_UNSPECIFIED) { return; } Button button_index_adjusted = (Button)(button_index - 1); - buttons = (buttons & ~(1UL << button_index_adjusted)) | (pressed << button_index_adjusted); + buttons = + (buttons & ~(1ULL << button_index_adjusted)) | ((uint64_t)pressed << button_index_adjusted); } -inline static bool get_button(uint64_t &buttons, Button button_index) { +inline bool get_button(const uint64_t &buttons, Button button_index) { if (button_index == BTN_UNSPECIFIED) { return false; } - return buttons & (1UL << (button_index - 1)); + return buttons & (1ULL << (button_index - 1)); } -inline static uint64_t make_button_mask(Button *buttons, size_t buttons_count) { +inline uint64_t make_button_mask(const Button *buttons, size_t buttons_count) { uint64_t button_mask = 0; for (size_t j = 0; j < buttons_count; j++) { - // TODO: Cache gamemode activation binding masks globally. - button_mask |= (1UL << (buttons[j] - 1)); + button_mask |= (1ULL << (buttons[j] - 1)); } return button_mask; } -inline static bool all_buttons_held(uint64_t &buttons, uint64_t button_mask) { +inline bool all_buttons_held(const uint64_t &buttons, uint64_t button_mask) { return button_mask != 0 && (buttons & button_mask) == button_mask; } diff --git a/include/input/GpioButtonInput.hpp b/include/input/GpioButtonInput.hpp index eda1ad13..6c9de3c7 100644 --- a/include/input/GpioButtonInput.hpp +++ b/include/input/GpioButtonInput.hpp @@ -14,12 +14,12 @@ typedef struct { class GpioButtonInput : public InputSource { public: - GpioButtonInput(GpioButtonMapping *button_mappings, size_t button_count); + GpioButtonInput(const GpioButtonMapping *button_mappings, size_t button_count); InputScanSpeed ScanSpeed(); void UpdateInputs(InputState &inputs); protected: - GpioButtonMapping *_button_mappings; + const GpioButtonMapping *_button_mappings; size_t _button_count; }; diff --git a/include/modes/DefaultKeyboardMode.hpp b/include/modes/DefaultKeyboardMode.hpp index 189fcb7e..da637bf3 100644 --- a/include/modes/DefaultKeyboardMode.hpp +++ b/include/modes/DefaultKeyboardMode.hpp @@ -6,7 +6,7 @@ class DefaultKeyboardMode : public KeyboardMode { public: - DefaultKeyboardMode(GameModeConfig &config); + DefaultKeyboardMode(const GameModeConfig &config); private: void UpdateKeys(InputState &inputs); diff --git a/include/modes/FgcMode.hpp b/include/modes/FgcMode.hpp index 281205dc..10b14af6 100644 --- a/include/modes/FgcMode.hpp +++ b/include/modes/FgcMode.hpp @@ -6,11 +6,11 @@ class FgcMode : public ControllerMode { public: - FgcMode(GameModeConfig &config); + FgcMode(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/Melee18Button.hpp b/include/modes/Melee18Button.hpp index c7163a0a..15cb1c19 100644 --- a/include/modes/Melee18Button.hpp +++ b/include/modes/Melee18Button.hpp @@ -10,15 +10,15 @@ typedef struct { class Melee18Button : public ControllerMode { public: - Melee18Button(GameModeConfig &config, Melee18ButtonOptions options = {}); + Melee18Button(const GameModeConfig &config, Melee18ButtonOptions options = {}); private: Melee18ButtonOptions _options; bool horizontal_socd; void HandleSocd(InputState &inputs); - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/Melee20Button.hpp b/include/modes/Melee20Button.hpp index 46e0fd64..0bb3ffea 100644 --- a/include/modes/Melee20Button.hpp +++ b/include/modes/Melee20Button.hpp @@ -12,11 +12,11 @@ typedef struct { class Melee20Button : public ControllerMode { public: - Melee20Button(GameModeConfig &config, Melee20ButtonOptions options = {}); + Melee20Button(const GameModeConfig &config, Melee20ButtonOptions options = {}); protected: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); private: Melee20ButtonOptions _options; diff --git a/include/modes/ProjectM.hpp b/include/modes/ProjectM.hpp index 52d37db3..cd373768 100644 --- a/include/modes/ProjectM.hpp +++ b/include/modes/ProjectM.hpp @@ -11,15 +11,15 @@ typedef struct { class ProjectM : public ControllerMode { public: - ProjectM(GameModeConfig &config, ProjectMOptions options = {}); + ProjectM(const GameModeConfig &config, ProjectMOptions options = {}); private: ProjectMOptions _options; bool _horizontal_socd; void HandleSocd(InputState &inputs); - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/RivalsOfAether.hpp b/include/modes/RivalsOfAether.hpp index 15a6e2b4..f929c49f 100644 --- a/include/modes/RivalsOfAether.hpp +++ b/include/modes/RivalsOfAether.hpp @@ -6,11 +6,11 @@ class RivalsOfAether : public ControllerMode { public: - RivalsOfAether(GameModeConfig &config); + RivalsOfAether(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/Ultimate.hpp b/include/modes/Ultimate.hpp index 986f09c5..111c5939 100644 --- a/include/modes/Ultimate.hpp +++ b/include/modes/Ultimate.hpp @@ -6,11 +6,11 @@ class Ultimate : public ControllerMode { public: - Ultimate(GameModeConfig &config); + Ultimate(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/DarkSouls.hpp b/include/modes/extra/DarkSouls.hpp index eda4e6b1..3dc157f8 100644 --- a/include/modes/extra/DarkSouls.hpp +++ b/include/modes/extra/DarkSouls.hpp @@ -7,11 +7,11 @@ class DarkSouls : public ControllerMode { public: - DarkSouls(GameModeConfig &config); + DarkSouls(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/HollowKnight.hpp b/include/modes/extra/HollowKnight.hpp index 7e03d8e1..3cf8ea1f 100644 --- a/include/modes/extra/HollowKnight.hpp +++ b/include/modes/extra/HollowKnight.hpp @@ -8,11 +8,11 @@ class HollowKnight : public ControllerMode { public: - HollowKnight(GameModeConfig &config); + HollowKnight(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/MKWii.hpp b/include/modes/extra/MKWii.hpp index 13766ed1..5c8c0ab0 100644 --- a/include/modes/extra/MKWii.hpp +++ b/include/modes/extra/MKWii.hpp @@ -7,11 +7,11 @@ class MKWii : public ControllerMode { public: - MKWii(GameModeConfig &config); + MKWii(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/MultiVersus.hpp b/include/modes/extra/MultiVersus.hpp index f48353cf..4f1b0c27 100644 --- a/include/modes/extra/MultiVersus.hpp +++ b/include/modes/extra/MultiVersus.hpp @@ -7,11 +7,11 @@ class MultiVersus : public ControllerMode { public: - MultiVersus(GameModeConfig &config); + MultiVersus(const GameModeConfig &config); protected: - virtual void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - virtual void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + virtual void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + virtual void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/RocketLeague.hpp b/include/modes/extra/RocketLeague.hpp index 0d229d0f..2356b977 100644 --- a/include/modes/extra/RocketLeague.hpp +++ b/include/modes/extra/RocketLeague.hpp @@ -7,12 +7,12 @@ class RocketLeague : public ControllerMode { public: - RocketLeague(GameModeConfig &config); + RocketLeague(const GameModeConfig &config); private: void HandleSocd(InputState &inputs); - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/SaltAndSanctuary.hpp b/include/modes/extra/SaltAndSanctuary.hpp index 7e259362..daae968b 100644 --- a/include/modes/extra/SaltAndSanctuary.hpp +++ b/include/modes/extra/SaltAndSanctuary.hpp @@ -7,11 +7,11 @@ class SaltAndSanctuary : public ControllerMode { public: - SaltAndSanctuary(GameModeConfig &config); + SaltAndSanctuary(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/ShovelKnight.hpp b/include/modes/extra/ShovelKnight.hpp index 60822ba8..601c00d9 100644 --- a/include/modes/extra/ShovelKnight.hpp +++ b/include/modes/extra/ShovelKnight.hpp @@ -7,11 +7,11 @@ class ShovelKnight : public ControllerMode { public: - ShovelKnight(GameModeConfig &config); + ShovelKnight(const GameModeConfig &config); private: - virtual void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - virtual void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + virtual void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + virtual void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/modes/extra/ToughLoveArena.hpp b/include/modes/extra/ToughLoveArena.hpp index 2e02f463..900d012c 100644 --- a/include/modes/extra/ToughLoveArena.hpp +++ b/include/modes/extra/ToughLoveArena.hpp @@ -7,7 +7,7 @@ class ToughLoveArena : public KeyboardMode { public: - ToughLoveArena(GameModeConfig &config); + ToughLoveArena(const GameModeConfig &config); private: void UpdateKeys(InputState &inputs); diff --git a/include/modes/extra/Ultimate2.hpp b/include/modes/extra/Ultimate2.hpp index 8b5f0c3e..9f619df6 100644 --- a/include/modes/extra/Ultimate2.hpp +++ b/include/modes/extra/Ultimate2.hpp @@ -7,11 +7,11 @@ class Ultimate2 : public ControllerMode { public: - Ultimate2(GameModeConfig &config); + Ultimate2(const GameModeConfig &config); private: - void UpdateDigitalOutputs(InputState &inputs, OutputState &outputs); - void UpdateAnalogOutputs(InputState &inputs, OutputState &outputs); + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; #endif diff --git a/include/reboot.hpp b/include/reboot.hpp new file mode 100644 index 00000000..506e0c57 --- /dev/null +++ b/include/reboot.hpp @@ -0,0 +1,7 @@ +#ifndef _REBOOT_HPP +#define _REBOOT_HPP + +void reboot_firmware(); +void reboot_bootloader(); + +#endif \ No newline at end of file diff --git a/src/core/CommunicationBackend.cpp b/src/core/CommunicationBackend.cpp index dfc3e677..b6df57ce 100644 --- a/src/core/CommunicationBackend.cpp +++ b/src/core/CommunicationBackend.cpp @@ -4,7 +4,12 @@ #include "core/InputSource.hpp" #include "core/state.hpp" -CommunicationBackend::CommunicationBackend(InputSource **input_sources, size_t input_source_count) { +CommunicationBackend::CommunicationBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count +) + : _inputs(inputs) { _gamemode = nullptr; _input_sources = input_sources; _input_source_count = input_source_count; diff --git a/src/core/ControllerMode.cpp b/src/core/ControllerMode.cpp index 75ecb61b..11f9bd24 100644 --- a/src/core/ControllerMode.cpp +++ b/src/core/ControllerMode.cpp @@ -1,11 +1,11 @@ #include "core/ControllerMode.hpp" -ControllerMode::ControllerMode(GameModeConfig &config) : InputMode(config) { +ControllerMode::ControllerMode(const GameModeConfig &config) : InputMode(config) { // Set up initial state. ResetDirections(); } -void ControllerMode::UpdateOutputs(InputState &inputs, OutputState &outputs) { +void ControllerMode::UpdateOutputs(const InputState &inputs, OutputState &outputs) { // Create a copy of the input state here so remapping can be many-to-one (many physical buttons // to one activated button). InputState remapped_inputs = inputs; diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index 4f751060..ee625362 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -3,7 +3,7 @@ #include "core/socd.hpp" #include "core/state.hpp" -InputMode::InputMode(GameModeConfig &config) : _config(config) { +InputMode::InputMode(const GameModeConfig &config) : _config(config) { _socd_states = new socd::SocdState[_config.socd_pairs_count]; } @@ -14,7 +14,7 @@ InputMode::~InputMode() { void InputMode::HandleSocd(InputState &inputs) { // Handle SOCD resolution for each SOCD button pair. for (size_t i = 0; i < _config.socd_pairs_count; i++) { - SocdPair &pair = _config.socd_pairs[i]; + const SocdPair &pair = _config.socd_pairs[i]; switch (pair.socd_type) { case SOCD_NEUTRAL: socd::neutral(inputs, pair.button_dir1, pair.button_dir2); @@ -48,13 +48,13 @@ void InputMode::HandleSocd(InputState &inputs) { } } -void InputMode::HandleRemap(InputState &original_inputs, InputState &remapped_inputs) { +void InputMode::HandleRemap(const InputState &original_inputs, InputState &remapped_inputs) { // Keep track of which buttons have been remapped so that we can avoid conflicts for buttons // that are remapped to multiple buttons and prevent macro remapping. uint64_t physical_buttons_already_remapped = 0; uint64_t buttons_already_mapped_to = 0; for (size_t i = 0; i < _config.button_remapping_count; i++) { - ButtonRemap &remapping = _config.button_remapping[i]; + const ButtonRemap &remapping = _config.button_remapping[i]; // If this physical button was already mapped to something else, ignore this remapping. This // is to prevent creating macro behaviour through remapping. if (get_button(physical_buttons_already_remapped, remapping.physical_button)) { diff --git a/src/core/config_utils.cpp b/src/core/config_utils.cpp index 42648c1e..091ad2e8 100644 --- a/src/core/config_utils.cpp +++ b/src/core/config_utils.cpp @@ -6,10 +6,9 @@ CommunicationBackendConfig backend_config_from_buttons( const InputState &inputs, - const Config &config + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count ) { - const CommunicationBackendConfig *backend_configs = config.communication_backend_configs; - size_t backend_configs_count = config.communication_backend_configs_count; for (size_t i = 0; i < backend_configs_count; i++) { const CommunicationBackendConfig &backend_config = backend_configs[i]; // Build bit mask for checking for matching button hold. @@ -32,10 +31,9 @@ CommunicationBackendConfig backend_config_from_buttons( CommunicationBackendConfig backend_config_from_id( CommunicationBackendId backend_id, - const Config &config + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count ) { - const CommunicationBackendConfig *backend_configs = config.communication_backend_configs; - size_t backend_configs_count = config.communication_backend_configs_count; // Find the first backend config that matches the detected console so we can check what the // configured default gamemode is. for (size_t i = 0; i < backend_configs_count; i++) { diff --git a/src/modes/DefaultKeyboardMode.cpp b/src/modes/DefaultKeyboardMode.cpp index 7dd3b3c4..81ad6ff9 100644 --- a/src/modes/DefaultKeyboardMode.cpp +++ b/src/modes/DefaultKeyboardMode.cpp @@ -3,7 +3,7 @@ #include "core/socd.hpp" #include "core/state.hpp" -DefaultKeyboardMode::DefaultKeyboardMode(GameModeConfig &config) : KeyboardMode(config) {} +DefaultKeyboardMode::DefaultKeyboardMode(const GameModeConfig &config) : KeyboardMode(config) {} void DefaultKeyboardMode::UpdateKeys(InputState &inputs) { Press(HID_KEY_A, inputs.l); diff --git a/src/modes/FgcMode.cpp b/src/modes/FgcMode.cpp index 529d68b1..cbc18409 100644 --- a/src/modes/FgcMode.cpp +++ b/src/modes/FgcMode.cpp @@ -1,8 +1,8 @@ #include "modes/FgcMode.hpp" -FgcMode::FgcMode(GameModeConfig &config) : ControllerMode(config) {} +FgcMode::FgcMode(const GameModeConfig &config) : ControllerMode(config) {} -void FgcMode::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void FgcMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Directions outputs.dpadLeft = inputs.left; outputs.dpadRight = inputs.right; @@ -27,7 +27,7 @@ void FgcMode::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.buttonL = inputs.midshield; } -void FgcMode::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void FgcMode::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { outputs.leftStickX = 128; outputs.leftStickY = 128; outputs.rightStickX = 128; diff --git a/src/modes/Melee18Button.cpp b/src/modes/Melee18Button.cpp index 21c701dd..0f8e7c0a 100644 --- a/src/modes/Melee18Button.cpp +++ b/src/modes/Melee18Button.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee18Button::Melee18Button(GameModeConfig &config, Melee18ButtonOptions options) +Melee18Button::Melee18Button(const GameModeConfig &config, Melee18ButtonOptions options) : ControllerMode(config) { _options = options; horizontal_socd = false; @@ -15,7 +15,7 @@ void Melee18Button::HandleSocd(InputState &inputs) { InputMode::HandleSocd(inputs); } -void Melee18Button::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void Melee18Button::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; outputs.b = inputs.b; outputs.x = inputs.x; @@ -47,7 +47,7 @@ void Melee18Button::UpdateDigitalOutputs(InputState &inputs, OutputState &output outputs.dpadRight = true; } -void Melee18Button::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, diff --git a/src/modes/Melee20Button.cpp b/src/modes/Melee20Button.cpp index 530ca515..96ef1c78 100644 --- a/src/modes/Melee20Button.cpp +++ b/src/modes/Melee20Button.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee20Button::Melee20Button(GameModeConfig &config, Melee20ButtonOptions options) +Melee20Button::Melee20Button(const GameModeConfig &config, Melee20ButtonOptions options) : ControllerMode(config) { _options = options; _horizontal_socd = false; @@ -15,7 +15,7 @@ void Melee20Button::HandleSocd(InputState &inputs) { InputMode::HandleSocd(inputs); } -void Melee20Button::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void Melee20Button::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; outputs.b = inputs.b; outputs.x = inputs.x; @@ -43,7 +43,7 @@ void Melee20Button::UpdateDigitalOutputs(InputState &inputs, OutputState &output outputs.dpadRight = true; } -void Melee20Button::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, diff --git a/src/modes/ProjectM.cpp b/src/modes/ProjectM.cpp index e32789cd..fafe9720 100644 --- a/src/modes/ProjectM.cpp +++ b/src/modes/ProjectM.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -ProjectM::ProjectM(GameModeConfig &config, ProjectMOptions options) : ControllerMode(config) { +ProjectM::ProjectM(const GameModeConfig &config, ProjectMOptions options) : ControllerMode(config) { _options = options; _horizontal_socd = false; } @@ -14,7 +14,7 @@ void ProjectM::HandleSocd(InputState &inputs) { InputMode::HandleSocd(inputs); } -void ProjectM::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void ProjectM::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; outputs.b = inputs.b; outputs.x = inputs.x; @@ -51,7 +51,7 @@ void ProjectM::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.dpadRight = true; } -void ProjectM::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( inputs.left, inputs.right, diff --git a/src/modes/RivalsOfAether.cpp b/src/modes/RivalsOfAether.cpp index 30d4d722..e6a62e26 100644 --- a/src/modes/RivalsOfAether.cpp +++ b/src/modes/RivalsOfAether.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -RivalsOfAether::RivalsOfAether(GameModeConfig &config) : ControllerMode(config) {} +RivalsOfAether::RivalsOfAether(const GameModeConfig &config) : ControllerMode(config) {} -void RivalsOfAether::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void RivalsOfAether::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; outputs.b = inputs.b; outputs.x = inputs.x; @@ -37,7 +37,7 @@ void RivalsOfAether::UpdateDigitalOutputs(InputState &inputs, OutputState &outpu } } -void RivalsOfAether::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void RivalsOfAether::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, diff --git a/src/modes/Ultimate.cpp b/src/modes/Ultimate.cpp index b4c242a4..57ecddff 100644 --- a/src/modes/Ultimate.cpp +++ b/src/modes/Ultimate.cpp @@ -5,9 +5,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate::Ultimate(GameModeConfig &config) : ControllerMode(config) {} +Ultimate::Ultimate(const GameModeConfig &config) : ControllerMode(config) {} -void Ultimate::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void Ultimate::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; outputs.b = inputs.b; outputs.x = inputs.x; @@ -29,7 +29,7 @@ void Ultimate::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { } } -void Ultimate::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, diff --git a/src/modes/extra/DarkSouls.cpp b/src/modes/extra/DarkSouls.cpp index d5e8ab43..e3effdee 100644 --- a/src/modes/extra/DarkSouls.cpp +++ b/src/modes/extra/DarkSouls.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -DarkSouls::DarkSouls(GameModeConfig &config) : ControllerMode(config) {} +DarkSouls::DarkSouls(const GameModeConfig &config) : ControllerMode(config) {} -void DarkSouls::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void DarkSouls::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.y = inputs.y; outputs.x = inputs.r; @@ -38,7 +38,7 @@ void DarkSouls::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { } } -void DarkSouls::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void DarkSouls::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( inputs.left, inputs.right, diff --git a/src/modes/extra/HollowKnight.cpp b/src/modes/extra/HollowKnight.cpp index c45e322e..45f79edd 100644 --- a/src/modes/extra/HollowKnight.cpp +++ b/src/modes/extra/HollowKnight.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -HollowKnight::HollowKnight(GameModeConfig &config) : ControllerMode(config) {} +HollowKnight::HollowKnight(const GameModeConfig &config) : ControllerMode(config) {} -void HollowKnight::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void HollowKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; // Attack outputs.b = inputs.b; // Dash outputs.x = inputs.x; // Jump @@ -20,7 +20,7 @@ void HollowKnight::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs outputs.start = inputs.start; // Pause } -void HollowKnight::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void HollowKnight::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( inputs.left, inputs.right, diff --git a/src/modes/extra/MKWii.cpp b/src/modes/extra/MKWii.cpp index 318f01c0..69fdb284 100644 --- a/src/modes/extra/MKWii.cpp +++ b/src/modes/extra/MKWii.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MKWii::MKWii(GameModeConfig &config) : ControllerMode(config) {} +MKWii::MKWii(const GameModeConfig &config) : ControllerMode(config) {} -void MKWii::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void MKWii::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.b; outputs.b = inputs.x; outputs.triggerLDigital = inputs.z; @@ -15,7 +15,7 @@ void MKWii::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.start = inputs.start; } -void MKWii::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void MKWii::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { bool up = inputs.down || inputs.mod_x || inputs.mod_y; UpdateDirections( diff --git a/src/modes/extra/MultiVersus.cpp b/src/modes/extra/MultiVersus.cpp index f27af54e..4fa34244 100644 --- a/src/modes/extra/MultiVersus.cpp +++ b/src/modes/extra/MultiVersus.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MultiVersus::MultiVersus(GameModeConfig &config) : ControllerMode(config) {} +MultiVersus::MultiVersus(const GameModeConfig &config) : ControllerMode(config) {} -void MultiVersus::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void MultiVersus::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Bind X and Y to "jump" in-game. outputs.x = inputs.x; outputs.y = inputs.y; @@ -67,7 +67,7 @@ void MultiVersus::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) } } -void MultiVersus::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void MultiVersus::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, diff --git a/src/modes/extra/RocketLeague.cpp b/src/modes/extra/RocketLeague.cpp index 1fd781ed..49df08cf 100644 --- a/src/modes/extra/RocketLeague.cpp +++ b/src/modes/extra/RocketLeague.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -RocketLeague::RocketLeague(GameModeConfig &config) : ControllerMode(config) {} +RocketLeague::RocketLeague(const GameModeConfig &config) : ControllerMode(config) {} -void RocketLeague::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void RocketLeague::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; outputs.b = inputs.b; outputs.x = inputs.midshield; @@ -39,7 +39,7 @@ void RocketLeague::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs } } -void RocketLeague::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void RocketLeague::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, diff --git a/src/modes/extra/SaltAndSanctuary.cpp b/src/modes/extra/SaltAndSanctuary.cpp index 2c792f3c..b07dc1c9 100644 --- a/src/modes/extra/SaltAndSanctuary.cpp +++ b/src/modes/extra/SaltAndSanctuary.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -SaltAndSanctuary::SaltAndSanctuary(GameModeConfig &config) : ControllerMode(config) {} +SaltAndSanctuary::SaltAndSanctuary(const GameModeConfig &config) : ControllerMode(config) {} -void SaltAndSanctuary::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void SaltAndSanctuary::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.dpadRight = inputs.l; // Block outputs.b = inputs.b; // Roll outputs.a = inputs.a; // Attack @@ -25,7 +25,7 @@ void SaltAndSanctuary::UpdateDigitalOutputs(InputState &inputs, OutputState &out outputs.start = inputs.start; // Inventory } -void SaltAndSanctuary::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void SaltAndSanctuary::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, diff --git a/src/modes/extra/ShovelKnight.cpp b/src/modes/extra/ShovelKnight.cpp index 138e78ef..4d6a95ed 100644 --- a/src/modes/extra/ShovelKnight.cpp +++ b/src/modes/extra/ShovelKnight.cpp @@ -4,9 +4,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -ShovelKnight::ShovelKnight(GameModeConfig &config) : ControllerMode(config) {} +ShovelKnight::ShovelKnight(const GameModeConfig &config) : ControllerMode(config) {} -void ShovelKnight::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void ShovelKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.dpadLeft = inputs.left; outputs.dpadRight = inputs.right; outputs.dpadDown = inputs.down; @@ -23,7 +23,7 @@ void ShovelKnight::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs outputs.start = inputs.start; // Pause } -void ShovelKnight::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void ShovelKnight::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( inputs.left, inputs.right, diff --git a/src/modes/extra/ToughLoveArena.cpp b/src/modes/extra/ToughLoveArena.cpp index 3f12429b..91cb16b2 100644 --- a/src/modes/extra/ToughLoveArena.cpp +++ b/src/modes/extra/ToughLoveArena.cpp @@ -1,6 +1,6 @@ #include "modes/extra/ToughLoveArena.hpp" -ToughLoveArena::ToughLoveArena(GameModeConfig &config) : KeyboardMode(config) {} +ToughLoveArena::ToughLoveArena(const GameModeConfig &config) : KeyboardMode(config) {} void ToughLoveArena::UpdateKeys(InputState &inputs) { Press(HID_KEY_S, inputs.left); diff --git a/src/modes/extra/Ultimate2.cpp b/src/modes/extra/Ultimate2.cpp index 7d9c62cd..073b28ac 100644 --- a/src/modes/extra/Ultimate2.cpp +++ b/src/modes/extra/Ultimate2.cpp @@ -5,9 +5,9 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate2::Ultimate2(GameModeConfig &config) : ControllerMode(config) {} +Ultimate2::Ultimate2(const GameModeConfig &config) : ControllerMode(config) {} -void Ultimate2::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { +void Ultimate2::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.a; outputs.b = inputs.b; outputs.x = inputs.x; @@ -31,7 +31,7 @@ void Ultimate2::UpdateDigitalOutputs(InputState &inputs, OutputState &outputs) { outputs.dpadRight = true; } -void Ultimate2::UpdateAnalogOutputs(InputState &inputs, OutputState &outputs) { +void Ultimate2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( inputs.left, From 4361d2f5faf7865b5de1e0119a16808be4b03afd Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 8 Oct 2023 17:31:15 +0100 Subject: [PATCH 009/167] Update B0XXInputViewer, Configurator, and mode_selection --- src/comms/B0XXInputViewer.cpp | 10 ++++--- src/comms/ConfiguratorBackend.cpp | 8 ++++-- src/core/mode_selection.cpp | 46 ++++++++++++++++++++----------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/comms/B0XXInputViewer.cpp b/src/comms/B0XXInputViewer.cpp index 89e1d9d9..cac37369 100644 --- a/src/comms/B0XXInputViewer.cpp +++ b/src/comms/B0XXInputViewer.cpp @@ -5,8 +5,12 @@ #define ASCII_BIT(x) (x ? '1' : '0'); -B0XXInputViewer::B0XXInputViewer(InputSource **input_sources, size_t input_source_count) - : CommunicationBackend(input_sources, input_source_count) { +B0XXInputViewer::B0XXInputViewer( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count +) + : CommunicationBackend(inputs, input_sources, input_source_count) { serial::init(115200); } @@ -29,8 +33,6 @@ void B0XXInputViewer::SendReport() { // Only scan fast input sources because we don't want to waste any more time than necessary // on the input viewer and we can't afford to read from something like a Nunchuk twice. - ScanInputs(InputScanSpeed::FAST); - _report[0] = ASCII_BIT(_inputs.start); _report[1] = ASCII_BIT(_inputs.y); _report[2] = ASCII_BIT(_inputs.x); diff --git a/src/comms/ConfiguratorBackend.cpp b/src/comms/ConfiguratorBackend.cpp index 62259293..c8ad31a4 100644 --- a/src/comms/ConfiguratorBackend.cpp +++ b/src/comms/ConfiguratorBackend.cpp @@ -1,17 +1,19 @@ #include "comms/ConfiguratorBackend.hpp" #include "core/InputSource.hpp" +#include "reboot.hpp" #include "serial.hpp" #include #include ConfiguratorBackend::ConfiguratorBackend( + InputState &inputs, InputSource **input_sources, size_t input_source_count, Config &config ) - : CommunicationBackend(input_sources, input_source_count), + : CommunicationBackend(inputs, input_sources, input_source_count), _config(config) { _in = new packetio::COBSStream(Serial); _out = new packetio::COBSPrint(Serial); @@ -40,10 +42,10 @@ void ConfiguratorBackend::SendReport() { HandleSetConfig(_cmd_buffer, packet_len); break; case CMD_REBOOT_FIRMWARE: - rp2040.reboot(); + reboot_firmware(); break; case CMD_REBOOT_BOOTLOADER: - rp2040.rebootToBootloader(); + reboot_bootloader(); break; case CMD_UNSPECIFIED: default: diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index eb3073fb..2e0dcccf 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -10,9 +10,10 @@ #include -extern const Config config; +// extern const Config config; -uint64_t gamemode_activation_masks[sizeof(config.game_mode_configs) / sizeof(GameModeConfig)]; +// uint64_t gamemode_activation_masks[sizeof(config.game_mode_configs) / sizeof(GameModeConfig)]; +uint64_t mode_activation_masks[10]; void set_mode(CommunicationBackend *backend, ControllerMode *mode) { // Delete keyboard mode in case one is set, so we don't end up getting both controller and @@ -62,11 +63,18 @@ void set_mode(CommunicationBackend *backend, const GameModeConfig &mode_config) } } -void set_mode(CommunicationBackend *backend, GameModeId mode_id) { +// TODO: Maybe remove this overload in favour of looking up the gamemode outside of here using a +// config_utils function. +void set_mode( + CommunicationBackend *backend, + GameModeId mode_id, + const GameModeConfig *mode_configs, + size_t mode_configs_count +) { // In this overload we only know the mode id so we need to find a mode config that matches this // ID. - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - const GameModeConfig &mode = config.game_mode_configs[i]; + for (size_t i = 0; i < mode_configs_count; i++) { + const GameModeConfig &mode = mode_configs[i]; if (mode.mode_id == mode_id) { set_mode(backend, mode); return; @@ -76,25 +84,31 @@ void set_mode(CommunicationBackend *backend, GameModeId mode_id) { void select_mode( CommunicationBackend *backend, - const GameModeConfig *game_mode_configs, - const size_t game_mode_configs_count + const GameModeConfig *mode_configs, + size_t mode_configs_count ) { // TODO: Use a counter variable to only run the contents of this function every x iterations // rather than on every single poll. InputState &inputs = backend->GetInputs(); + // uint64_t buttons = backend->GetInputs().buttons; - for (size_t i = 0; i < game_mode_configs_count; i++) { - const GameModeConfig &mode_config = game_mode_configs[i]; - // TODO: Cache gamemode activation binding masks globally so they aren't rebuilt in main - // loop. - // Build bit mask for checking for matching button hold. - uint64_t activation_binding_mask = - make_button_mask(mode_config.activation_binding, mode_config.activation_binding_count); - - if (all_buttons_held(inputs.buttons, activation_binding_mask)) { + for (size_t i = 0; i < mode_configs_count; i++) { + const GameModeConfig &mode_config = mode_configs[i]; + // if (all_buttons_held(buttons, mode_activation_masks[i])) { + if (all_buttons_held(inputs.buttons, mode_activation_masks[i])) { set_mode(backend, mode_config); return; } } } + +void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count) { + // Build bit masks for checking for matching button holds. + for (size_t i = 0; i < mode_configs_count; i++) { + mode_activation_masks[i] = make_button_mask( + mode_configs[i].activation_binding, + mode_configs[i].activation_binding_count + ); + } +} \ No newline at end of file From 5246ce17a6ff260b556ef8249d34af31b9c06ba8 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 9 Oct 2023 00:14:45 +0100 Subject: [PATCH 010/167] fix: resolve AVR performance issues --- .../avr_usb/include/comms/DInputBackend.hpp | 1 - HAL/avr/avr_usb/src/comms/DInputBackend.cpp | 67 +------ HAL/avr/include/util/state_util.hpp | 175 ++++++++++++++++++ HAL/pico/include/util/state_util.hpp | 36 ++++ include/core/mode_selection.hpp | 1 - include/core/state.hpp | 33 +--- src/core/InputMode.cpp | 1 + src/core/config_utils.cpp | 1 + src/core/mode_selection.cpp | 1 + src/core/socd.cpp | 2 + src/input/GpioButtonInput.cpp | 3 +- 11 files changed, 233 insertions(+), 88 deletions(-) create mode 100644 HAL/avr/include/util/state_util.hpp create mode 100644 HAL/pico/include/util/state_util.hpp diff --git a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp index 0f980188..a9fbf183 100644 --- a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp +++ b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp @@ -16,7 +16,6 @@ class DInputBackend : public CommunicationBackend { void SendReport(); private: - int16_t GetDpadAngle(bool left, bool right, bool down, bool up); Joystick_ *_joystick; }; diff --git a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp index cdf4e034..b2027063 100644 --- a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp +++ b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp @@ -11,31 +11,8 @@ DInputBackend::DInputBackend( size_t input_source_count ) : CommunicationBackend(inputs, input_sources, input_source_count) { - _joystick = new Joystick_( - JOYSTICK_DEFAULT_REPORT_ID, - JOYSTICK_TYPE_GAMEPAD, - 16, // Button Count - 1, // Hat Switch Count - true, // X Axis - true, // Y Axis - true, // Z Axis - true, // Rx Axis - true, // Ry Axis - true, // Rz Axis - false, // No rudder - false, // No throttle - false, // No accelerator - false, // No brake - false // No steering - ); - - _joystick->begin(false); - _joystick->setXAxisRange(0, 255); - _joystick->setYAxisRange(0, 255); - _joystick->setRxAxisRange(0, 255); - _joystick->setRyAxisRange(0, 255); - _joystick->setZAxisRange(0, 255); - _joystick->setRzAxisRange(0, 255); + _joystick = new Joystick_(); + _joystick->begin(); } DInputBackend::~DInputBackend() { @@ -65,40 +42,16 @@ void DInputBackend::SendReport() { _joystick->setButton(12, _outputs.home); // Analog outputs - _joystick->setXAxis(_outputs.leftStickX); - _joystick->setYAxis(255 - _outputs.leftStickY); - _joystick->setRxAxis(_outputs.rightStickX); - _joystick->setRyAxis(255 - _outputs.rightStickY); - _joystick->setZAxis(_outputs.triggerLAnalog + 1); - _joystick->setRzAxis(_outputs.triggerRAnalog + 1); + _joystick->setLeftXAxis(_outputs.leftStickX); + _joystick->setLeftYAxis(255 - _outputs.leftStickY); + _joystick->setRightXAxis(_outputs.rightStickX); + _joystick->setRightYAxis(255 - _outputs.rightStickY); + _joystick->setLeftTrigger(_outputs.triggerLAnalog + 1); + _joystick->setRightTrigger(_outputs.triggerRAnalog + 1); // D-pad Hat Switch - _joystick->setHatSwitch( - 0, - GetDpadAngle(_outputs.dpadLeft, _outputs.dpadRight, _outputs.dpadDown, _outputs.dpadUp) - ); + _joystick + ->setHatSwitch(_outputs.dpadLeft, _outputs.dpadRight, _outputs.dpadDown, _outputs.dpadUp); _joystick->sendState(); } - -int16_t DInputBackend::GetDpadAngle(bool left, bool right, bool down, bool up) { - int16_t angle = -1; - if (right && !left) { - angle = 90; - if (down) - angle = 135; - if (up) - angle = 45; - } else if (left && !right) { - angle = 270; - if (down) - angle = 225; - if (up) - angle = 315; - } else if (down && !up) { - angle = 180; - } else if (up && !down) { - angle = 0; - } - return angle; -} diff --git a/HAL/avr/include/util/state_util.hpp b/HAL/avr/include/util/state_util.hpp new file mode 100644 index 00000000..29f644c6 --- /dev/null +++ b/HAL/avr/include/util/state_util.hpp @@ -0,0 +1,175 @@ +#ifndef _UTIL_STATE_UTIL_HPP +#define _UTIL_STATE_UTIL_HPP + +#include "core/state.hpp" +#include "stdlib.hpp" + +#include + +typedef struct _ButtonState { + bool left : 1; + bool right : 1; + bool down : 1; + bool up : 1; + bool c_left : 1; + bool c_right : 1; + bool c_down : 1; + bool c_up : 1; + bool a : 1; + bool b : 1; + bool x : 1; + bool y : 1; + bool l : 1; + bool r : 1; + bool z : 1; + bool lightshield : 1; + bool midshield : 1; + bool select : 1; + bool start : 1; + bool home : 1; + bool mod_x : 1; + bool mod_y : 1; +} ButtonState; + +inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { + ButtonState &inputs = (ButtonState &)buttons; + if (button_index == BTN_UNSPECIFIED) { + return; + } + switch (button_index) { + case BTN_LEFT: + inputs.left = pressed; + break; + case BTN_RIGHT: + inputs.right = pressed; + break; + case BTN_DOWN: + inputs.down = pressed; + break; + case BTN_UP: + inputs.up = pressed; + break; + case BTN_C_LEFT: + inputs.c_left = pressed; + break; + case BTN_C_RIGHT: + inputs.c_right = pressed; + break; + case BTN_C_DOWN: + inputs.c_down = pressed; + break; + case BTN_C_UP: + inputs.c_up = pressed; + break; + case BTN_A: + inputs.a = pressed; + break; + case BTN_B: + inputs.b = pressed; + break; + case BTN_X: + inputs.x = pressed; + break; + case BTN_Y: + inputs.y = pressed; + break; + case BTN_L: + inputs.l = pressed; + break; + case BTN_R: + inputs.r = pressed; + break; + case BTN_Z: + inputs.z = pressed; + break; + case BTN_LIGHTSHIELD: + inputs.lightshield = pressed; + break; + case BTN_MIDSHIELD: + inputs.midshield = pressed; + break; + case BTN_SELECT: + inputs.select = pressed; + break; + case BTN_START: + inputs.start = pressed; + break; + case BTN_HOME: + inputs.home = pressed; + break; + case BTN_MOD_X: + inputs.mod_x = pressed; + break; + case BTN_MOD_Y: + inputs.mod_y = pressed; + break; + default: + break; + } +} + +inline bool get_button(const uint64_t &buttons, Button button_index) { + ButtonState &inputs = (ButtonState &)buttons; + switch (button_index) { + case BTN_LEFT: + return inputs.left; + case BTN_RIGHT: + return inputs.right; + case BTN_DOWN: + return inputs.down; + case BTN_UP: + return inputs.up; + case BTN_C_LEFT: + return inputs.c_left; + case BTN_C_RIGHT: + return inputs.c_right; + case BTN_C_DOWN: + return inputs.c_down; + case BTN_C_UP: + return inputs.c_up; + case BTN_A: + return inputs.a; + case BTN_B: + return inputs.b; + case BTN_X: + return inputs.x; + case BTN_Y: + return inputs.y; + case BTN_L: + return inputs.l; + case BTN_R: + return inputs.r; + case BTN_Z: + return inputs.z; + case BTN_LIGHTSHIELD: + return inputs.lightshield; + case BTN_MIDSHIELD: + return inputs.midshield; + case BTN_SELECT: + return inputs.select; + case BTN_START: + return inputs.start; + case BTN_HOME: + return inputs.home; + case BTN_MOD_X: + return inputs.mod_x; + case BTN_MOD_Y: + return inputs.mod_y; + default: + return false; + } +} + +inline uint64_t make_button_mask(const Button *buttons, size_t buttons_count) { + uint64_t button_mask = 0; + for (size_t j = 0; j < buttons_count; j++) { + button_mask |= (1ULL << (buttons[j] - 1)); + } + return button_mask; +} + +inline bool all_buttons_held(const uint64_t &buttons, uint64_t button_mask) { + return button_mask != 0 && (buttons & button_mask) == button_mask; +} + +#endif \ No newline at end of file diff --git a/HAL/pico/include/util/state_util.hpp b/HAL/pico/include/util/state_util.hpp new file mode 100644 index 00000000..7ff0bcaf --- /dev/null +++ b/HAL/pico/include/util/state_util.hpp @@ -0,0 +1,36 @@ +#ifndef _UTIL_STATE_UTIL_HPP +#define _UTIL_STATE_UTIL_HPP + +#include "stdlib.hpp" + +#include + +inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { + if (button_index == BTN_UNSPECIFIED) { + return; + } + Button button_index_adjusted = (Button)(button_index - 1); + buttons = + (buttons & ~(1ULL << button_index_adjusted)) | ((uint64_t)pressed << button_index_adjusted); +} + +inline bool get_button(const uint64_t &buttons, Button button_index) { + if (button_index == BTN_UNSPECIFIED) { + return false; + } + return buttons & (1ULL << (button_index - 1)); +} + +inline uint64_t make_button_mask(const Button *buttons, size_t buttons_count) { + uint64_t button_mask = 0; + for (size_t j = 0; j < buttons_count; j++) { + button_mask |= (1ULL << (buttons[j] - 1)); + } + return button_mask; +} + +inline bool all_buttons_held(const uint64_t &buttons, uint64_t button_mask) { + return button_mask != 0 && (buttons & button_mask) == button_mask; +} + +#endif \ No newline at end of file diff --git a/include/core/mode_selection.hpp b/include/core/mode_selection.hpp index 7ad789b1..8f529fa5 100644 --- a/include/core/mode_selection.hpp +++ b/include/core/mode_selection.hpp @@ -7,7 +7,6 @@ #include -// extern Config config; extern KeyboardMode *current_kb_mode; void set_mode(CommunicationBackend *backend, ControllerMode *mode); diff --git a/include/core/state.hpp b/include/core/state.hpp index d3f0054f..051102e1 100644 --- a/include/core/state.hpp +++ b/include/core/state.hpp @@ -6,6 +6,11 @@ #include // Button state. +// typedef union _ButtonState { +// uint64_t buttons = 0; + +// } ButtonState; + typedef struct _InputState { // Rectangle inputs. union { @@ -52,34 +57,6 @@ typedef struct _InputState { int8_t nunchuk_y = 0; } InputState; -inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { - if (button_index == BTN_UNSPECIFIED) { - return; - } - Button button_index_adjusted = (Button)(button_index - 1); - buttons = - (buttons & ~(1ULL << button_index_adjusted)) | ((uint64_t)pressed << button_index_adjusted); -} - -inline bool get_button(const uint64_t &buttons, Button button_index) { - if (button_index == BTN_UNSPECIFIED) { - return false; - } - return buttons & (1ULL << (button_index - 1)); -} - -inline uint64_t make_button_mask(const Button *buttons, size_t buttons_count) { - uint64_t button_mask = 0; - for (size_t j = 0; j < buttons_count; j++) { - button_mask |= (1ULL << (buttons[j] - 1)); - } - return button_mask; -} - -inline bool all_buttons_held(const uint64_t &buttons, uint64_t button_mask) { - return button_mask != 0 && (buttons & button_mask) == button_mask; -} - // State describing stick direction at the quadrant level. typedef struct { bool horizontal; diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index ee625362..ed72732f 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -2,6 +2,7 @@ #include "core/socd.hpp" #include "core/state.hpp" +#include "util/state_util.hpp" InputMode::InputMode(const GameModeConfig &config) : _config(config) { _socd_states = new socd::SocdState[_config.socd_pairs_count]; diff --git a/src/core/config_utils.cpp b/src/core/config_utils.cpp index 091ad2e8..defeef2c 100644 --- a/src/core/config_utils.cpp +++ b/src/core/config_utils.cpp @@ -1,6 +1,7 @@ #include "core/config_utils.hpp" #include "core/state.hpp" +#include "util/state_util.hpp" #include diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 2e0dcccf..dc3aacc3 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -7,6 +7,7 @@ #include "modes/ProjectM.hpp" #include "modes/RivalsOfAether.hpp" #include "modes/Ultimate.hpp" +#include "util/state_util.hpp" #include diff --git a/src/core/socd.cpp b/src/core/socd.cpp index bf2ebe71..81a0d53f 100644 --- a/src/core/socd.cpp +++ b/src/core/socd.cpp @@ -1,5 +1,7 @@ #include "core/socd.hpp" +#include "util/state_util.hpp" + void socd::second_input_priority_no_reactivation( InputState &inputs, Button button_dir1, diff --git a/src/input/GpioButtonInput.cpp b/src/input/GpioButtonInput.cpp index 96ec0242..9567664b 100644 --- a/src/input/GpioButtonInput.cpp +++ b/src/input/GpioButtonInput.cpp @@ -1,8 +1,9 @@ #include "input/GpioButtonInput.hpp" #include "gpio.hpp" +#include "util/state_util.hpp" -GpioButtonInput::GpioButtonInput(GpioButtonMapping *button_mappings, size_t button_count) { +GpioButtonInput::GpioButtonInput(const GpioButtonMapping *button_mappings, size_t button_count) { _button_mappings = button_mappings; _button_count = button_count; From 512e5a4281bdc164b59ebdbfe7655e39a594c183 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 9 Oct 2023 00:35:29 +0100 Subject: [PATCH 011/167] feat: update pico and c53 configs --- HAL/pico/src/comms/backend_init.cpp | 2 +- config/c53/config.cpp | 185 ++++++++++++++++------------ config/pico/config.cpp | 151 +++-------------------- include/input/SwitchMatrixInput.hpp | 22 ++-- platformio.ini | 2 +- 5 files changed, 138 insertions(+), 224 deletions(-) diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 6f84eb10..805e75d5 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -91,7 +91,7 @@ size_t initialize_backends( mode_id = MODE_MELEE; } - set_mode(primary_backend, mode_id); + set_mode(primary_backend, mode_id, config.game_mode_configs, config.game_mode_configs_count); return backend_count; } \ No newline at end of file diff --git a/config/c53/config.cpp b/config/c53/config.cpp index 78ee81a0..3d180403 100644 --- a/config/c53/config.cpp +++ b/config/c53/config.cpp @@ -1,22 +1,92 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "comms/NintendoSwitchBackend.hpp" -#include "comms/XInputBackend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" #include "core/KeyboardMode.hpp" +#include "core/Persistence.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/SwitchMatrixInput.hpp" -#include "joybus_utils.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -#include +Config config = { + .default_backend = COMMS_BACKEND_XINPUT, + .game_mode_configs_count = 4, + .game_mode_configs = { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_L }, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_LEFT }, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_DOWN }, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_MOD_X, .button_dir2 = BTN_C_UP, .socd_type = SOCD_DIR1_PRIORITY }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_MOD_X, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_MOD_X, BTN_START, BTN_RIGHT }, + }, + }, + .communication_backend_configs_count = 3, + .communication_backend_configs = { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_XINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 0, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 1, + .activation_binding = { BTN_Z }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_CONFIGURATOR, + .default_mode = MODE_UNSPECIFIED, + .activation_binding_count = 1, + .activation_binding = { BTN_C_DOWN }, + } + }, +}; CommunicationBackend **backends; size_t backend_count; @@ -24,15 +94,15 @@ KeyboardMode *current_kb_mode = nullptr; const size_t num_rows = 5; const size_t num_cols = 13; -uint row_pins[num_rows] = { 20, 19, 18, 17, 16 }; -uint col_pins[num_cols] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; +const uint row_pins[num_rows] = { 20, 19, 18, 17, 16 }; +const uint col_pins[num_cols] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; // clang-format off -SwitchMatrixElement matrix[num_rows][num_cols] = { - {NA, NA, NA, NA, NA, BTN(select), BTN(start), BTN(home), NA, BTN(r), BTN(y), BTN(lightshield), BTN(midshield)}, - { BTN(l), BTN(left), BTN(down), BTN(right), NA, NA, NA, NA, NA, BTN(b), BTN(x), BTN(z), BTN(up) }, - { NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, - { NA, NA, NA, NA, NA, NA, NA, NA, NA, BTN(c_left), BTN(c_up), BTN(c_right), NA }, - { NA, NA, BTN(mod_x), BTN(mod_y), NA, NA, NA, NA, NA, BTN(c_down), BTN(a), NA, NA }, +const Button matrix[num_rows][num_cols] = { + {NA, NA, NA, NA, NA, BTN_SELECT, BTN_START, BTN_HOME, NA, BTN_R, BTN_Y, BTN_LIGHTSHIELD, BTN_MIDSHIELD}, + { BTN_L, BTN_LEFT, BTN_DOWN, BTN_RIGHT, NA, NA, NA, NA, NA, BTN_B, BTN_X, BTN_Z, BTN_UP }, + { NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, + { NA, NA, NA, NA, NA, NA, NA, NA, NA, BTN_C_LEFT, BTN_C_UP, BTN_C_RIGHT, NA }, + { NA, NA, BTN_MOD_X, BTN_MOD_Y, NA, NA, NA, NA, NA, BTN_C_DOWN, BTN_A, NA, NA }, }; // clang-format on DiodeDirection diode_direction = DiodeDirection::COL2ROW; @@ -46,16 +116,15 @@ const Pinout pinout = { }; void setup() { - // Create switch matrix input source and use it to read button states for checking button holds. - SwitchMatrixInput *matrix_input = - new SwitchMatrixInput(row_pins, col_pins, matrix, diode_direction); + static InputState inputs; - InputState button_holds; - matrix_input->UpdateInputs(button_holds); + // Create switch matrix input source and use it to read button states for checking button holds. + SwitchMatrixInput matrix_input(row_pins, col_pins, matrix, diode_direction); + matrix_input.UpdateInputs(inputs); // Bootsel button hold as early as possible for safety. - if (button_holds.start) { - reset_usb_boot(0, 0); + if (inputs.start) { + reboot_bootloader(); } // Turn on LED to indicate firmware booted. @@ -63,63 +132,25 @@ void setup() { gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); + // Attempt to load config, or write default config to flash if failed to load config. + Persistence *persistence = new Persistence(); + if (!persistence->LoadConfig(config)) { + persistence->SaveConfig(config); + } + delete persistence; + // Create array of input sources to be used. - static InputSource *input_sources[] = { matrix_input }; + static InputSource *input_sources[] = { &matrix_input }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - ConnectedConsole console = detect_console(pinout.joybus_data); - - /* Select communication backend. */ - CommunicationBackend *primary_backend; - if (console == ConnectedConsole::NONE) { - if (button_holds.x) { - // If no console detected and X is held on plugin then use Switch USB backend. - NintendoSwitchBackend::RegisterDescriptor(); - backend_count = 1; - primary_backend = new NintendoSwitchBackend(input_sources, input_source_count); - backends = new CommunicationBackend *[backend_count] { primary_backend }; - - // Default to Ultimate mode on Switch. - primary_backend->SetGameMode(new Ultimate(socd::SOCD_2IP)); - return; - } else if (button_holds.z) { - // If no console detected and Z is held on plugin then use DInput backend. - TUGamepad::registerDescriptor(); - TUKeyboard::registerDescriptor(); - backend_count = 2; - primary_backend = new DInputBackend(input_sources, input_source_count); - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - // Default to XInput mode if no console detected and no other mode forced. - backend_count = 2; - primary_backend = new XInputBackend(input_sources, input_source_count); - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } - } else { - if (console == ConnectedConsole::GAMECUBE) { - primary_backend = - new GamecubeBackend(input_sources, input_source_count, pinout.joybus_data); - } else if (console == ConnectedConsole::N64) { - primary_backend = new N64Backend(input_sources, input_source_count, pinout.joybus_data); - } - - // If console then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends[0], config.game_mode_configs, config.game_mode_configs_count); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 074dd896..e1792773 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -1,25 +1,14 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/ConfiguratorBackend.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "comms/NintendoSwitchBackend.hpp" -#include "comms/XInputBackend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" #include "core/KeyboardMode.hpp" #include "core/Persistence.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" #include "input/NunchukInput.hpp" -#include "joybus_utils.hpp" -#include "modes/Melee20Button.hpp" #include "stdlib.hpp" -#include #include Config config = { @@ -101,10 +90,6 @@ Config config = { }, }; -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; - GpioButtonMapping button_mappings[] = { {BTN_L, 5 }, { BTN_LEFT, 4 }, @@ -144,22 +129,19 @@ const Pinout pinout = { .nunchuk_scl = -1, }; -void set_comms_backend( - CommunicationBackendId backend_id, - GameModeId mode_id, - InputSource **input_sources, - size_t input_source_count -); +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; void setup() { - // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static InputState inputs; - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + // Create GPIO input source and use it to read button states for checking button holds. + static GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - // Bootsel button hold as early as possible for safety. - if (button_holds.start) { + // Check bootsel button hold as early as possible for safety. + if (inputs.start) { rp2040.rebootToBootloader(); } @@ -168,6 +150,7 @@ void setup() { gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); + // Attempt to load config, or write default config to flash if failed to load config. Persistence *persistence = new Persistence(); if (!persistence->LoadConfig(config)) { persistence->SaveConfig(config); @@ -175,117 +158,17 @@ void setup() { delete persistence; // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input }; + static InputSource *input_sources[] = { &gpio_input }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - for (size_t i = 0; i < config.communication_backend_configs_count; i++) { - CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; - // Build bit mask for checking for matching button hold. - uint64_t button_hold_mask = make_button_mask( - backend_config.activation_binding, - backend_config.activation_binding_count - ); - - // Check if button hold matches. - if (all_buttons_held(button_holds.buttons, button_hold_mask)) { - set_comms_backend( - backend_config.backend_id, - backend_config.default_mode, - input_sources, - input_source_count - ); - return; - } - } - - // If no backend selected using button holds, run auto detection. - ConnectedConsole console = detect_console(pinout.joybus_data); - CommunicationBackendId backend_id = COMMS_BACKEND_UNSPECIFIED; - switch (console) { - case ConnectedConsole::GAMECUBE: - backend_id = COMMS_BACKEND_GAMECUBE; - break; - case ConnectedConsole::N64: - backend_id = COMMS_BACKEND_N64; - break; - case ConnectedConsole::NONE: - default: - backend_id = config.default_backend; - } - - // No button hold was matched to a comms backend so we need to find a backend config that - // matches the detected console so we can check what the configured default gamemode is. - // Fall back to Melee mode if no other match found. - GameModeId mode_id = MODE_MELEE; - for (size_t i = 0; i < config.communication_backend_configs_count; i++) { - CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; - if (backend_config.backend_id == backend_id) { - mode_id = backend_config.default_mode; - } - } - - set_comms_backend(backend_id, mode_id, input_sources, input_source_count); -} - -void set_comms_backend( - CommunicationBackendId backend_id, - GameModeId mode_id, - InputSource **input_sources, - size_t input_source_count -) { - if (mode_id == MODE_UNSPECIFIED) { - mode_id = MODE_MELEE; - } - - CommunicationBackend *primary_backend; - - switch (backend_id) { - case COMMS_BACKEND_DINPUT: - TUGamepad::registerDescriptor(); - TUKeyboard::registerDescriptor(); - primary_backend = new DInputBackend(input_sources, input_source_count); - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - break; - case COMMS_BACKEND_XINPUT: - primary_backend = new XInputBackend(input_sources, input_source_count); - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - break; - case COMMS_BACKEND_GAMECUBE: - primary_backend = - new GamecubeBackend(input_sources, input_source_count, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - break; - case COMMS_BACKEND_N64: - primary_backend = new N64Backend(input_sources, input_source_count, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - break; - case COMMS_BACKEND_NINTENDO_SWITCH: - NintendoSwitchBackend::RegisterDescriptor(); - primary_backend = new NintendoSwitchBackend(input_sources, input_source_count); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - break; - case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. - case COMMS_BACKEND_CONFIGURATOR: - default: - primary_backend = new ConfiguratorBackend(input_sources, input_source_count, config); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - set_mode(primary_backend, mode_id); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends[0], config.game_mode_configs, config.game_mode_configs_count); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/include/input/SwitchMatrixInput.hpp b/include/input/SwitchMatrixInput.hpp index 69023725..ec4aff27 100644 --- a/include/input/SwitchMatrixInput.hpp +++ b/include/input/SwitchMatrixInput.hpp @@ -4,9 +4,11 @@ #include "core/InputSource.hpp" #include "core/state.hpp" #include "gpio.hpp" +#include "util/state_util.hpp" -#define BTN(x) &InputState::x -#define NA nullptr +#include + +#define NA BTN_UNSPECIFIED enum class DiodeDirection { ROW2COL, @@ -16,9 +18,9 @@ enum class DiodeDirection { template class SwitchMatrixInput : public InputSource { public: SwitchMatrixInput( - uint row_pins[num_rows], - uint col_pins[num_cols], - Button (&matrix)[num_rows][num_cols], + const uint row_pins[num_rows], + const uint col_pins[num_cols], + const Button (&matrix)[num_rows][num_cols], DiodeDirection direction ) : _matrix(matrix) { @@ -66,9 +68,7 @@ template class SwitchMatrixInput : public Inp for (size_t j = 0; j < _num_inputs; j++) { Button button = _direction == DiodeDirection::ROW2COL ? _matrix[j][i] : _matrix[i][j]; - if (button != nullptr) { - set_button(inputs.buttons, button, !gpio::read_digital(_input_pins[j])); - } + set_button(inputs.buttons, button, !gpio::read_digital(_input_pins[j])); } // Deactivate the column/row. @@ -79,9 +79,9 @@ template class SwitchMatrixInput : public Inp protected: size_t _num_outputs; size_t _num_inputs; - uint *_output_pins; - uint *_input_pins; - Button (&_matrix)[num_rows][num_cols]; + const uint *_output_pins; + const uint *_input_pins; + const Button (&_matrix)[num_rows][num_cols]; DiodeDirection _direction; }; diff --git a/platformio.ini b/platformio.ini index d4f0098a..e0ea8c68 100644 --- a/platformio.ini +++ b/platformio.ini @@ -70,7 +70,7 @@ build_src_filter = + lib_deps = ${avr_base.lib_deps} - mheironimus/Joystick@^2.1.1 + https://github.com/JonnyHaystack/ArduinoJoystickLibrary/archive/refs/tags/v0.0.1.zip https://github.com/JonnyHaystack/ArduinoKeyboard/archive/refs/tags/1.0.5.zip [arduino_pico_base] From abd1222f1e38be37ba6bf7fa1f99b3abf8ee769d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 9 Oct 2023 16:11:41 +0100 Subject: [PATCH 012/167] feat: update everything to use new standardised button names --- HAL/avr/avr_usb/src/comms/backend_init.cpp | 2 +- HAL/avr/include/util/state_util.hpp | 448 ++++++++++++++++----- config/c53/config.cpp | 61 +-- config/mode_selection.hpp | 98 ----- config/pico/config.cpp | 108 ++--- include/core/state.hpp | 88 ++-- platformio.ini | 2 +- src/comms/B0XXInputViewer.cpp | 40 +- src/core/mode_selection.cpp | 1 - src/modes/DefaultKeyboardMode.cpp | 44 +- src/modes/FgcMode.cpp | 30 +- src/modes/Melee18Button.cpp | 108 ++--- src/modes/Melee20Button.cpp | 98 ++--- src/modes/ProjectM.cpp | 90 ++--- src/modes/RivalsOfAether.cpp | 87 ++-- src/modes/Ultimate.cpp | 106 ++--- src/modes/extra/DarkSouls.cpp | 52 +-- src/modes/extra/HollowKnight.cpp | 36 +- src/modes/extra/MKWii.cpp | 22 +- src/modes/extra/MultiVersus.cpp | 62 +-- src/modes/extra/RocketLeague.cpp | 56 +-- src/modes/extra/SaltAndSanctuary.cpp | 40 +- src/modes/extra/ShovelKnight.cpp | 40 +- src/modes/extra/ToughLoveArena.cpp | 10 +- src/modes/extra/Ultimate2.cpp | 68 ++-- 25 files changed, 980 insertions(+), 817 deletions(-) delete mode 100644 config/mode_selection.hpp diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp index 7ecd11db..85ae7369 100644 --- a/HAL/avr/avr_usb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -44,7 +44,7 @@ size_t initialize_backends( inputs, input_sources, input_source_count, - inputs.a ? 0 : 125, + inputs.rt1 ? 0 : 125, pinout.joybus_data ); backend_count = 1; diff --git a/HAL/avr/include/util/state_util.hpp b/HAL/avr/include/util/state_util.hpp index 29f644c6..97ea8a40 100644 --- a/HAL/avr/include/util/state_util.hpp +++ b/HAL/avr/include/util/state_util.hpp @@ -7,28 +7,66 @@ #include typedef struct _ButtonState { - bool left : 1; - bool right : 1; - bool down : 1; - bool up : 1; - bool c_left : 1; - bool c_right : 1; - bool c_down : 1; - bool c_up : 1; - bool a : 1; - bool b : 1; - bool x : 1; - bool y : 1; - bool l : 1; - bool r : 1; - bool z : 1; - bool lightshield : 1; - bool midshield : 1; - bool select : 1; - bool start : 1; - bool home : 1; - bool mod_x : 1; - bool mod_y : 1; + bool lf1 : 1; + bool lf2 : 1; + bool lf3 : 1; + bool lf4 : 1; + bool lf5 : 1; + bool lf6 : 1; + bool lf7 : 1; + bool lf8 : 1; + bool lf9 : 1; + bool lf10 : 1; + bool lf11 : 1; + bool lf12 : 1; + bool lf13 : 1; + bool lf14 : 1; + bool lf15 : 1; + bool lf16 : 1; + bool rf1 : 1; + bool rf2 : 1; + bool rf3 : 1; + bool rf4 : 1; + bool rf5 : 1; + bool rf6 : 1; + bool rf7 : 1; + bool rf8 : 1; + bool rf9 : 1; + bool rf10 : 1; + bool rf11 : 1; + bool rf12 : 1; + bool rf13 : 1; + bool rf14 : 1; + bool rf15 : 1; + bool rf16 : 1; + bool lt1 : 1; + bool lt2 : 1; + bool lt3 : 1; + bool lt4 : 1; + bool lt5 : 1; + bool lt6 : 1; + bool lt7 : 1; + bool lt8 : 1; + bool rt1 : 1; + bool rt2 : 1; + bool rt3 : 1; + bool rt4 : 1; + bool rt5 : 1; + bool rt6 : 1; + bool rt7 : 1; + bool rt8 : 1; + bool mb1 : 1; + bool mb2 : 1; + bool mb3 : 1; + bool mb4 : 1; + bool mb5 : 1; + bool mb6 : 1; + bool mb7 : 1; + bool mb8 : 1; + bool mb9 : 1; + bool mb10 : 1; + bool mb11 : 1; + bool mb12 : 1; } ButtonState; inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { @@ -37,71 +75,185 @@ inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { return; } switch (button_index) { - case BTN_LEFT: - inputs.left = pressed; + case BTN_LF1: + inputs.lf1 = pressed; break; - case BTN_RIGHT: - inputs.right = pressed; + case BTN_LF2: + inputs.lf2 = pressed; break; - case BTN_DOWN: - inputs.down = pressed; + case BTN_LF3: + inputs.lf3 = pressed; break; - case BTN_UP: - inputs.up = pressed; + case BTN_LF4: + inputs.lf4 = pressed; break; - case BTN_C_LEFT: - inputs.c_left = pressed; + case BTN_LF5: + inputs.lf5 = pressed; break; - case BTN_C_RIGHT: - inputs.c_right = pressed; + case BTN_LF6: + inputs.lf6 = pressed; break; - case BTN_C_DOWN: - inputs.c_down = pressed; + case BTN_LF7: + inputs.lf7 = pressed; break; - case BTN_C_UP: - inputs.c_up = pressed; + case BTN_LF8: + inputs.lf8 = pressed; break; - case BTN_A: - inputs.a = pressed; + case BTN_LF9: + inputs.lf9 = pressed; break; - case BTN_B: - inputs.b = pressed; + case BTN_LF10: + inputs.lf10 = pressed; break; - case BTN_X: - inputs.x = pressed; + case BTN_LF11: + inputs.lf11 = pressed; break; - case BTN_Y: - inputs.y = pressed; + case BTN_LF12: + inputs.lf12 = pressed; break; - case BTN_L: - inputs.l = pressed; + case BTN_LF13: + inputs.lf13 = pressed; break; - case BTN_R: - inputs.r = pressed; + case BTN_LF14: + inputs.lf14 = pressed; break; - case BTN_Z: - inputs.z = pressed; + case BTN_LF15: + inputs.lf15 = pressed; break; - case BTN_LIGHTSHIELD: - inputs.lightshield = pressed; + case BTN_LF16: + inputs.lf16 = pressed; break; - case BTN_MIDSHIELD: - inputs.midshield = pressed; + case BTN_RF1: + inputs.rf1 = pressed; break; - case BTN_SELECT: - inputs.select = pressed; + case BTN_RF2: + inputs.rf2 = pressed; break; - case BTN_START: - inputs.start = pressed; + case BTN_RF3: + inputs.rf3 = pressed; break; - case BTN_HOME: - inputs.home = pressed; + case BTN_RF4: + inputs.rf4 = pressed; break; - case BTN_MOD_X: - inputs.mod_x = pressed; + case BTN_RF5: + inputs.rf5 = pressed; break; - case BTN_MOD_Y: - inputs.mod_y = pressed; + case BTN_RF6: + inputs.rf6 = pressed; + break; + case BTN_RF7: + inputs.rf7 = pressed; + break; + case BTN_RF8: + inputs.rf8 = pressed; + break; + case BTN_RF9: + inputs.rf9 = pressed; + break; + case BTN_RF10: + inputs.rf10 = pressed; + break; + case BTN_RF11: + inputs.rf11 = pressed; + break; + case BTN_RF12: + inputs.rf12 = pressed; + break; + case BTN_RF13: + inputs.rf13 = pressed; + break; + case BTN_RF14: + inputs.rf14 = pressed; + break; + case BTN_RF15: + inputs.rf15 = pressed; + break; + case BTN_RF16: + inputs.rf16 = pressed; + break; + case BTN_LT1: + inputs.lt1 = pressed; + break; + case BTN_LT2: + inputs.lt2 = pressed; + break; + case BTN_LT3: + inputs.lt3 = pressed; + break; + case BTN_LT4: + inputs.lt4 = pressed; + break; + case BTN_LT5: + inputs.lt5 = pressed; + break; + case BTN_LT6: + inputs.lt6 = pressed; + break; + case BTN_LT7: + inputs.lt7 = pressed; + break; + case BTN_LT8: + inputs.lt8 = pressed; + break; + case BTN_RT1: + inputs.rt1 = pressed; + break; + case BTN_RT2: + inputs.rt2 = pressed; + break; + case BTN_RT3: + inputs.rt3 = pressed; + break; + case BTN_RT4: + inputs.rt4 = pressed; + break; + case BTN_RT5: + inputs.rt5 = pressed; + break; + case BTN_RT6: + inputs.rt6 = pressed; + break; + case BTN_RT7: + inputs.rt7 = pressed; + break; + case BTN_RT8: + inputs.rt8 = pressed; + break; + case BTN_MB1: + inputs.mb1 = pressed; + break; + case BTN_MB2: + inputs.mb2 = pressed; + break; + case BTN_MB3: + inputs.mb3 = pressed; + break; + case BTN_MB4: + inputs.mb4 = pressed; + break; + case BTN_MB5: + inputs.mb5 = pressed; + break; + case BTN_MB6: + inputs.mb6 = pressed; + break; + case BTN_MB7: + inputs.mb7 = pressed; + break; + case BTN_MB8: + inputs.mb8 = pressed; + break; + case BTN_MB9: + inputs.mb9 = pressed; + break; + case BTN_MB10: + inputs.mb10 = pressed; + break; + case BTN_MB11: + inputs.mb11 = pressed; + break; + case BTN_MB12: + inputs.mb12 = pressed; break; default: break; @@ -111,50 +263,126 @@ inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { inline bool get_button(const uint64_t &buttons, Button button_index) { ButtonState &inputs = (ButtonState &)buttons; switch (button_index) { - case BTN_LEFT: - return inputs.left; - case BTN_RIGHT: - return inputs.right; - case BTN_DOWN: - return inputs.down; - case BTN_UP: - return inputs.up; - case BTN_C_LEFT: - return inputs.c_left; - case BTN_C_RIGHT: - return inputs.c_right; - case BTN_C_DOWN: - return inputs.c_down; - case BTN_C_UP: - return inputs.c_up; - case BTN_A: - return inputs.a; - case BTN_B: - return inputs.b; - case BTN_X: - return inputs.x; - case BTN_Y: - return inputs.y; - case BTN_L: - return inputs.l; - case BTN_R: - return inputs.r; - case BTN_Z: - return inputs.z; - case BTN_LIGHTSHIELD: - return inputs.lightshield; - case BTN_MIDSHIELD: - return inputs.midshield; - case BTN_SELECT: - return inputs.select; - case BTN_START: - return inputs.start; - case BTN_HOME: - return inputs.home; - case BTN_MOD_X: - return inputs.mod_x; - case BTN_MOD_Y: - return inputs.mod_y; + case BTN_LF1: + return inputs.lf1; + case BTN_LF2: + return inputs.lf2; + case BTN_LF3: + return inputs.lf3; + case BTN_LF4: + return inputs.lf4; + case BTN_LF5: + return inputs.lf5; + case BTN_LF6: + return inputs.lf6; + case BTN_LF7: + return inputs.lf7; + case BTN_LF8: + return inputs.lf8; + case BTN_LF9: + return inputs.lf9; + case BTN_LF10: + return inputs.lf10; + case BTN_LF11: + return inputs.lf11; + case BTN_LF12: + return inputs.lf12; + case BTN_LF13: + return inputs.lf13; + case BTN_LF14: + return inputs.lf14; + case BTN_LF15: + return inputs.lf15; + case BTN_LF16: + return inputs.lf16; + case BTN_RF1: + return inputs.rf1; + case BTN_RF2: + return inputs.rf2; + case BTN_RF3: + return inputs.rf3; + case BTN_RF4: + return inputs.rf4; + case BTN_RF5: + return inputs.rf5; + case BTN_RF6: + return inputs.rf6; + case BTN_RF7: + return inputs.rf7; + case BTN_RF8: + return inputs.rf8; + case BTN_RF9: + return inputs.rf9; + case BTN_RF10: + return inputs.rf10; + case BTN_RF11: + return inputs.rf11; + case BTN_RF12: + return inputs.rf12; + case BTN_RF13: + return inputs.rf13; + case BTN_RF14: + return inputs.rf14; + case BTN_RF15: + return inputs.rf15; + case BTN_RF16: + return inputs.rf16; + case BTN_LT1: + return inputs.lt1; + case BTN_LT2: + return inputs.lt2; + case BTN_LT3: + return inputs.lt3; + case BTN_LT4: + return inputs.lt4; + case BTN_LT5: + return inputs.lt5; + case BTN_LT6: + return inputs.lt6; + case BTN_LT7: + return inputs.lt7; + case BTN_LT8: + return inputs.lt8; + case BTN_RT1: + return inputs.rt1; + case BTN_RT2: + return inputs.rt2; + case BTN_RT3: + return inputs.rt3; + case BTN_RT4: + return inputs.rt4; + case BTN_RT5: + return inputs.rt5; + case BTN_RT6: + return inputs.rt6; + case BTN_RT7: + return inputs.rt7; + case BTN_RT8: + return inputs.rt8; + case BTN_MB1: + return inputs.mb1; + case BTN_MB2: + return inputs.mb2; + case BTN_MB3: + return inputs.mb3; + case BTN_MB4: + return inputs.mb4; + case BTN_MB5: + return inputs.mb5; + case BTN_MB6: + return inputs.mb6; + case BTN_MB7: + return inputs.mb7; + case BTN_MB8: + return inputs.mb8; + case BTN_MB9: + return inputs.mb9; + case BTN_MB10: + return inputs.mb10; + case BTN_MB11: + return inputs.mb11; + case BTN_MB12: + return inputs.mb12; default: return false; } diff --git a/config/c53/config.cpp b/config/c53/config.cpp index 3d180403..ef67c9d2 100644 --- a/config/c53/config.cpp +++ b/config/c53/config.cpp @@ -17,53 +17,54 @@ Config config = { .mode_id = MODE_MELEE, .socd_pairs_count = 4, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, }, .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_L }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, }, GameModeConfig { .mode_id = MODE_PROJECT_M, .socd_pairs_count = 4, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, }, .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_LEFT }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF3 }, }, GameModeConfig { .mode_id = MODE_ULTIMATE, .socd_pairs_count = 4, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, }, .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_DOWN }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF2 }, }, GameModeConfig { .mode_id = MODE_FGC, - .socd_pairs_count = 4, + .socd_pairs_count = 2, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_MOD_X, .button_dir2 = BTN_C_UP, .socd_type = SOCD_DIR1_PRIORITY }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_MOD_X, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 1, + .button_remapping = { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, }, - .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_RIGHT }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, }, }, .communication_backend_configs_count = 3, @@ -77,13 +78,13 @@ Config config = { .backend_id = COMMS_BACKEND_DINPUT, .default_mode = MODE_MELEE, .activation_binding_count = 1, - .activation_binding = { BTN_Z }, + .activation_binding = { BTN_RF3 }, }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_CONFIGURATOR, .default_mode = MODE_UNSPECIFIED, .activation_binding_count = 1, - .activation_binding = { BTN_C_DOWN }, + .activation_binding = { BTN_RT2 }, } }, }; @@ -98,11 +99,11 @@ const uint row_pins[num_rows] = { 20, 19, 18, 17, 16 }; const uint col_pins[num_cols] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; // clang-format off const Button matrix[num_rows][num_cols] = { - {NA, NA, NA, NA, NA, BTN_SELECT, BTN_START, BTN_HOME, NA, BTN_R, BTN_Y, BTN_LIGHTSHIELD, BTN_MIDSHIELD}, - { BTN_L, BTN_LEFT, BTN_DOWN, BTN_RIGHT, NA, NA, NA, NA, NA, BTN_B, BTN_X, BTN_Z, BTN_UP }, - { NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, - { NA, NA, NA, NA, NA, NA, NA, NA, NA, BTN_C_LEFT, BTN_C_UP, BTN_C_RIGHT, NA }, - { NA, NA, BTN_MOD_X, BTN_MOD_Y, NA, NA, NA, NA, NA, BTN_C_DOWN, BTN_A, NA, NA }, + {BTN_LF8, BTN_LF7, BTN_LF6, BTN_LF5, NA, BTN_MB3, BTN_MB1, BTN_MB2, NA, BTN_RF5, BTN_RF6, BTN_RF7, BTN_RF8 }, + { BTN_LF4, BTN_LF3, BTN_LF2, BTN_LF1, NA, BTN_MB4, BTN_MB5, BTN_MB6, NA, BTN_RT1, BTN_RT2, BTN_RF3, BTN_RF4 }, + { BTN_LF12, BTN_LF11, BTN_LF10, BTN_LF9, NA, BTN_MB7, BTN_MB8, BTN_MB9, NA, BTN_RF9, BTN_RF10, BTN_RF11, BTN_RF12}, + { NA, BTN_LT5, BTN_LT4, BTN_LT3, NA, BTN_MB10, BTN_MB11, BTN_MB12, NA, BTN_RT3, BTN_RT4, BTN_RT5, NA }, + { NA, NA, BTN_LT1, BTN_LT2, NA, BTN_LT6, BTN_RT7, BTN_RT6, NA, BTN_RT2, BTN_RT1, NA, NA }, }; // clang-format on DiodeDirection diode_direction = DiodeDirection::COL2ROW; @@ -123,7 +124,7 @@ void setup() { matrix_input.UpdateInputs(inputs); // Bootsel button hold as early as possible for safety. - if (inputs.start) { + if (inputs.mb1) { reboot_bootloader(); } diff --git a/config/mode_selection.hpp b/config/mode_selection.hpp deleted file mode 100644 index b8abcf1e..00000000 --- a/config/mode_selection.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef _CONFIG_MODE_SELECTION_HPP -#define _CONFIG_MODE_SELECTION_HPP - -#include "core/state.hpp" -#include "modes/DefaultKeyboardMode.hpp" -#include "modes/FgcMode.hpp" -#include "modes/Melee20Button.hpp" -#include "modes/ProjectM.hpp" -#include "modes/RivalsOfAether.hpp" -#include "modes/Ultimate.hpp" - -#include - -extern Config config; -extern KeyboardMode *current_kb_mode; - -void set_mode(CommunicationBackend *backend, ControllerMode *mode) { - // Delete keyboard mode in case one is set, so we don't end up getting both controller and - // keyboard inputs. - delete current_kb_mode; - current_kb_mode = nullptr; - - // Set new controller mode. - backend->SetGameMode(mode); -} - -void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { - // Delete and reassign current keyboard mode. - delete current_kb_mode; - current_kb_mode = mode; - - // Unset the current controller mode so backend only gives neutral inputs. - backend->SetGameMode(nullptr); -} - -void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config) { - switch (mode_config.mode_id) { - case MODE_MELEE: - set_mode(backend, new Melee20Button(mode_config, { .crouch_walk_os = false })); - break; - case MODE_PROJECT_M: - set_mode( - backend, - new ProjectM( - mode_config, - { .true_z_press = false, .ledgedash_max_jump_traj = true } - ) - ); - break; - case MODE_ULTIMATE: - set_mode(backend, new Ultimate(mode_config)); - break; - case MODE_FGC: - set_mode(backend, new FgcMode(mode_config)); - break; - case MODE_RIVALS_OF_AETHER: - set_mode(backend, new RivalsOfAether(mode_config)); - break; - case MODE_UNSPECIFIED: - default: - break; - } -} - -void set_mode(CommunicationBackend *backend, GameModeId mode_id) { - // In this overload we only know the mode id so we need to find a mode config that matches this - // ID. - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode = config.game_mode_configs[i]; - if (mode.mode_id == mode_id) { - set_mode(backend, mode); - return; - } - } -} - -void select_mode(CommunicationBackend *backend) { - // TODO: Use a counter variable to only run the contents of this function every x iterations - // rather than on every single poll. - - InputState &inputs = backend->GetInputs(); - - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode_config = config.game_mode_configs[i]; - // TODO: Cache gamemode activation binding masks globally so they aren't rebuilt in main - // loop. - // Build bit mask for checking for matching button hold. - uint64_t activation_binding_mask = - make_button_mask(mode_config.activation_binding, mode_config.activation_binding_count); - - if (all_buttons_held(inputs.buttons, activation_binding_mask)) { - set_mode(backend, mode_config); - return; - } - } -} - -#endif diff --git a/config/pico/config.cpp b/config/pico/config.cpp index e1792773..c0224f66 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -7,6 +7,7 @@ #include "core/state.hpp" #include "input/GpioButtonInput.hpp" #include "input/NunchukInput.hpp" +#include "reboot.hpp" #include "stdlib.hpp" #include @@ -19,53 +20,54 @@ Config config = { .mode_id = MODE_MELEE, .socd_pairs_count = 4, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, }, .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_L }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, }, GameModeConfig { .mode_id = MODE_PROJECT_M, .socd_pairs_count = 4, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, }, .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_LEFT }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF3 }, }, GameModeConfig { .mode_id = MODE_ULTIMATE, .socd_pairs_count = 4, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_UP, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_C_LEFT, .button_dir2 = BTN_C_RIGHT, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_C_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, }, .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_DOWN }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF2 }, }, GameModeConfig { .mode_id = MODE_FGC, - .socd_pairs_count = 4, + .socd_pairs_count = 2, .socd_pairs = { - SocdPair { .button_dir1 = BTN_LEFT, .button_dir2 = BTN_RIGHT, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_MOD_X, .button_dir2 = BTN_C_UP, .socd_type = SOCD_DIR1_PRIORITY }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_MOD_X, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_DOWN, .button_dir2 = BTN_C_UP, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 1, + .button_remapping = { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, }, - .button_remapping_count = 0, .activation_binding_count = 3, - .activation_binding = { BTN_MOD_X, BTN_START, BTN_RIGHT }, + .activation_binding = { BTN_RT1, BTN_MB1, BTN_LF1 }, }, }, .communication_backend_configs_count = 3, @@ -79,45 +81,45 @@ Config config = { .backend_id = COMMS_BACKEND_DINPUT, .default_mode = MODE_MELEE, .activation_binding_count = 1, - .activation_binding = { BTN_Z }, + .activation_binding = { BTN_RT3 }, }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_CONFIGURATOR, .default_mode = MODE_UNSPECIFIED, .activation_binding_count = 1, - .activation_binding = { BTN_C_DOWN }, + .activation_binding = { BTN_RT2 }, } }, }; GpioButtonMapping button_mappings[] = { - {BTN_L, 5 }, - { BTN_LEFT, 4 }, - { BTN_DOWN, 3 }, - { BTN_RIGHT, 2 }, - - { BTN_MOD_X, 6 }, - { BTN_MOD_Y, 7 }, - - { BTN_SELECT, 10}, - { BTN_START, 0 }, - { BTN_HOME, 11}, - - { BTN_C_LEFT, 13}, - { BTN_C_UP, 12}, - { BTN_C_DOWN, 15}, - { BTN_A, 14}, - { BTN_C_RIGHT, 16}, - - { BTN_B, 26}, - { BTN_X, 21}, - { BTN_Z, 19}, - { BTN_UP, 17}, - - { BTN_R, 27}, - { BTN_Y, 22}, - { BTN_LIGHTSHIELD, 20}, - { BTN_MIDSHIELD, 18}, + {BTN_LF1, 2 }, + { BTN_LF2, 3 }, + { BTN_LF3, 4 }, + { BTN_LF4, 5 }, + + { BTN_LT1, 6 }, + { BTN_LT2, 7 }, + + { BTN_MB1, 0 }, + { BTN_MB2, 10}, + { BTN_MB3, 11}, + + { BTN_RT1, 14}, + { BTN_RT2, 15}, + { BTN_RT3, 13}, + { BTN_RT4, 12}, + { BTN_RT5, 16}, + + { BTN_RF1, 26}, + { BTN_RF2, 21}, + { BTN_RF3, 19}, + { BTN_RF4, 17}, + + { BTN_RT5, 27}, + { BTN_RT6, 22}, + { BTN_RT7, 20}, + { BTN_RT8, 18}, }; size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); @@ -141,8 +143,8 @@ void setup() { gpio_input.UpdateInputs(inputs); // Check bootsel button hold as early as possible for safety. - if (inputs.start) { - rp2040.rebootToBootloader(); + if (inputs.mb1) { + reboot_bootloader(); } // Turn on LED to indicate firmware booted. diff --git a/include/core/state.hpp b/include/core/state.hpp index 051102e1..987a0aae 100644 --- a/include/core/state.hpp +++ b/include/core/state.hpp @@ -5,40 +5,72 @@ #include -// Button state. -// typedef union _ButtonState { -// uint64_t buttons = 0; - -// } ButtonState; - typedef struct _InputState { // Rectangle inputs. union { uint64_t buttons = 0; struct { - bool left : 1; - bool right : 1; - bool down : 1; - bool up : 1; - bool c_left : 1; - bool c_right : 1; - bool c_down : 1; - bool c_up : 1; - bool a : 1; - bool b : 1; - bool x : 1; - bool y : 1; - bool l : 1; - bool r : 1; - bool z : 1; - bool lightshield : 1; - bool midshield : 1; - bool select : 1; - bool start : 1; - bool home : 1; - bool mod_x : 1; - bool mod_y : 1; + bool lf1 : 1; + bool lf2 : 1; + bool lf3 : 1; + bool lf4 : 1; + bool lf5 : 1; + bool lf6 : 1; + bool lf7 : 1; + bool lf8 : 1; + bool lf9 : 1; + bool lf10 : 1; + bool lf11 : 1; + bool lf12 : 1; + bool lf13 : 1; + bool lf14 : 1; + bool lf15 : 1; + bool lf16 : 1; + bool rf1 : 1; + bool rf2 : 1; + bool rf3 : 1; + bool rf4 : 1; + bool rf5 : 1; + bool rf6 : 1; + bool rf7 : 1; + bool rf8 : 1; + bool rf9 : 1; + bool rf10 : 1; + bool rf11 : 1; + bool rf12 : 1; + bool rf13 : 1; + bool rf14 : 1; + bool rf15 : 1; + bool rf16 : 1; + bool lt1 : 1; + bool lt2 : 1; + bool lt3 : 1; + bool lt4 : 1; + bool lt5 : 1; + bool lt6 : 1; + bool lt7 : 1; + bool lt8 : 1; + bool rt1 : 1; + bool rt2 : 1; + bool rt3 : 1; + bool rt4 : 1; + bool rt5 : 1; + bool rt6 : 1; + bool rt7 : 1; + bool rt8 : 1; + bool mb1 : 1; + bool mb2 : 1; + bool mb3 : 1; + bool mb4 : 1; + bool mb5 : 1; + bool mb6 : 1; + bool mb7 : 1; + bool mb8 : 1; + bool mb9 : 1; + bool mb10 : 1; + bool mb11 : 1; + bool mb12 : 1; }; }; diff --git a/platformio.ini b/platformio.ini index e0ea8c68..2fbd212b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,7 @@ custom_nanopb_protos = +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> lib_deps = https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip - git+git@github.com:JonnyHaystack/HayBox-proto#33bdbc1 + git+git@github.com:JonnyHaystack/HayBox-proto#0160c12 eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 diff --git a/src/comms/B0XXInputViewer.cpp b/src/comms/B0XXInputViewer.cpp index cac37369..18b83c46 100644 --- a/src/comms/B0XXInputViewer.cpp +++ b/src/comms/B0XXInputViewer.cpp @@ -33,26 +33,26 @@ void B0XXInputViewer::SendReport() { // Only scan fast input sources because we don't want to waste any more time than necessary // on the input viewer and we can't afford to read from something like a Nunchuk twice. - _report[0] = ASCII_BIT(_inputs.start); - _report[1] = ASCII_BIT(_inputs.y); - _report[2] = ASCII_BIT(_inputs.x); - _report[3] = ASCII_BIT(_inputs.b); - _report[4] = ASCII_BIT(_inputs.a); - _report[5] = ASCII_BIT(_inputs.l); - _report[6] = ASCII_BIT(_inputs.r); - _report[7] = ASCII_BIT(_inputs.z); - _report[8] = ASCII_BIT(_inputs.up); - _report[9] = ASCII_BIT(_inputs.down); - _report[10] = ASCII_BIT(_inputs.right); - _report[11] = ASCII_BIT(_inputs.left); - _report[12] = ASCII_BIT(_inputs.mod_x); - _report[13] = ASCII_BIT(_inputs.mod_y); - _report[14] = ASCII_BIT(_inputs.c_left); - _report[15] = ASCII_BIT(_inputs.c_right); - _report[16] = ASCII_BIT(_inputs.c_up); - _report[17] = ASCII_BIT(_inputs.c_down); - _report[18] = ASCII_BIT(_inputs.lightshield); - _report[19] = ASCII_BIT(_inputs.midshield); + _report[0] = ASCII_BIT(_inputs.mb1); + _report[1] = ASCII_BIT(_inputs.rf6); + _report[2] = ASCII_BIT(_inputs.rf2); + _report[3] = ASCII_BIT(_inputs.rf1); + _report[4] = ASCII_BIT(_inputs.rt1); + _report[5] = ASCII_BIT(_inputs.lf4); + _report[6] = ASCII_BIT(_inputs.rf5); + _report[7] = ASCII_BIT(_inputs.rf2); + _report[8] = ASCII_BIT(_inputs.rf4); + _report[9] = ASCII_BIT(_inputs.lf2); + _report[10] = ASCII_BIT(_inputs.lf1); + _report[11] = ASCII_BIT(_inputs.lf3); + _report[12] = ASCII_BIT(_inputs.lt1); + _report[13] = ASCII_BIT(_inputs.lt2); + _report[14] = ASCII_BIT(_inputs.rt3); + _report[15] = ASCII_BIT(_inputs.rt5); + _report[16] = ASCII_BIT(_inputs.rt4); + _report[17] = ASCII_BIT(_inputs.rt2); + _report[18] = ASCII_BIT(_inputs.rf7); + _report[19] = ASCII_BIT(_inputs.rf8); _report[20] = ASCII_BIT(false); _report[21] = ASCII_BIT(false); _report[22] = ASCII_BIT(false); diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index dc3aacc3..f1d4374f 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -92,7 +92,6 @@ void select_mode( // rather than on every single poll. InputState &inputs = backend->GetInputs(); - // uint64_t buttons = backend->GetInputs().buttons; for (size_t i = 0; i < mode_configs_count; i++) { const GameModeConfig &mode_config = mode_configs[i]; diff --git a/src/modes/DefaultKeyboardMode.cpp b/src/modes/DefaultKeyboardMode.cpp index 81ad6ff9..91b657e6 100644 --- a/src/modes/DefaultKeyboardMode.cpp +++ b/src/modes/DefaultKeyboardMode.cpp @@ -6,26 +6,26 @@ DefaultKeyboardMode::DefaultKeyboardMode(const GameModeConfig &config) : KeyboardMode(config) {} void DefaultKeyboardMode::UpdateKeys(InputState &inputs) { - Press(HID_KEY_A, inputs.l); - Press(HID_KEY_B, inputs.left); - Press(HID_KEY_C, inputs.down); - Press(HID_KEY_D, inputs.right); - Press(HID_KEY_E, inputs.mod_x); - Press(HID_KEY_F, inputs.mod_y); - Press(HID_KEY_G, inputs.select); - Press(HID_KEY_H, inputs.start); - Press(HID_KEY_I, inputs.home); - Press(HID_KEY_J, inputs.r); - Press(HID_KEY_K, inputs.y); - Press(HID_KEY_L, inputs.lightshield); - Press(HID_KEY_M, inputs.midshield); - Press(HID_KEY_N, inputs.b); - Press(HID_KEY_O, inputs.x); - Press(HID_KEY_P, inputs.z); - Press(HID_KEY_Q, inputs.up); - Press(HID_KEY_R, inputs.c_up); - Press(HID_KEY_S, inputs.c_left); - Press(HID_KEY_T, inputs.c_right); - Press(HID_KEY_U, inputs.a); - Press(HID_KEY_V, inputs.c_down); + Press(HID_KEY_A, inputs.lf4); + Press(HID_KEY_B, inputs.lf3); + Press(HID_KEY_C, inputs.lf2); + Press(HID_KEY_D, inputs.lf1); + Press(HID_KEY_E, inputs.lt1); + Press(HID_KEY_F, inputs.lt2); + Press(HID_KEY_G, inputs.mb3); + Press(HID_KEY_H, inputs.mb1); + Press(HID_KEY_I, inputs.mb2); + Press(HID_KEY_J, inputs.rf5); + Press(HID_KEY_K, inputs.rf6); + Press(HID_KEY_L, inputs.rf7); + Press(HID_KEY_M, inputs.rf8); + Press(HID_KEY_N, inputs.rf1); + Press(HID_KEY_O, inputs.rf2); + Press(HID_KEY_P, inputs.rf3); + Press(HID_KEY_Q, inputs.rf4); + Press(HID_KEY_R, inputs.rt4); + Press(HID_KEY_S, inputs.rt3); + Press(HID_KEY_T, inputs.rt5); + Press(HID_KEY_U, inputs.rt1); + Press(HID_KEY_V, inputs.rt2); } diff --git a/src/modes/FgcMode.cpp b/src/modes/FgcMode.cpp index cbc18409..0fea6781 100644 --- a/src/modes/FgcMode.cpp +++ b/src/modes/FgcMode.cpp @@ -4,27 +4,27 @@ FgcMode::FgcMode(const GameModeConfig &config) : ControllerMode(config) {} void FgcMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Directions - outputs.dpadLeft = inputs.left; - outputs.dpadRight = inputs.right; - outputs.dpadDown = inputs.down; - outputs.dpadUp = inputs.mod_x || inputs.c_up; + outputs.dpadLeft = inputs.lf3; + outputs.dpadRight = inputs.lf1; + outputs.dpadDown = inputs.lf2; + outputs.dpadUp = inputs.lt1; // Menu keys - outputs.start = inputs.start; - outputs.select = inputs.c_left; - outputs.home = inputs.c_down; + outputs.start = inputs.mb1; + outputs.select = inputs.rt3; + outputs.home = inputs.rt2; // Right hand bottom row - outputs.a = inputs.b; - outputs.b = inputs.x; - outputs.triggerRDigital = inputs.z; - outputs.triggerLDigital = inputs.up; + outputs.a = inputs.rf1; + outputs.b = inputs.rf2; + outputs.triggerRDigital = inputs.rf3; + outputs.triggerLDigital = inputs.rf4; // Right hand top row - outputs.x = inputs.r; - outputs.y = inputs.y; - outputs.buttonR = inputs.lightshield; - outputs.buttonL = inputs.midshield; + outputs.x = inputs.rf5; + outputs.y = inputs.rf6; + outputs.buttonR = inputs.rf7; + outputs.buttonL = inputs.rf8; } void FgcMode::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { diff --git a/src/modes/Melee18Button.cpp b/src/modes/Melee18Button.cpp index 0f8e7c0a..d6cdcbde 100644 --- a/src/modes/Melee18Button.cpp +++ b/src/modes/Melee18Button.cpp @@ -11,16 +11,16 @@ Melee18Button::Melee18Button(const GameModeConfig &config, Melee18ButtonOptions } void Melee18Button::HandleSocd(InputState &inputs) { - horizontal_socd = inputs.left && inputs.right; + horizontal_socd = inputs.lf3 && inputs.lf1; InputMode::HandleSocd(inputs); } void Melee18Button::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.x = inputs.x; - outputs.y = inputs.y; - outputs.buttonR = inputs.z; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; + outputs.buttonR = inputs.rf3; if (inputs.nunchuk_connected) { // Lightshield with C button. if (inputs.nunchuk_c) { @@ -28,50 +28,50 @@ void Melee18Button::UpdateDigitalOutputs(const InputState &inputs, OutputState & } outputs.triggerLDigital = inputs.nunchuk_z; } else { - outputs.triggerLDigital = inputs.l; + outputs.triggerLDigital = inputs.lf4; } - outputs.triggerRDigital = inputs.r; - outputs.start = inputs.start; + outputs.triggerRDigital = inputs.rf5; + outputs.start = inputs.mb1; // Activate D-Pad layer by holding Mod X + Mod Y. - if (inputs.mod_x && inputs.mod_y) { - outputs.dpadUp = inputs.c_up; - outputs.dpadDown = inputs.c_down; - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; + if (inputs.lt1 && inputs.lt2) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; } - if (inputs.select) + if (inputs.mb3) outputs.dpadLeft = true; - if (inputs.home) + if (inputs.mb2) outputs.dpadRight = true; } void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.up, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - bool shield_button_pressed = inputs.l || inputs.r; + bool shield_button_pressed = inputs.lf4 || inputs.rf5; if (directions.diagonal && directions.y == -1 && _options.crouch_walk_os) { outputs.leftStickX = 128 + (directions.x * 56); outputs.leftStickY = 128 + (directions.y * 55); } - if (inputs.mod_x) { + if (inputs.lt1) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 53); } @@ -92,48 +92,48 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o outputs.leftStickX = 128 + (directions.x * 59); outputs.leftStickY = 128 + (directions.y * 25); // 27.37104 - 7000 3625 (27.38) = 56 29 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 56); outputs.leftStickY = 128 + (directions.y * 29); } // 31.77828 - 7875 4875 (31.76) = 63 39 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 63); outputs.leftStickY = 128 + (directions.y * 39); } // 36.18552 - 7000 5125 (36.21) = 56 41 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 56); outputs.leftStickY = 128 + (directions.y * 41); } // 40.59276 - 6125 5250 (40.6) = 49 42 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 49); outputs.leftStickY = 128 + (directions.y * 42); } /* Extended Up B Angles */ - if (inputs.b) { + if (inputs.rf1) { // 22.9638 - 9125 3875 (23.0) = 73 31 outputs.leftStickX = 128 + (directions.x * 73); outputs.leftStickY = 128 + (directions.y * 31); // 27.37104 - 8750 4500 (27.2) = 70 36 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 70); outputs.leftStickY = 128 + (directions.y * 36); } // 31.77828 - 8500 5250 (31.7) = 68 42 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 68); outputs.leftStickY = 128 + (directions.y * 42); } // 36.18552 - 7375 5375 (36.1) = 59 43 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 59); outputs.leftStickY = 128 + (directions.y * 43); } // 40.59276 - 6375 5375 (40.1) = 51 43 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 51); outputs.leftStickY = 128 + (directions.y * 43); } @@ -141,7 +141,7 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } } - if (inputs.mod_y) { + if (inputs.lt2) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 27); } @@ -150,7 +150,7 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } // Turnaround neutral B nerf - if (inputs.b) { + if (inputs.rf1) { outputs.leftStickX = 128 + (directions.x * 80); } @@ -160,48 +160,48 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o outputs.leftStickX = 128 + (directions.x * 25); outputs.leftStickY = 128 + (directions.y * 59); // 62.62896 - 3625 7000 (62.62) = 29 56 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 29); outputs.leftStickY = 128 + (directions.y * 56); } // 58.22172 - 4875 7875 (58.24) = 39 63 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 39); outputs.leftStickY = 128 + (directions.y * 63); } // 53.81448 - 5125 7000 (53.79) = 41 56 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 41); outputs.leftStickY = 128 + (directions.y * 56); } // 49.40724 - 6375 7625 (50.10) = 51 61 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 51); outputs.leftStickY = 128 + (directions.y * 61); } /* Extended Up B Angles */ - if (inputs.b) { + if (inputs.rf1) { // 67.0362 - 3875 9125 = 31 73 outputs.leftStickX = 128 + (directions.x * 31); outputs.leftStickY = 128 + (directions.y * 73); // 62.62896 - 4500 8750 (62.8) = 36 70 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 36); outputs.leftStickY = 128 + (directions.y * 70); } // 58.22172 - 5250 8500 (58.3) = 42 68 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 42); outputs.leftStickY = 128 + (directions.y * 68); } // 53.81448 - 5875 8000 (53.7) = 47 64 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 47); outputs.leftStickY = 128 + (directions.y * 64); } // 49.40724 - 5875 7125 (50.49) = 47 57 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 47); outputs.leftStickY = 128 + (directions.y * 57); } @@ -209,7 +209,7 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } } - if (inputs.l) { + if (inputs.lf4) { // L overrides modifiers, both for wavedash nerf and so MX/MY can give midshield/lightshield // without forcing shield tilt. if (directions.horizontal) { @@ -228,7 +228,7 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } // L + Mod X = midshield - if (inputs.mod_x) { + if (inputs.lt1) { outputs.triggerLDigital = false; outputs.triggerRAnalog = 94; @@ -238,7 +238,7 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } } // L + Mod Y = lightshield - if (inputs.mod_y) { + if (inputs.lt2) { outputs.triggerLDigital = false; outputs.triggerRAnalog = 49; @@ -250,7 +250,7 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } // Holding R gives special shield tilt and wavedash coordinates. - if (inputs.r) { + if (inputs.rf5) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 51); } @@ -259,11 +259,11 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } if (directions.diagonal) { outputs.leftStickX = 128 + (directions.x * 43); - if (inputs.mod_x) { + if (inputs.lt1) { outputs.leftStickX = 128 + (directions.x * 51); outputs.leftStickY = 128 + (directions.y * 30); } - if (inputs.mod_y) { + if (inputs.lt2) { outputs.leftStickX = 128 + (directions.x * 40); outputs.leftStickY = 128 + (directions.y * 68); } @@ -280,12 +280,12 @@ void Melee18Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o // Horizontal SOCD overrides X-axis modifiers (for ledgedash maximum jump // trajectory). - if (!inputs.r && horizontal_socd && !directions.vertical) { + if (!inputs.rf5 && horizontal_socd && !directions.vertical) { outputs.leftStickX = 128 + (directions.x * 80); } // Shut off C-stick when using D-Pad layer. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { outputs.rightStickX = 128; outputs.rightStickY = 128; } diff --git a/src/modes/Melee20Button.cpp b/src/modes/Melee20Button.cpp index 96ef1c78..38747f63 100644 --- a/src/modes/Melee20Button.cpp +++ b/src/modes/Melee20Button.cpp @@ -11,56 +11,56 @@ Melee20Button::Melee20Button(const GameModeConfig &config, Melee20ButtonOptions } void Melee20Button::HandleSocd(InputState &inputs) { - _horizontal_socd = inputs.left && inputs.right; + _horizontal_socd = inputs.lf3 && inputs.lf1; InputMode::HandleSocd(inputs); } void Melee20Button::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.x = inputs.x; - outputs.y = inputs.y; - outputs.buttonR = inputs.z; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; + outputs.buttonR = inputs.rf3; if (inputs.nunchuk_connected) { outputs.triggerLDigital = inputs.nunchuk_z; } else { - outputs.triggerLDigital = inputs.l; + outputs.triggerLDigital = inputs.lf4; } - outputs.triggerRDigital = inputs.r; - outputs.start = inputs.start; + outputs.triggerRDigital = inputs.rf5; + outputs.start = inputs.mb1; // Activate D-Pad layer by holding Mod X + Mod Y or Nunchuk C button. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { - outputs.dpadUp = inputs.c_up; - outputs.dpadDown = inputs.c_down; - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; } - if (inputs.select) + if (inputs.mb3) outputs.dpadLeft = true; - if (inputs.home) + if (inputs.mb2) outputs.dpadRight = true; } void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.up, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - bool shield_button_pressed = inputs.l || inputs.r || inputs.lightshield || inputs.midshield; + bool shield_button_pressed = inputs.lf4 || inputs.rf5 || inputs.rf7 || inputs.rf8; if (directions.diagonal) { // q1/2 = 7000 7000 outputs.leftStickX = 128 + (directions.x * 56); @@ -74,7 +74,7 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } } - if (inputs.mod_x) { + if (inputs.lt1) { // MX + Horizontal (even if shield is held) = 6625 = 53 if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 53); @@ -95,48 +95,48 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o outputs.leftStickX = 128 + (directions.x * 59); outputs.leftStickY = 128 + (directions.y * 25); // 27.37104 - 7000 3625 (27.38) = 56 29 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 56); outputs.leftStickY = 128 + (directions.y * 29); } // 31.77828 - 7875 4875 (31.76) = 63 39 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 63); outputs.leftStickY = 128 + (directions.y * 39); } // 36.18552 - 7000 5125 (36.21) = 56 41 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 56); outputs.leftStickY = 128 + (directions.y * 41); } // 40.59276 - 6125 5250 (40.6) = 49 42 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 49); outputs.leftStickY = 128 + (directions.y * 42); } /* Extended Up B Angles */ - if (inputs.b) { + if (inputs.rf1) { // 22.9638 - 9125 3875 (23.0) = 73 31 outputs.leftStickX = 128 + (directions.x * 73); outputs.leftStickY = 128 + (directions.y * 31); // 27.37104 - 8750 4500 (27.2) = 70 36 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 70); outputs.leftStickY = 128 + (directions.y * 36); } // 31.77828 - 8500 5250 (31.7) = 68 42 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 68); outputs.leftStickY = 128 + (directions.y * 42); } // 36.18552 - 7375 5375 (36.1) = 59 43 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 59); outputs.leftStickY = 128 + (directions.y * 43); } // 40.59276 - 6375 5375 (40.1) = 51 43 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 51); outputs.leftStickY = 128 + (directions.y * 43); } @@ -151,7 +151,7 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } } - if (inputs.mod_y) { + if (inputs.lt2) { // MY + Horizontal (even if shield is held) = 3375 = 27 if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 27); @@ -172,7 +172,7 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } // Turnaround neutral B nerf - if (inputs.b) { + if (inputs.rf1) { outputs.leftStickX = 128 + (directions.x * 80); } @@ -182,48 +182,48 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o outputs.leftStickX = 128 + (directions.x * 25); outputs.leftStickY = 128 + (directions.y * 59); // 62.62896 - 3625 7000 (62.62) = 29 56 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 29); outputs.leftStickY = 128 + (directions.y * 56); } // 58.22172 - 4875 7875 (58.24) = 39 63 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 39); outputs.leftStickY = 128 + (directions.y * 63); } // 53.81448 - 5125 7000 (53.79) = 41 56 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 41); outputs.leftStickY = 128 + (directions.y * 56); } // 49.40724 - 6375 7625 (50.10) = 51 61 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 51); outputs.leftStickY = 128 + (directions.y * 61); } /* Extended Up B Angles */ - if (inputs.b) { + if (inputs.rf1) { // 67.0362 - 3875 9125 = 31 73 outputs.leftStickX = 128 + (directions.x * 31); outputs.leftStickY = 128 + (directions.y * 73); // 62.62896 - 4500 8750 (62.8) = 36 70 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 36); outputs.leftStickY = 128 + (directions.y * 70); } // 58.22172 - 5250 8500 (58.3) = 42 68 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 42); outputs.leftStickY = 128 + (directions.y * 68); } // 53.81448 - 5875 8000 (53.7) = 47 64 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 47); outputs.leftStickY = 128 + (directions.y * 64); } // 49.40724 - 5875 7125 (50.49) = 47 57 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 47); outputs.leftStickY = 128 + (directions.y * 57); } @@ -245,10 +245,10 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o outputs.leftStickX = 128 + (directions.x * 80); } - if (inputs.lightshield) { + if (inputs.rf7) { outputs.triggerRAnalog = 49; } - if (inputs.midshield) { + if (inputs.rf8) { outputs.triggerRAnalog = 94; } @@ -260,7 +260,7 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } // Shut off C-stick when using D-Pad layer. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { outputs.rightStickX = 128; outputs.rightStickY = 128; } diff --git a/src/modes/ProjectM.cpp b/src/modes/ProjectM.cpp index fafe9720..833bb0f3 100644 --- a/src/modes/ProjectM.cpp +++ b/src/modes/ProjectM.cpp @@ -10,64 +10,64 @@ ProjectM::ProjectM(const GameModeConfig &config, ProjectMOptions options) : Cont } void ProjectM::HandleSocd(InputState &inputs) { - _horizontal_socd = inputs.left && inputs.right; + _horizontal_socd = inputs.lf3 && inputs.lf1; InputMode::HandleSocd(inputs); } void ProjectM::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.x = inputs.x; - outputs.y = inputs.y; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; // True Z press vs macro lightshield + A. - if (_options.true_z_press || inputs.mod_x) { - outputs.buttonR = inputs.z; + if (_options.true_z_press || inputs.lt1) { + outputs.buttonR = inputs.rf3; } else { - outputs.a = inputs.a || inputs.z; + outputs.a = inputs.rt1 || inputs.rf3; } if (inputs.nunchuk_connected) { outputs.triggerLDigital = inputs.nunchuk_z; } else { - outputs.triggerLDigital = inputs.l; + outputs.triggerLDigital = inputs.lf4; } - outputs.triggerRDigital = inputs.r; - outputs.start = inputs.start; + outputs.triggerRDigital = inputs.rf5; + outputs.start = inputs.mb1; // Activate D-Pad layer by holding Mod X + Mod Y or Nunchuk C button. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { - outputs.dpadUp = inputs.c_up; - outputs.dpadDown = inputs.c_down; - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; } // Don't override dpad up if it's already pressed using the MX + MY dpad // layer. - outputs.dpadUp = outputs.dpadUp || inputs.midshield; + outputs.dpadUp = outputs.dpadUp || inputs.rf8; - if (inputs.select) + if (inputs.mb3) outputs.dpadLeft = true; - if (inputs.home) + if (inputs.mb2) outputs.dpadRight = true; } void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.up, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - bool shield_button_pressed = inputs.l || inputs.lightshield; + bool shield_button_pressed = inputs.lf4 || inputs.rf7; if (directions.diagonal) { if (directions.y == 1) { @@ -76,7 +76,7 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output } } - if (inputs.mod_x) { + if (inputs.lt1) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 70); } @@ -93,39 +93,39 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickX = 128 + (directions.x * 70); outputs.leftStickY = 128 + (directions.y * 34); - if (inputs.b) { + if (inputs.rf1) { outputs.leftStickX = 128 + (directions.x * 85); outputs.leftStickY = 128 + (directions.y * 31); } - if (inputs.r) { + if (inputs.rf5) { outputs.leftStickX = 128 + (directions.x * 82); outputs.leftStickY = 128 + (directions.y * 35); } - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 77); outputs.leftStickY = 128 + (directions.y * 55); } - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 82); outputs.leftStickY = 128 + (directions.y * 36); } - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 84); outputs.leftStickY = 128 + (directions.y * 50); } - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 72); outputs.leftStickY = 128 + (directions.y * 61); } } } - if (inputs.mod_y) { + if (inputs.lt2) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 35); } @@ -137,32 +137,32 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickX = 128 + (directions.x * 28); outputs.leftStickY = 128 + (directions.y * 58); - if (inputs.b) { + if (inputs.rf1) { outputs.leftStickX = 128 + (directions.x * 28); outputs.leftStickY = 128 + (directions.y * 85); } - if (inputs.r) { + if (inputs.rf5) { outputs.leftStickX = 128 + (directions.x * 51); outputs.leftStickY = 128 + (directions.y * 82); } - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 55); outputs.leftStickY = 128 + (directions.y * 77); } - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 34); outputs.leftStickY = 128 + (directions.y * 82); } - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 40); outputs.leftStickY = 128 + (directions.y * 84); } - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 62); outputs.leftStickY = 128 + (directions.y * 72); } @@ -186,12 +186,12 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickX = 128 + (directions.x * 100); } - if (inputs.lightshield) { + if (inputs.rf7) { outputs.triggerRAnalog = 49; } // Send lightshield input if we are using Z = lightshield + A macro. - if (inputs.z && !(inputs.mod_x || _options.true_z_press)) { + if (inputs.rf3 && !(inputs.lt1 || _options.true_z_press)) { outputs.triggerRAnalog = 49; } @@ -204,7 +204,7 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output } // Shut off C-stick when using D-Pad layer. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { outputs.rightStickX = 128; outputs.rightStickY = 128; } diff --git a/src/modes/RivalsOfAether.cpp b/src/modes/RivalsOfAether.cpp index e6a62e26..977544ff 100644 --- a/src/modes/RivalsOfAether.cpp +++ b/src/modes/RivalsOfAether.cpp @@ -7,11 +7,11 @@ RivalsOfAether::RivalsOfAether(const GameModeConfig &config) : ControllerMode(config) {} void RivalsOfAether::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.x = inputs.x; - outputs.y = inputs.y; - outputs.buttonR = inputs.z; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; + outputs.buttonR = inputs.rf3; if (inputs.nunchuk_connected) { // Lightshield with C button. if (inputs.nunchuk_c) { @@ -19,51 +19,50 @@ void RivalsOfAether::UpdateDigitalOutputs(const InputState &inputs, OutputState } outputs.triggerLDigital = inputs.nunchuk_z; } else { - outputs.triggerLDigital = inputs.l; + outputs.triggerLDigital = inputs.lf4; } - outputs.triggerRDigital = inputs.r; - outputs.start = inputs.start; - outputs.select = inputs.select; - outputs.home = inputs.home; - outputs.leftStickClick = inputs.lightshield; - outputs.rightStickClick = inputs.midshield; + outputs.triggerRDigital = inputs.rf5; + outputs.start = inputs.mb1; + outputs.select = inputs.mb3; + outputs.home = inputs.mb2; + outputs.leftStickClick = inputs.rf7; + outputs.rightStickClick = inputs.rf8; // Activate D-Pad layer by holding Mod X + Mod Y. - if (inputs.mod_x && inputs.mod_y) { - outputs.dpadUp = inputs.c_up; - outputs.dpadDown = inputs.c_down; - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; + if (inputs.lt1 && inputs.lt2) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; } } void RivalsOfAether::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.up, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - bool shield_button_pressed = inputs.l || inputs.r; - + bool shield_button_pressed = inputs.lf4 || inputs.rf5; // 48 total DI angles, 24 total Up b angles, 16 total airdodge angles - if (inputs.mod_x) { + if (inputs.lt1) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 66); // MX Horizontal Tilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 44); } } @@ -71,7 +70,7 @@ void RivalsOfAether::UpdateAnalogOutputs(const InputState &inputs, OutputState & if(directions.vertical) { outputs.leftStickY = 128 + (directions.y * 44); // MX Vertical Tilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickY = 128 + (directions.y * 67); } } @@ -82,30 +81,30 @@ void RivalsOfAether::UpdateAnalogOutputs(const InputState &inputs, OutputState & outputs.leftStickY = 128 + (directions.y * 23); // Angles just for DI and Up B - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 49); outputs.leftStickY = 128 + (directions.y * 24); } // Angles just for DI - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 52); outputs.leftStickY = 128 + (directions.y * 31); } - - if (inputs.c_up) { + + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 49); outputs.leftStickY = 128 + (directions.y * 35); } - - if (inputs.c_right) { + + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 51); outputs.leftStickY = 128 + (directions.y * 43); } } } - if (inputs.mod_y) { + if (inputs.lt2) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 44); } @@ -120,23 +119,23 @@ void RivalsOfAether::UpdateAnalogOutputs(const InputState &inputs, OutputState & outputs.leftStickY = 128 + (directions.y * 113); // Angles just for DI and Up B - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 44); outputs.leftStickY = 128 + (directions.y * 90); } // Angles just for DI - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 44); outputs.leftStickY = 128 + (directions.y * 74); } - - if (inputs.c_up) { + + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 45); outputs.leftStickY = 128 + (directions.y * 63); } - - if (inputs.c_right) { + + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 47); outputs.leftStickY = 128 + (directions.y * 57); } @@ -144,7 +143,7 @@ void RivalsOfAether::UpdateAnalogOutputs(const InputState &inputs, OutputState & } // Shut off C-stick when using D-Pad layer. - if (inputs.mod_x && inputs.mod_y) { + if (inputs.lt1 && inputs.lt2) { outputs.rightStickX = 128; outputs.rightStickY = 128; } diff --git a/src/modes/Ultimate.cpp b/src/modes/Ultimate.cpp index 57ecddff..19545570 100644 --- a/src/modes/Ultimate.cpp +++ b/src/modes/Ultimate.cpp @@ -8,47 +8,47 @@ Ultimate::Ultimate(const GameModeConfig &config) : ControllerMode(config) {} void Ultimate::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.x = inputs.x; - outputs.y = inputs.y; - outputs.buttonL = inputs.lightshield; - outputs.buttonR = inputs.z || inputs.midshield; - outputs.triggerLDigital = inputs.l; - outputs.triggerRDigital = inputs.r; - outputs.start = inputs.start; - outputs.select = inputs.select; - outputs.home = inputs.home; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; + outputs.buttonL = inputs.rf7; + outputs.buttonR = inputs.rf3 || inputs.rf8; + outputs.triggerLDigital = inputs.lf4; + outputs.triggerRDigital = inputs.rf5; + outputs.start = inputs.mb1; + outputs.select = inputs.mb3; + outputs.home = inputs.mb2; // Turn on D-Pad layer by holding Mod X + Mod Y or Nunchuk C button. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { - outputs.dpadUp = inputs.c_up; - outputs.dpadDown = inputs.c_down; - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; } } void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.up, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - bool shield_button_pressed = inputs.l || inputs.r; + bool shield_button_pressed = inputs.lf4 || inputs.rf5; - if (inputs.mod_x) { + if (inputs.lt1) { // MX + Horizontal = 6625 = 53 if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 53); @@ -57,7 +57,7 @@ void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickX = 128 + (directions.x * 51); } // Horizontal Tilts = 36 - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 36); } } @@ -92,67 +92,67 @@ void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickX = 128 + (directions.x * 53); outputs.leftStickY = 128 + (directions.y * 35); // (39.05) = 53 43 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 53); outputs.leftStickY = 128 + (directions.y * 43); } // (36.35) = 53 39 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 53); outputs.leftStickY = 128 + (directions.y * 39); } // (30.32) = 56 41 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 53); outputs.leftStickY = 128 + (directions.y * 31); } // (27.85) = 49 42 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 53); outputs.leftStickY = 128 + (directions.y * 28); } /* Extended Up B Angles */ - if (inputs.b) { + if (inputs.rf1) { // (33.29) = 67 44 outputs.leftStickX = 128 + (directions.x * 67); outputs.leftStickY = 128 + (directions.y * 44); // (39.38) = 67 55 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 67); outputs.leftStickY = 128 + (directions.y * 55); } // (36.18) = 67 49 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 67); outputs.leftStickY = 128 + (directions.y * 49); } // (30.2) = 67 39 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 67); outputs.leftStickY = 128 + (directions.y * 39); } // (27.58) = 67 35 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 67); outputs.leftStickY = 128 + (directions.y * 35); } } // Angled Ftilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 36); outputs.leftStickY = 128 + (directions.y * 26); } } } - if (inputs.mod_y) { + if (inputs.lt2) { // MY + Horizontal (even if shield is held) = 41 if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 41); // MY Horizontal Tilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 36); } } @@ -160,7 +160,7 @@ void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &output if (directions.vertical) { outputs.leftStickY = 128 + (directions.y * 53); // MY Vertical Tilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickY = 128 + (directions.y * 36); } } @@ -186,55 +186,55 @@ void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickX = 128 + (directions.x * 35); outputs.leftStickY = 128 + (directions.y * 53); // (50.95) = 43 53 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 43); outputs.leftStickY = 128 + (directions.y * 53); } // (53.65) = 39 53 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 49); outputs.leftStickY = 128 + (directions.y * 53); } // (59.68) = 31 53 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 31); outputs.leftStickY = 128 + (directions.y * 53); } // (62.15) = 28 53 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 28); outputs.leftStickY = 128 + (directions.y * 53); } /* Extended Up B Angles */ - if (inputs.b) { + if (inputs.rf1) { // (56.71) = 44 67 outputs.leftStickX = 128 + (directions.x * 44); outputs.leftStickY = 128 + (directions.y * 67); // (50.62) = 55 67 - if (inputs.c_down) { + if (inputs.rt2) { outputs.leftStickX = 128 + (directions.x * 55); outputs.leftStickY = 128 + (directions.y * 67); } // (53.82) = 49 67 - if (inputs.c_left) { + if (inputs.rt3) { outputs.leftStickX = 128 + (directions.x * 49); outputs.leftStickY = 128 + (directions.y * 67); } // (59.8) = 39 67 - if (inputs.c_up) { + if (inputs.rt4) { outputs.leftStickX = 128 + (directions.x * 39); outputs.leftStickY = 128 + (directions.y * 67); } // (62.42) = 35 67 - if (inputs.c_right) { + if (inputs.rt5) { outputs.leftStickX = 128 + (directions.x * 35); outputs.leftStickY = 128 + (directions.y * 67); } } // MY Pivot Uptilt/Dtilt - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 34); outputs.leftStickY = 128 + (directions.y * 38); } @@ -249,16 +249,16 @@ void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.rightStickY = 128 + (directions.cy * 68); } - if (inputs.l) { + if (inputs.lf4) { outputs.triggerLAnalog = 140; } - if (inputs.r) { + if (inputs.rf5) { outputs.triggerRAnalog = 140; } // Shut off C-stick when using D-Pad layer. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { outputs.rightStickX = 128; outputs.rightStickY = 128; } diff --git a/src/modes/extra/DarkSouls.cpp b/src/modes/extra/DarkSouls.cpp index e3effdee..7392afee 100644 --- a/src/modes/extra/DarkSouls.cpp +++ b/src/modes/extra/DarkSouls.cpp @@ -7,47 +7,47 @@ DarkSouls::DarkSouls(const GameModeConfig &config) : ControllerMode(config) {} void DarkSouls::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.y = inputs.y; - outputs.x = inputs.r; + outputs.y = inputs.rf6; + outputs.x = inputs.rf5; // Base layer. - bool layer0 = !inputs.x && !inputs.nunchuk_c; + bool layer0 = !inputs.rf2 && !inputs.nunchuk_c; // Secondary layer when X is held. - bool layerX = inputs.x && !inputs.nunchuk_c; + bool layerX = inputs.rf2 && !inputs.nunchuk_c; // DPad layer when Nunchuk C is held. bool layerC = inputs.nunchuk_c; if (layer0) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.buttonR = inputs.z; - outputs.buttonL = inputs.up; - outputs.start = inputs.start | inputs.nunchuk_z; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.buttonR = inputs.rf3; + outputs.buttonL = inputs.rf4; + outputs.start = inputs.mb1 | inputs.nunchuk_z; } else if (layerX) { - outputs.rightStickClick = inputs.a; - outputs.triggerRDigital = inputs.z; - outputs.triggerLDigital = inputs.up; - outputs.select = inputs.start; + outputs.rightStickClick = inputs.rt1; + outputs.triggerRDigital = inputs.rf3; + outputs.triggerLDigital = inputs.rf4; + outputs.select = inputs.mb1; } else if (layerC) { - outputs.a = inputs.a; - outputs.dpadLeft = inputs.b; - outputs.dpadDown = inputs.x; - outputs.dpadUp = inputs.z; - outputs.dpadRight = inputs.up; + outputs.a = inputs.rt1; + outputs.dpadLeft = inputs.rf1; + outputs.dpadDown = inputs.rf2; + outputs.dpadUp = inputs.rf3; + outputs.dpadRight = inputs.rf4; outputs.select = inputs.nunchuk_z; } } void DarkSouls::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.mod_x, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, + inputs.lf1, + inputs.lf2, + inputs.lt1, + inputs.rt3, + inputs.rt5, + inputs.rt2, + inputs.rt4, ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, diff --git a/src/modes/extra/HollowKnight.cpp b/src/modes/extra/HollowKnight.cpp index 45f79edd..8a9af817 100644 --- a/src/modes/extra/HollowKnight.cpp +++ b/src/modes/extra/HollowKnight.cpp @@ -7,29 +7,29 @@ HollowKnight::HollowKnight(const GameModeConfig &config) : ControllerMode(config) {} void HollowKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; // Attack - outputs.b = inputs.b; // Dash - outputs.x = inputs.x; // Jump - outputs.y = inputs.mod_y; // Quick Cast - outputs.triggerLDigital = inputs.r; // Focus / Cast - outputs.triggerRDigital = inputs.z; // C-Dash - outputs.buttonR = inputs.up; // Dream Nail + outputs.a = inputs.rt1; // Attack + outputs.b = inputs.rf1; // Dash + outputs.x = inputs.rf2; // Jump + outputs.y = inputs.lt2; // Quick Cast + outputs.triggerLDigital = inputs.rf5; // Focus / Cast + outputs.triggerRDigital = inputs.rf3; // C-Dash + outputs.buttonR = inputs.rf4; // Dream Nail - outputs.buttonL = inputs.lightshield; // Map - outputs.select = inputs.midshield; // Inventory - outputs.start = inputs.start; // Pause + outputs.buttonL = inputs.rf7; // Map + outputs.select = inputs.rf8; // Inventory + outputs.start = inputs.mb1; // Pause } void HollowKnight::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.mod_x, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, + inputs.lf1, + inputs.lf2, + inputs.lt1, + inputs.rt3, + inputs.rt5, + inputs.rt2, + inputs.rt4, ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, diff --git a/src/modes/extra/MKWii.cpp b/src/modes/extra/MKWii.cpp index 69fdb284..2ab4d97a 100644 --- a/src/modes/extra/MKWii.cpp +++ b/src/modes/extra/MKWii.cpp @@ -7,21 +7,21 @@ MKWii::MKWii(const GameModeConfig &config) : ControllerMode(config) {} void MKWii::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.b; - outputs.b = inputs.x; - outputs.triggerLDigital = inputs.z; - outputs.buttonR = inputs.up; - outputs.dpadUp = inputs.a; - outputs.start = inputs.start; + outputs.a = inputs.rf1; + outputs.b = inputs.rf2; + outputs.triggerLDigital = inputs.rf3; + outputs.buttonR = inputs.rf4; + outputs.dpadUp = inputs.rt1; + outputs.start = inputs.mb1; } void MKWii::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { - bool up = inputs.down || inputs.mod_x || inputs.mod_y; + bool up = inputs.lf2 || inputs.lt1 || inputs.lt2; UpdateDirections( - inputs.left, - inputs.right, - inputs.l, + inputs.lf3, + inputs.lf1, + inputs.lf4, up, false, false, @@ -33,7 +33,7 @@ void MKWii::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) outputs ); - if (inputs.z) { + if (inputs.rf3) { outputs.triggerLAnalog = 140; } diff --git a/src/modes/extra/MultiVersus.cpp b/src/modes/extra/MultiVersus.cpp index 4fa34244..ea4a2510 100644 --- a/src/modes/extra/MultiVersus.cpp +++ b/src/modes/extra/MultiVersus.cpp @@ -8,83 +8,83 @@ MultiVersus::MultiVersus(const GameModeConfig &config) : ControllerMode(config) void MultiVersus::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Bind X and Y to "jump" in-game. - outputs.x = inputs.x; - outputs.y = inputs.y; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; - outputs.start = !inputs.mod_y && inputs.start; + outputs.start = !inputs.lt2 && inputs.mb1; // Select, MS, or MY + Start for "Reset" in the Lab. Not supported by GameCube adapter. - outputs.select = inputs.select || inputs.midshield || (inputs.mod_y && inputs.start); + outputs.select = inputs.mb3 || inputs.rf8 || (inputs.lt2 && inputs.mb1); // Home not supported by GameCube adapter. - outputs.home = inputs.home; + outputs.home = inputs.mb2; // L or Nunchuk Z = LT. Bind to "dodge" in-game. if (inputs.nunchuk_connected) { outputs.triggerLDigital = inputs.nunchuk_z; } else { - outputs.triggerLDigital = inputs.l; + outputs.triggerLDigital = inputs.lf4; } // R = RT. Can be bound to "pickup item" or left unbound. - outputs.triggerRDigital = inputs.r; + outputs.triggerRDigital = inputs.rf5; - if (!inputs.mod_x) { + if (!inputs.lt1) { // Bind A to "attack" in-game. - outputs.a = inputs.a; + outputs.a = inputs.rt1; // Bind B to "special" in-game. - outputs.b = inputs.b; + outputs.b = inputs.rf1; // Z = RB. Bind to "dodge" in-game. - outputs.buttonR = inputs.z; + outputs.buttonR = inputs.rf3; // LS = LB. Not supported by GameCube adapter. - outputs.buttonL = inputs.lightshield; + outputs.buttonL = inputs.rf7; } // MX activates a layer for "neutral" binds. Uses D-Pad buttons. - if (inputs.mod_x && !inputs.mod_y) { + if (inputs.lt1 && !inputs.lt2) { // MX + A = D-Pad Left. Bind to "neutral attack" in-game. - outputs.dpadLeft = inputs.a; + outputs.dpadLeft = inputs.rt1; // MX + B = D-Pad Right. Bind to "neutral special" in-game. - outputs.dpadRight = inputs.b; + outputs.dpadRight = inputs.rf1; // MX + Z = D-Pad Down. Bind to "neutral evade" in-game. - outputs.dpadDown = inputs.z; + outputs.dpadDown = inputs.rf3; // MX + LS = D-Pad Up. Bind to "taunt 1" in-game. - outputs.dpadUp = inputs.lightshield; + outputs.dpadUp = inputs.rf7; } // MY activates C-Stick to D-Pad conversion. - if (inputs.mod_y && !inputs.mod_x) { - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; - outputs.dpadDown = inputs.c_down; - outputs.dpadUp = inputs.c_up; + if (inputs.lt2 && !inputs.lt1) { + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; + outputs.dpadDown = inputs.rt2; + outputs.dpadUp = inputs.rt4; } } void MultiVersus::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.up, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - if (inputs.mod_y && !inputs.mod_x) { + if (inputs.lt2 && !inputs.lt1) { // MY slows down the cursor for easier menu navigation. // Menu cursor speed can also be turned down in-game under "Interface" settings. // 128 ± 76 results in the slowest cursor that still actuates directional inputs in-game. diff --git a/src/modes/extra/RocketLeague.cpp b/src/modes/extra/RocketLeague.cpp index 49df08cf..be3b801e 100644 --- a/src/modes/extra/RocketLeague.cpp +++ b/src/modes/extra/RocketLeague.cpp @@ -7,56 +7,56 @@ RocketLeague::RocketLeague(const GameModeConfig &config) : ControllerMode(config) {} void RocketLeague::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.x = inputs.midshield; - outputs.y = inputs.up; - outputs.buttonL = inputs.l; - outputs.buttonR = inputs.lightshield; - outputs.triggerLDigital = inputs.z; - outputs.triggerRDigital = inputs.x; - outputs.leftStickClick = inputs.r; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf8; + outputs.y = inputs.rf4; + outputs.buttonL = inputs.lf4; + outputs.buttonR = inputs.rf7; + outputs.triggerLDigital = inputs.rf3; + outputs.triggerRDigital = inputs.rf2; + outputs.leftStickClick = inputs.rf5; // Hold accelerate and reverse simultaneously for rear view. - if (inputs.z && inputs.x) { + if (inputs.rf3 && inputs.rf2) { outputs.rightStickClick = true; // Override (deactivate) accelerator. outputs.triggerRDigital = false; } // MX + Start = Select - if (inputs.mod_x) - outputs.select = inputs.start; + if (inputs.lt1) + outputs.select = inputs.mb1; else - outputs.start = inputs.start; + outputs.start = inputs.mb1; // D-Pad - if (inputs.mod_x && inputs.mod_y) { - outputs.dpadUp = inputs.c_up; - outputs.dpadDown = inputs.c_down; - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; + if (inputs.lt1 && inputs.lt2) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; } } void RocketLeague::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.mod_x, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, + inputs.lf1, + inputs.lf2, + inputs.lt1, + inputs.rt3, + inputs.rt5, + inputs.rt2, + inputs.rt4, ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - if (inputs.mod_y) { + if (inputs.lt2) { if (directions.diagonal) { outputs.leftStickX = ANALOG_STICK_NEUTRAL + (directions.x * 70); // outputs.leftStickY = @@ -72,7 +72,7 @@ void RocketLeague::UpdateAnalogOutputs(const InputState &inputs, OutputState &ou } // Shut off right stick when using dpad layer. - if (inputs.mod_x && inputs.mod_y) { + if (inputs.lt1 && inputs.lt2) { outputs.rightStickX = ANALOG_STICK_NEUTRAL; outputs.rightStickY = ANALOG_STICK_NEUTRAL; } diff --git a/src/modes/extra/SaltAndSanctuary.cpp b/src/modes/extra/SaltAndSanctuary.cpp index b07dc1c9..0f244ea6 100644 --- a/src/modes/extra/SaltAndSanctuary.cpp +++ b/src/modes/extra/SaltAndSanctuary.cpp @@ -7,35 +7,35 @@ SaltAndSanctuary::SaltAndSanctuary(const GameModeConfig &config) : ControllerMode(config) {} void SaltAndSanctuary::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.dpadRight = inputs.l; // Block - outputs.b = inputs.b; // Roll - outputs.a = inputs.a; // Attack - outputs.y = inputs.z; // Strong - outputs.dpadDown = inputs.mod_y; // Use - outputs.x = inputs.x; // Jump + outputs.dpadRight = inputs.lf4; // Block + outputs.b = inputs.rf1; // Roll + outputs.a = inputs.rt1; // Attack + outputs.y = inputs.rf3; // Strong + outputs.dpadDown = inputs.lt2; // Use + outputs.x = inputs.rf2; // Jump - outputs.buttonL = inputs.r; // Previous item - outputs.buttonR = inputs.y; // Next item - outputs.triggerLDigital = inputs.lightshield; // Use item + outputs.buttonL = inputs.rf5; // Previous item + outputs.buttonR = inputs.rf6; // Next item + outputs.triggerLDigital = inputs.rf7; // Use item - outputs.triggerRDigital = inputs.midshield; // Use torch + outputs.triggerRDigital = inputs.rf8; // Use torch - outputs.dpadLeft = inputs.up; // Switch loadout + outputs.dpadLeft = inputs.rf4; // Switch loadout - outputs.start = inputs.start; // Inventory + outputs.start = inputs.mb1; // Inventory } void SaltAndSanctuary::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.mod_x, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, + inputs.lf1, + inputs.lf2, + inputs.lt1, + inputs.rt3, + inputs.rt5, + inputs.rt2, + inputs.rt4, ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, diff --git a/src/modes/extra/ShovelKnight.cpp b/src/modes/extra/ShovelKnight.cpp index 4d6a95ed..2d05c1de 100644 --- a/src/modes/extra/ShovelKnight.cpp +++ b/src/modes/extra/ShovelKnight.cpp @@ -7,32 +7,32 @@ ShovelKnight::ShovelKnight(const GameModeConfig &config) : ControllerMode(config) {} void ShovelKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.dpadLeft = inputs.left; - outputs.dpadRight = inputs.right; - outputs.dpadDown = inputs.down; - outputs.dpadUp = inputs.mod_x; + outputs.dpadLeft = inputs.lf3; + outputs.dpadRight = inputs.lf1; + outputs.dpadDown = inputs.lf2; + outputs.dpadUp = inputs.lt1; - outputs.b = inputs.x; // Jump - outputs.a = inputs.a; // Attack - outputs.y = inputs.b; // Attack - outputs.x = inputs.z; // Subweapon - outputs.buttonL = inputs.r; // Subweapon prev - outputs.buttonR = inputs.y; // Subweapon next + outputs.b = inputs.rf2; // Jump + outputs.a = inputs.rt1; // Attack + outputs.y = inputs.rf1; // Attack + outputs.x = inputs.rf3; // Subweapon + outputs.buttonL = inputs.rf5; // Subweapon prev + outputs.buttonR = inputs.rf6; // Subweapon next - outputs.select = inputs.lightshield; // Inventory - outputs.start = inputs.start; // Pause + outputs.select = inputs.rf7; // Inventory + outputs.start = inputs.mb1; // Pause } void ShovelKnight::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.mod_x, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, + inputs.lf1, + inputs.lf2, + inputs.lt1, + inputs.rt3, + inputs.rt5, + inputs.rt2, + inputs.rt4, ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, diff --git a/src/modes/extra/ToughLoveArena.cpp b/src/modes/extra/ToughLoveArena.cpp index 91cb16b2..89d2a3e3 100644 --- a/src/modes/extra/ToughLoveArena.cpp +++ b/src/modes/extra/ToughLoveArena.cpp @@ -3,9 +3,9 @@ ToughLoveArena::ToughLoveArena(const GameModeConfig &config) : KeyboardMode(config) {} void ToughLoveArena::UpdateKeys(InputState &inputs) { - Press(HID_KEY_S, inputs.left); - Press(HID_KEY_D, inputs.right); - Press(HID_KEY_J, inputs.b); - Press(HID_KEY_K, inputs.x); - Press(HID_KEY_L, inputs.z); + Press(HID_KEY_S, inputs.lf3); + Press(HID_KEY_D, inputs.lf1); + Press(HID_KEY_J, inputs.rf1); + Press(HID_KEY_K, inputs.rf2); + Press(HID_KEY_L, inputs.rf3); } diff --git a/src/modes/extra/Ultimate2.cpp b/src/modes/extra/Ultimate2.cpp index 073b28ac..44ae066a 100644 --- a/src/modes/extra/Ultimate2.cpp +++ b/src/modes/extra/Ultimate2.cpp @@ -8,49 +8,49 @@ Ultimate2::Ultimate2(const GameModeConfig &config) : ControllerMode(config) {} void Ultimate2::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - outputs.a = inputs.a; - outputs.b = inputs.b; - outputs.x = inputs.x; - outputs.y = inputs.y; - outputs.buttonR = inputs.z; - outputs.triggerLDigital = inputs.l; - outputs.triggerRDigital = inputs.r; - outputs.start = inputs.start; + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; + outputs.buttonR = inputs.rf3; + outputs.triggerLDigital = inputs.lf4; + outputs.triggerRDigital = inputs.rf5; + outputs.start = inputs.mb1; // Turn on D-Pad layer by holding Mod X + Mod Y, or Nunchuk C button. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { - outputs.dpadUp = inputs.c_up; - outputs.dpadDown = inputs.c_down; - outputs.dpadLeft = inputs.c_left; - outputs.dpadRight = inputs.c_right; + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; } - if (inputs.select) + if (inputs.mb3) outputs.dpadLeft = true; - if (inputs.home) + if (inputs.mb2) outputs.dpadRight = true; } void Ultimate2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { // Coordinate calculations to make modifier handling simpler. UpdateDirections( - inputs.left, - inputs.right, - inputs.down, - inputs.up, - inputs.c_left, - inputs.c_right, - inputs.c_down, - inputs.c_up, + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up ANALOG_STICK_MIN, ANALOG_STICK_NEUTRAL, ANALOG_STICK_MAX, outputs ); - bool shield_button_pressed = inputs.l || inputs.r || inputs.lightshield || inputs.midshield; + bool shield_button_pressed = inputs.lf4 || inputs.rf5 || inputs.rf7 || inputs.rf8; - if (inputs.mod_x) { + if (inputs.lt1) { // MX + Horizontal = 6625 = 53 if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 53); @@ -59,7 +59,7 @@ void Ultimate2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outpu outputs.leftStickX = 128 + (directions.x * 51); } // Horizontal Tilts = 36 - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 36); } } @@ -95,19 +95,19 @@ void Ultimate2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outpu outputs.leftStickY = 128 + (directions.y * 40); // Angled Ftilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 36); outputs.leftStickY = 128 + (directions.y * 26); } } } - if (inputs.mod_y) { + if (inputs.lt2) { // MY + Horizontal (even if shield is held) = 41 if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 41); // MY Horizontal Tilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 36); } } @@ -115,7 +115,7 @@ void Ultimate2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outpu if (directions.vertical) { outputs.leftStickY = 128 + (directions.y * 44); // MY Vertical Tilts - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickY = 128 + (directions.y * 36); } } @@ -142,7 +142,7 @@ void Ultimate2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outpu outputs.leftStickY = 128 + (directions.y * 44); // MY Pivot Uptilt/Dtilt - if (inputs.a) { + if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 34); outputs.leftStickY = 128 + (directions.y * 38); } @@ -157,16 +157,16 @@ void Ultimate2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outpu outputs.rightStickY = 128 + (directions.cy * 68); } - if (inputs.l) { + if (inputs.lf4) { outputs.triggerLAnalog = 140; } - if (inputs.r) { + if (inputs.rf5) { outputs.triggerRAnalog = 140; } // Shut off C-stick when using D-Pad layer. - if ((inputs.mod_x && inputs.mod_y) || inputs.nunchuk_c) { + if ((inputs.lt1 && inputs.lt2) || inputs.nunchuk_c) { outputs.rightStickX = 128; outputs.rightStickY = 128; } From 50855e160b3f4cb64da8939cc7834f3380d05d2d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 15 Oct 2023 03:02:56 +0100 Subject: [PATCH 013/167] feat: use watchdog and magic key for reboot firmware/bootloader on AVR --- HAL/avr/src/reboot.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/HAL/avr/src/reboot.cpp b/HAL/avr/src/reboot.cpp index b57cf9c3..3c4f98ea 100644 --- a/HAL/avr/src/reboot.cpp +++ b/HAL/avr/src/reboot.cpp @@ -2,13 +2,19 @@ #include "stdlib.hpp" -void (*resetFunc)(void) = 0; +#include void reboot_firmware() { - resetFunc(); + wdt_enable(WDTO_15MS); + while (true) { + delay(1); + } } void reboot_bootloader() { + uint16_t *magic_key_pos = (uint16_t *)MAGIC_KEY_POS; + *magic_key_pos = MAGIC_KEY; + wdt_enable(WDTO_15MS); while (true) { delay(1); } From 4dfa0b740ad86f408927d8bc7f42d263cd410531 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 15 Oct 2023 03:20:29 +0100 Subject: [PATCH 014/167] fix: RT1 -> LT1 in MODE_FGC activation binding --- config/pico/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index c0224f66..2a250542 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -67,7 +67,7 @@ Config config = { ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, }, .activation_binding_count = 3, - .activation_binding = { BTN_RT1, BTN_MB1, BTN_LF1 }, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, }, }, .communication_backend_configs_count = 3, From acb2300245aea3be1910a9dcfef87b56bd9f5475 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 20 Oct 2023 01:23:54 +0100 Subject: [PATCH 015/167] fix: correct default DInputBackend binding --- config/pico/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 2a250542..e31700b9 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -81,7 +81,7 @@ Config config = { .backend_id = COMMS_BACKEND_DINPUT, .default_mode = MODE_MELEE, .activation_binding_count = 1, - .activation_binding = { BTN_RT3 }, + .activation_binding = { BTN_RF3 }, }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_CONFIGURATOR, From 773ec53a8f3dde9184a8bffb078824ab1c27506e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 20 Oct 2023 17:33:26 +0100 Subject: [PATCH 016/167] feat: improve console detection on Pico Checking connected bit in sie_status register instead of VBUS power pin, so works for other RP2040 boards (like Pico W) and might be more reliable for selecting USB backend fast enough --- HAL/pico/src/comms/backend_init.cpp | 1 + HAL/pico/src/comms/console_detection.cpp | 16 +++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 805e75d5..f88a20c4 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -31,6 +31,7 @@ size_t initialize_backends( config.communication_backend_configs_count ); if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { + delay(250); CommunicationBackendId detected_backend_id = detect_console(pinout); backend_config = backend_config_from_id( detected_backend_id, diff --git a/HAL/pico/src/comms/console_detection.cpp b/HAL/pico/src/comms/console_detection.cpp index 9c9c003f..7b681859 100644 --- a/HAL/pico/src/comms/console_detection.cpp +++ b/HAL/pico/src/comms/console_detection.cpp @@ -5,21 +5,19 @@ #include #include #include - -#define VBUS_SENSE_PIN 24 +#include CommunicationBackendId detect_console(const Pinout &pinout) { - gpio_init(VBUS_SENSE_PIN); - gpio_set_dir(VBUS_SENSE_PIN, GPIO_IN); - bool vbus_powered = gpio_get(VBUS_SENSE_PIN); + bool usb_connected = usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS; + if (usb_connected) { + return COMMS_BACKEND_XINPUT; + } if (GamecubeConsole(pinout.joybus_data).Detect()) { return COMMS_BACKEND_GAMECUBE; } - // 5V is not connected when plugged into N64 so we check that first to save time. - if (!vbus_powered && N64Console(pinout.joybus_data).Detect()) { + if (N64Console(pinout.joybus_data).Detect()) { return COMMS_BACKEND_N64; } - - return COMMS_BACKEND_XINPUT; + return COMMS_BACKEND_UNSPECIFIED; } \ No newline at end of file From 39a457ca231d37a8e923c0727089af7ec871e467 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 20 Oct 2023 18:46:38 +0100 Subject: [PATCH 017/167] fix: make input source static in c53 config and correct RF1 and RF2 buttons --- config/c53/config.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/c53/config.cpp b/config/c53/config.cpp index ef67c9d2..557897fe 100644 --- a/config/c53/config.cpp +++ b/config/c53/config.cpp @@ -100,7 +100,7 @@ const uint col_pins[num_cols] = { 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; // clang-format off const Button matrix[num_rows][num_cols] = { {BTN_LF8, BTN_LF7, BTN_LF6, BTN_LF5, NA, BTN_MB3, BTN_MB1, BTN_MB2, NA, BTN_RF5, BTN_RF6, BTN_RF7, BTN_RF8 }, - { BTN_LF4, BTN_LF3, BTN_LF2, BTN_LF1, NA, BTN_MB4, BTN_MB5, BTN_MB6, NA, BTN_RT1, BTN_RT2, BTN_RF3, BTN_RF4 }, + { BTN_LF4, BTN_LF3, BTN_LF2, BTN_LF1, NA, BTN_MB4, BTN_MB5, BTN_MB6, NA, BTN_RF1, BTN_RF2, BTN_RF3, BTN_RF4 }, { BTN_LF12, BTN_LF11, BTN_LF10, BTN_LF9, NA, BTN_MB7, BTN_MB8, BTN_MB9, NA, BTN_RF9, BTN_RF10, BTN_RF11, BTN_RF12}, { NA, BTN_LT5, BTN_LT4, BTN_LT3, NA, BTN_MB10, BTN_MB11, BTN_MB12, NA, BTN_RT3, BTN_RT4, BTN_RT5, NA }, { NA, NA, BTN_LT1, BTN_LT2, NA, BTN_LT6, BTN_RT7, BTN_RT6, NA, BTN_RT2, BTN_RT1, NA, NA }, @@ -120,7 +120,8 @@ void setup() { static InputState inputs; // Create switch matrix input source and use it to read button states for checking button holds. - SwitchMatrixInput matrix_input(row_pins, col_pins, matrix, diode_direction); + static SwitchMatrixInput + matrix_input(row_pins, col_pins, matrix, diode_direction); matrix_input.UpdateInputs(inputs); // Bootsel button hold as early as possible for safety. From 593b86b68607d48c5af60690b7d252371c553ae7 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 20 Oct 2023 21:35:53 +0100 Subject: [PATCH 018/167] refactor: calculate game_mode_configs max length --- src/core/mode_selection.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index f1d4374f..8d1c0607 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -11,10 +11,7 @@ #include -// extern const Config config; - -// uint64_t gamemode_activation_masks[sizeof(config.game_mode_configs) / sizeof(GameModeConfig)]; -uint64_t mode_activation_masks[10]; +uint64_t mode_activation_masks[sizeof(Config::game_mode_configs) / sizeof(GameModeConfig)]; void set_mode(CommunicationBackend *backend, ControllerMode *mode) { // Delete keyboard mode in case one is set, so we don't end up getting both controller and @@ -95,7 +92,6 @@ void select_mode( for (size_t i = 0; i < mode_configs_count; i++) { const GameModeConfig &mode_config = mode_configs[i]; - // if (all_buttons_held(buttons, mode_activation_masks[i])) { if (all_buttons_held(inputs.buttons, mode_activation_masks[i])) { set_mode(backend, mode_config); return; From 970fe262b33778b3ae3296f08fccd5c0c1d00000 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 02:13:27 +0100 Subject: [PATCH 019/167] refactor: remove large stack and heap allocations --- include/core/Persistence.hpp | 20 +++++++++++++++++++- src/core/Persistence.cpp | 30 ++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/include/core/Persistence.hpp b/include/core/Persistence.hpp index 6ee1c285..2096c1e6 100644 --- a/include/core/Persistence.hpp +++ b/include/core/Persistence.hpp @@ -1,3 +1,20 @@ +/* + * This file is part of HayBox + * Copyright (C) 2023 Jonathan Haylett + * + * HayBox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software. If not, see . + */ + #ifndef _CORE_PERSISTENCE_HPP #define _CORE_PERSISTENCE_HPP @@ -21,7 +38,8 @@ class Persistence { static constexpr size_t config_offset = sizeof(ConfigHeader); private: - uint8_t _buffer[eeprom_size - config_offset]; + static Config _config; + static uint8_t _buffer[eeprom_size - config_offset]; }; #endif \ No newline at end of file diff --git a/src/core/Persistence.cpp b/src/core/Persistence.cpp index 4801206d..d48ce2c3 100644 --- a/src/core/Persistence.cpp +++ b/src/core/Persistence.cpp @@ -1,3 +1,20 @@ +/* + * This file is part of HayBox + * Copyright (C) 2023 Jonathan Haylett + * + * HayBox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software. If not, see . + */ + #include "core/Persistence.hpp" #include "stdlib.hpp" @@ -7,8 +24,15 @@ #include #include +Config Persistence::_config; +uint8_t Persistence::_buffer[eeprom_size - config_offset]; + Persistence::Persistence() { +#ifdef ARDUINO_PICO_REVISION EEPROM.begin(eeprom_size); +#else + EEPROM.begin(); +#endif } Persistence::~Persistence() { @@ -51,15 +75,13 @@ bool Persistence::LoadConfig(Config &config) { pb_istream_t istream = pb_istream_from_buffer(_buffer, config_size); - Config original = config; - // Return true if successfully decoded. - if (pb_decode(&istream, Config_fields, &config)) { + if (pb_decode(&istream, Config_fields, &_config)) { + config = _config; return true; } // Otherwise reset back to original config. - config = original; return false; } From b63ee1c705555c416b5b2a5670f4bffccaae2d51 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 02:24:43 +0100 Subject: [PATCH 020/167] feat: add configurable keyboard mode support --- .../avr_nousb/include/core/KeyboardMode.hpp | 4 +-- HAL/avr/avr_nousb/src/core/KeyboardMode.cpp | 2 +- HAL/avr/avr_usb/include/core/KeyboardMode.hpp | 4 +-- HAL/avr/avr_usb/src/core/KeyboardMode.cpp | 2 +- HAL/pico/include/core/KeyboardMode.hpp | 4 +-- HAL/pico/src/core/KeyboardMode.cpp | 4 +-- config/c53/config.cpp | 8 +++++- config/pico/config.cpp | 8 +++++- include/core/mode_selection.hpp | 15 ++++++++--- include/modes/CustomKeyboardMode.hpp | 19 +++++++++++++ include/modes/DefaultKeyboardMode.hpp | 2 +- include/modes/extra/ToughLoveArena.hpp | 2 +- src/core/mode_selection.cpp | 27 ++++++++++++++----- src/modes/CustomKeyboardMode.cpp | 24 +++++++++++++++++ src/modes/DefaultKeyboardMode.cpp | 2 +- src/modes/extra/ToughLoveArena.cpp | 2 +- 16 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 include/modes/CustomKeyboardMode.hpp create mode 100644 src/modes/CustomKeyboardMode.cpp diff --git a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp index 1a6e30ed..f8354dfc 100644 --- a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp @@ -10,13 +10,13 @@ class KeyboardMode : public InputMode { public: KeyboardMode(const GameModeConfig &config); ~KeyboardMode(); - void SendReport(InputState &inputs); + void SendReport(const InputState &inputs); protected: void Press(uint8_t keycode, bool press); private: - virtual void UpdateKeys(InputState &inputs) = 0; + virtual void UpdateKeys(const InputState &inputs) = 0; }; #endif diff --git a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp index 6c9d77f2..0509739d 100644 --- a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp @@ -6,6 +6,6 @@ KeyboardMode::KeyboardMode(const GameModeConfig &config) : InputMode(config) {} KeyboardMode::~KeyboardMode() {} -void KeyboardMode::SendReport(InputState &inputs) {} +void KeyboardMode::SendReport(const InputState &inputs) {} void KeyboardMode::Press(uint8_t keycode, bool press) {} \ No newline at end of file diff --git a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp index dbfb3ba4..a9dd3148 100644 --- a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp @@ -11,13 +11,13 @@ class KeyboardMode : public InputMode { public: KeyboardMode(const GameModeConfig &config); ~KeyboardMode(); - void SendReport(InputState &inputs); + void SendReport(const InputState &inputs); protected: void Press(uint8_t keycode, bool press); private: - virtual void UpdateKeys(InputState &inputs) = 0; + virtual void UpdateKeys(const InputState &inputs) = 0; }; #endif diff --git a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp index 79135297..dd1c912f 100644 --- a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp @@ -11,7 +11,7 @@ KeyboardMode::~KeyboardMode() { _keyboard.sendReport(); } -void KeyboardMode::SendReport(InputState &inputs) { +void KeyboardMode::SendReport(const InputState &inputs) { InputState remapped_inputs = inputs; HandleRemap(inputs, remapped_inputs); HandleSocd(remapped_inputs); diff --git a/HAL/pico/include/core/KeyboardMode.hpp b/HAL/pico/include/core/KeyboardMode.hpp index 3a51cbf4..ab11ebfe 100644 --- a/HAL/pico/include/core/KeyboardMode.hpp +++ b/HAL/pico/include/core/KeyboardMode.hpp @@ -12,7 +12,7 @@ class KeyboardMode : public InputMode { public: KeyboardMode(const GameModeConfig &config); ~KeyboardMode(); - void SendReport(InputState &inputs); + void SendReport(const InputState &inputs); protected: void Press(uint8_t keycode, bool press); @@ -20,7 +20,7 @@ class KeyboardMode : public InputMode { private: TUKeyboard *_keyboard; - virtual void UpdateKeys(InputState &inputs) = 0; + virtual void UpdateKeys(const InputState &inputs) = 0; }; #endif diff --git a/HAL/pico/src/core/KeyboardMode.cpp b/HAL/pico/src/core/KeyboardMode.cpp index 36a08257..126fba6f 100644 --- a/HAL/pico/src/core/KeyboardMode.cpp +++ b/HAL/pico/src/core/KeyboardMode.cpp @@ -15,7 +15,7 @@ KeyboardMode::~KeyboardMode() { delete _keyboard; } -void KeyboardMode::SendReport(InputState &inputs) { +void KeyboardMode::SendReport(const InputState &inputs) { InputState remapped_inputs = inputs; HandleRemap(inputs, remapped_inputs); HandleSocd(remapped_inputs); @@ -25,4 +25,4 @@ void KeyboardMode::SendReport(InputState &inputs) { void KeyboardMode::Press(uint8_t keycode, bool press) { _keyboard->setPressed(keycode, press); -} \ No newline at end of file +} diff --git a/config/c53/config.cpp b/config/c53/config.cpp index 557897fe..68f46bed 100644 --- a/config/c53/config.cpp +++ b/config/c53/config.cpp @@ -152,7 +152,13 @@ void setup() { } void loop() { - select_mode(backends[0], config.game_mode_configs, config.game_mode_configs_count); + select_mode( + backends[0], + config.game_mode_configs, + config.game_mode_configs_count, + config.keyboard_modes, + config.keyboard_modes_count + ); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/pico/config.cpp b/config/pico/config.cpp index e31700b9..e7e364cc 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -170,7 +170,13 @@ void setup() { } void loop() { - select_mode(backends[0], config.game_mode_configs, config.game_mode_configs_count); + select_mode( + backends[0], + config.game_mode_configs, + config.game_mode_configs_count, + config.keyboard_modes, + config.keyboard_modes_count + ); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/include/core/mode_selection.hpp b/include/core/mode_selection.hpp index 8f529fa5..88c05ed3 100644 --- a/include/core/mode_selection.hpp +++ b/include/core/mode_selection.hpp @@ -11,17 +11,26 @@ extern KeyboardMode *current_kb_mode; void set_mode(CommunicationBackend *backend, ControllerMode *mode); void set_mode(CommunicationBackend *backend, KeyboardMode *mode); -void set_mode(CommunicationBackend *backend, const GameModeConfig &mode_config); +void set_mode( + CommunicationBackend *backend, + const GameModeConfig &mode_config, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count +); void set_mode( CommunicationBackend *backend, GameModeId mode_id, const GameModeConfig *mode_configs, - size_t mode_configs_count + size_t mode_configs_count, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count ); void select_mode( CommunicationBackend *backend, const GameModeConfig *mode_configs, - size_t mode_configs_count + size_t mode_configs_count, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count ); void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count); diff --git a/include/modes/CustomKeyboardMode.hpp b/include/modes/CustomKeyboardMode.hpp new file mode 100644 index 00000000..25f34d5c --- /dev/null +++ b/include/modes/CustomKeyboardMode.hpp @@ -0,0 +1,19 @@ +#ifndef _MODES_CUSTOMKEYBOARDMODE_HPP +#define _MODES_CUSTOMKEYBOARDMODE_HPP + +#include "core/KeyboardMode.hpp" +#include "core/state.hpp" + +#include + +class CustomKeyboardMode : public KeyboardMode { + public: + CustomKeyboardMode(const GameModeConfig &config, const KeyboardModeConfig &keyboard_config); + + private: + const KeyboardModeConfig &_keyboard_config; + + void UpdateKeys(const InputState &inputs); +}; + +#endif \ No newline at end of file diff --git a/include/modes/DefaultKeyboardMode.hpp b/include/modes/DefaultKeyboardMode.hpp index da637bf3..b5ca9836 100644 --- a/include/modes/DefaultKeyboardMode.hpp +++ b/include/modes/DefaultKeyboardMode.hpp @@ -9,7 +9,7 @@ class DefaultKeyboardMode : public KeyboardMode { DefaultKeyboardMode(const GameModeConfig &config); private: - void UpdateKeys(InputState &inputs); + void UpdateKeys(const InputState &inputs); }; #endif diff --git a/include/modes/extra/ToughLoveArena.hpp b/include/modes/extra/ToughLoveArena.hpp index 900d012c..f00a0cbc 100644 --- a/include/modes/extra/ToughLoveArena.hpp +++ b/include/modes/extra/ToughLoveArena.hpp @@ -10,7 +10,7 @@ class ToughLoveArena : public KeyboardMode { ToughLoveArena(const GameModeConfig &config); private: - void UpdateKeys(InputState &inputs); + void UpdateKeys(const InputState &inputs); }; #endif diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 8d1c0607..2da87c01 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -1,7 +1,7 @@ #include "core/mode_selection.hpp" #include "core/state.hpp" -#include "modes/DefaultKeyboardMode.hpp" +#include "modes/CustomKeyboardMode.hpp" #include "modes/FgcMode.hpp" #include "modes/Melee20Button.hpp" #include "modes/ProjectM.hpp" @@ -32,7 +32,12 @@ void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { backend->SetGameMode(nullptr); } -void set_mode(CommunicationBackend *backend, const GameModeConfig &mode_config) { +void set_mode( + CommunicationBackend *backend, + const GameModeConfig &mode_config, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count +) { switch (mode_config.mode_id) { case MODE_MELEE: set_mode(backend, new Melee20Button(mode_config, { .crouch_walk_os = false })); @@ -55,6 +60,12 @@ void set_mode(CommunicationBackend *backend, const GameModeConfig &mode_config) case MODE_RIVALS_OF_AETHER: set_mode(backend, new RivalsOfAether(mode_config)); break; + case MODE_KEYBOARD: + set_mode( + backend, + new CustomKeyboardMode(mode_config, keyboard_modes[mode_config.keyboard_mode_id]) + ); + break; case MODE_UNSPECIFIED: default: break; @@ -67,14 +78,16 @@ void set_mode( CommunicationBackend *backend, GameModeId mode_id, const GameModeConfig *mode_configs, - size_t mode_configs_count + size_t mode_configs_count, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count ) { // In this overload we only know the mode id so we need to find a mode config that matches this // ID. for (size_t i = 0; i < mode_configs_count; i++) { const GameModeConfig &mode = mode_configs[i]; if (mode.mode_id == mode_id) { - set_mode(backend, mode); + set_mode(backend, mode, keyboard_modes, keyboard_modes_count); return; } } @@ -83,7 +96,9 @@ void set_mode( void select_mode( CommunicationBackend *backend, const GameModeConfig *mode_configs, - size_t mode_configs_count + size_t mode_configs_count, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count ) { // TODO: Use a counter variable to only run the contents of this function every x iterations // rather than on every single poll. @@ -93,7 +108,7 @@ void select_mode( for (size_t i = 0; i < mode_configs_count; i++) { const GameModeConfig &mode_config = mode_configs[i]; if (all_buttons_held(inputs.buttons, mode_activation_masks[i])) { - set_mode(backend, mode_config); + set_mode(backend, mode_config, keyboard_modes, keyboard_modes_count); return; } } diff --git a/src/modes/CustomKeyboardMode.cpp b/src/modes/CustomKeyboardMode.cpp new file mode 100644 index 00000000..400025ce --- /dev/null +++ b/src/modes/CustomKeyboardMode.cpp @@ -0,0 +1,24 @@ +#include "modes/CustomKeyboardMode.hpp" + +#include "core/state.hpp" +#include "util/state_util.hpp" + +#include + +CustomKeyboardMode::CustomKeyboardMode( + const GameModeConfig &config, + const KeyboardModeConfig &keyboard_config +) + : KeyboardMode(config), + _keyboard_config(keyboard_config) {} + +void CustomKeyboardMode::UpdateKeys(const InputState &inputs) { + const ButtonToKeycodeMapping *keymap = _keyboard_config.buttons_to_keycodes; + size_t key_count = _keyboard_config.buttons_to_keycodes_count; + for (size_t i = 0; i < key_count; i++) { + if (keymap[i].button == BTN_UNSPECIFIED) { + continue; + } + Press(keymap[i].keycode, get_button(inputs.buttons, keymap[i].button)); + } +} \ No newline at end of file diff --git a/src/modes/DefaultKeyboardMode.cpp b/src/modes/DefaultKeyboardMode.cpp index 91b657e6..d7c9ef77 100644 --- a/src/modes/DefaultKeyboardMode.cpp +++ b/src/modes/DefaultKeyboardMode.cpp @@ -5,7 +5,7 @@ DefaultKeyboardMode::DefaultKeyboardMode(const GameModeConfig &config) : KeyboardMode(config) {} -void DefaultKeyboardMode::UpdateKeys(InputState &inputs) { +void DefaultKeyboardMode::UpdateKeys(const InputState &inputs) { Press(HID_KEY_A, inputs.lf4); Press(HID_KEY_B, inputs.lf3); Press(HID_KEY_C, inputs.lf2); diff --git a/src/modes/extra/ToughLoveArena.cpp b/src/modes/extra/ToughLoveArena.cpp index 89d2a3e3..0f9c8a4b 100644 --- a/src/modes/extra/ToughLoveArena.cpp +++ b/src/modes/extra/ToughLoveArena.cpp @@ -2,7 +2,7 @@ ToughLoveArena::ToughLoveArena(const GameModeConfig &config) : KeyboardMode(config) {} -void ToughLoveArena::UpdateKeys(InputState &inputs) { +void ToughLoveArena::UpdateKeys(const InputState &inputs) { Press(HID_KEY_S, inputs.lf3); Press(HID_KEY_D, inputs.lf1); Press(HID_KEY_J, inputs.rf1); From 83819867bc2ef4a885fd7fca82d67eaa673dc96a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 02:29:08 +0100 Subject: [PATCH 021/167] fix: fix console detection with Model U --- HAL/avr/avr_usb/src/comms/backend_init.cpp | 3 +-- .../avr_usb/src/comms/console_detection.cpp | 23 +------------------ HAL/pico/src/comms/DInputBackend.cpp | 4 ---- HAL/pico/src/comms/XInputBackend.cpp | 4 ---- HAL/pico/src/comms/backend_init.cpp | 22 ++++++++++++++---- HAL/pico/src/comms/console_detection.cpp | 1 + 6 files changed, 21 insertions(+), 36 deletions(-) diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp index 85ae7369..6a7cf1a8 100644 --- a/HAL/avr/avr_usb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -23,13 +23,12 @@ size_t initialize_backends( size_t game_mode_configs_count, const Pinout &pinout ) { - CommunicationBackend *primary_backend; + CommunicationBackend *primary_backend = nullptr; CommunicationBackendConfig backend_config = backend_config_from_buttons(inputs, backend_configs, backend_configs_count); if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { primary_backend = new DInputBackend(inputs, input_sources, input_source_count); - delay(500); CommunicationBackendId detected_backend_id = detect_console(pinout); backend_config = backend_config_from_id(detected_backend_id, backend_configs, backend_configs_count); diff --git a/HAL/avr/avr_usb/src/comms/console_detection.cpp b/HAL/avr/avr_usb/src/comms/console_detection.cpp index 0d9d2ef9..e639e0a0 100644 --- a/HAL/avr/avr_usb/src/comms/console_detection.cpp +++ b/HAL/avr/avr_usb/src/comms/console_detection.cpp @@ -6,29 +6,8 @@ #include -// extern const Pinout pinout; - -/* -ConnectedConsole detect_console() { - // InputState inputs; - // CommunicationBackend *dinput = new DInputBackend(inputs, nullptr, 0); - Serial.begin(115200); - // delay(100); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - // USBD_Connected(); - // Serial.end(); - // delete dinput; - - if (usb_connected) { - return ConnectedConsole::NONE; - } - - return ConnectedConsole::GAMECUBE; -} -*/ - CommunicationBackendId detect_console(const Pinout &pinout) { + delay(500); bool usb_connected = UDADDR & _BV(ADDEN); if (usb_connected) { diff --git a/HAL/pico/src/comms/DInputBackend.cpp b/HAL/pico/src/comms/DInputBackend.cpp index f141d03c..c420234b 100644 --- a/HAL/pico/src/comms/DInputBackend.cpp +++ b/HAL/pico/src/comms/DInputBackend.cpp @@ -13,10 +13,6 @@ DInputBackend::DInputBackend( : CommunicationBackend(inputs, input_sources, input_source_count) { _gamepad = new TUGamepad(); _gamepad->begin(); - - while (!USBDevice.mounted()) { - delay(1); - } } DInputBackend::~DInputBackend() { diff --git a/HAL/pico/src/comms/XInputBackend.cpp b/HAL/pico/src/comms/XInputBackend.cpp index d7ded9d2..1644526a 100644 --- a/HAL/pico/src/comms/XInputBackend.cpp +++ b/HAL/pico/src/comms/XInputBackend.cpp @@ -17,10 +17,6 @@ XInputBackend::XInputBackend( Serial.begin(115200); TinyUSBDevice.setID(0x0738, 0x4726); - - while (!_xinput->ready()) { - delay(1); - } } XInputBackend::~XInputBackend() { diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index f88a20c4..b6a27ff8 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -25,13 +25,15 @@ size_t initialize_backends( Config &config, const Pinout &pinout ) { + CommunicationBackend *primary_backend = nullptr; + CommunicationBackendConfig backend_config = backend_config_from_buttons( inputs, config.communication_backend_configs, config.communication_backend_configs_count ); if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { - delay(250); + primary_backend = new XInputBackend(inputs, input_sources, input_source_count); CommunicationBackendId detected_backend_id = detect_console(pinout); backend_config = backend_config_from_id( detected_backend_id, @@ -40,11 +42,11 @@ size_t initialize_backends( ); } - CommunicationBackend *primary_backend; size_t backend_count; switch (backend_config.backend_id) { case COMMS_BACKEND_DINPUT: + delete primary_backend; TUGamepad::registerDescriptor(); TUKeyboard::registerDescriptor(); primary_backend = new DInputBackend(inputs, input_sources, input_source_count); @@ -54,25 +56,29 @@ size_t initialize_backends( }; break; case COMMS_BACKEND_XINPUT: - primary_backend = new XInputBackend(inputs, input_sources, input_source_count); + // delete primary_backend; + // primary_backend = new XInputBackend(inputs, input_sources, input_source_count); backend_count = 2; backends = new CommunicationBackend *[backend_count] { primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) }; break; case COMMS_BACKEND_GAMECUBE: + delete primary_backend; primary_backend = new GamecubeBackend(inputs, input_sources, input_source_count, pinout.joybus_data); backend_count = 1; backends = new CommunicationBackend *[backend_count] { primary_backend }; break; case COMMS_BACKEND_N64: + delete primary_backend; primary_backend = new N64Backend(inputs, input_sources, input_source_count, pinout.joybus_data); backend_count = 1; backends = new CommunicationBackend *[backend_count] { primary_backend }; break; case COMMS_BACKEND_NINTENDO_SWITCH: + delete primary_backend; NintendoSwitchBackend::RegisterDescriptor(); primary_backend = new NintendoSwitchBackend(inputs, input_sources, input_source_count); backend_count = 1; @@ -81,6 +87,7 @@ size_t initialize_backends( case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. case COMMS_BACKEND_CONFIGURATOR: default: + delete primary_backend; primary_backend = new ConfiguratorBackend(inputs, input_sources, input_source_count, config); backend_count = 1; @@ -92,7 +99,14 @@ size_t initialize_backends( mode_id = MODE_MELEE; } - set_mode(primary_backend, mode_id, config.game_mode_configs, config.game_mode_configs_count); + set_mode( + primary_backend, + mode_id, + config.game_mode_configs, + config.game_mode_configs_count, + config.keyboard_modes, + config.keyboard_modes_count + ); return backend_count; } \ No newline at end of file diff --git a/HAL/pico/src/comms/console_detection.cpp b/HAL/pico/src/comms/console_detection.cpp index 7b681859..eb86b968 100644 --- a/HAL/pico/src/comms/console_detection.cpp +++ b/HAL/pico/src/comms/console_detection.cpp @@ -8,6 +8,7 @@ #include CommunicationBackendId detect_console(const Pinout &pinout) { + delay(500); bool usb_connected = usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS; if (usb_connected) { From 01a970ed1183188056e1ba372ade0806d651be34 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 02:53:33 +0100 Subject: [PATCH 022/167] feat: update HayBox-proto and enable more warnings --- platformio.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 2fbd212b..78022e3e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,7 @@ custom_nanopb_protos = +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> lib_deps = https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip - git+git@github.com:JonnyHaystack/HayBox-proto#0160c12 + git+git@github.com:JonnyHaystack/HayBox-proto#8cd8367 eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 @@ -89,7 +89,9 @@ build_flags = -D USE_TINYUSB -D CFG_TUSB_CONFIG_FILE=\"tusb_config_pico.h\" -D NDEBUG - -Wstack-usage=4096 + -Wall + -Wstack-usage=1024 + -Wno-unused-variable -O3 -I HAL/pico/include build_src_filter = From 030f478af90aac7916abb45bb5cda5050900acdf Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 03:05:41 +0100 Subject: [PATCH 023/167] refactor: fix delete-non-virtual-dtor warnings --- HAL/pico/include/comms/XInputBackend.hpp | 3 +- HAL/pico/src/comms/XInputBackend.cpp | 14 +++------ include/comms/ConfiguratorBackend.hpp | 21 +++++++++++-- src/comms/ConfiguratorBackend.cpp | 39 ++++++++++++++++-------- 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/HAL/pico/include/comms/XInputBackend.hpp b/HAL/pico/include/comms/XInputBackend.hpp index f139323d..72140782 100644 --- a/HAL/pico/include/comms/XInputBackend.hpp +++ b/HAL/pico/include/comms/XInputBackend.hpp @@ -10,11 +10,10 @@ class XInputBackend : public CommunicationBackend { public: XInputBackend(InputState &inputs, InputSource **input_sources, size_t input_source_count); - ~XInputBackend(); void SendReport(); private: - Adafruit_USBD_XInput *_xinput; + Adafruit_USBD_XInput _xinput; xinput_report_t _report = {}; }; diff --git a/HAL/pico/src/comms/XInputBackend.cpp b/HAL/pico/src/comms/XInputBackend.cpp index 1644526a..343eac38 100644 --- a/HAL/pico/src/comms/XInputBackend.cpp +++ b/HAL/pico/src/comms/XInputBackend.cpp @@ -10,24 +10,20 @@ XInputBackend::XInputBackend( InputSource **input_sources, size_t input_source_count ) - : CommunicationBackend(inputs, input_sources, input_source_count) { + : CommunicationBackend(inputs, input_sources, input_source_count), + _xinput() { Serial.end(); - _xinput = new Adafruit_USBD_XInput(); - _xinput->begin(); + _xinput.begin(); Serial.begin(115200); TinyUSBDevice.setID(0x0738, 0x4726); } -XInputBackend::~XInputBackend() { - delete _xinput; -} - void XInputBackend::SendReport() { ScanInputs(InputScanSpeed::SLOW); ScanInputs(InputScanSpeed::MEDIUM); - while (!_xinput->ready()) { + while (!_xinput.ready()) { tight_loop_contents(); } @@ -59,5 +55,5 @@ void XInputBackend::SendReport() { _report.rx = (_outputs.rightStickX - 128) * 65535 / 255 + 128; _report.ry = (_outputs.rightStickY - 128) * 65535 / 255 + 128; - _xinput->sendReport(&_report); + _xinput.sendReport(&_report); } \ No newline at end of file diff --git a/include/comms/ConfiguratorBackend.hpp b/include/comms/ConfiguratorBackend.hpp index 25daeaaa..58f84040 100644 --- a/include/comms/ConfiguratorBackend.hpp +++ b/include/comms/ConfiguratorBackend.hpp @@ -1,3 +1,20 @@ +/* + * This file is part of HayBox + * Copyright (C) 2023 Jonathan Haylett + * + * HayBox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software. If not, see . + */ + #ifndef _COMMS_CONFIGURATORBACKEND_HPP #define _COMMS_CONFIGURATORBACKEND_HPP @@ -27,8 +44,8 @@ class ConfiguratorBackend : public CommunicationBackend { bool HandleGetConfig(); bool HandleSetConfig(uint8_t *buffer, size_t len); - packetio::COBSStream *_in; - packetio::COBSPrint *_out; + packetio::COBSStream _in; + packetio::COBSPrint _out; Persistence *_persistence; uint8_t _cmd_buffer[Persistence::eeprom_size - Persistence::config_offset]; Config &_config; diff --git a/src/comms/ConfiguratorBackend.cpp b/src/comms/ConfiguratorBackend.cpp index c8ad31a4..85d2e73f 100644 --- a/src/comms/ConfiguratorBackend.cpp +++ b/src/comms/ConfiguratorBackend.cpp @@ -1,3 +1,20 @@ +/* + * This file is part of HayBox + * Copyright (C) 2023 Jonathan Haylett + * + * HayBox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This software 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software. If not, see . + */ + #include "comms/ConfiguratorBackend.hpp" #include "core/InputSource.hpp" @@ -14,9 +31,9 @@ ConfiguratorBackend::ConfiguratorBackend( Config &config ) : CommunicationBackend(inputs, input_sources, input_source_count), + _in(Serial), + _out(Serial), _config(config) { - _in = new packetio::COBSStream(Serial); - _out = new packetio::COBSPrint(Serial); serial::init(115200); _persistence = new Persistence(); } @@ -24,8 +41,6 @@ ConfiguratorBackend::ConfiguratorBackend( ConfiguratorBackend::~ConfiguratorBackend() { serial::close(); delete _persistence; - delete _in; - delete _out; } void ConfiguratorBackend::SendReport() { @@ -60,30 +75,30 @@ size_t ConfiguratorBackend::ReadPacket(uint8_t *buffer, size_t max_len) { delay(1); } while (true) { - int result = _in->read(); - if (result == _in->EOF) { + int result = _in.read(); + if (result == _in.EOF) { continue; } - if (result == _in->EOP) { + if (result == _in.EOP) { break; } buffer[bytes_read++] = result; if (bytes_read >= max_len) { - _in->next(); + _in.next(); return bytes_read; } } - _in->next(); + _in.next(); return bytes_read; } bool ConfiguratorBackend::WritePacket(Command command_id, uint8_t *buffer, size_t len) { - _out->write((uint8_t)command_id); + _out.write((uint8_t)command_id); for (size_t i = 0; i < len; i++) { - _out->write(buffer[i]); + _out.write(buffer[i]); } - return _out->end(); + return _out.end(); } bool ConfiguratorBackend::HandleGetDeviceInfo() { From 775a5c0e5fb8258b6565b3cf69799e9c85006fa0 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 14:45:25 +0100 Subject: [PATCH 024/167] fix: update avr_usb backend init with keyboard mode configs --- HAL/avr/avr_usb/include/comms/backend_init.hpp | 2 ++ HAL/avr/avr_usb/src/comms/backend_init.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/HAL/avr/avr_usb/include/comms/backend_init.hpp b/HAL/avr/avr_usb/include/comms/backend_init.hpp index 34778cae..ff6ad3df 100644 --- a/HAL/avr/avr_usb/include/comms/backend_init.hpp +++ b/HAL/avr/avr_usb/include/comms/backend_init.hpp @@ -29,6 +29,8 @@ size_t initialize_backends( size_t backend_configs_count, const GameModeConfig *game_mode_configs, size_t game_mode_configs_count, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count, const Pinout &pinout ); diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp index 6a7cf1a8..3a82b928 100644 --- a/HAL/avr/avr_usb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -21,6 +21,8 @@ size_t initialize_backends( size_t backend_configs_count, const GameModeConfig *game_mode_configs, size_t game_mode_configs_count, + const KeyboardModeConfig *keyboard_modes, + size_t keyboard_modes_count, const Pinout &pinout ) { CommunicationBackend *primary_backend = nullptr; @@ -70,7 +72,14 @@ size_t initialize_backends( mode_id = MODE_MELEE; } - set_mode(primary_backend, mode_id, game_mode_configs, game_mode_configs_count); + set_mode( + primary_backend, + mode_id, + game_mode_configs, + game_mode_configs_count, + keyboard_modes, + keyboard_modes_count + ); return backend_count; } \ No newline at end of file From 66ed1bf2374ca7e07222adcd31b9870c49e14f73 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 14:47:35 +0100 Subject: [PATCH 025/167] feat: track current game mode config index Track index of current game mode config to prevent switching from one GameModeConfig to the same GameModeConfig, which in turn prevents spamming of keypresses when entering a keyboard mode on RP2040. Closes #21 --- src/core/mode_selection.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 2da87c01..d0b897f2 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -13,6 +13,8 @@ uint64_t mode_activation_masks[sizeof(Config::game_mode_configs) / sizeof(GameModeConfig)]; +size_t current_mode_index = 0; + void set_mode(CommunicationBackend *backend, ControllerMode *mode) { // Delete keyboard mode in case one is set, so we don't end up getting both controller and // keyboard inputs. @@ -107,7 +109,8 @@ void select_mode( for (size_t i = 0; i < mode_configs_count; i++) { const GameModeConfig &mode_config = mode_configs[i]; - if (all_buttons_held(inputs.buttons, mode_activation_masks[i])) { + if (all_buttons_held(inputs.buttons, mode_activation_masks[i]) && i != current_mode_index) { + current_mode_index = i; set_mode(backend, mode_config, keyboard_modes, keyboard_modes_count); return; } From 4e16eca333540679efad031b9e8fc993e960de1c Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 14:51:36 +0100 Subject: [PATCH 026/167] build: update HayBox-proto to reduce integer sizes --- platformio.ini | 3 ++- src/core/mode_selection.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 78022e3e..1f333a41 100644 --- a/platformio.ini +++ b/platformio.ini @@ -20,7 +20,7 @@ custom_nanopb_protos = +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> lib_deps = https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip - git+git@github.com:JonnyHaystack/HayBox-proto#8cd8367 + git+git@github.com:JonnyHaystack/HayBox-proto#414231a eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 @@ -37,6 +37,7 @@ build_flags = -ffunction-sections -fno-sized-deallocation -Wl,--gc-sections + -Wno-unused-variable -I HAL/avr/include -D PB_BUFFER_ONLY -D PB_WITHOUT_64BIT diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index d0b897f2..0e127b93 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -13,7 +13,7 @@ uint64_t mode_activation_masks[sizeof(Config::game_mode_configs) / sizeof(GameModeConfig)]; -size_t current_mode_index = 0; +size_t current_mode_index = SIZE_MAX; void set_mode(CommunicationBackend *backend, ControllerMode *mode) { // Delete keyboard mode in case one is set, so we don't end up getting both controller and From dfaf28926b38713214883f5abb47cbbb603de314 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 19:31:33 +0100 Subject: [PATCH 027/167] refactor: reduce AVR RAM usage for Protobuf arrays --- HAL/avr/include/util/state_util.hpp | 1 - HAL/avr/proto/config.options | 46 +++++++++++++++++++++++++++++ platformio.ini | 5 ++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 HAL/avr/proto/config.options diff --git a/HAL/avr/include/util/state_util.hpp b/HAL/avr/include/util/state_util.hpp index 97ea8a40..1efaaa4d 100644 --- a/HAL/avr/include/util/state_util.hpp +++ b/HAL/avr/include/util/state_util.hpp @@ -1,7 +1,6 @@ #ifndef _UTIL_STATE_UTIL_HPP #define _UTIL_STATE_UTIL_HPP -#include "core/state.hpp" #include "stdlib.hpp" #include diff --git a/HAL/avr/proto/config.options b/HAL/avr/proto/config.options new file mode 100644 index 00000000..a3e87485 --- /dev/null +++ b/HAL/avr/proto/config.options @@ -0,0 +1,46 @@ +ButtonRemap.physical_button int_size:IS_8 +ButtonRemap.activates int_size:IS_8 + +SocdPair.button_dir1 int_size:IS_8 +SocdPair.button_dir2 int_size:IS_8 +SocdPair.socd_type int_size:IS_8 + +ButtonToKeycodeMapping.button int_size:IS_8 +ButtonToKeycodeMapping.keycode int_size:IS_8 + +GameModeConfig.mode_id int_size:IS_8 +GameModeConfig.socd_pairs max_count:10 +GameModeConfig.socd_pairs type:FT_POINTER +GameModeConfig.button_remapping max_count:60 +GameModeConfig.button_remapping type:FT_POINTER +GameModeConfig.activation_binding max_count:4 +GameModeConfig.activation_binding type:FT_POINTER +GameModeConfig.keyboard_mode_id int_size:IS_8 + +KeyboardModeConfig.id int_size:IS_8 +KeyboardModeConfig.name max_length:20 +KeyboardModeConfig.buttons_to_keycodes max_count:60 +KeyboardModeConfig.buttons_to_keycodes type:FT_POINTER + +CommunicationBackendConfig.backend_id int_size:IS_8 +CommunicationBackendConfig.default_mode int_size:IS_8 +CommunicationBackendConfig.activation_binding max_count:2 +CommunicationBackendConfig.activation_binding type:FT_POINTER + +Config.default_backend int_size:IS_8 +Config.game_mode_configs max_count:10 +Config.game_mode_configs type:FT_POINTER +Config.communication_backend_configs max_count:10 +Config.communication_backend_configs type:FT_POINTER +Config.keyboard_modes max_count:5 +Config.keyboard_modes type:FT_POINTER + +DeviceInfo.firmware_name max_length:25 +DeviceInfo.firmware_version max_length:8 +DeviceInfo.device_name max_length:30 + +Command long_names:false +Button long_names:false +SocdType long_names:false +GameModeId long_names:false +CommunicationBackendId long_names:false \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 1f333a41..242423f9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,6 +18,8 @@ build_src_filter = + custom_nanopb_protos = +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> +custom_nanopb_options = + --error-on-unmatched lib_deps = https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip git+git@github.com:JonnyHaystack/HayBox-proto#414231a @@ -46,6 +48,9 @@ build_flags = build_src_filter = ${env.build_src_filter} + +custom_nanopb_options = + ${env.custom_nanopb_options} + --options-file ../../../../HAL/avr/proto/config.options lib_deps = ${env.lib_deps} nicohood/Nintendo@^1.4.0 From d0851f107bfea9da92d70d1e23cf47be688b6b56 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 20:21:53 +0100 Subject: [PATCH 028/167] feat: add HTangl V1 config --- config/htangl_v1/config.cpp | 342 ++++++++++++++++++++++++++++++++++++ config/htangl_v1/env.ini | 6 + 2 files changed, 348 insertions(+) create mode 100644 config/htangl_v1/config.cpp create mode 100644 config/htangl_v1/env.ini diff --git a/config/htangl_v1/config.cpp b/config/htangl_v1/config.cpp new file mode 100644 index 00000000..9bb2d9a8 --- /dev/null +++ b/config/htangl_v1/config.cpp @@ -0,0 +1,342 @@ +#include "comms/backend_init.hpp" +#include "core/CommunicationBackend.hpp" +#include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" +#include "core/pinout.hpp" +#include "core/state.hpp" +#include "input/GpioButtonInput.hpp" +#include "reboot.hpp" +#include "stdlib.hpp" + +#include + +// clang-format off + +const Config config = { + .default_backend = COMMS_BACKEND_DINPUT, + .game_mode_configs_count = 5, + .game_mode_configs = new GameModeConfig[5] { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 2, + .socd_pairs = new SocdPair[2] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 1, + .button_remapping = new ButtonRemap[1] { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, + }, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, + }, + GameModeConfig { + .mode_id = MODE_KEYBOARD, + .socd_pairs_count = 2, + .socd_pairs = new SocdPair[2] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT2, BTN_MB1, BTN_LF4 }, + }, + }, + .communication_backend_configs_count = 1, + .communication_backend_configs = new CommunicationBackendConfig[1] { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RF3 }, + }, + }, + .keyboard_modes_count = 1, + .keyboard_modes = new KeyboardModeConfig[1] { + KeyboardModeConfig { + 0, + "Default", + 22, + new ButtonToKeycodeMapping[22] { + { BTN_LF4, HID_KEY_A }, + { BTN_LF3, HID_KEY_B }, + { BTN_LF2, HID_KEY_C }, + { BTN_LF1, HID_KEY_D }, + { BTN_LT1, HID_KEY_E }, + { BTN_LT2, HID_KEY_F }, + { BTN_MB3, HID_KEY_G }, + { BTN_MB1, HID_KEY_H }, + { BTN_MB2, HID_KEY_I }, + { BTN_RF5, HID_KEY_J }, + { BTN_RF6, HID_KEY_K }, + { BTN_RF7, HID_KEY_L }, + { BTN_RF8, HID_KEY_M }, + { BTN_RF1, HID_KEY_N }, + { BTN_RF2, HID_KEY_O }, + { BTN_RF3, HID_KEY_P }, + { BTN_RF4, HID_KEY_Q }, + { BTN_RT4, HID_KEY_R }, + { BTN_RT3, HID_KEY_S }, + { BTN_RT5, HID_KEY_T }, + { BTN_RT1, HID_KEY_U }, + { BTN_RT2, HID_KEY_V }, + }, + }, + }, +}; + +/* +const GameModeConfig game_mode_configs[] = { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 2, + .socd_pairs = new SocdPair[2] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 1, + .button_remapping = new ButtonRemap[1] { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, + }, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, + }, + GameModeConfig { + .mode_id = MODE_KEYBOARD, + .socd_pairs_count = 2, + .socd_pairs = new SocdPair[2] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT2, BTN_MB1, BTN_LF4 }, + } +}; +size_t game_mode_configs_count = sizeof(game_mode_configs) / sizeof(GameModeConfig); + +const KeyboardModeConfig keyboard_modes[] = { + KeyboardModeConfig { + 0, + "Default", + 22, + { + { BTN_LF4, HID_KEY_A }, + { BTN_LF3, HID_KEY_B }, + { BTN_LF2, HID_KEY_C }, + { BTN_LF1, HID_KEY_D }, + { BTN_LT1, HID_KEY_E }, + { BTN_LT2, HID_KEY_F }, + { BTN_MB3, HID_KEY_G }, + { BTN_MB1, HID_KEY_H }, + { BTN_MB2, HID_KEY_I }, + { BTN_RF5, HID_KEY_J }, + { BTN_RF6, HID_KEY_K }, + { BTN_RF7, HID_KEY_L }, + { BTN_RF8, HID_KEY_M }, + { BTN_RF1, HID_KEY_N }, + { BTN_RF2, HID_KEY_O }, + { BTN_RF3, HID_KEY_P }, + { BTN_RF4, HID_KEY_Q }, + { BTN_RT4, HID_KEY_R }, + { BTN_RT3, HID_KEY_S }, + { BTN_RT5, HID_KEY_T }, + { BTN_RT1, HID_KEY_U }, + { BTN_RT2, HID_KEY_V }, + }, + }, +}; +size_t keyboard_modes_count = sizeof(keyboard_modes) / sizeof(KeyboardModeConfig); + +const CommunicationBackendConfig backend_configs[] = { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RF3 }, + }, +}; +size_t backend_configs_count = sizeof(backend_configs) / sizeof(CommunicationBackendConfig); +*/ + +// clang-format on + +const GpioButtonMapping button_mappings[] = { + {BTN_LF4, 6 }, + { BTN_LF3, 4 }, + { BTN_LF2, 0 }, + { BTN_LF1, 1 }, + + { BTN_LT1, 14}, + { BTN_LT2, 16}, + + { BTN_MB3, 2 }, + { BTN_MB1, 3 }, + { BTN_MB2, 5 }, + + { BTN_RT3, A2}, + { BTN_RT4, A3}, + { BTN_RT2, 15}, + { BTN_RT1, A5}, + { BTN_RT5, A4}, + + { BTN_RF1, 10}, + { BTN_RF2, 11}, + { BTN_RF3, 13}, + { BTN_RF4, A1}, + + { BTN_RF5, 7 }, + { BTN_RF6, 9 }, + { BTN_RF7, 12}, + { BTN_RF8, A0}, +}; +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); + +const Pinout pinout = { + .joybus_data = 8, + .mux = -1, + .nunchuk_detect = -1, + .nunchuk_sda = -1, + .nunchuk_scl = -1, +}; + +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + +void setup() { + static InputState inputs; + + // Create GPIO input source and use it to read button states for checking button holds. + static GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); + + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } + + // Create array of input sources to be used. + static InputSource *input_sources[] = { &gpio_input }; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = initialize_backends( + backends, + inputs, + input_sources, + input_source_count, + config.communication_backend_configs, + config.communication_backend_configs_count, + config.game_mode_configs, + config.game_mode_configs_count, + config.keyboard_modes, + config.keyboard_modes_count, + pinout + ); + + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); +} + +void loop() { + select_mode( + backends[0], + config.game_mode_configs, + config.game_mode_configs_count, + config.keyboard_modes, + config.keyboard_modes_count + ); + + for (size_t i = 0; i < backend_count; i++) { + backends[i]->SendReport(); + } + + if (current_kb_mode != nullptr) { + current_kb_mode->SendReport(backends[0]->GetInputs()); + } +} diff --git a/config/htangl_v1/env.ini b/config/htangl_v1/env.ini new file mode 100644 index 00000000..9ef86037 --- /dev/null +++ b/config/htangl_v1/env.ini @@ -0,0 +1,6 @@ +[env:htangl_v1] +extends = avr_usb +board = leonardo +build_src_filter = + ${avr_usb.build_src_filter} + + \ No newline at end of file From 88450fea11798a0e80d87b9b9e8ecd0108c0c2c9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:27:59 +0100 Subject: [PATCH 029/167] build: optimise AVR memory usage a bit --- platformio.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 242423f9..59ddcc67 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,6 +38,8 @@ build_flags = -fdata-sections -ffunction-sections -fno-sized-deallocation + -flto + -fshort-enums -Wl,--gc-sections -Wno-unused-variable -I HAL/avr/include @@ -92,13 +94,13 @@ board_build.f_cpu = 130000000L build_unflags = -Os build_flags = ${env.build_flags} + -O3 -D USE_TINYUSB -D CFG_TUSB_CONFIG_FILE=\"tusb_config_pico.h\" -D NDEBUG -Wall -Wstack-usage=1024 -Wno-unused-variable - -O3 -I HAL/pico/include build_src_filter = ${env.build_src_filter} From 7ffd24e7da53b07ce12eedf9273f03c7a9b31847 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:29:09 +0100 Subject: [PATCH 030/167] feat: add keyboard mode to Pico default config --- config/pico/config.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index e7e364cc..7b98cac4 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -90,6 +90,38 @@ Config config = { .activation_binding = { BTN_RT2 }, } }, + .keyboard_modes_count = 1, + .keyboard_modes = { + KeyboardModeConfig { + 0, + "Default", + 22, + { + { BTN_LF4, HID_KEY_A }, + { BTN_LF3, HID_KEY_B }, + { BTN_LF2, HID_KEY_C }, + { BTN_LF1, HID_KEY_D }, + { BTN_LT1, HID_KEY_E }, + { BTN_LT2, HID_KEY_F }, + { BTN_MB3, HID_KEY_G }, + { BTN_MB1, HID_KEY_H }, + { BTN_MB2, HID_KEY_I }, + { BTN_RF5, HID_KEY_J }, + { BTN_RF6, HID_KEY_K }, + { BTN_RF7, HID_KEY_L }, + { BTN_RF8, HID_KEY_M }, + { BTN_RF1, HID_KEY_N }, + { BTN_RF2, HID_KEY_O }, + { BTN_RF3, HID_KEY_P }, + { BTN_RF4, HID_KEY_Q }, + { BTN_RT4, HID_KEY_R }, + { BTN_RT3, HID_KEY_S }, + { BTN_RT5, HID_KEY_T }, + { BTN_RT1, HID_KEY_U }, + { BTN_RT2, HID_KEY_V }, + }, + }, + }, }; GpioButtonMapping button_mappings[] = { From e58164ba1f516a9a2334fa7986adacfa73ca9eda Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:48:29 +0100 Subject: [PATCH 031/167] refactor: extract default config for reusability --- HAL/avr/avr_usb/include/config_defaults.hpp | 127 ++++++++++++++++++++ config/htangl_v1/config.cpp | 120 +----------------- 2 files changed, 131 insertions(+), 116 deletions(-) create mode 100644 HAL/avr/avr_usb/include/config_defaults.hpp diff --git a/HAL/avr/avr_usb/include/config_defaults.hpp b/HAL/avr/avr_usb/include/config_defaults.hpp new file mode 100644 index 00000000..341def16 --- /dev/null +++ b/HAL/avr/avr_usb/include/config_defaults.hpp @@ -0,0 +1,127 @@ +#ifndef _CONFIG_DEFAULTS_HPP +#define _CONFIG_DEFAULTS_HPP + +#include +#include + +// clang-format off + +const Config default_config = { + .default_backend = COMMS_BACKEND_DINPUT, + .game_mode_configs_count = 5, + .game_mode_configs = new GameModeConfig[5] { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 2, + .socd_pairs = new SocdPair[2] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 1, + .button_remapping = new ButtonRemap[1] { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, + }, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, + }, + GameModeConfig { + .mode_id = MODE_KEYBOARD, + .socd_pairs_count = 2, + .socd_pairs = new SocdPair[2] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT2, BTN_MB1, BTN_LF4 }, + }, + }, + .communication_backend_configs_count = 1, + .communication_backend_configs = new CommunicationBackendConfig[1] { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RF3 }, + }, + }, + .keyboard_modes_count = 1, + .keyboard_modes = new KeyboardModeConfig[1] { + KeyboardModeConfig { + 0, + "Default", + 22, + new ButtonToKeycodeMapping[22] { + { BTN_LF4, HID_KEY_A }, + { BTN_LF3, HID_KEY_B }, + { BTN_LF2, HID_KEY_C }, + { BTN_LF1, HID_KEY_D }, + { BTN_LT1, HID_KEY_E }, + { BTN_LT2, HID_KEY_F }, + { BTN_MB3, HID_KEY_G }, + { BTN_MB1, HID_KEY_H }, + { BTN_MB2, HID_KEY_I }, + { BTN_RF5, HID_KEY_J }, + { BTN_RF6, HID_KEY_K }, + { BTN_RF7, HID_KEY_L }, + { BTN_RF8, HID_KEY_M }, + { BTN_RF1, HID_KEY_N }, + { BTN_RF2, HID_KEY_O }, + { BTN_RF3, HID_KEY_P }, + { BTN_RF4, HID_KEY_Q }, + { BTN_RT4, HID_KEY_R }, + { BTN_RT3, HID_KEY_S }, + { BTN_RT5, HID_KEY_T }, + { BTN_RT1, HID_KEY_U }, + { BTN_RT2, HID_KEY_V }, + }, + }, + }, +}; + +// clang-format on + +#endif \ No newline at end of file diff --git a/config/htangl_v1/config.cpp b/config/htangl_v1/config.cpp index 9bb2d9a8..a55a1f6f 100644 --- a/config/htangl_v1/config.cpp +++ b/config/htangl_v1/config.cpp @@ -1,4 +1,5 @@ #include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" #include "core/KeyboardMode.hpp" #include "core/mode_selection.hpp" @@ -12,6 +13,9 @@ // clang-format off +const Config config = default_config; + +/* const Config config = { .default_backend = COMMS_BACKEND_DINPUT, .game_mode_configs_count = 5, @@ -127,122 +131,6 @@ const Config config = { }, }, }; - -/* -const GameModeConfig game_mode_configs[] = { - GameModeConfig { - .mode_id = MODE_MELEE, - .socd_pairs_count = 4, - .socd_pairs = new SocdPair[4] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, - }, - GameModeConfig { - .mode_id = MODE_PROJECT_M, - .socd_pairs_count = 4, - .socd_pairs = new SocdPair[4] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, - }, - GameModeConfig { - .mode_id = MODE_ULTIMATE, - .socd_pairs_count = 4, - .socd_pairs = new SocdPair[4] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, - }, - GameModeConfig { - .mode_id = MODE_FGC, - .socd_pairs_count = 2, - .socd_pairs = new SocdPair[2] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, - }, - .button_remapping_count = 1, - .button_remapping = new ButtonRemap[1] { - ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, - }, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, - }, - GameModeConfig { - .mode_id = MODE_KEYBOARD, - .socd_pairs_count = 2, - .socd_pairs = new SocdPair[2] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT2, BTN_MB1, BTN_LF4 }, - } -}; -size_t game_mode_configs_count = sizeof(game_mode_configs) / sizeof(GameModeConfig); - -const KeyboardModeConfig keyboard_modes[] = { - KeyboardModeConfig { - 0, - "Default", - 22, - { - { BTN_LF4, HID_KEY_A }, - { BTN_LF3, HID_KEY_B }, - { BTN_LF2, HID_KEY_C }, - { BTN_LF1, HID_KEY_D }, - { BTN_LT1, HID_KEY_E }, - { BTN_LT2, HID_KEY_F }, - { BTN_MB3, HID_KEY_G }, - { BTN_MB1, HID_KEY_H }, - { BTN_MB2, HID_KEY_I }, - { BTN_RF5, HID_KEY_J }, - { BTN_RF6, HID_KEY_K }, - { BTN_RF7, HID_KEY_L }, - { BTN_RF8, HID_KEY_M }, - { BTN_RF1, HID_KEY_N }, - { BTN_RF2, HID_KEY_O }, - { BTN_RF3, HID_KEY_P }, - { BTN_RF4, HID_KEY_Q }, - { BTN_RT4, HID_KEY_R }, - { BTN_RT3, HID_KEY_S }, - { BTN_RT5, HID_KEY_T }, - { BTN_RT1, HID_KEY_U }, - { BTN_RT2, HID_KEY_V }, - }, - }, -}; -size_t keyboard_modes_count = sizeof(keyboard_modes) / sizeof(KeyboardModeConfig); - -const CommunicationBackendConfig backend_configs[] = { - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_DINPUT, - .default_mode = MODE_MELEE, - .activation_binding_count = 1, - .activation_binding = new Button[1] { BTN_RF3 }, - }, -}; -size_t backend_configs_count = sizeof(backend_configs) / sizeof(CommunicationBackendConfig); */ // clang-format on From 4afed5eddcebb636c3b0892f35e5f2e713e9d9c7 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:51:42 +0100 Subject: [PATCH 032/167] feat: add config for MODE_KEYBOARD in pico config --- config/pico/config.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 7b98cac4..aefb278b 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -14,7 +14,7 @@ Config config = { .default_backend = COMMS_BACKEND_XINPUT, - .game_mode_configs_count = 4, + .game_mode_configs_count = 5, .game_mode_configs = { GameModeConfig { .mode_id = MODE_MELEE, @@ -69,6 +69,17 @@ Config config = { .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, }, + GameModeConfig { + .mode_id = MODE_KEYBOARD, + .socd_pairs_count = 2, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_LT2, BTN_MB1, BTN_LF4 }, + }, }, .communication_backend_configs_count = 3, .communication_backend_configs = { From df90428353842aa787f5100ac29dfcab868a12b7 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:54:39 +0100 Subject: [PATCH 033/167] refactor: extract Pico default config for reusability --- HAL/pico/include/config_defaults.hpp | 134 +++++++++++++++++++++++++++ config/pico/config.cpp | 124 +------------------------ 2 files changed, 136 insertions(+), 122 deletions(-) create mode 100644 HAL/pico/include/config_defaults.hpp diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp new file mode 100644 index 00000000..cc30ab71 --- /dev/null +++ b/HAL/pico/include/config_defaults.hpp @@ -0,0 +1,134 @@ +#ifndef _CONFIG_DEFAULTS_HPP +#define _CONFIG_DEFAULTS_HPP + +#include +#include + +// clang-format off + +const Config default_config = { + .default_backend = COMMS_BACKEND_XINPUT, + .game_mode_configs_count = 5, + .game_mode_configs = { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF3 }, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF2 }, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 2, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 1, + .button_remapping = { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, + }, + .activation_binding_count = 3, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, + }, + GameModeConfig { + .mode_id = MODE_KEYBOARD, + .socd_pairs_count = 2, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_LT2, BTN_MB1, BTN_LF4 }, + }, + }, + .communication_backend_configs_count = 3, + .communication_backend_configs = { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_XINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 0, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode = MODE_MELEE, + .activation_binding_count = 1, + .activation_binding = { BTN_RF3 }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_CONFIGURATOR, + .default_mode = MODE_UNSPECIFIED, + .activation_binding_count = 1, + .activation_binding = { BTN_RT2 }, + } + }, + .keyboard_modes_count = 1, + .keyboard_modes = { + KeyboardModeConfig { + 0, + "Default", + 22, + { + { BTN_LF4, HID_KEY_A }, + { BTN_LF3, HID_KEY_B }, + { BTN_LF2, HID_KEY_C }, + { BTN_LF1, HID_KEY_D }, + { BTN_LT1, HID_KEY_E }, + { BTN_LT2, HID_KEY_F }, + { BTN_MB3, HID_KEY_G }, + { BTN_MB1, HID_KEY_H }, + { BTN_MB2, HID_KEY_I }, + { BTN_RF5, HID_KEY_J }, + { BTN_RF6, HID_KEY_K }, + { BTN_RF7, HID_KEY_L }, + { BTN_RF8, HID_KEY_M }, + { BTN_RF1, HID_KEY_N }, + { BTN_RF2, HID_KEY_O }, + { BTN_RF3, HID_KEY_P }, + { BTN_RF4, HID_KEY_Q }, + { BTN_RT4, HID_KEY_R }, + { BTN_RT3, HID_KEY_S }, + { BTN_RT5, HID_KEY_T }, + { BTN_RT1, HID_KEY_U }, + { BTN_RT2, HID_KEY_V }, + }, + }, + }, +}; + +// clang-format on + +#endif \ No newline at end of file diff --git a/config/pico/config.cpp b/config/pico/config.cpp index aefb278b..5854aa23 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -11,129 +11,9 @@ #include "stdlib.hpp" #include +#include -Config config = { - .default_backend = COMMS_BACKEND_XINPUT, - .game_mode_configs_count = 5, - .game_mode_configs = { - GameModeConfig { - .mode_id = MODE_MELEE, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, - }, - GameModeConfig { - .mode_id = MODE_PROJECT_M, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF3 }, - }, - GameModeConfig { - .mode_id = MODE_ULTIMATE, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF2 }, - }, - GameModeConfig { - .mode_id = MODE_FGC, - .socd_pairs_count = 2, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, - }, - .button_remapping_count = 1, - .button_remapping = { - ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, - }, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, - }, - GameModeConfig { - .mode_id = MODE_KEYBOARD, - .socd_pairs_count = 2, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .activation_binding_count = 3, - .activation_binding = { BTN_LT2, BTN_MB1, BTN_LF4 }, - }, - }, - .communication_backend_configs_count = 3, - .communication_backend_configs = { - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_XINPUT, - .default_mode = MODE_MELEE, - .activation_binding_count = 0, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_DINPUT, - .default_mode = MODE_MELEE, - .activation_binding_count = 1, - .activation_binding = { BTN_RF3 }, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_CONFIGURATOR, - .default_mode = MODE_UNSPECIFIED, - .activation_binding_count = 1, - .activation_binding = { BTN_RT2 }, - } - }, - .keyboard_modes_count = 1, - .keyboard_modes = { - KeyboardModeConfig { - 0, - "Default", - 22, - { - { BTN_LF4, HID_KEY_A }, - { BTN_LF3, HID_KEY_B }, - { BTN_LF2, HID_KEY_C }, - { BTN_LF1, HID_KEY_D }, - { BTN_LT1, HID_KEY_E }, - { BTN_LT2, HID_KEY_F }, - { BTN_MB3, HID_KEY_G }, - { BTN_MB1, HID_KEY_H }, - { BTN_MB2, HID_KEY_I }, - { BTN_RF5, HID_KEY_J }, - { BTN_RF6, HID_KEY_K }, - { BTN_RF7, HID_KEY_L }, - { BTN_RF8, HID_KEY_M }, - { BTN_RF1, HID_KEY_N }, - { BTN_RF2, HID_KEY_O }, - { BTN_RF3, HID_KEY_P }, - { BTN_RF4, HID_KEY_Q }, - { BTN_RT4, HID_KEY_R }, - { BTN_RT3, HID_KEY_S }, - { BTN_RT5, HID_KEY_T }, - { BTN_RT1, HID_KEY_U }, - { BTN_RT2, HID_KEY_V }, - }, - }, - }, -}; +Config config = default_config; GpioButtonMapping button_mappings[] = { {BTN_LF1, 2 }, From 29c8d101a99987ed04b96612a0bf177419ba2c8b Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:55:11 +0100 Subject: [PATCH 034/167] build: move Persistence dependencies to arduino_pico_base --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 59ddcc67..1977ecd0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -23,8 +23,6 @@ custom_nanopb_options = lib_deps = https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip git+git@github.com:JonnyHaystack/HayBox-proto#414231a - eric-wieser/PacketIO@^0.3.0 - bakercp/CRC32@^2.0.0 [avr_base] platform = atmelavr @@ -113,4 +111,6 @@ lib_deps = https://github.com/JonnyHaystack/joybus-pio/archive/refs/tags/v1.2.3.zip https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput + eric-wieser/PacketIO@^0.3.0 + bakercp/CRC32@^2.0.0 TUCompositeHID From 70663403ca791dd1917874eca8853c193248651a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:59:17 +0100 Subject: [PATCH 035/167] refactor: move Persistence to Pico HAL --- {include => HAL/pico/include}/core/Persistence.hpp | 0 {src => HAL/pico/src}/core/Persistence.cpp | 6 ------ 2 files changed, 6 deletions(-) rename {include => HAL/pico/include}/core/Persistence.hpp (100%) rename {src => HAL/pico/src}/core/Persistence.cpp (96%) diff --git a/include/core/Persistence.hpp b/HAL/pico/include/core/Persistence.hpp similarity index 100% rename from include/core/Persistence.hpp rename to HAL/pico/include/core/Persistence.hpp diff --git a/src/core/Persistence.cpp b/HAL/pico/src/core/Persistence.cpp similarity index 96% rename from src/core/Persistence.cpp rename to HAL/pico/src/core/Persistence.cpp index d48ce2c3..f7137b6d 100644 --- a/src/core/Persistence.cpp +++ b/HAL/pico/src/core/Persistence.cpp @@ -28,11 +28,7 @@ Config Persistence::_config; uint8_t Persistence::_buffer[eeprom_size - config_offset]; Persistence::Persistence() { -#ifdef ARDUINO_PICO_REVISION - EEPROM.begin(eeprom_size); -#else EEPROM.begin(); -#endif } Persistence::~Persistence() { @@ -58,9 +54,7 @@ bool Persistence::SaveConfig(Config &config) { for (size_t i = 0; i < header.config_size; i++) { EEPROM.write(config_offset + i, _buffer[i]); } -#ifdef ARDUINO_PICO_REVISION EEPROM.commit(); -#endif return true; } From b5d455e8aba2a037a40fedea1e7ab8c50f4485c7 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 22:59:37 +0100 Subject: [PATCH 036/167] feat: add config defaults for avr_nousb --- HAL/avr/avr_nousb/include/config_defaults.hpp | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 HAL/avr/avr_nousb/include/config_defaults.hpp diff --git a/HAL/avr/avr_nousb/include/config_defaults.hpp b/HAL/avr/avr_nousb/include/config_defaults.hpp new file mode 100644 index 00000000..8668191f --- /dev/null +++ b/HAL/avr/avr_nousb/include/config_defaults.hpp @@ -0,0 +1,85 @@ +#ifndef _CONFIG_DEFAULTS_HPP +#define _CONFIG_DEFAULTS_HPP + +#include +#include + +// clang-format off + +const Config default_config = { + .default_backend = COMMS_BACKEND_DINPUT, + .game_mode_configs_count = 4, + .game_mode_configs = new GameModeConfig[4] { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = new SocdPair[4] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .button_remapping = {}, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 2, + .socd_pairs = new SocdPair[2] { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 1, + .button_remapping = new ButtonRemap[1] { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, + }, + .activation_binding_count = 3, + .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, + }, + }, + .communication_backend_configs_count = 1, + .communication_backend_configs = new CommunicationBackendConfig[1] { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_GAMECUBE, + .default_mode = MODE_MELEE, + .activation_binding_count = 0, + .activation_binding = {}, + }, + }, + .keyboard_modes_count = 0, + .keyboard_modes = {}, +}; + +// clang-format on + +#endif \ No newline at end of file From c58477e95c96c2ad7336092da4131dc981de4f38 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 23:09:50 +0100 Subject: [PATCH 037/167] refactor: move ConfiguratorBackend to Pico HAL --- {include => HAL/pico/include}/comms/ConfiguratorBackend.hpp | 0 {src => HAL/pico/src}/comms/ConfiguratorBackend.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {include => HAL/pico/include}/comms/ConfiguratorBackend.hpp (100%) rename {src => HAL/pico/src}/comms/ConfiguratorBackend.cpp (100%) diff --git a/include/comms/ConfiguratorBackend.hpp b/HAL/pico/include/comms/ConfiguratorBackend.hpp similarity index 100% rename from include/comms/ConfiguratorBackend.hpp rename to HAL/pico/include/comms/ConfiguratorBackend.hpp diff --git a/src/comms/ConfiguratorBackend.cpp b/HAL/pico/src/comms/ConfiguratorBackend.cpp similarity index 100% rename from src/comms/ConfiguratorBackend.cpp rename to HAL/pico/src/comms/ConfiguratorBackend.cpp From 2fd72e98a6f289b892888c50fb9d1ff51380a3b3 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 21 Oct 2023 23:15:54 +0100 Subject: [PATCH 038/167] fix: add back missing argument to EEPROM.begin() --- HAL/pico/src/core/Persistence.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HAL/pico/src/core/Persistence.cpp b/HAL/pico/src/core/Persistence.cpp index f7137b6d..6825485f 100644 --- a/HAL/pico/src/core/Persistence.cpp +++ b/HAL/pico/src/core/Persistence.cpp @@ -28,7 +28,7 @@ Config Persistence::_config; uint8_t Persistence::_buffer[eeprom_size - config_offset]; Persistence::Persistence() { - EEPROM.begin(); + EEPROM.begin(eeprom_size); } Persistence::~Persistence() { From d2839c5903b08222994bd489f3a63f150efebdca Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 22 Oct 2023 16:56:16 +0100 Subject: [PATCH 039/167] fix: Pico config incorrect button names in pinout --- config/pico/config.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 5854aa23..82921077 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -39,10 +39,10 @@ GpioButtonMapping button_mappings[] = { { BTN_RF3, 19}, { BTN_RF4, 17}, - { BTN_RT5, 27}, - { BTN_RT6, 22}, - { BTN_RT7, 20}, - { BTN_RT8, 18}, + { BTN_RF5, 27}, + { BTN_RF6, 22}, + { BTN_RF7, 20}, + { BTN_RF8, 18}, }; size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); From 5687c9dda436959c5618a7e0b0030fdafdc12398 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 26 Oct 2023 03:08:00 +0100 Subject: [PATCH 040/167] fix: revert back to manually specified mode activation masks array length to fix issue when using dynamic memory allocation --- src/core/mode_selection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 0e127b93..32eb88ca 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -11,7 +11,7 @@ #include -uint64_t mode_activation_masks[sizeof(Config::game_mode_configs) / sizeof(GameModeConfig)]; +uint64_t mode_activation_masks[10]; size_t current_mode_index = SIZE_MAX; From bc0b16da34d905da8e0ce3027d76a0b96aed74e3 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 11 Nov 2023 14:49:56 +0000 Subject: [PATCH 041/167] refactor: use array indices instead of enum values for mode and backend IDs --- .../avr_nousb/include/comms/backend_init.hpp | 14 +++++-- .../avr_usb/include/comms/backend_init.hpp | 18 ++++---- HAL/avr/avr_usb/include/config_defaults.hpp | 5 ++- HAL/avr/avr_usb/src/comms/backend_init.cpp | 41 +++++++++---------- HAL/avr/proto/config.options | 6 +-- HAL/pico/include/config_defaults.hpp | 24 ++++++++--- config/htangl_v1/config.cpp | 15 +------ config/pico/config.cpp | 2 +- include/core/config_utils.hpp | 6 +++ platformio.ini | 2 +- src/core/config_utils.cpp | 19 ++++++++- src/core/mode_selection.cpp | 9 +++- 12 files changed, 99 insertions(+), 62 deletions(-) diff --git a/HAL/avr/avr_nousb/include/comms/backend_init.hpp b/HAL/avr/avr_nousb/include/comms/backend_init.hpp index 02099334..0d778251 100644 --- a/HAL/avr/avr_nousb/include/comms/backend_init.hpp +++ b/HAL/avr/avr_nousb/include/comms/backend_init.hpp @@ -12,22 +12,28 @@ * @brief Initialize the backends array and return the number of elements in the array * * @param backends The reference to assign to the created backends array - * @param backend_config The selected backend config that we want to map to an array of - * communication backends * @param inputs Reference to the InputState struct to pass into each backend's constructor * @param input_sources Input sources array to pass into each backend's constructor * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct * @param pinout Pinout struct used for GameCube/N64 communication backends - * @param config Reference to global config struct, to be used by ConfiguratorBackend * @return size_t The number of backends in the array */ size_t initialize_backends( CommunicationBackend **&backends, - const CommunicationBackendConfig &backend_config, InputState &inputs, InputSource **input_sources, size_t input_source_count, + const Config &config, const Pinout &pinout ); +bool initialize_backends_custom( + CommunicationBackend **&backends, + InputSource **input_sources, + size_t input_source_count +) __attribute__((weak)); + +void select_backend_custom(CommunicationBackendConfig &backend_config) __attribute__((weak)); + #endif \ No newline at end of file diff --git a/HAL/avr/avr_usb/include/comms/backend_init.hpp b/HAL/avr/avr_usb/include/comms/backend_init.hpp index ff6ad3df..0d778251 100644 --- a/HAL/avr/avr_usb/include/comms/backend_init.hpp +++ b/HAL/avr/avr_usb/include/comms/backend_init.hpp @@ -15,8 +15,7 @@ * @param inputs Reference to the InputState struct to pass into each backend's constructor * @param input_sources Input sources array to pass into each backend's constructor * @param input_source_count Number of elements in the input_sources array - * @param backend_configs Array of backend configs to select from - * @param backend_configs_count Number of elements in the backend_configs array + * @param config Reference to global config struct * @param pinout Pinout struct used for GameCube/N64 communication backends * @return size_t The number of backends in the array */ @@ -25,13 +24,16 @@ size_t initialize_backends( InputState &inputs, InputSource **input_sources, size_t input_source_count, - const CommunicationBackendConfig *backend_configs, - size_t backend_configs_count, - const GameModeConfig *game_mode_configs, - size_t game_mode_configs_count, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count, + const Config &config, const Pinout &pinout ); +bool initialize_backends_custom( + CommunicationBackend **&backends, + InputSource **input_sources, + size_t input_source_count +) __attribute__((weak)); + +void select_backend_custom(CommunicationBackendConfig &backend_config) __attribute__((weak)); + #endif \ No newline at end of file diff --git a/HAL/avr/avr_usb/include/config_defaults.hpp b/HAL/avr/avr_usb/include/config_defaults.hpp index 341def16..c1a45352 100644 --- a/HAL/avr/avr_usb/include/config_defaults.hpp +++ b/HAL/avr/avr_usb/include/config_defaults.hpp @@ -7,7 +7,7 @@ // clang-format off const Config default_config = { - .default_backend = COMMS_BACKEND_DINPUT, + .default_backend_config = 1, .game_mode_configs_count = 5, .game_mode_configs = new GameModeConfig[5] { GameModeConfig { @@ -77,13 +77,14 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT2, BTN_MB1, BTN_LF4 }, + .keyboard_mode_config = 1, }, }, .communication_backend_configs_count = 1, .communication_backend_configs = new CommunicationBackendConfig[1] { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_DINPUT, - .default_mode = MODE_MELEE, + .default_mode_config = 1, .activation_binding_count = 1, .activation_binding = new Button[1] { BTN_RF3 }, }, diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp index 3a82b928..405541ac 100644 --- a/HAL/avr/avr_usb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -17,23 +17,28 @@ size_t initialize_backends( InputState &inputs, InputSource **input_sources, size_t input_source_count, - const CommunicationBackendConfig *backend_configs, - size_t backend_configs_count, - const GameModeConfig *game_mode_configs, - size_t game_mode_configs_count, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count, + const Config &config, const Pinout &pinout ) { CommunicationBackend *primary_backend = nullptr; - CommunicationBackendConfig backend_config = - backend_config_from_buttons(inputs, backend_configs, backend_configs_count); + CommunicationBackendConfig backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { primary_backend = new DInputBackend(inputs, input_sources, input_source_count); CommunicationBackendId detected_backend_id = detect_console(pinout); - backend_config = - backend_config_from_id(detected_backend_id, backend_configs, backend_configs_count); + backend_config = backend_config_from_id( + detected_backend_id, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + } + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED && + config.default_backend_config > 0) { + backend_config = config.communication_backend_configs[config.default_backend_config - 1]; } size_t backend_count; @@ -67,19 +72,11 @@ size_t initialize_backends( break; } - GameModeId mode_id = backend_config.default_mode; - if (backend_config.default_mode == MODE_UNSPECIFIED) { - mode_id = MODE_MELEE; + if (backend_config.default_mode_config > 0) { + const GameModeConfig &mode_config = + config.game_mode_configs[backend_config.default_mode_config - 1]; + set_mode(primary_backend, mode_config, config.keyboard_modes, config.keyboard_modes_count); } - set_mode( - primary_backend, - mode_id, - game_mode_configs, - game_mode_configs_count, - keyboard_modes, - keyboard_modes_count - ); - return backend_count; } \ No newline at end of file diff --git a/HAL/avr/proto/config.options b/HAL/avr/proto/config.options index a3e87485..5d544304 100644 --- a/HAL/avr/proto/config.options +++ b/HAL/avr/proto/config.options @@ -15,7 +15,7 @@ GameModeConfig.button_remapping max_count:60 GameModeConfig.button_remapping type:FT_POINTER GameModeConfig.activation_binding max_count:4 GameModeConfig.activation_binding type:FT_POINTER -GameModeConfig.keyboard_mode_id int_size:IS_8 +GameModeConfig.keyboard_mode_config int_size:IS_8 KeyboardModeConfig.id int_size:IS_8 KeyboardModeConfig.name max_length:20 @@ -23,11 +23,11 @@ KeyboardModeConfig.buttons_to_keycodes max_count:60 KeyboardModeConfig.buttons_to_keycodes type:FT_POINTER CommunicationBackendConfig.backend_id int_size:IS_8 -CommunicationBackendConfig.default_mode int_size:IS_8 +CommunicationBackendConfig.default_mode_config int_size:IS_8 CommunicationBackendConfig.activation_binding max_count:2 CommunicationBackendConfig.activation_binding type:FT_POINTER -Config.default_backend int_size:IS_8 +Config.default_backend_config int_size:IS_8 Config.game_mode_configs max_count:10 Config.game_mode_configs type:FT_POINTER Config.communication_backend_configs max_count:10 diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index cc30ab71..44ad19a8 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -7,7 +7,6 @@ // clang-format off const Config default_config = { - .default_backend = COMMS_BACKEND_XINPUT, .game_mode_configs_count = 5, .game_mode_configs = { GameModeConfig { @@ -73,24 +72,37 @@ const Config default_config = { .button_remapping_count = 0, .activation_binding_count = 3, .activation_binding = { BTN_LT2, BTN_MB1, BTN_LF4 }, + .keyboard_mode_config = 1, }, }, .communication_backend_configs_count = 3, .communication_backend_configs = { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_XINPUT, - .default_mode = MODE_MELEE, - .activation_binding_count = 0, + .default_mode_config = 1, }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_DINPUT, - .default_mode = MODE_MELEE, + .default_mode_config = 5, .activation_binding_count = 1, .activation_binding = { BTN_RF3 }, }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_NINTENDO_SWITCH, + .default_mode_config = 3, + .activation_binding_count = 1, + .activation_binding = { BTN_RF2 }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_GAMECUBE, + .default_mode_config = 1, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_N64, + .default_mode_config = 1, + }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_CONFIGURATOR, - .default_mode = MODE_UNSPECIFIED, .activation_binding_count = 1, .activation_binding = { BTN_RT2 }, } @@ -127,6 +139,8 @@ const Config default_config = { }, }, }, + .default_backend_config = 1, + .default_usb_backend_config = 1, }; // clang-format on diff --git a/config/htangl_v1/config.cpp b/config/htangl_v1/config.cpp index a55a1f6f..1e7f15d2 100644 --- a/config/htangl_v1/config.cpp +++ b/config/htangl_v1/config.cpp @@ -194,19 +194,8 @@ void setup() { static InputSource *input_sources[] = { &gpio_input }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - backend_count = initialize_backends( - backends, - inputs, - input_sources, - input_source_count, - config.communication_backend_configs, - config.communication_backend_configs_count, - config.game_mode_configs, - config.game_mode_configs_count, - config.keyboard_modes, - config.keyboard_modes_count, - pinout - ); + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 82921077..9d428439 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -1,4 +1,5 @@ #include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" #include "core/KeyboardMode.hpp" #include "core/Persistence.hpp" @@ -11,7 +12,6 @@ #include "stdlib.hpp" #include -#include Config config = default_config; diff --git a/include/core/config_utils.hpp b/include/core/config_utils.hpp index 643d6294..7fc1e161 100644 --- a/include/core/config_utils.hpp +++ b/include/core/config_utils.hpp @@ -17,4 +17,10 @@ CommunicationBackendConfig backend_config_from_id( size_t backend_configs_count ); +uint8_t mode_config_id_from_mode_id( + GameModeId mode_id, + const GameModeConfig *mode_configs, + size_t mode_configs_count +); + #endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 1977ecd0..fe990ed8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip - git+git@github.com:JonnyHaystack/HayBox-proto#414231a + git+git@github.com:JonnyHaystack/HayBox-proto#3be8d12 [avr_base] platform = atmelavr diff --git a/src/core/config_utils.cpp b/src/core/config_utils.cpp index defeef2c..59841deb 100644 --- a/src/core/config_utils.cpp +++ b/src/core/config_utils.cpp @@ -26,7 +26,7 @@ CommunicationBackendConfig backend_config_from_buttons( return CommunicationBackendConfig{ .backend_id = COMMS_BACKEND_UNSPECIFIED, - .default_mode = MODE_UNSPECIFIED, + .default_mode_config = 0, }; } @@ -46,6 +46,21 @@ CommunicationBackendConfig backend_config_from_id( return CommunicationBackendConfig{ .backend_id = backend_id, - .default_mode = MODE_UNSPECIFIED, + .default_mode_config = 0, }; +} + +uint8_t mode_config_id_from_mode_id( + GameModeId mode_id, + const GameModeConfig *mode_configs, + size_t mode_configs_count +) { + for (size_t i = 0; i < mode_configs_count; i++) { + const GameModeConfig &mode = mode_configs[i]; + if (mode.mode_id == mode_id) { + return i + 1; + } + } + + return 0; } \ No newline at end of file diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 32eb88ca..d9dc3f6f 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -63,9 +63,16 @@ void set_mode( set_mode(backend, new RivalsOfAether(mode_config)); break; case MODE_KEYBOARD: + if (mode_config.keyboard_mode_config < 1 || + mode_config.keyboard_mode_config > keyboard_modes_count) { + break; + } set_mode( backend, - new CustomKeyboardMode(mode_config, keyboard_modes[mode_config.keyboard_mode_id]) + new CustomKeyboardMode( + mode_config, + keyboard_modes[mode_config.keyboard_mode_config - 1] + ) ); break; case MODE_UNSPECIFIED: From 279b2028e78f7925b219db575226eaa7f5552607 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 11 Nov 2023 15:36:50 +0000 Subject: [PATCH 042/167] feat: making backend initialization stuff overridable --- HAL/pico/include/comms/backend_init.hpp | 128 ++++++++++++++++++- HAL/pico/src/comms/backend_init.cpp | 158 +++++++++++++++++------- 2 files changed, 239 insertions(+), 47 deletions(-) diff --git a/HAL/pico/include/comms/backend_init.hpp b/HAL/pico/include/comms/backend_init.hpp index e40017d4..6779d22a 100644 --- a/HAL/pico/include/comms/backend_init.hpp +++ b/HAL/pico/include/comms/backend_init.hpp @@ -17,7 +17,7 @@ * @param input_source_count Number of elements in the input_sources array * @param config Reference to global config struct * @param pinout Pinout struct used for GameCube/N64 communication backends - * @return size_t The number of backends in the array + * @return The number of backends in the array */ size_t initialize_backends( CommunicationBackend **&backends, @@ -28,4 +28,130 @@ size_t initialize_backends( const Pinout &pinout ); +/** + * @brief Optionally defined function that allows a device config to hook into initialize_backends() + * and use a custom method for selecting backend config before console detection + * + * @param backend_config The reference to the current backend config after checking for button holds + * and connected console + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param config Reference to the global Config struct + * @return true if the passed in backend config was altered, otherwise false + */ +bool backend_config_custom( + CommunicationBackendConfig &backend_config, + const InputState &inputs, + const Config &config +) __attribute__((weak)); + +/** + * @brief Optionally defined function that allows a device config to hook into initialize_backends() + * and use a custom method for selecting the default USB communication backend to initialize prior + * to console/USB detection + * + * @param backend_config The reference to the current backend config after checking for button holds + * and connected console + * @param config Reference to the global Config struct + * @return true if the passed in backend config was altered, otherwise false + */ +bool usb_backend_config_custom(CommunicationBackendConfig &backend_config, const Config &config) + __attribute__((weak)); + +void detect_console_custom(Pinout &pinout); + +/** + * @brief Initialize primary backend based on the passed in backend id + * + * @param primary_backend The reference to the primary backend pointer to initialize + * @param backend_id The id of the backend to initialize + * @param backends The reference to assign to the created backends array + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct + * @param pinout Pinout struct used for GameCube/N64 communication backends + */ +void init_primary_backend( + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +); + +/** + * @brief Optionally defined function that allows a device config to hook into initialize_backends() + * and override initialization of primary backend + * + * @param primary_backend The reference to the primary backend pointer to initialize + * @param backend_id The id of the backend to initialize + * @param backends The reference to assign to the created backends array + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct + * @param pinout Pinout struct used for GameCube/N64 communication backends + */ +void init_primary_backend_custom( + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) __attribute__((weak)); + +/** + * @brief Initialize secondary backends and the backends array and return the number of elements in + * the array + * + * @param backends The reference to assign to the created backends array + * @param primary_backend The reference to the primary backend to insert first in the backends array + * @param backend_id The id indicating the primary backend + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct + * @param pinout Pinout struct used for GameCube/N64 communication backends + * @return The number of backends in the array + */ +size_t init_secondary_backends( + CommunicationBackend **&backends, + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +); + +/** + * @brief Optionally defined function that allows a device config to hook into initialize_backends() + * and override initialization of secondary backends + * + * @param backends The reference to assign to the created backends array + * @param primary_backend The reference to the primary backend to insert first in the backends array + * @param backend_id The id indicating the primary backend + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct + * @param pinout Pinout struct used for GameCube/N64 communication backends + * @return The number of backends in the array + */ +size_t init_secondary_backends_custom( + CommunicationBackend **&backends, + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) __attribute__((weak)); + #endif \ No newline at end of file diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index b6a27ff8..3d94191f 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -27,62 +27,119 @@ size_t initialize_backends( ) { CommunicationBackend *primary_backend = nullptr; + /* First check button holds for a matching comms backend config. */ CommunicationBackendConfig backend_config = backend_config_from_buttons( inputs, config.communication_backend_configs, config.communication_backend_configs_count ); + + // TODO: weakly defined backend_config_custom() + + /* If no match found for button hold, use console/USB detection to select backend instead. */ if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { - primary_backend = new XInputBackend(inputs, input_sources, input_source_count); - CommunicationBackendId detected_backend_id = detect_console(pinout); - backend_config = backend_config_from_id( - detected_backend_id, - config.communication_backend_configs, - config.communication_backend_configs_count + /* Must check default USB backend here and initialize it before console detection, so that + * we can respond correctly to device descriptor requests from host. */ + const CommunicationBackendConfig &usb_backend_config = + config.communication_backend_configs[config.default_usb_backend_config - 1]; + // TODO: weakly defined usb_backend_config_custom() + init_primary_backend( + primary_backend, + usb_backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout ); + // TODO: weakly defined detect_console_custom() + CommunicationBackendId detected_backend_id = detect_console(pinout); + if (detected_backend_id == COMMS_BACKEND_XINPUT) { + backend_config = usb_backend_config; + } else { + backend_config = backend_config_from_id( + detected_backend_id, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + } + } + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED && + config.default_backend_config > 0) { + backend_config = config.communication_backend_configs[config.default_backend_config - 1]; } size_t backend_count; - switch (backend_config.backend_id) { + // TODO: weakly defined init_primary_backend_custom() + init_primary_backend( + primary_backend, + backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); + // TODO: weakly defined init_secondary_backends_custom() + backend_count = init_secondary_backends( + backends, + primary_backend, + backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); + + if (backend_config.default_mode_config > 0) { + const GameModeConfig &mode_config = + config.game_mode_configs[backend_config.default_mode_config - 1]; + set_mode(primary_backend, mode_config, config.keyboard_modes, config.keyboard_modes_count); + } + + return backend_count; +} + +void init_primary_backend( + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + switch (backend_id) { case COMMS_BACKEND_DINPUT: - delete primary_backend; - TUGamepad::registerDescriptor(); - TUKeyboard::registerDescriptor(); - primary_backend = new DInputBackend(inputs, input_sources, input_source_count); - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) - }; + if (primary_backend == nullptr) { + TUGamepad::registerDescriptor(); + TUKeyboard::registerDescriptor(); + primary_backend = new DInputBackend(inputs, input_sources, input_source_count); + } + break; + case COMMS_BACKEND_NINTENDO_SWITCH: + if (primary_backend == nullptr) { + NintendoSwitchBackend::RegisterDescriptor(); + primary_backend = + new NintendoSwitchBackend(inputs, input_sources, input_source_count); + } break; case COMMS_BACKEND_XINPUT: - // delete primary_backend; - // primary_backend = new XInputBackend(inputs, input_sources, input_source_count); - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) - }; + if (primary_backend == nullptr) { + primary_backend = new XInputBackend(inputs, input_sources, input_source_count); + } break; case COMMS_BACKEND_GAMECUBE: delete primary_backend; primary_backend = new GamecubeBackend(inputs, input_sources, input_source_count, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; break; case COMMS_BACKEND_N64: delete primary_backend; primary_backend = new N64Backend(inputs, input_sources, input_source_count, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - break; - case COMMS_BACKEND_NINTENDO_SWITCH: - delete primary_backend; - NintendoSwitchBackend::RegisterDescriptor(); - primary_backend = new NintendoSwitchBackend(inputs, input_sources, input_source_count); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; break; case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. case COMMS_BACKEND_CONFIGURATOR: @@ -90,23 +147,32 @@ size_t initialize_backends( delete primary_backend; primary_backend = new ConfiguratorBackend(inputs, input_sources, input_source_count, config); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; } +} - GameModeId mode_id = backend_config.default_mode; - if (backend_config.default_mode == MODE_UNSPECIFIED) { - mode_id = MODE_MELEE; - } +size_t init_secondary_backends( + CommunicationBackend **&backends, + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + size_t backend_count = 0; - set_mode( - primary_backend, - mode_id, - config.game_mode_configs, - config.game_mode_configs_count, - config.keyboard_modes, - config.keyboard_modes_count - ); + switch (backend_id) { + case COMMS_BACKEND_DINPUT: + case COMMS_BACKEND_XINPUT: + backend_count = 2; + backends = new CommunicationBackend *[backend_count] { + primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) + }; + default: + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; + } return backend_count; } \ No newline at end of file From 596d2b2ffc285f446bb4073d3de922828526b18f Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 11 Nov 2023 15:37:33 +0000 Subject: [PATCH 043/167] fix: remove HandleSocd override from RocketLeague mode --- include/modes/extra/RocketLeague.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/modes/extra/RocketLeague.hpp b/include/modes/extra/RocketLeague.hpp index 2356b977..615bafdc 100644 --- a/include/modes/extra/RocketLeague.hpp +++ b/include/modes/extra/RocketLeague.hpp @@ -10,7 +10,6 @@ class RocketLeague : public ControllerMode { RocketLeague(const GameModeConfig &config); private: - void HandleSocd(InputState &inputs); void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); }; From 71f100558b8987625b2bce84984bcd56c8947b49 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 11 Nov 2023 15:38:30 +0000 Subject: [PATCH 044/167] feat: add array bound checks for set config command --- HAL/pico/src/comms/ConfiguratorBackend.cpp | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/HAL/pico/src/comms/ConfiguratorBackend.cpp b/HAL/pico/src/comms/ConfiguratorBackend.cpp index 85d2e73f..8216e03e 100644 --- a/HAL/pico/src/comms/ConfiguratorBackend.cpp +++ b/HAL/pico/src/comms/ConfiguratorBackend.cpp @@ -134,6 +134,53 @@ bool ConfiguratorBackend::HandleSetConfig(uint8_t *buffer, size_t len) { return false; } + if (_config.default_backend_config > _config.communication_backend_configs_count) { + char errmsg[75]; + size_t errmsg_len = snprintf( + errmsg, + sizeof(errmsg), + "Default backend ID is %d but only %d backend configs are defined", + (uint8_t)_config.default_backend_config, + (uint8_t)_config.communication_backend_configs_count + ); + WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); + return false; + } + + for (size_t i = 0; i < _config.communication_backend_configs_count; i++) { + uint8_t default_mode_id = _config.communication_backend_configs[i].default_mode_config; + if (default_mode_id > _config.game_mode_configs_count) { + char errmsg[75]; + size_t errmsg_len = snprintf( + errmsg, + sizeof(errmsg), + "Default mode ID is %d for backend %d but only %d modes are defined", + (uint8_t)default_mode_id, + (uint8_t)i + 1, + (uint8_t)_config.game_mode_configs_count + ); + WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); + return false; + } + } + + for (size_t i = 0; i < _config.game_mode_configs_count; i++) { + uint8_t keyboard_mode_id = _config.game_mode_configs[i].keyboard_mode_config; + if (keyboard_mode_id > _config.keyboard_modes_count) { + char errmsg[85]; + size_t errmsg_len = snprintf( + errmsg, + sizeof(errmsg), + "Keyboard mode ID %d is for game mode %d but only %d keyboard modes are defined", + (uint8_t)keyboard_mode_id, + (uint8_t)i + 1, + (uint8_t)_config.keyboard_modes_count + ); + WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); + return false; + } + } + if (!_persistence->SaveConfig(_config)) { char errmsg[] = "Failed to save config to memory"; WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); From 7b1520a48f7b0f58f5dd5a12650ac686d4f25aa2 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 11 Nov 2023 17:21:42 +0000 Subject: [PATCH 045/167] refactor: improve backend init overriding --- HAL/avr/proto/config.options | 3 +- HAL/pico/include/comms/backend_init.hpp | 88 ++++++++----------------- HAL/pico/src/comms/backend_init.cpp | 76 ++++++++++++++------- platformio.ini | 2 +- 4 files changed, 85 insertions(+), 84 deletions(-) diff --git a/HAL/avr/proto/config.options b/HAL/avr/proto/config.options index 5d544304..6d56d3ec 100644 --- a/HAL/avr/proto/config.options +++ b/HAL/avr/proto/config.options @@ -27,13 +27,14 @@ CommunicationBackendConfig.default_mode_config int_size:IS_8 CommunicationBackendConfig.activation_binding max_count:2 CommunicationBackendConfig.activation_binding type:FT_POINTER -Config.default_backend_config int_size:IS_8 Config.game_mode_configs max_count:10 Config.game_mode_configs type:FT_POINTER Config.communication_backend_configs max_count:10 Config.communication_backend_configs type:FT_POINTER Config.keyboard_modes max_count:5 Config.keyboard_modes type:FT_POINTER +Config.default_backend_config int_size:IS_8 +Config.default_usb_backend_config int_size:IS_8 DeviceInfo.firmware_name max_length:25 DeviceInfo.firmware_version max_length:8 diff --git a/HAL/pico/include/comms/backend_init.hpp b/HAL/pico/include/comms/backend_init.hpp index 6779d22a..e00ae2b5 100644 --- a/HAL/pico/include/comms/backend_init.hpp +++ b/HAL/pico/include/comms/backend_init.hpp @@ -1,6 +1,7 @@ #ifndef _COMMS_BACKEND_INIT_HPP #define _COMMS_BACKEND_INIT_HPP +#include "comms/console_detection.hpp" #include "core/CommunicationBackend.hpp" #include "core/InputSource.hpp" #include "core/pinout.hpp" @@ -8,25 +9,7 @@ #include -/** - * @brief Initialize the backends array and return the number of elements in the array - * - * @param backends The reference to assign to the created backends array - * @param inputs Reference to the InputState struct to pass into each backend's constructor - * @param input_sources Input sources array to pass into each backend's constructor - * @param input_source_count Number of elements in the input_sources array - * @param config Reference to global config struct - * @param pinout Pinout struct used for GameCube/N64 communication backends - * @return The number of backends in the array - */ -size_t initialize_backends( - CommunicationBackend **&backends, - InputState &inputs, - InputSource **input_sources, - size_t input_source_count, - Config &config, - const Pinout &pinout -); +// clang-format off /** * @brief Optionally defined function that allows a device config to hook into initialize_backends() @@ -38,11 +21,11 @@ size_t initialize_backends( * @param config Reference to the global Config struct * @return true if the passed in backend config was altered, otherwise false */ -bool backend_config_custom( +typedef void (*backend_config_selector_t)( CommunicationBackendConfig &backend_config, const InputState &inputs, const Config &config -) __attribute__((weak)); +); /** * @brief Optionally defined function that allows a device config to hook into initialize_backends() @@ -54,10 +37,12 @@ bool backend_config_custom( * @param config Reference to the global Config struct * @return true if the passed in backend config was altered, otherwise false */ -bool usb_backend_config_custom(CommunicationBackendConfig &backend_config, const Config &config) - __attribute__((weak)); - -void detect_console_custom(Pinout &pinout); +// bool usb_backend_config_custom(CommunicationBackendConfig &backend_config, const Config &config) +// __attribute__((weak)); +typedef void (*usb_backend_getter_t)( + CommunicationBackendConfig &backend_config, + const Config &config +); /** * @brief Initialize primary backend based on the passed in backend id @@ -71,7 +56,7 @@ void detect_console_custom(Pinout &pinout); * @param config Reference to global config struct * @param pinout Pinout struct used for GameCube/N64 communication backends */ -void init_primary_backend( +typedef void (*primary_backend_initializer_t)( CommunicationBackend *&primary_backend, CommunicationBackendId backend_id, InputState &inputs, @@ -81,29 +66,6 @@ void init_primary_backend( const Pinout &pinout ); -/** - * @brief Optionally defined function that allows a device config to hook into initialize_backends() - * and override initialization of primary backend - * - * @param primary_backend The reference to the primary backend pointer to initialize - * @param backend_id The id of the backend to initialize - * @param backends The reference to assign to the created backends array - * @param inputs Reference to the InputState struct to pass into each backend's constructor - * @param input_sources Input sources array to pass into each backend's constructor - * @param input_source_count Number of elements in the input_sources array - * @param config Reference to global config struct - * @param pinout Pinout struct used for GameCube/N64 communication backends - */ -void init_primary_backend_custom( - CommunicationBackend *&primary_backend, - CommunicationBackendId backend_id, - InputState &inputs, - InputSource **input_sources, - size_t input_source_count, - Config &config, - const Pinout &pinout -) __attribute__((weak)); - /** * @brief Initialize secondary backends and the backends array and return the number of elements in * the array @@ -118,7 +80,7 @@ void init_primary_backend_custom( * @param pinout Pinout struct used for GameCube/N64 communication backends * @return The number of backends in the array */ -size_t init_secondary_backends( +typedef size_t (*secondary_backend_initializer_t)( CommunicationBackend **&backends, CommunicationBackend *&primary_backend, CommunicationBackendId backend_id, @@ -129,13 +91,18 @@ size_t init_secondary_backends( const Pinout &pinout ); +typedef CommunicationBackendId (*detect_console_t)(const Pinout &pinout); + +// clang-format on + +extern usb_backend_getter_t get_usb_backend_config_default; +extern primary_backend_initializer_t init_primary_backend_default; +extern secondary_backend_initializer_t init_secondary_backends_default; + /** - * @brief Optionally defined function that allows a device config to hook into initialize_backends() - * and override initialization of secondary backends + * @brief Initialize the backends array and return the number of elements in the array * * @param backends The reference to assign to the created backends array - * @param primary_backend The reference to the primary backend to insert first in the backends array - * @param backend_id The id indicating the primary backend * @param inputs Reference to the InputState struct to pass into each backend's constructor * @param input_sources Input sources array to pass into each backend's constructor * @param input_source_count Number of elements in the input_sources array @@ -143,15 +110,18 @@ size_t init_secondary_backends( * @param pinout Pinout struct used for GameCube/N64 communication backends * @return The number of backends in the array */ -size_t init_secondary_backends_custom( +size_t initialize_backends( CommunicationBackend **&backends, - CommunicationBackend *&primary_backend, - CommunicationBackendId backend_id, InputState &inputs, InputSource **input_sources, size_t input_source_count, Config &config, - const Pinout &pinout -) __attribute__((weak)); + const Pinout &pinout, + usb_backend_getter_t get_usb_backend_config = get_usb_backend_config_default, + detect_console_t detect_console = &detect_console, + secondary_backend_initializer_t init_secondary_backends = init_secondary_backends_default, + primary_backend_initializer_t init_primary_backend = init_primary_backend_default, + backend_config_selector_t get_backend_config_custom = nullptr +); #endif \ No newline at end of file diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 3d94191f..22057f14 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -7,7 +7,6 @@ #include "comms/N64Backend.hpp" #include "comms/NintendoSwitchBackend.hpp" #include "comms/XInputBackend.hpp" -#include "comms/console_detection.hpp" #include "core/CommunicationBackend.hpp" #include "core/config_utils.hpp" #include "core/mode_selection.hpp" @@ -23,8 +22,19 @@ size_t initialize_backends( InputSource **input_sources, size_t input_source_count, Config &config, - const Pinout &pinout + const Pinout &pinout, + usb_backend_getter_t get_usb_backend_config, + detect_console_t detect_console, + secondary_backend_initializer_t init_secondary_backends, + primary_backend_initializer_t init_primary_backend, + backend_config_selector_t get_backend_config_custom ) { + // Make sure required function pointers are not null. + if (init_primary_backend == nullptr || get_usb_backend_config == nullptr || + detect_console == nullptr) { + return 0; + } + CommunicationBackend *primary_backend = nullptr; /* First check button holds for a matching comms backend config. */ @@ -34,15 +44,17 @@ size_t initialize_backends( config.communication_backend_configs_count ); - // TODO: weakly defined backend_config_custom() + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED && + get_backend_config_custom != nullptr) { + get_backend_config_custom(backend_config, inputs, config); + } /* If no match found for button hold, use console/USB detection to select backend instead. */ if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { /* Must check default USB backend here and initialize it before console detection, so that * we can respond correctly to device descriptor requests from host. */ - const CommunicationBackendConfig &usb_backend_config = - config.communication_backend_configs[config.default_usb_backend_config - 1]; - // TODO: weakly defined usb_backend_config_custom() + CommunicationBackendConfig usb_backend_config; + get_usb_backend_config(usb_backend_config, config); init_primary_backend( primary_backend, usb_backend_config.backend_id, @@ -52,8 +64,8 @@ size_t initialize_backends( config, pinout ); - // TODO: weakly defined detect_console_custom() - CommunicationBackendId detected_backend_id = detect_console(pinout); + CommunicationBackendId detected_backend_id = COMMS_BACKEND_UNSPECIFIED; + detected_backend_id = detect_console(pinout); if (detected_backend_id == COMMS_BACKEND_XINPUT) { backend_config = usb_backend_config; } else { @@ -69,9 +81,6 @@ size_t initialize_backends( backend_config = config.communication_backend_configs[config.default_backend_config - 1]; } - size_t backend_count; - - // TODO: weakly defined init_primary_backend_custom() init_primary_backend( primary_backend, backend_config.backend_id, @@ -81,17 +90,20 @@ size_t initialize_backends( config, pinout ); - // TODO: weakly defined init_secondary_backends_custom() - backend_count = init_secondary_backends( - backends, - primary_backend, - backend_config.backend_id, - inputs, - input_sources, - input_source_count, - config, - pinout - ); + + size_t backend_count = 1; + if (init_secondary_backends != nullptr) { + backend_count = init_secondary_backends( + backends, + primary_backend, + backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); + } if (backend_config.default_mode_config > 0) { const GameModeConfig &mode_config = @@ -175,4 +187,22 @@ size_t init_secondary_backends( } return backend_count; -} \ No newline at end of file +} + +// clang-format off + +usb_backend_getter_t get_usb_backend_config_default = []( + CommunicationBackendConfig &backend_config, + const Config &config +) { + if (config.default_usb_backend_config > 0 && + config.default_usb_backend_config <= config.communication_backend_configs_count) { + backend_config = + config.communication_backend_configs[config.default_usb_backend_config - 1]; + } +}; + +// clang-format on + +primary_backend_initializer_t init_primary_backend_default = &init_primary_backend; +secondary_backend_initializer_t init_secondary_backends_default = &init_secondary_backends; \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index fe990ed8..6384235e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip - git+git@github.com:JonnyHaystack/HayBox-proto#3be8d12 + git+git@github.com:JonnyHaystack/HayBox-proto#62a1bbb [avr_base] platform = atmelavr From 1e44fe978e5817b726f0c7c29bce52c6cecb50cb Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 13 Nov 2023 00:18:42 +0000 Subject: [PATCH 046/167] fix: incorrect backend configs count in default pico config --- HAL/pico/include/comms/backend_init.hpp | 5 ++-- HAL/pico/include/config_defaults.hpp | 2 +- HAL/pico/src/comms/backend_init.cpp | 37 ++++++++++++++----------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/HAL/pico/include/comms/backend_init.hpp b/HAL/pico/include/comms/backend_init.hpp index e00ae2b5..2ee95d25 100644 --- a/HAL/pico/include/comms/backend_init.hpp +++ b/HAL/pico/include/comms/backend_init.hpp @@ -95,6 +95,7 @@ typedef CommunicationBackendId (*detect_console_t)(const Pinout &pinout); // clang-format on +extern backend_config_selector_t get_backend_config_default; extern usb_backend_getter_t get_usb_backend_config_default; extern primary_backend_initializer_t init_primary_backend_default; extern secondary_backend_initializer_t init_secondary_backends_default; @@ -117,11 +118,11 @@ size_t initialize_backends( size_t input_source_count, Config &config, const Pinout &pinout, + backend_config_selector_t get_backend_config_custom = get_backend_config_default, usb_backend_getter_t get_usb_backend_config = get_usb_backend_config_default, detect_console_t detect_console = &detect_console, secondary_backend_initializer_t init_secondary_backends = init_secondary_backends_default, - primary_backend_initializer_t init_primary_backend = init_primary_backend_default, - backend_config_selector_t get_backend_config_custom = nullptr + primary_backend_initializer_t init_primary_backend = init_primary_backend_default ); #endif \ No newline at end of file diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 44ad19a8..8a4cde49 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -75,7 +75,7 @@ const Config default_config = { .keyboard_mode_config = 1, }, }, - .communication_backend_configs_count = 3, + .communication_backend_configs_count = 6, .communication_backend_configs = { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_XINPUT, diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 22057f14..8570f66d 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -23,31 +23,22 @@ size_t initialize_backends( size_t input_source_count, Config &config, const Pinout &pinout, + backend_config_selector_t get_backend_config, usb_backend_getter_t get_usb_backend_config, detect_console_t detect_console, secondary_backend_initializer_t init_secondary_backends, - primary_backend_initializer_t init_primary_backend, - backend_config_selector_t get_backend_config_custom + primary_backend_initializer_t init_primary_backend ) { // Make sure required function pointers are not null. - if (init_primary_backend == nullptr || get_usb_backend_config == nullptr || - detect_console == nullptr) { + if (get_backend_config == nullptr || get_usb_backend_config == nullptr || + init_primary_backend == nullptr || detect_console == nullptr) { return 0; } - CommunicationBackend *primary_backend = nullptr; + CommunicationBackendConfig backend_config = CommunicationBackendConfig_init_zero; + get_backend_config(backend_config, inputs, config); - /* First check button holds for a matching comms backend config. */ - CommunicationBackendConfig backend_config = backend_config_from_buttons( - inputs, - config.communication_backend_configs, - config.communication_backend_configs_count - ); - - if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED && - get_backend_config_custom != nullptr) { - get_backend_config_custom(backend_config, inputs, config); - } + CommunicationBackend *primary_backend = nullptr; /* If no match found for button hold, use console/USB detection to select backend instead. */ if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { @@ -191,6 +182,20 @@ size_t init_secondary_backends( // clang-format off +/* Default is to first check button holds for a matching comms backend config. */ +backend_config_selector_t get_backend_config_default = []( + CommunicationBackendConfig &backend_config, + const InputState &inputs, + const Config &config +) { + backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); +}; + +/* Default is to get default USB backend from config. */ usb_backend_getter_t get_usb_backend_config_default = []( CommunicationBackendConfig &backend_config, const Config &config From 4b3241073cef91452bad729d15cfe1b2ad22d8f3 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 15 Nov 2023 18:28:59 +0000 Subject: [PATCH 047/167] feat: add DebouncedGpioButtonInput and DebouncedSwitchMatrixInput for Pico --- .../input/DebouncedGpioButtonInput.hpp | 35 +++++++++++++++++ .../input/DebouncedSwitchMatrixInput.hpp | 38 +++++++++++++++++++ HAL/pico/include/input/debounce.hpp | 31 +++++++++++++++ include/input/GpioButtonInput.hpp | 3 ++ include/input/SwitchMatrixInput.hpp | 20 ++++++++-- src/input/GpioButtonInput.cpp | 11 +++++- 6 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 HAL/pico/include/input/DebouncedGpioButtonInput.hpp create mode 100644 HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp create mode 100644 HAL/pico/include/input/debounce.hpp diff --git a/HAL/pico/include/input/DebouncedGpioButtonInput.hpp b/HAL/pico/include/input/DebouncedGpioButtonInput.hpp new file mode 100644 index 00000000..916c34d9 --- /dev/null +++ b/HAL/pico/include/input/DebouncedGpioButtonInput.hpp @@ -0,0 +1,35 @@ +#ifndef _INPUT_DEBOUNCEDGPIOBUTTONINPUT_HPP +#define _INPUT_DEBOUNCEDGPIOBUTTONINPUT_HPP + +#include "core/state.hpp" +#include "input/GpioButtonInput.hpp" +#include "input/debounce.hpp" +#include "util/state_util.hpp" + +template class DebouncedGpioButtonInput : public GpioButtonInput { + public: + DebouncedGpioButtonInput( + const GpioButtonMapping button_mappings[button_count], + uint32_t debounce_period_ms = 5 + ) + : GpioButtonInput(button_mappings, button_count) { + _debounce_period_ms = debounce_period_ms; + } + + private: + DebounceState _debounce_state[button_count]; + uint32_t _debounce_period_ms; + + void UpdateButtonState(InputState &inputs, size_t button_mapping_index, bool pressed) { + bool state_changed = update_debounce_state( + _debounce_state[button_mapping_index], + pressed, + _debounce_period_ms + ); + if (state_changed) { + set_button(inputs.buttons, _button_mappings[button_mapping_index].button, pressed); + } + } +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp b/HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp new file mode 100644 index 00000000..6ef85584 --- /dev/null +++ b/HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp @@ -0,0 +1,38 @@ +#ifndef _INPUT_DEBOUNCEDSWITCHMATRIXINPUT_HPP +#define _INPUT_DEBOUNCEDSWITCHMATRIXINPUT_HPP + +#include "input/SwitchMatrixInput.hpp" +#include "input/debounce.hpp" + +template +class DebouncedSwitchMatrixInput : public SwitchMatrixInput { + public: + DebouncedSwitchMatrixInput( + const uint row_pins[num_rows], + const uint col_pins[num_cols], + const Button (&matrix)[num_rows][num_cols], + DiodeDirection direction, + uint32_t debounce_period_ms = 5 + ) + : SwitchMatrixInput(row_pins, col_pins, matrix, direction) { + _debounce_period_ms = debounce_period_ms; + } + + private: + DebounceState _debounce_state[num_rows][num_cols]; + uint32_t _debounce_period_ms; + + void UpdateButtonState(InputState &inputs, size_t col_index, size_t row_index, bool pressed) { + bool state_changed = update_debounce_state( + _debounce_state[col_index][row_index], + pressed, + _debounce_period_ms + ); + if (state_changed) { + Button button = _matrix[col_index][row_index]; + set_button(inputs.buttons, button, pressed); + } + }; +}; + +#endif diff --git a/HAL/pico/include/input/debounce.hpp b/HAL/pico/include/input/debounce.hpp new file mode 100644 index 00000000..3ce9513d --- /dev/null +++ b/HAL/pico/include/input/debounce.hpp @@ -0,0 +1,31 @@ +#ifndef _DEBOUNCE_HPP +#define _DEBOUNCE_HPP + +#include "stdlib.hpp" + +typedef struct _DebounceState { + absolute_time_t locked_until = 0; + bool pressed = false; +} DebounceState; + +inline bool update_debounce_state( + DebounceState &debounce_state, + bool current_reading, + uint32_t debounce_period_ms +) { + // If currently locked out, do nothing. + if (!time_reached(debounce_state.locked_until)) { + return false; + } + + // If latest reading differs from the last known state, update the value and timeout. + if (current_reading != debounce_state.pressed) { + debounce_state.pressed = current_reading; + debounce_state.locked_until = make_timeout_time_ms(debounce_period_ms); + return true; + } + + return false; +} + +#endif \ No newline at end of file diff --git a/include/input/GpioButtonInput.hpp b/include/input/GpioButtonInput.hpp index 6c9de3c7..fdc4c9b6 100644 --- a/include/input/GpioButtonInput.hpp +++ b/include/input/GpioButtonInput.hpp @@ -21,6 +21,9 @@ class GpioButtonInput : public InputSource { protected: const GpioButtonMapping *_button_mappings; size_t _button_count; + + private: + virtual void UpdateButtonState(InputState &inputs, size_t button_mapping_index, bool pressed); }; #endif \ No newline at end of file diff --git a/include/input/SwitchMatrixInput.hpp b/include/input/SwitchMatrixInput.hpp index ec4aff27..0af88440 100644 --- a/include/input/SwitchMatrixInput.hpp +++ b/include/input/SwitchMatrixInput.hpp @@ -66,9 +66,12 @@ template class SwitchMatrixInput : public Inp // Read each cell in the column/row. for (size_t j = 0; j < _num_inputs; j++) { - Button button = - _direction == DiodeDirection::ROW2COL ? _matrix[j][i] : _matrix[i][j]; - set_button(inputs.buttons, button, !gpio::read_digital(_input_pins[j])); + UpdateButtonState( + inputs, + DiodeDirection::ROW2COL ? j : i, + DiodeDirection::ROW2COL ? i : j, + !gpio::read_digital(_input_pins[j]) + ); } // Deactivate the column/row. @@ -83,6 +86,17 @@ template class SwitchMatrixInput : public Inp const uint *_input_pins; const Button (&_matrix)[num_rows][num_cols]; DiodeDirection _direction; + + private: + virtual void UpdateButtonState( + InputState &inputs, + size_t col_index, + size_t row_index, + bool pressed + ) { + Button button = _matrix[col_index][row_index]; + set_button(inputs.buttons, button, pressed); + }; }; #endif \ No newline at end of file diff --git a/src/input/GpioButtonInput.cpp b/src/input/GpioButtonInput.cpp index 9567664b..69fc2ee1 100644 --- a/src/input/GpioButtonInput.cpp +++ b/src/input/GpioButtonInput.cpp @@ -20,7 +20,14 @@ InputScanSpeed GpioButtonInput::ScanSpeed() { void GpioButtonInput::UpdateInputs(InputState &inputs) { for (size_t i = 0; i < _button_count; i++) { - GpioButtonMapping button_mapping = _button_mappings[i]; - set_button(inputs.buttons, button_mapping.button, !gpio::read_digital(button_mapping.pin)); + UpdateButtonState(inputs, i, !gpio::read_digital(_button_mappings[i].pin)); } } + +void GpioButtonInput::UpdateButtonState( + InputState &inputs, + size_t button_mapping_index, + bool pressed +) { + set_button(inputs.buttons, _button_mappings[button_mapping_index].button, pressed); +} From f60064536cf0c5f17072c5e35595b4b81742799a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 Nov 2023 11:17:43 +0000 Subject: [PATCH 048/167] fix: build errors in SwitchMatrixInput and DebouncedSwitchMatrixInput --- HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp | 2 +- include/input/SwitchMatrixInput.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp b/HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp index 6ef85584..bd6d6dd8 100644 --- a/HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp +++ b/HAL/pico/include/input/DebouncedSwitchMatrixInput.hpp @@ -29,7 +29,7 @@ class DebouncedSwitchMatrixInput : public SwitchMatrixInput _debounce_period_ms ); if (state_changed) { - Button button = _matrix[col_index][row_index]; + Button button = this->_matrix[col_index][row_index]; set_button(inputs.buttons, button, pressed); } }; diff --git a/include/input/SwitchMatrixInput.hpp b/include/input/SwitchMatrixInput.hpp index 0af88440..d499de64 100644 --- a/include/input/SwitchMatrixInput.hpp +++ b/include/input/SwitchMatrixInput.hpp @@ -68,8 +68,8 @@ template class SwitchMatrixInput : public Inp for (size_t j = 0; j < _num_inputs; j++) { UpdateButtonState( inputs, - DiodeDirection::ROW2COL ? j : i, - DiodeDirection::ROW2COL ? i : j, + _direction == DiodeDirection::ROW2COL ? j : i, + _direction == DiodeDirection::ROW2COL ? i : j, !gpio::read_digital(_input_pins[j]) ); } From d60daf163c4f03ce4a48deb91b0219f0beccb74b Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 Nov 2023 12:04:36 +0000 Subject: [PATCH 049/167] feat: add initial Glyph config including 4pos switch implementation --- config/glyph/config.cpp | 121 +++++++++++++++++++++++ config/glyph/env.ini | 8 ++ config/glyph/include/glyph_overrides.hpp | 57 +++++++++++ 3 files changed, 186 insertions(+) create mode 100644 config/glyph/config.cpp create mode 100644 config/glyph/env.ini create mode 100644 config/glyph/include/glyph_overrides.hpp diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp new file mode 100644 index 00000000..04b9944a --- /dev/null +++ b/config/glyph/config.cpp @@ -0,0 +1,121 @@ +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" +#include "core/CommunicationBackend.hpp" +#include "core/KeyboardMode.hpp" +#include "core/Persistence.hpp" +#include "core/mode_selection.hpp" +#include "core/pinout.hpp" +#include "core/state.hpp" +#include "glyph_overrides.hpp" +#include "input/DebouncedSwitchMatrixInput.hpp" +#include "reboot.hpp" +#include "stdlib.hpp" + +#include + +Config config = default_config; + +const size_t num_rows = 4; +const size_t num_cols = 11; +const uint row_pins[num_rows] = { 26, 25, 24, 23 }; +const uint col_pins[num_cols] = { 15, 14, 13, 12, 16, 17, 21, 20, 19, 18, 22 }; +// clang-format off +const Button matrix[num_rows][num_cols] = { + {BTN_MB1, BTN_MB2, BTN_MB3, BTN_MB4, BTN_MB5, BTN_MB6, BTN_MB7, NA, NA, NA, NA }, + { BTN_LF3, BTN_LF2, BTN_LF6, BTN_LF7, BTN_RF12, BTN_RF13, BTN_RF14, BTN_RF5, BTN_RF6, BTN_RF7, BTN_RF8}, + { BTN_LF4, BTN_LF5, BTN_LF1, BTN_LF8, BTN_RF9, BTN_RF10, BTN_RF11, BTN_RF1, BTN_RF2, BTN_RF3, BTN_RF4}, + { BTN_LT5, BTN_LT4, BTN_LT1, BTN_LT3, BTN_LT2, BTN_LT6, BTN_RT2, BTN_RT3, BTN_RT1, BTN_RT4, BTN_RT5}, +}; +// clang-format on + +DebouncedSwitchMatrixInput matrix_input( + row_pins, + col_pins, + matrix, + DiodeDirection::COL2ROW +); + +const Pinout pinout = { + .joybus_data = 4, + .mux = -1, + .nunchuk_detect = -1, + .nunchuk_sda = -1, + .nunchuk_scl = -1, +}; + +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + +void setup() { + static InputState inputs; + + // Create GPIO input source and use it to read button states for checking button holds. + matrix_input.UpdateInputs(inputs); + + // Check bootsel button hold as early as possible for safety. + if (inputs.mb1) { + reboot_bootloader(); + } + + // Turn on LED to indicate firmware booted. + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + gpio_put(PICO_DEFAULT_LED_PIN, 1); + + // Attempt to load config, or write default config to flash if failed to load config. + Persistence *persistence = new Persistence(); + if (!persistence->LoadConfig(config)) { + persistence->SaveConfig(config); + } + delete persistence; + + // Create array of input sources to be used. + static InputSource *input_sources[] = {}; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = initialize_backends( + backends, + inputs, + input_sources, + input_source_count, + config, + pinout, + get_backend_config_default, + &usb_backend_from_4pos_switch + ); + + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); +} + +void loop() { + select_mode( + backends[0], + config.game_mode_configs, + config.game_mode_configs_count, + config.keyboard_modes, + config.keyboard_modes_count + ); + + for (size_t i = 0; i < backend_count; i++) { + backends[i]->SendReport(); + } + + if (current_kb_mode != nullptr) { + current_kb_mode->SendReport(backends[0]->GetInputs()); + } +} + +/* Button inputs are read from the second core */ + +void setup1() { + while (backends == nullptr) { + tight_loop_contents(); + } +} + +void loop1() { + if (backends != nullptr) { + matrix_input.UpdateInputs(backends[0]->GetInputs()); + } +} diff --git a/config/glyph/env.ini b/config/glyph/env.ini new file mode 100644 index 00000000..39d2f3f0 --- /dev/null +++ b/config/glyph/env.ini @@ -0,0 +1,8 @@ +[env:glyph] +extends = arduino_pico_base +build_flags = + ${arduino_pico_base.build_flags} + -I config/glyph/include +build_src_filter = + ${arduino_pico_base.build_src_filter} + + diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp new file mode 100644 index 00000000..06833afd --- /dev/null +++ b/config/glyph/include/glyph_overrides.hpp @@ -0,0 +1,57 @@ +#include "core/config_utils.hpp" +#include "stdlib.hpp" + +#include + +void usb_backend_from_4pos_switch( + CommunicationBackendConfig &backend_config, + const Config &config +) { + const uint pin2 = 8; + const uint pin3 = 9; + const uint pin4 = 10; + const uint pin5 = 11; + + pinMode(pin2, INPUT_PULLUP); + pinMode(pin3, INPUT_PULLUP); + pinMode(pin4, INPUT_PULLUP); + pinMode(pin5, INPUT_PULLUP); + + uint toggle_switch_state = 0; + if (!digitalRead(pin3)) { + toggle_switch_state = 1; + } else if (!digitalRead(pin4)) { + toggle_switch_state = 4; + } else { + pinMode(pin2, OUTPUT); + digitalWrite(pin2, LOW); + + if (!digitalRead(pin4)) { + toggle_switch_state = 2; + } else { + toggle_switch_state = 3; + } + } + + CommunicationBackendId backend_id = COMMS_BACKEND_UNSPECIFIED; + + switch (toggle_switch_state) { + case 1: + backend_id = COMMS_BACKEND_XINPUT; + break; + case 2: + backend_id = COMMS_BACKEND_DINPUT; + break; + case 3: + backend_id = COMMS_BACKEND_NINTENDO_SWITCH; + break; + case 4: + break; + } + + backend_config = backend_config_from_id( + backend_id, + config.communication_backend_configs, + config.communication_backend_configs_count + ); +} From 7018adcd89bbf01bd8da2770bbfea229f5c08e2d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 Nov 2023 12:05:35 +0000 Subject: [PATCH 050/167] feat: use debounced input on core1 in pico config --- config/pico/config.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 9d428439..669b2b0f 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -6,7 +6,7 @@ #include "core/mode_selection.hpp" #include "core/pinout.hpp" #include "core/state.hpp" -#include "input/GpioButtonInput.hpp" +#include "input/DebouncedGpioButtonInput.hpp" #include "input/NunchukInput.hpp" #include "reboot.hpp" #include "stdlib.hpp" @@ -44,7 +44,9 @@ GpioButtonMapping button_mappings[] = { { BTN_RF7, 20}, { BTN_RF8, 18}, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); + +DebouncedGpioButtonInput gpio_input(button_mappings, 5); const Pinout pinout = { .joybus_data = 28, @@ -62,7 +64,6 @@ void setup() { static InputState inputs; // Create GPIO input source and use it to read button states for checking button holds. - static GpioButtonInput gpio_input(button_mappings, button_count); gpio_input.UpdateInputs(inputs); // Check bootsel button hold as early as possible for safety. @@ -83,7 +84,7 @@ void setup() { delete persistence; // Create array of input sources to be used. - static InputSource *input_sources[] = { &gpio_input }; + static InputSource *input_sources[] = {}; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); backend_count = @@ -110,21 +111,16 @@ void loop() { } } -/* Nunchuk code runs on the second core */ -NunchukInput *nunchuk = nullptr; +/* Button inputs are read from the second core */ void setup1() { while (backends == nullptr) { tight_loop_contents(); } - - // Create Nunchuk input source. - nunchuk = new NunchukInput(Wire, pinout.nunchuk_detect, pinout.nunchuk_sda, pinout.nunchuk_scl); } void loop1() { if (backends != nullptr) { - nunchuk->UpdateInputs(backends[0]->GetInputs()); - busy_wait_us(50); + gpio_input.UpdateInputs(backends[0]->GetInputs()); } } From bdefb91e61ca0f27de5a1e9c9bd736cd12c2cba5 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Nov 2023 19:39:09 +0000 Subject: [PATCH 051/167] fix: default AVR config was broken --- HAL/avr/avr_usb/include/config_defaults.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HAL/avr/avr_usb/include/config_defaults.hpp b/HAL/avr/avr_usb/include/config_defaults.hpp index c1a45352..44863937 100644 --- a/HAL/avr/avr_usb/include/config_defaults.hpp +++ b/HAL/avr/avr_usb/include/config_defaults.hpp @@ -7,7 +7,6 @@ // clang-format off const Config default_config = { - .default_backend_config = 1, .game_mode_configs_count = 5, .game_mode_configs = new GameModeConfig[5] { GameModeConfig { @@ -121,6 +120,8 @@ const Config default_config = { }, }, }, + .default_backend_config = 1, + .default_usb_backend_config = 1, }; // clang-format on From a88fd857274bd1281ef2b2590aab14e376794cae Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Nov 2023 19:40:02 +0000 Subject: [PATCH 052/167] build: update arduino-pico version to 3.6.1 --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 6384235e..50235dc0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -104,7 +104,7 @@ build_src_filter = ${env.build_src_filter} + platform_packages = - framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.0 + framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.1 lib_archive = no lib_deps = ${env.lib_deps} From 15539105460f5475da57fb0e33e53459225283e1 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Nov 2023 19:41:34 +0000 Subject: [PATCH 053/167] feat: add initial version of NeoPixelBackend --- HAL/pico/include/comms/NeoPixelBackend.hpp | 31 +++++++++++++++++++ HAL/pico/src/comms/NeoPixelBackend.cpp | 35 ++++++++++++++++++++++ platformio.ini | 1 + 3 files changed, 67 insertions(+) create mode 100644 HAL/pico/include/comms/NeoPixelBackend.hpp create mode 100644 HAL/pico/src/comms/NeoPixelBackend.cpp diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp new file mode 100644 index 00000000..fa59623d --- /dev/null +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -0,0 +1,31 @@ +#ifndef _COMMS_NEOPIXELBACKEND_HPP +#define _COMMS_NEOPIXELBACKEND_HPP + +#include "core/CommunicationBackend.hpp" + +#include + +class NeoPixelBackend : public CommunicationBackend { + public: + NeoPixelBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + uint8_t control_pin, + uint16_t pixel_count + ); + ~NeoPixelBackend(); + virtual void SendReport(); + + protected: + static constexpr uint8_t _max_pixels_per_cycle = 5; + const uint8_t _cycles_per_show = _pixel_count / _max_pixels_per_cycle; + + Adafruit_NeoPixel _strip; + uint8_t _current_cycle = 0; + + private: + const uint16_t _pixel_count; +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/src/comms/NeoPixelBackend.cpp b/HAL/pico/src/comms/NeoPixelBackend.cpp new file mode 100644 index 00000000..6cedad1c --- /dev/null +++ b/HAL/pico/src/comms/NeoPixelBackend.cpp @@ -0,0 +1,35 @@ +#include "comms/NeoPixelBackend.hpp" + +NeoPixelBackend::NeoPixelBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + uint8_t control_pin, + uint16_t pixel_count +) + : CommunicationBackend(inputs, input_sources, input_source_count), + _strip(pixel_count, control_pin), + _pixel_count(pixel_count) { + _strip.begin(); + _strip.setBrightness(100); + if (_strip.canShow()) { + _strip.show(); + } +} + +NeoPixelBackend::~NeoPixelBackend() { + _strip.clear(); +} + +void NeoPixelBackend::SendReport() { + if (!_strip.canShow()) { + return; + } + uint8_t start_pixel = _current_cycle * _max_pixels_per_cycle; + uint8_t pixels_to_fill = min(_max_pixels_per_cycle, _pixel_count - start_pixel); + _strip.fill(Adafruit_NeoPixel::Color(30, 30, 30), start_pixel, pixels_to_fill); + _strip.show(); + if (++_current_cycle >= _cycles_per_show) { + _current_cycle = 0; + } +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 50235dc0..fefa69cd 100644 --- a/platformio.ini +++ b/platformio.ini @@ -114,3 +114,4 @@ lib_deps = eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 TUCompositeHID + adafruit/Adafruit NeoPixel@^1.12.0 From 992ca2d720f60c66376191cb82c0892247e21763 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Nov 2023 19:42:25 +0000 Subject: [PATCH 054/167] feat: add NeoPixelBackend to Glyph secondary backends --- config/glyph/config.cpp | 10 +++--- config/glyph/include/glyph_overrides.hpp | 46 ++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 04b9944a..b897105a 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -59,9 +59,9 @@ void setup() { } // Turn on LED to indicate firmware booted. - gpio_init(PICO_DEFAULT_LED_PIN); - gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - gpio_put(PICO_DEFAULT_LED_PIN, 1); + // gpio_init(PICO_DEFAULT_LED_PIN); + // gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + // gpio_put(PICO_DEFAULT_LED_PIN, 1); // Attempt to load config, or write default config to flash if failed to load config. Persistence *persistence = new Persistence(); @@ -82,7 +82,9 @@ void setup() { config, pinout, get_backend_config_default, - &usb_backend_from_4pos_switch + &usb_backend_from_4pos_switch, + &detect_console, + &init_secondary_backends_glyph ); setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 06833afd..03ab7fad 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -1,8 +1,13 @@ +#include "comms/B0XXInputViewer.hpp" +#include "comms/NeoPixelBackend.hpp" #include "core/config_utils.hpp" #include "stdlib.hpp" #include +#define LED_PIN 7 +#define LED_COUNT 72 + void usb_backend_from_4pos_switch( CommunicationBackendConfig &backend_config, const Config &config @@ -10,12 +15,10 @@ void usb_backend_from_4pos_switch( const uint pin2 = 8; const uint pin3 = 9; const uint pin4 = 10; - const uint pin5 = 11; pinMode(pin2, INPUT_PULLUP); pinMode(pin3, INPUT_PULLUP); pinMode(pin4, INPUT_PULLUP); - pinMode(pin5, INPUT_PULLUP); uint toggle_switch_state = 0; if (!digitalRead(pin3)) { @@ -55,3 +58,42 @@ void usb_backend_from_4pos_switch( config.communication_backend_configs_count ); } + +size_t init_secondary_backends_glyph( + CommunicationBackend **&backends, + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + size_t backend_count = init_secondary_backends_default( + backends, + primary_backend, + backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); + + // Create new array containing all old backends but with length increased by 1 to make space for + // NeoPixel backend. + CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 1]; + for (size_t i = 0; i < backend_count; i++) { + new_backends[i] = backends[i]; + } + + // Add new backend to array and increase backend count to reflect this. + new_backends[backend_count++] = + new NeoPixelBackend(inputs, input_sources, input_source_count, LED_PIN, LED_COUNT); + + // Delete the old backends array and reassign it. + delete backends; + backends = new_backends; + + return backend_count; +} \ No newline at end of file From dc4d71875670379d4a4f9c6cf12b0b45a7cecbcb Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Nov 2023 19:42:55 +0000 Subject: [PATCH 055/167] fix: use default configs for C53 --- config/c53/config.cpp | 81 ++----------------------------------------- 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/config/c53/config.cpp b/config/c53/config.cpp index 68f46bed..a1989668 100644 --- a/config/c53/config.cpp +++ b/config/c53/config.cpp @@ -1,4 +1,5 @@ #include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" #include "core/KeyboardMode.hpp" #include "core/Persistence.hpp" @@ -9,85 +10,7 @@ #include "reboot.hpp" #include "stdlib.hpp" -Config config = { - .default_backend = COMMS_BACKEND_XINPUT, - .game_mode_configs_count = 4, - .game_mode_configs = { - GameModeConfig { - .mode_id = MODE_MELEE, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, - }, - GameModeConfig { - .mode_id = MODE_PROJECT_M, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF3 }, - }, - GameModeConfig { - .mode_id = MODE_ULTIMATE, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF2 }, - }, - GameModeConfig { - .mode_id = MODE_FGC, - .socd_pairs_count = 2, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, - }, - .button_remapping_count = 1, - .button_remapping = { - ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, - }, - .activation_binding_count = 3, - .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, - }, - }, - .communication_backend_configs_count = 3, - .communication_backend_configs = { - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_XINPUT, - .default_mode = MODE_MELEE, - .activation_binding_count = 0, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_DINPUT, - .default_mode = MODE_MELEE, - .activation_binding_count = 1, - .activation_binding = { BTN_RF3 }, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_CONFIGURATOR, - .default_mode = MODE_UNSPECIFIED, - .activation_binding_count = 1, - .activation_binding = { BTN_RT2 }, - } - }, -}; +Config config = default_config; CommunicationBackend **backends; size_t backend_count; From f8cd71628188936c92022251ad4997e89d764f4a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Nov 2023 19:43:25 +0000 Subject: [PATCH 056/167] fix: input viewer had wrong input for Z --- src/comms/B0XXInputViewer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/comms/B0XXInputViewer.cpp b/src/comms/B0XXInputViewer.cpp index 18b83c46..e9b3dfe4 100644 --- a/src/comms/B0XXInputViewer.cpp +++ b/src/comms/B0XXInputViewer.cpp @@ -31,8 +31,6 @@ void B0XXInputViewer::SendReport() { } _clock = 0; - // Only scan fast input sources because we don't want to waste any more time than necessary - // on the input viewer and we can't afford to read from something like a Nunchuk twice. _report[0] = ASCII_BIT(_inputs.mb1); _report[1] = ASCII_BIT(_inputs.rf6); _report[2] = ASCII_BIT(_inputs.rf2); @@ -40,7 +38,7 @@ void B0XXInputViewer::SendReport() { _report[4] = ASCII_BIT(_inputs.rt1); _report[5] = ASCII_BIT(_inputs.lf4); _report[6] = ASCII_BIT(_inputs.rf5); - _report[7] = ASCII_BIT(_inputs.rf2); + _report[7] = ASCII_BIT(_inputs.rf3); _report[8] = ASCII_BIT(_inputs.rf4); _report[9] = ASCII_BIT(_inputs.lf2); _report[10] = ASCII_BIT(_inputs.lf1); From bf79a42b35b12cced182da2be1dd6d16b7120a46 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 28 Nov 2023 19:39:50 +0000 Subject: [PATCH 057/167] fix: undefined behaviour --- HAL/pico/include/comms/NeoPixelBackend.hpp | 6 ++---- HAL/pico/src/comms/NeoPixelBackend.cpp | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index fa59623d..aafe81a7 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -19,13 +19,11 @@ class NeoPixelBackend : public CommunicationBackend { protected: static constexpr uint8_t _max_pixels_per_cycle = 5; - const uint8_t _cycles_per_show = _pixel_count / _max_pixels_per_cycle; + const uint16_t _pixel_count; + const uint8_t _cycles_per_show; Adafruit_NeoPixel _strip; uint8_t _current_cycle = 0; - - private: - const uint16_t _pixel_count; }; #endif \ No newline at end of file diff --git a/HAL/pico/src/comms/NeoPixelBackend.cpp b/HAL/pico/src/comms/NeoPixelBackend.cpp index 6cedad1c..5a55d976 100644 --- a/HAL/pico/src/comms/NeoPixelBackend.cpp +++ b/HAL/pico/src/comms/NeoPixelBackend.cpp @@ -9,7 +9,8 @@ NeoPixelBackend::NeoPixelBackend( ) : CommunicationBackend(inputs, input_sources, input_source_count), _strip(pixel_count, control_pin), - _pixel_count(pixel_count) { + _pixel_count(pixel_count), + _cycles_per_show(pixel_count / _max_pixels_per_cycle) { _strip.begin(); _strip.setBrightness(100); if (_strip.canShow()) { From 7e88f2ba0ad697abc7e003794e2acf9b4ca44861 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 28 Nov 2023 19:40:04 +0000 Subject: [PATCH 058/167] fix: add missing break --- HAL/pico/src/comms/backend_init.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 8570f66d..5a3a7313 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -172,6 +172,7 @@ size_t init_secondary_backends( backends = new CommunicationBackend *[backend_count] { primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) }; + break; default: backend_count = 1; backends = new CommunicationBackend *[backend_count] { primary_backend }; From 783f414ae369ac340fa529045982830aac2537f7 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 28 Nov 2023 19:41:11 +0000 Subject: [PATCH 059/167] ci: add Glyph config to CI --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04b5a3da..3fccaade 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,6 +14,8 @@ jobs: include: - env: c53 bin_ext: uf2 + - env: glyph + bin_ext: uf2 - env: pico bin_ext: uf2 - env: arduino_uno @@ -71,4 +73,4 @@ jobs: uses: softprops/action-gh-release@v1 if: github.ref_type == 'tag' with: - files: ${{ matrix.env }}/HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} \ No newline at end of file + files: ${{ matrix.env }}/HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} From ef9a4c39dd8b334c6dc38775264a8a77ebcf64dd Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 29 Nov 2023 15:23:48 +0000 Subject: [PATCH 060/167] build: update nanopb to new stable release --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index fefa69cd..58be7572 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,7 +21,7 @@ custom_nanopb_protos = custom_nanopb_options = --error-on-unmatched lib_deps = - https://github.com/nanopb/nanopb/archive/f5f65a90c8057a591f3cc98de40874bd78c9880d.zip + nanopb/Nanopb@^0.4.8 git+git@github.com:JonnyHaystack/HayBox-proto#62a1bbb [avr_base] From c76ec0c7cb90861823e62fc94e3294ed9c5ecf24 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 30 Nov 2023 14:30:10 +0000 Subject: [PATCH 061/167] feat: update HayBox-proto to add RGB configuration --- HAL/avr/avr_usb/include/config_defaults.hpp | 2 ++ HAL/avr/proto/config.options | 12 +++++++++++- platformio.ini | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/HAL/avr/avr_usb/include/config_defaults.hpp b/HAL/avr/avr_usb/include/config_defaults.hpp index 44863937..68a030b7 100644 --- a/HAL/avr/avr_usb/include/config_defaults.hpp +++ b/HAL/avr/avr_usb/include/config_defaults.hpp @@ -120,6 +120,8 @@ const Config default_config = { }, }, }, + .rgb_configs_count = 0, + .rgb_configs = {}, .default_backend_config = 1, .default_usb_backend_config = 1, }; diff --git a/HAL/avr/proto/config.options b/HAL/avr/proto/config.options index 6d56d3ec..d6b360c5 100644 --- a/HAL/avr/proto/config.options +++ b/HAL/avr/proto/config.options @@ -8,6 +8,8 @@ SocdPair.socd_type int_size:IS_8 ButtonToKeycodeMapping.button int_size:IS_8 ButtonToKeycodeMapping.keycode int_size:IS_8 +ButtonToColorMapping.button int_size:IS_8 + GameModeConfig.mode_id int_size:IS_8 GameModeConfig.socd_pairs max_count:10 GameModeConfig.socd_pairs type:FT_POINTER @@ -27,12 +29,19 @@ CommunicationBackendConfig.default_mode_config int_size:IS_8 CommunicationBackendConfig.activation_binding max_count:2 CommunicationBackendConfig.activation_binding type:FT_POINTER +RgbConfig.button_colors max_count:60 +RgbConfig.button_colors type:FT_POINTER +RgbConfig.animation int_size:IS_8 +RgbConfig.speed int_size:IS_8 + Config.game_mode_configs max_count:10 Config.game_mode_configs type:FT_POINTER Config.communication_backend_configs max_count:10 Config.communication_backend_configs type:FT_POINTER Config.keyboard_modes max_count:5 Config.keyboard_modes type:FT_POINTER +Config.rgb_configs max_count:10 +Config.rgb_configs type:FT_POINTER Config.default_backend_config int_size:IS_8 Config.default_usb_backend_config int_size:IS_8 @@ -44,4 +53,5 @@ Command long_names:false Button long_names:false SocdType long_names:false GameModeId long_names:false -CommunicationBackendId long_names:false \ No newline at end of file +CommunicationBackendId long_names:false +RgbAnimationId long_names:false \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 58be7572..0df70b82 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - git+git@github.com:JonnyHaystack/HayBox-proto#62a1bbb + git+git@github.com:JonnyHaystack/HayBox-proto#3e7fb48 [avr_base] platform = atmelavr From 58599bafa20a2a1cb284525e5dd6058cbe40fad1 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 12 Dec 2023 21:24:00 +0000 Subject: [PATCH 062/167] feat: implement RGB config support --- HAL/pico/include/comms/NeoPixelBackend.hpp | 21 ++++++-- HAL/pico/src/comms/NeoPixelBackend.cpp | 48 ++++++++++++++---- config/glyph/config.cpp | 13 +---- config/glyph/include/glyph_overrides.hpp | 57 ++++++++++++++++++++-- include/core/InputMode.hpp | 1 + include/core/mode_selection.hpp | 8 +-- src/core/InputMode.cpp | 4 ++ src/core/mode_selection.cpp | 23 ++++----- 8 files changed, 129 insertions(+), 46 deletions(-) diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index aafe81a7..143410bc 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -4,6 +4,7 @@ #include "core/CommunicationBackend.hpp" #include +#include class NeoPixelBackend : public CommunicationBackend { public: @@ -11,19 +12,31 @@ class NeoPixelBackend : public CommunicationBackend { InputState &inputs, InputSource **input_sources, size_t input_source_count, + const Button *button_mappings, + const RgbConfig *rgb_configs, + size_t rgb_configs_count, uint8_t control_pin, uint16_t pixel_count ); ~NeoPixelBackend(); + virtual void SetGameMode(ControllerMode *gamemode); virtual void SendReport(); protected: - static constexpr uint8_t _max_pixels_per_cycle = 5; - const uint16_t _pixel_count; - const uint8_t _cycles_per_show; + static constexpr uint8_t max_pixels_per_cycle = 10; + static constexpr size_t button_colors_count = + sizeof(RgbConfig::button_colors) / sizeof(ButtonToColorMapping); + + const Button *button_mappings; + const RgbConfig *rgb_configs; + const size_t rgb_configs_count; + const uint16_t pixel_count; + const uint8_t cycles_per_show; + const RgbConfig *config = nullptr; Adafruit_NeoPixel _strip; - uint8_t _current_cycle = 0; + size_t _current_pixel = 0; + uint32_t _button_colors[button_colors_count]; }; #endif \ No newline at end of file diff --git a/HAL/pico/src/comms/NeoPixelBackend.cpp b/HAL/pico/src/comms/NeoPixelBackend.cpp index 5a55d976..05944b7e 100644 --- a/HAL/pico/src/comms/NeoPixelBackend.cpp +++ b/HAL/pico/src/comms/NeoPixelBackend.cpp @@ -4,13 +4,19 @@ NeoPixelBackend::NeoPixelBackend( InputState &inputs, InputSource **input_sources, size_t input_source_count, + const Button *button_mappings, + const RgbConfig *rgb_configs, + size_t rgb_configs_count, uint8_t control_pin, uint16_t pixel_count ) : CommunicationBackend(inputs, input_sources, input_source_count), - _strip(pixel_count, control_pin), - _pixel_count(pixel_count), - _cycles_per_show(pixel_count / _max_pixels_per_cycle) { + button_mappings(button_mappings), + rgb_configs(rgb_configs), + rgb_configs_count(rgb_configs_count), + pixel_count(pixel_count), + cycles_per_show(pixel_count / max_pixels_per_cycle), + _strip(pixel_count, control_pin) { _strip.begin(); _strip.setBrightness(100); if (_strip.canShow()) { @@ -22,15 +28,39 @@ NeoPixelBackend::~NeoPixelBackend() { _strip.clear(); } +void NeoPixelBackend::SetGameMode(ControllerMode *gamemode) { + // Clear current button colors. + for (size_t i = 0; i < button_colors_count; i++) { + _button_colors[i] = 0; + } + + uint8_t rgb_config_id = gamemode->GetConfig().rgb_config; + if (rgb_config_id == 0 || rgb_config_id > rgb_configs_count) { + config = nullptr; + return; + } + config = &rgb_configs[rgb_config_id - 1]; + + // Build new mapping array to give O(n) lookup later. + for (size_t i = 0; i < config->button_colors_count; i++) { + ButtonToColorMapping mapping = config->button_colors[i]; + _button_colors[max(0, mapping.button - 1)] = mapping.color; + } +} + void NeoPixelBackend::SendReport() { if (!_strip.canShow()) { return; } - uint8_t start_pixel = _current_cycle * _max_pixels_per_cycle; - uint8_t pixels_to_fill = min(_max_pixels_per_cycle, _pixel_count - start_pixel); - _strip.fill(Adafruit_NeoPixel::Color(30, 30, 30), start_pixel, pixels_to_fill); - _strip.show(); - if (++_current_cycle >= _cycles_per_show) { - _current_cycle = 0; + + uint8_t stop_pixel = min(pixel_count, _current_pixel + max_pixels_per_cycle); + for (; _current_pixel < stop_pixel; _current_pixel++) { + volatile Button button = this->button_mappings[_current_pixel]; + volatile uint32_t color = _button_colors[max(0, button - 1)]; + _strip.fill(color, _current_pixel, 1); + } + if (_current_pixel >= pixel_count) { + _current_pixel = 0; } + _strip.show(); } \ No newline at end of file diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index b897105a..5c2e5b1d 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -58,11 +58,6 @@ void setup() { reboot_bootloader(); } - // Turn on LED to indicate firmware booted. - // gpio_init(PICO_DEFAULT_LED_PIN); - // gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - // gpio_put(PICO_DEFAULT_LED_PIN, 1); - // Attempt to load config, or write default config to flash if failed to load config. Persistence *persistence = new Persistence(); if (!persistence->LoadConfig(config)) { @@ -91,13 +86,7 @@ void setup() { } void loop() { - select_mode( - backends[0], - config.game_mode_configs, - config.game_mode_configs_count, - config.keyboard_modes, - config.keyboard_modes_count - ); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 03ab7fad..496dba3e 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -8,6 +8,49 @@ #define LED_PIN 7 #define LED_COUNT 72 +// clang-format off + +const Button pixel_to_button_mappings[LED_COUNT] = { + BTN_MB1, BTN_MB1, + BTN_LF4, BTN_LF4, + BTN_LF3, BTN_LF3, + BTN_LF5, BTN_LF5, + BTN_LF2, BTN_LF2, + BTN_LF1, BTN_LF1, + BTN_LF6, BTN_LF6, + BTN_LF7, BTN_LF7, + BTN_LF8, BTN_LF8, + BTN_RF12, BTN_RF12, + BTN_RF13, BTN_RF13, + BTN_RF14, BTN_RF14, + BTN_RF5, BTN_RF5, + BTN_RF6, BTN_RF6, + BTN_RF7, BTN_RF7, + BTN_RF8, BTN_RF8, + BTN_RF4, BTN_RF4, + BTN_RF3, BTN_RF3, + BTN_RF2, BTN_RF2, + BTN_RF1, BTN_RF1, + BTN_RF11, BTN_RF11, + BTN_RF10, BTN_RF10, + BTN_RF9, BTN_RF9, + BTN_RT3, BTN_RT3, + BTN_RT4, BTN_RT4, + BTN_RT5, BTN_RT5, + BTN_RT1, BTN_RT1, + BTN_RT1, BTN_RT1, + BTN_RT2, BTN_RT2, + BTN_LT6, BTN_LT6, + BTN_LT3, BTN_LT3, + BTN_LT4, BTN_LT4, + BTN_LT5, BTN_LT5, + BTN_LT1, BTN_LT1, + BTN_LT1, BTN_LT1, + BTN_LT2, BTN_LT2, +}; + +// clang-format on + void usb_backend_from_4pos_switch( CommunicationBackendConfig &backend_config, const Config &config @@ -88,11 +131,19 @@ size_t init_secondary_backends_glyph( } // Add new backend to array and increase backend count to reflect this. - new_backends[backend_count++] = - new NeoPixelBackend(inputs, input_sources, input_source_count, LED_PIN, LED_COUNT); + new_backends[backend_count++] = new NeoPixelBackend( + inputs, + input_sources, + input_source_count, + pixel_to_button_mappings, + config.rgb_configs, + config.rgb_configs_count, + LED_PIN, + LED_COUNT + ); // Delete the old backends array and reassign it. - delete backends; + delete[] backends; backends = new_backends; return backend_count; diff --git a/include/core/InputMode.hpp b/include/core/InputMode.hpp index 17e745d1..95d7c5ba 100644 --- a/include/core/InputMode.hpp +++ b/include/core/InputMode.hpp @@ -10,6 +10,7 @@ class InputMode { public: InputMode(const GameModeConfig &config); virtual ~InputMode(); + const GameModeConfig &GetConfig(); protected: const GameModeConfig &_config; diff --git a/include/core/mode_selection.hpp b/include/core/mode_selection.hpp index 88c05ed3..e0e92efb 100644 --- a/include/core/mode_selection.hpp +++ b/include/core/mode_selection.hpp @@ -25,13 +25,7 @@ void set_mode( const KeyboardModeConfig *keyboard_modes, size_t keyboard_modes_count ); -void select_mode( - CommunicationBackend *backend, - const GameModeConfig *mode_configs, - size_t mode_configs_count, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count -); +void select_mode(CommunicationBackend **backends, size_t backends_count, const Config &config); void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count); #endif diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index ed72732f..5261c152 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -12,6 +12,10 @@ InputMode::~InputMode() { delete[] _socd_states; } +const GameModeConfig &InputMode::GetConfig() { + return _config; +} + void InputMode::HandleSocd(InputState &inputs) { // Handle SOCD resolution for each SOCD button pair. for (size_t i = 0; i < _config.socd_pairs_count; i++) { diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index d9dc3f6f..3e354eb7 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -102,23 +102,24 @@ void set_mode( } } -void select_mode( - CommunicationBackend *backend, - const GameModeConfig *mode_configs, - size_t mode_configs_count, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count -) { +void select_mode(CommunicationBackend **backends, size_t backends_count, const Config &config) { // TODO: Use a counter variable to only run the contents of this function every x iterations // rather than on every single poll. - InputState &inputs = backend->GetInputs(); + InputState &inputs = backends[0]->GetInputs(); - for (size_t i = 0; i < mode_configs_count; i++) { - const GameModeConfig &mode_config = mode_configs[i]; + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + const GameModeConfig &mode_config = config.game_mode_configs[i]; if (all_buttons_held(inputs.buttons, mode_activation_masks[i]) && i != current_mode_index) { current_mode_index = i; - set_mode(backend, mode_config, keyboard_modes, keyboard_modes_count); + for (size_t i = 0; i < backends_count; i++) { + set_mode( + backends[i], + mode_config, + config.keyboard_modes, + config.keyboard_modes_count + ); + } return; } } From c95b733b3475261f39c9012ba77948393a257fa7 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 12 Dec 2023 21:27:47 +0000 Subject: [PATCH 063/167] fix: handle some edge cases in NeoPixelBackend --- HAL/pico/src/comms/NeoPixelBackend.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/HAL/pico/src/comms/NeoPixelBackend.cpp b/HAL/pico/src/comms/NeoPixelBackend.cpp index 05944b7e..a9b83702 100644 --- a/HAL/pico/src/comms/NeoPixelBackend.cpp +++ b/HAL/pico/src/comms/NeoPixelBackend.cpp @@ -34,6 +34,9 @@ void NeoPixelBackend::SetGameMode(ControllerMode *gamemode) { _button_colors[i] = 0; } + // Reset current pixel bookmark. + _current_pixel = 0; + uint8_t rgb_config_id = gamemode->GetConfig().rgb_config; if (rgb_config_id == 0 || rgb_config_id > rgb_configs_count) { config = nullptr; @@ -49,7 +52,7 @@ void NeoPixelBackend::SetGameMode(ControllerMode *gamemode) { } void NeoPixelBackend::SendReport() { - if (!_strip.canShow()) { + if (config == nullptr || !_strip.canShow()) { return; } From b57a3878d2929145be7065b7c297c99e1001a374 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 12 Dec 2023 21:31:57 +0000 Subject: [PATCH 064/167] feat: set gamemode for all backends on init --- HAL/pico/src/comms/backend_init.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 5a3a7313..959bf9e5 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -99,7 +99,9 @@ size_t initialize_backends( if (backend_config.default_mode_config > 0) { const GameModeConfig &mode_config = config.game_mode_configs[backend_config.default_mode_config - 1]; - set_mode(primary_backend, mode_config, config.keyboard_modes, config.keyboard_modes_count); + for (size_t i = 0; i < backend_count; i++) { + set_mode(backends[i], mode_config, config.keyboard_modes, config.keyboard_modes_count); + } } return backend_count; From f0cb9c3de60ba4ccb1cc1b7cba7aed0cd782c0f6 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 17 Dec 2023 16:26:21 +0000 Subject: [PATCH 065/167] feat: add NesBackend and SnesBackend --- HAL/pico/include/comms/NesBackend.hpp | 29 +++++++++++++ HAL/pico/include/comms/SnesBackend.hpp | 29 +++++++++++++ HAL/pico/include/config_defaults.hpp | 58 ++++++++++++++++++++++++++ HAL/pico/src/comms/NesBackend.cpp | 38 +++++++++++++++++ HAL/pico/src/comms/SnesBackend.cpp | 42 +++++++++++++++++++ config/glyph/config.cpp | 3 ++ include/core/pinout.hpp | 3 ++ platformio.ini | 3 +- 8 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 HAL/pico/include/comms/NesBackend.hpp create mode 100644 HAL/pico/include/comms/SnesBackend.hpp create mode 100644 HAL/pico/src/comms/NesBackend.cpp create mode 100644 HAL/pico/src/comms/SnesBackend.cpp diff --git a/HAL/pico/include/comms/NesBackend.hpp b/HAL/pico/include/comms/NesBackend.hpp new file mode 100644 index 00000000..816a9ce2 --- /dev/null +++ b/HAL/pico/include/comms/NesBackend.hpp @@ -0,0 +1,29 @@ +#ifndef _COMMS_NESBACKEND_HPP +#define _COMMS_NESBACKEND_HPP + +#include "core/CommunicationBackend.hpp" + +#include + +class NesBackend : public CommunicationBackend { + public: + NesBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + uint data_pin, + uint clock_pin, + uint latch_pin, + PIO pio = pio0, + int sm = -1, + int offset = -1 + ); + void SendReport(); + int GetOffset(); + + private: + NesConsole _nes; + nes_report_t _report; +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/include/comms/SnesBackend.hpp b/HAL/pico/include/comms/SnesBackend.hpp new file mode 100644 index 00000000..45eb2ae7 --- /dev/null +++ b/HAL/pico/include/comms/SnesBackend.hpp @@ -0,0 +1,29 @@ +#ifndef _COMMS_SNESBACKEND_HPP +#define _COMMS_SNESBACKEND_HPP + +#include "core/CommunicationBackend.hpp" + +#include + +class SnesBackend : public CommunicationBackend { + public: + SnesBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + uint data_pin, + uint clock_pin, + uint latch_pin, + PIO pio = pio0, + int sm = -1, + int offset = -1 + ); + void SendReport(); + int GetOffset(); + + private: + SnesConsole _snes; + snes_report_t _report; +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 8a4cde49..38779061 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -21,6 +21,7 @@ const Config default_config = { .button_remapping_count = 0, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, + .rgb_config = 1, }, GameModeConfig { .mode_id = MODE_PROJECT_M, @@ -34,6 +35,7 @@ const Config default_config = { .button_remapping_count = 0, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF3 }, + .rgb_config = 1, }, GameModeConfig { .mode_id = MODE_ULTIMATE, @@ -47,6 +49,7 @@ const Config default_config = { .button_remapping_count = 0, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF2 }, + .rgb_config = 1, }, GameModeConfig { .mode_id = MODE_FGC, @@ -61,6 +64,7 @@ const Config default_config = { }, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, + .rgb_config = 2, }, GameModeConfig { .mode_id = MODE_KEYBOARD, @@ -101,6 +105,16 @@ const Config default_config = { .backend_id = COMMS_BACKEND_N64, .default_mode_config = 1, }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_NES, + .default_mode_config = 1, + .activation_binding = { BTN_LT1 }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_SNES, + .default_mode_config = 1, + .activation_binding = { BTN_LT2 }, + }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_CONFIGURATOR, .activation_binding_count = 1, @@ -139,6 +153,50 @@ const Config default_config = { }, }, }, + .rgb_configs_count = 2, + .rgb_configs = { + RgbConfig { + .button_colors_count = 19, + .button_colors = { + { BTN_LF1, 0x0000ff }, + { BTN_LF2, 0x0000ff }, + { BTN_LF3, 0x0000ff }, + { BTN_LF4, 0x0000ff }, + { BTN_LT1, 0x0000ff }, + { BTN_LT2, 0x0000ff }, + { BTN_RF1, 0x0000ff }, + { BTN_RF2, 0x0000ff }, + { BTN_RF3, 0x0000ff }, + { BTN_RF4, 0x0000ff }, + { BTN_RF5, 0x0000ff }, + { BTN_RF6, 0x0000ff }, + { BTN_RF7, 0x0000ff }, + { BTN_RF8, 0x0000ff }, + { BTN_RT1, 0x0000ff }, + { BTN_RT2, 0x0000ff }, + { BTN_RT3, 0x0000ff }, + { BTN_RT4, 0x0000ff }, + { BTN_RT5, 0x0000ff }, + }, + }, + RgbConfig { + .button_colors_count = 12, + .button_colors = { + { BTN_LF6, 0xff0000 }, + { BTN_LF7, 0xff0000 }, + { BTN_LF8, 0xff0000 }, + { BTN_LT6, 0xff0000 }, + { BTN_RF9, 0xff0000 }, + { BTN_RF10, 0xff0000 }, + { BTN_RF11, 0xff0000 }, + { BTN_RF1, 0xff0000 }, + { BTN_RF12, 0xff0000 }, + { BTN_RF13, 0xff0000 }, + { BTN_RF14, 0xff0000 }, + { BTN_RF5, 0xff0000 }, + }, + }, + }, .default_backend_config = 1, .default_usb_backend_config = 1, }; diff --git a/HAL/pico/src/comms/NesBackend.cpp b/HAL/pico/src/comms/NesBackend.cpp new file mode 100644 index 00000000..832724ea --- /dev/null +++ b/HAL/pico/src/comms/NesBackend.cpp @@ -0,0 +1,38 @@ +#include "comms/NesBackend.hpp" + +NesBackend::NesBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + uint data_pin, + uint clock_pin, + uint latch_pin, + PIO pio, + int sm, + int offset +) + : CommunicationBackend(inputs, input_sources, input_source_count), + _nes(data_pin, clock_pin, latch_pin, pio, sm, offset) {} + +void NesBackend::SendReport() { + ScanInputs(); + + // Run gamemode logic + UpdateOutputs(); + + // Digital outputs + _report.a = _outputs.a; + _report.b = _outputs.b; + _report.select = _outputs.select; + _report.start = _outputs.start; + _report.dpad_left = _outputs.dpadLeft || _outputs.leftStickX < 128; + _report.dpad_right = _outputs.dpadRight || _outputs.leftStickX > 128; + _report.dpad_down = _outputs.dpadDown || _outputs.leftStickY < 128; + _report.dpad_up = _outputs.dpadUp || _outputs.leftStickY > 128; + + _nes.SendReport(_report); +} + +int NesBackend::GetOffset() { + return _nes.GetOffset(); +} \ No newline at end of file diff --git a/HAL/pico/src/comms/SnesBackend.cpp b/HAL/pico/src/comms/SnesBackend.cpp new file mode 100644 index 00000000..1643bc6e --- /dev/null +++ b/HAL/pico/src/comms/SnesBackend.cpp @@ -0,0 +1,42 @@ +#include "comms/SnesBackend.hpp" + +SnesBackend::SnesBackend( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + uint data_pin, + uint clock_pin, + uint latch_pin, + PIO pio, + int sm, + int offset +) + : CommunicationBackend(inputs, input_sources, input_source_count), + _snes(data_pin, clock_pin, latch_pin, pio, sm, offset) {} + +void SnesBackend::SendReport() { + ScanInputs(); + + // Run gamemode logic + UpdateOutputs(); + + // Digital outputs + _report.a = _outputs.a; + _report.b = _outputs.b; + _report.x = _outputs.x; + _report.y = _outputs.y; + _report.l = _outputs.buttonL || _outputs.triggerLDigital; + _report.r = _outputs.buttonR || _outputs.triggerRDigital; + _report.select = _outputs.select; + _report.start = _outputs.start; + _report.dpad_left = _outputs.dpadLeft || _outputs.leftStickX < 128; + _report.dpad_right = _outputs.dpadRight || _outputs.leftStickX > 128; + _report.dpad_down = _outputs.dpadDown || _outputs.leftStickY < 128; + _report.dpad_up = _outputs.dpadUp || _outputs.leftStickY > 128; + + _snes.SendReport(_report); +} + +int SnesBackend::GetOffset() { + return _snes.GetOffset(); +} \ No newline at end of file diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 5c2e5b1d..53ea207c 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -37,6 +37,9 @@ DebouncedSwitchMatrixInput matrix_input( const Pinout pinout = { .joybus_data = 4, + .nes_data = 4, + .nes_clock = 5, + .nes_latch = 6, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, diff --git a/include/core/pinout.hpp b/include/core/pinout.hpp index 539cca18..79426892 100644 --- a/include/core/pinout.hpp +++ b/include/core/pinout.hpp @@ -5,6 +5,9 @@ typedef struct { uint8_t joybus_data; + uint8_t nes_data; + uint8_t nes_clock; + uint8_t nes_latch; int mux; int nunchuk_detect; int nunchuk_sda; diff --git a/platformio.ini b/platformio.ini index 0df70b82..dcaf05bb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - git+git@github.com:JonnyHaystack/HayBox-proto#3e7fb48 + https://github.com/JonnyHaystack/HayBox-proto#381ef9d [avr_base] platform = atmelavr @@ -109,6 +109,7 @@ lib_archive = no lib_deps = ${env.lib_deps} https://github.com/JonnyHaystack/joybus-pio/archive/refs/tags/v1.2.3.zip + https://github.com/JonnyHaystack/nes-pio#b15c04f https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput eric-wieser/PacketIO@^0.3.0 From 975855303aa2105c81113a365741722690f5ceb9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 17 Dec 2023 16:43:37 +0000 Subject: [PATCH 066/167] feat: use FastLED instead of Adafruit_NeoPixel --- HAL/pico/include/comms/NeoPixelBackend.hpp | 67 +++++++++++++++------ HAL/pico/src/comms/NeoPixelBackend.cpp | 69 ---------------------- config/glyph/include/glyph_overrides.hpp | 6 +- platformio.ini | 2 +- 4 files changed, 52 insertions(+), 92 deletions(-) delete mode 100644 HAL/pico/src/comms/NeoPixelBackend.cpp diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index 143410bc..567413c3 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -3,10 +3,10 @@ #include "core/CommunicationBackend.hpp" -#include +#include #include -class NeoPixelBackend : public CommunicationBackend { +template class NeoPixelBackend : public CommunicationBackend { public: NeoPixelBackend( InputState &inputs, @@ -14,28 +14,59 @@ class NeoPixelBackend : public CommunicationBackend { size_t input_source_count, const Button *button_mappings, const RgbConfig *rgb_configs, - size_t rgb_configs_count, - uint8_t control_pin, - uint16_t pixel_count - ); - ~NeoPixelBackend(); - virtual void SetGameMode(ControllerMode *gamemode); - virtual void SendReport(); + size_t rgb_configs_count + ) + : CommunicationBackend(inputs, input_sources, input_source_count), + _button_mappings(button_mappings), + _rgb_configs(rgb_configs), + _rgb_configs_count(rgb_configs_count) { + FastLED.addLeds(_leds, led_count); + FastLED.setMaxPowerInVoltsAndMilliamps(5, 200); + } + + ~NeoPixelBackend() { FastLED.clear(true); } + + virtual void SetGameMode(ControllerMode *gamemode) { + // Clear current button colors. + for (size_t i = 0; i < button_colors_count; i++) { + _button_colors[i] = 0; + } + + uint8_t rgb_config_id = gamemode->GetConfig().rgb_config; + if (rgb_config_id == 0 || rgb_config_id > _rgb_configs_count) { + _config = nullptr; + return; + } + _config = &_rgb_configs[rgb_config_id - 1]; + + // Build new mapping array to give O(n) lookup later. + for (size_t i = 0; i < _config->button_colors_count; i++) { + ButtonToColorMapping mapping = _config->button_colors[i]; + _button_colors[max(0, mapping.button - 1)] = mapping.color; + } + } + + virtual void SendReport() { + if (_config == nullptr) { + return; + } + for (int i = 0; i < led_count; i++) { + Button button = this->_button_mappings[i]; + _leds[i] = _button_colors[max(0, button - 1)]; + } + FastLED.show(); + } protected: - static constexpr uint8_t max_pixels_per_cycle = 10; static constexpr size_t button_colors_count = sizeof(RgbConfig::button_colors) / sizeof(ButtonToColorMapping); - const Button *button_mappings; - const RgbConfig *rgb_configs; - const size_t rgb_configs_count; - const uint16_t pixel_count; - const uint8_t cycles_per_show; - const RgbConfig *config = nullptr; + const Button *_button_mappings; + const RgbConfig *_rgb_configs; + const size_t _rgb_configs_count; + const RgbConfig *_config = nullptr; - Adafruit_NeoPixel _strip; - size_t _current_pixel = 0; + CRGB _leds[led_count]; uint32_t _button_colors[button_colors_count]; }; diff --git a/HAL/pico/src/comms/NeoPixelBackend.cpp b/HAL/pico/src/comms/NeoPixelBackend.cpp deleted file mode 100644 index a9b83702..00000000 --- a/HAL/pico/src/comms/NeoPixelBackend.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "comms/NeoPixelBackend.hpp" - -NeoPixelBackend::NeoPixelBackend( - InputState &inputs, - InputSource **input_sources, - size_t input_source_count, - const Button *button_mappings, - const RgbConfig *rgb_configs, - size_t rgb_configs_count, - uint8_t control_pin, - uint16_t pixel_count -) - : CommunicationBackend(inputs, input_sources, input_source_count), - button_mappings(button_mappings), - rgb_configs(rgb_configs), - rgb_configs_count(rgb_configs_count), - pixel_count(pixel_count), - cycles_per_show(pixel_count / max_pixels_per_cycle), - _strip(pixel_count, control_pin) { - _strip.begin(); - _strip.setBrightness(100); - if (_strip.canShow()) { - _strip.show(); - } -} - -NeoPixelBackend::~NeoPixelBackend() { - _strip.clear(); -} - -void NeoPixelBackend::SetGameMode(ControllerMode *gamemode) { - // Clear current button colors. - for (size_t i = 0; i < button_colors_count; i++) { - _button_colors[i] = 0; - } - - // Reset current pixel bookmark. - _current_pixel = 0; - - uint8_t rgb_config_id = gamemode->GetConfig().rgb_config; - if (rgb_config_id == 0 || rgb_config_id > rgb_configs_count) { - config = nullptr; - return; - } - config = &rgb_configs[rgb_config_id - 1]; - - // Build new mapping array to give O(n) lookup later. - for (size_t i = 0; i < config->button_colors_count; i++) { - ButtonToColorMapping mapping = config->button_colors[i]; - _button_colors[max(0, mapping.button - 1)] = mapping.color; - } -} - -void NeoPixelBackend::SendReport() { - if (config == nullptr || !_strip.canShow()) { - return; - } - - uint8_t stop_pixel = min(pixel_count, _current_pixel + max_pixels_per_cycle); - for (; _current_pixel < stop_pixel; _current_pixel++) { - volatile Button button = this->button_mappings[_current_pixel]; - volatile uint32_t color = _button_colors[max(0, button - 1)]; - _strip.fill(color, _current_pixel, 1); - } - if (_current_pixel >= pixel_count) { - _current_pixel = 0; - } - _strip.show(); -} \ No newline at end of file diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 496dba3e..3ac883fd 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -131,15 +131,13 @@ size_t init_secondary_backends_glyph( } // Add new backend to array and increase backend count to reflect this. - new_backends[backend_count++] = new NeoPixelBackend( + new_backends[backend_count++] = new NeoPixelBackend( inputs, input_sources, input_source_count, pixel_to_button_mappings, config.rgb_configs, - config.rgb_configs_count, - LED_PIN, - LED_COUNT + config.rgb_configs_count ); // Delete the old backends array and reassign it. diff --git a/platformio.ini b/platformio.ini index dcaf05bb..8a106ac2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -112,7 +112,7 @@ lib_deps = https://github.com/JonnyHaystack/nes-pio#b15c04f https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput + https://github.com/JonnyHaystack/FastLED#all_rp2040_fixes eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 TUCompositeHID - adafruit/Adafruit NeoPixel@^1.12.0 From 3be650330989c69637f6e4af51cc9823e1b48ac9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 17 Dec 2023 16:44:10 +0000 Subject: [PATCH 067/167] fix: add NES/SNES backends to backend_init --- HAL/pico/src/comms/backend_init.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 959bf9e5..d6cc9d08 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -5,7 +5,9 @@ #include "comms/DInputBackend.hpp" #include "comms/GamecubeBackend.hpp" #include "comms/N64Backend.hpp" +#include "comms/NesBackend.hpp" #include "comms/NintendoSwitchBackend.hpp" +#include "comms/SnesBackend.hpp" #include "comms/XInputBackend.hpp" #include "core/CommunicationBackend.hpp" #include "core/config_utils.hpp" @@ -146,6 +148,28 @@ void init_primary_backend( primary_backend = new N64Backend(inputs, input_sources, input_source_count, pinout.joybus_data); break; + case COMMS_BACKEND_NES: + delete primary_backend; + primary_backend = new NesBackend( + inputs, + input_sources, + input_source_count, + pinout.nes_data, + pinout.nes_clock, + pinout.nes_latch + ); + break; + case COMMS_BACKEND_SNES: + delete primary_backend; + primary_backend = new SnesBackend( + inputs, + input_sources, + input_source_count, + pinout.nes_data, + pinout.nes_clock, + pinout.nes_latch + ); + break; case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. case COMMS_BACKEND_CONFIGURATOR: default: From 520f2619aac2f0603c5c033117a14f3813017c28 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 17 Dec 2023 16:45:42 +0000 Subject: [PATCH 068/167] perf: get rid of unnecessary dynamic allocations --- .../avr_usb/include/comms/DInputBackend.hpp | 2 +- HAL/avr/avr_usb/src/comms/DInputBackend.cpp | 46 ++++++++--------- HAL/avr/include/comms/GamecubeBackend.hpp | 3 +- HAL/avr/include/comms/N64Backend.hpp | 3 +- HAL/avr/src/comms/GamecubeBackend.cpp | 10 ++-- HAL/avr/src/comms/N64Backend.cpp | 8 +-- HAL/pico/include/comms/DInputBackend.hpp | 2 +- HAL/pico/include/comms/GamecubeBackend.hpp | 3 +- HAL/pico/include/comms/N64Backend.hpp | 3 +- HAL/pico/src/comms/DInputBackend.cpp | 50 +++++++++---------- HAL/pico/src/comms/GamecubeBackend.cpp | 16 +++--- HAL/pico/src/comms/N64Backend.cpp | 14 ++---- 12 files changed, 68 insertions(+), 92 deletions(-) diff --git a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp index a9fbf183..e5f041b8 100644 --- a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp +++ b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp @@ -16,7 +16,7 @@ class DInputBackend : public CommunicationBackend { void SendReport(); private: - Joystick_ *_joystick; + Joystick_ _joystick; }; #endif diff --git a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp index b2027063..918a6015 100644 --- a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp +++ b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp @@ -11,13 +11,11 @@ DInputBackend::DInputBackend( size_t input_source_count ) : CommunicationBackend(inputs, input_sources, input_source_count) { - _joystick = new Joystick_(); - _joystick->begin(); + _joystick.begin(); } DInputBackend::~DInputBackend() { - _joystick->end(); - delete _joystick; + _joystick.end(); } void DInputBackend::SendReport() { @@ -27,31 +25,31 @@ void DInputBackend::SendReport() { UpdateOutputs(); // Digital outputs - _joystick->setButton(0, _outputs.b); - _joystick->setButton(1, _outputs.a); - _joystick->setButton(2, _outputs.y); - _joystick->setButton(3, _outputs.x); - _joystick->setButton(4, _outputs.buttonR); - _joystick->setButton(5, _outputs.triggerRDigital); - _joystick->setButton(6, _outputs.buttonL); - _joystick->setButton(7, _outputs.triggerLDigital); - _joystick->setButton(8, _outputs.select); - _joystick->setButton(9, _outputs.start); - _joystick->setButton(10, _outputs.rightStickClick); - _joystick->setButton(11, _outputs.leftStickClick); - _joystick->setButton(12, _outputs.home); + _joystick.setButton(0, _outputs.b); + _joystick.setButton(1, _outputs.a); + _joystick.setButton(2, _outputs.y); + _joystick.setButton(3, _outputs.x); + _joystick.setButton(4, _outputs.buttonR); + _joystick.setButton(5, _outputs.triggerRDigital); + _joystick.setButton(6, _outputs.buttonL); + _joystick.setButton(7, _outputs.triggerLDigital); + _joystick.setButton(8, _outputs.select); + _joystick.setButton(9, _outputs.start); + _joystick.setButton(10, _outputs.rightStickClick); + _joystick.setButton(11, _outputs.leftStickClick); + _joystick.setButton(12, _outputs.home); // Analog outputs - _joystick->setLeftXAxis(_outputs.leftStickX); - _joystick->setLeftYAxis(255 - _outputs.leftStickY); - _joystick->setRightXAxis(_outputs.rightStickX); - _joystick->setRightYAxis(255 - _outputs.rightStickY); - _joystick->setLeftTrigger(_outputs.triggerLAnalog + 1); - _joystick->setRightTrigger(_outputs.triggerRAnalog + 1); + _joystick.setLeftXAxis(_outputs.leftStickX); + _joystick.setLeftYAxis(255 - _outputs.leftStickY); + _joystick.setRightXAxis(_outputs.rightStickX); + _joystick.setRightYAxis(255 - _outputs.rightStickY); + _joystick.setLeftTrigger(_outputs.triggerLAnalog + 1); + _joystick.setRightTrigger(_outputs.triggerRAnalog + 1); // D-pad Hat Switch _joystick ->setHatSwitch(_outputs.dpadLeft, _outputs.dpadRight, _outputs.dpadDown, _outputs.dpadUp); - _joystick->sendState(); + _joystick.sendState(); } diff --git a/HAL/avr/include/comms/GamecubeBackend.hpp b/HAL/avr/include/comms/GamecubeBackend.hpp index 9544c068..7127a620 100644 --- a/HAL/avr/include/comms/GamecubeBackend.hpp +++ b/HAL/avr/include/comms/GamecubeBackend.hpp @@ -15,11 +15,10 @@ class GamecubeBackend : public CommunicationBackend { int polling_rate, int data_pin ); - ~GamecubeBackend(); void SendReport(); private: - CGamecubeConsole *_gamecube; + CGamecubeConsole _gamecube; Gamecube_Data_t _data; int _delay; }; diff --git a/HAL/avr/include/comms/N64Backend.hpp b/HAL/avr/include/comms/N64Backend.hpp index 0326aaca..6c90197b 100644 --- a/HAL/avr/include/comms/N64Backend.hpp +++ b/HAL/avr/include/comms/N64Backend.hpp @@ -15,11 +15,10 @@ class N64Backend : public CommunicationBackend { int polling_rate, int data_pin ); - ~N64Backend(); void SendReport(); private: - CN64Console *_n64; + CN64Console _n64; N64_Data_t _data; int _delay; }; diff --git a/HAL/avr/src/comms/GamecubeBackend.cpp b/HAL/avr/src/comms/GamecubeBackend.cpp index 0b292863..11c29745 100644 --- a/HAL/avr/src/comms/GamecubeBackend.cpp +++ b/HAL/avr/src/comms/GamecubeBackend.cpp @@ -12,8 +12,8 @@ GamecubeBackend::GamecubeBackend( int polling_rate, int data_pin ) - : CommunicationBackend(inputs, input_sources, input_source_count) { - _gamecube = new CGamecubeConsole(data_pin); + : CommunicationBackend(inputs, input_sources, input_source_count), + _gamecube(data_pin) { _data = defaultGamecubeData; if (polling_rate > 0) { @@ -26,10 +26,6 @@ GamecubeBackend::GamecubeBackend( } } -GamecubeBackend::~GamecubeBackend() { - delete _gamecube; -} - void GamecubeBackend::SendReport() { // Update inputs from all sources at once. ScanInputs(); @@ -60,7 +56,7 @@ void GamecubeBackend::SendReport() { _data.report.right = _outputs.triggerRAnalog + 31; // Send outputs to console. - _gamecube->write(_data); + _gamecube.write(_data); delayMicroseconds(_delay); } diff --git a/HAL/avr/src/comms/N64Backend.cpp b/HAL/avr/src/comms/N64Backend.cpp index 0817ffef..98e88deb 100644 --- a/HAL/avr/src/comms/N64Backend.cpp +++ b/HAL/avr/src/comms/N64Backend.cpp @@ -9,8 +9,8 @@ N64Backend::N64Backend( int polling_rate, int data_pin ) - : CommunicationBackend(inputs, input_sources, input_source_count) { - _n64 = new CN64Console(data_pin); + : CommunicationBackend(inputs, input_sources, input_source_count), + _n64(data_pin) { _data = defaultN64Data; if (polling_rate > 0) { @@ -23,10 +23,6 @@ N64Backend::N64Backend( } } -N64Backend::~N64Backend() { - delete _n64; -} - void N64Backend::SendReport() { // Update inputs from all sources at once. ScanInputs(); diff --git a/HAL/pico/include/comms/DInputBackend.hpp b/HAL/pico/include/comms/DInputBackend.hpp index 96281ec4..6f890f8a 100644 --- a/HAL/pico/include/comms/DInputBackend.hpp +++ b/HAL/pico/include/comms/DInputBackend.hpp @@ -14,7 +14,7 @@ class DInputBackend : public CommunicationBackend { void SendReport(); private: - TUGamepad *_gamepad; + TUGamepad _gamepad; }; #endif diff --git a/HAL/pico/include/comms/GamecubeBackend.hpp b/HAL/pico/include/comms/GamecubeBackend.hpp index dac858f2..ad3ee553 100644 --- a/HAL/pico/include/comms/GamecubeBackend.hpp +++ b/HAL/pico/include/comms/GamecubeBackend.hpp @@ -17,12 +17,11 @@ class GamecubeBackend : public CommunicationBackend { int sm = -1, int offset = -1 ); - ~GamecubeBackend(); void SendReport(); int GetOffset(); private: - GamecubeConsole *_gamecube; + GamecubeConsole _gamecube; gc_report_t _report; }; diff --git a/HAL/pico/include/comms/N64Backend.hpp b/HAL/pico/include/comms/N64Backend.hpp index 0f4b7f64..7266cf6d 100644 --- a/HAL/pico/include/comms/N64Backend.hpp +++ b/HAL/pico/include/comms/N64Backend.hpp @@ -17,12 +17,11 @@ class N64Backend : public CommunicationBackend { int sm = -1, int offset = -1 ); - ~N64Backend(); void SendReport(); int GetOffset(); private: - N64Console *_n64; + N64Console _n64; n64_report_t _report; }; diff --git a/HAL/pico/src/comms/DInputBackend.cpp b/HAL/pico/src/comms/DInputBackend.cpp index c420234b..0b5204d6 100644 --- a/HAL/pico/src/comms/DInputBackend.cpp +++ b/HAL/pico/src/comms/DInputBackend.cpp @@ -11,20 +11,18 @@ DInputBackend::DInputBackend( size_t input_source_count ) : CommunicationBackend(inputs, input_sources, input_source_count) { - _gamepad = new TUGamepad(); - _gamepad->begin(); + _gamepad.begin(); } DInputBackend::~DInputBackend() { - _gamepad->resetInputs(); - delete _gamepad; + _gamepad.resetInputs(); } void DInputBackend::SendReport() { ScanInputs(InputScanSpeed::SLOW); ScanInputs(InputScanSpeed::MEDIUM); - while (!_gamepad->ready()) { + while (!_gamepad.ready()) { tight_loop_contents(); } @@ -33,30 +31,30 @@ void DInputBackend::SendReport() { UpdateOutputs(); // Digital outputs - _gamepad->setButton(0, _outputs.b); - _gamepad->setButton(1, _outputs.a); - _gamepad->setButton(2, _outputs.y); - _gamepad->setButton(3, _outputs.x); - _gamepad->setButton(4, _outputs.buttonR); - _gamepad->setButton(5, _outputs.triggerRDigital); - _gamepad->setButton(6, _outputs.buttonL); - _gamepad->setButton(7, _outputs.triggerLDigital); - _gamepad->setButton(8, _outputs.select); - _gamepad->setButton(9, _outputs.start); - _gamepad->setButton(10, _outputs.rightStickClick); - _gamepad->setButton(11, _outputs.leftStickClick); - _gamepad->setButton(12, _outputs.home); + _gamepad.setButton(0, _outputs.b); + _gamepad.setButton(1, _outputs.a); + _gamepad.setButton(2, _outputs.y); + _gamepad.setButton(3, _outputs.x); + _gamepad.setButton(4, _outputs.buttonR); + _gamepad.setButton(5, _outputs.triggerRDigital); + _gamepad.setButton(6, _outputs.buttonL); + _gamepad.setButton(7, _outputs.triggerLDigital); + _gamepad.setButton(8, _outputs.select); + _gamepad.setButton(9, _outputs.start); + _gamepad.setButton(10, _outputs.rightStickClick); + _gamepad.setButton(11, _outputs.leftStickClick); + _gamepad.setButton(12, _outputs.home); // Analog outputs - _gamepad->leftXAxis(_outputs.leftStickX); - _gamepad->leftYAxis(255 - _outputs.leftStickY); - _gamepad->rightXAxis(_outputs.rightStickX); - _gamepad->rightYAxis(255 - _outputs.rightStickY); - _gamepad->triggerLAnalog(_outputs.triggerLAnalog + 1); - _gamepad->triggerRAnalog(_outputs.triggerRAnalog + 1); + _gamepad.leftXAxis(_outputs.leftStickX); + _gamepad.leftYAxis(255 - _outputs.leftStickY); + _gamepad.rightXAxis(_outputs.rightStickX); + _gamepad.rightYAxis(255 - _outputs.rightStickY); + _gamepad.triggerLAnalog(_outputs.triggerLAnalog + 1); + _gamepad.triggerRAnalog(_outputs.triggerRAnalog + 1); // D-pad Hat Switch - _gamepad->hatSwitch(_outputs.dpadLeft, _outputs.dpadRight, _outputs.dpadDown, _outputs.dpadUp); + _gamepad.hatSwitch(_outputs.dpadLeft, _outputs.dpadRight, _outputs.dpadDown, _outputs.dpadUp); - _gamepad->sendState(); + _gamepad.sendState(); } diff --git a/HAL/pico/src/comms/GamecubeBackend.cpp b/HAL/pico/src/comms/GamecubeBackend.cpp index 43249488..b5d7aa9d 100644 --- a/HAL/pico/src/comms/GamecubeBackend.cpp +++ b/HAL/pico/src/comms/GamecubeBackend.cpp @@ -15,22 +15,18 @@ GamecubeBackend::GamecubeBackend( int sm, int offset ) - : CommunicationBackend(inputs, input_sources, input_source_count) { - _gamecube = new GamecubeConsole(data_pin, pio, sm, offset); + : CommunicationBackend(inputs, input_sources, input_source_count), + _gamecube(data_pin, pio, sm, offset) { _report = default_gc_report; } -GamecubeBackend::~GamecubeBackend() { - delete _gamecube; -} - void GamecubeBackend::SendReport() { // Update slower inputs before we start waiting for poll. ScanInputs(InputScanSpeed::SLOW); ScanInputs(InputScanSpeed::MEDIUM); // Read inputs - _gamecube->WaitForPollStart(); + _gamecube.WaitForPollStart(); // Update fast inputs in response to poll. // But wait 40us first so that we read inputs at the start of the 3rd byte of the poll command @@ -64,11 +60,11 @@ void GamecubeBackend::SendReport() { _report.r_analog = _outputs.triggerRAnalog; // Send outputs to console unless poll command is invalid. - if (_gamecube->WaitForPollEnd() != PollStatus::ERROR) { - _gamecube->SendReport(&_report); + if (_gamecube.WaitForPollEnd() != PollStatus::ERROR) { + _gamecube.SendReport(&_report); } } int GamecubeBackend::GetOffset() { - return _gamecube->GetOffset(); + return _gamecube.GetOffset(); } diff --git a/HAL/pico/src/comms/N64Backend.cpp b/HAL/pico/src/comms/N64Backend.cpp index 8193c7b6..d01018d7 100644 --- a/HAL/pico/src/comms/N64Backend.cpp +++ b/HAL/pico/src/comms/N64Backend.cpp @@ -14,22 +14,18 @@ N64Backend::N64Backend( int sm, int offset ) - : CommunicationBackend(inputs, input_sources, input_source_count) { - _n64 = new N64Console(data_pin, pio, sm, offset); + : CommunicationBackend(inputs, input_sources, input_source_count), + _n64(data_pin, pio, sm, offset) { _report = default_n64_report; } -N64Backend::~N64Backend() { - delete _n64; -} - void N64Backend::SendReport() { // Update slower inputs before we start waiting for poll. ScanInputs(InputScanSpeed::SLOW); ScanInputs(InputScanSpeed::MEDIUM); // Read inputs - _n64->WaitForPoll(); + _n64.WaitForPoll(); // Update fast inputs in response to poll. ScanInputs(InputScanSpeed::FAST); @@ -59,9 +55,9 @@ void N64Backend::SendReport() { _report.stick_y = _outputs.leftStickY - 128; // Send outputs to console. - _n64->SendReport(&_report); + _n64.SendReport(&_report); } int N64Backend::GetOffset() { - return _n64->GetOffset(); + return _n64.GetOffset(); } From 58ba272121796f150317b217258948b5157d2d50 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 20 Dec 2023 14:36:33 +0000 Subject: [PATCH 069/167] build: fix missing FastLED option --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 8a106ac2..a7f5c098 100644 --- a/platformio.ini +++ b/platformio.ini @@ -96,6 +96,7 @@ build_flags = -D USE_TINYUSB -D CFG_TUSB_CONFIG_FILE=\"tusb_config_pico.h\" -D NDEBUG + -D FASTLED_RP2040_CLOCKLESS_M0_FALLBACK=0 -Wall -Wstack-usage=1024 -Wno-unused-variable From 608ebf1de5440234fef5deaab95ebf56a49a5dc9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 22 Dec 2023 00:47:47 +0000 Subject: [PATCH 070/167] fix: wrong array length fields in default Pico config --- HAL/pico/include/config_defaults.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 38779061..459e9a12 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -79,7 +79,7 @@ const Config default_config = { .keyboard_mode_config = 1, }, }, - .communication_backend_configs_count = 6, + .communication_backend_configs_count = 8, .communication_backend_configs = { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_XINPUT, @@ -108,11 +108,13 @@ const Config default_config = { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_NES, .default_mode_config = 1, + .activation_binding_count = 1, .activation_binding = { BTN_LT1 }, }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_SNES, .default_mode_config = 1, + .activation_binding_count = 1, .activation_binding = { BTN_LT2 }, }, CommunicationBackendConfig { From d28159115e7794028162e2d58ba050437fb1d97e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 2 Jan 2024 18:22:10 +0000 Subject: [PATCH 071/167] fix: update pico config --- config/pico/config.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 669b2b0f..cae924d4 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -46,7 +46,7 @@ GpioButtonMapping button_mappings[] = { }; const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -DebouncedGpioButtonInput gpio_input(button_mappings, 5); +DebouncedGpioButtonInput gpio_input(button_mappings); const Pinout pinout = { .joybus_data = 28, @@ -94,13 +94,7 @@ void setup() { } void loop() { - select_mode( - backends[0], - config.game_mode_configs, - config.game_mode_configs_count, - config.keyboard_modes, - config.keyboard_modes_count - ); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); From 7443bb5982eaf39a8ef262167d604e0d3fb15d7c Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 2 Jan 2024 18:22:33 +0000 Subject: [PATCH 072/167] build: pin XInput lib to specific tag --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index a7f5c098..6ab71780 100644 --- a/platformio.ini +++ b/platformio.ini @@ -112,7 +112,7 @@ lib_deps = https://github.com/JonnyHaystack/joybus-pio/archive/refs/tags/v1.2.3.zip https://github.com/JonnyHaystack/nes-pio#b15c04f https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip - https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput + https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput#4b5617b https://github.com/JonnyHaystack/FastLED#all_rp2040_fixes eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 From b686722bd65b3fbd9a71fbd1dcfc811347e9662f Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 3 Jan 2024 18:08:16 +0000 Subject: [PATCH 073/167] build: update HayBox-proto version --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 6ab71780..45aee7b0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#381ef9d + https://github.com/JonnyHaystack/HayBox-proto#ad75259 [avr_base] platform = atmelavr From 5aa2a7fc90331d8ab88494876b81169501651e74 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 30 Jan 2024 00:35:57 +0000 Subject: [PATCH 074/167] ci: make build workflow safer --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3fccaade..de522c60 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,7 +61,7 @@ jobs: run: | pio run -e ${{ matrix.env }} mkdir -p ${{ matrix.env }} - cp .pio/build/${{ matrix.env }}/firmware.${{ matrix.bin_ext }} ${{ matrix.env }}/HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} + cp ".pio/build/${{ matrix.env }}/firmware.${{ matrix.bin_ext }}" "${{ matrix.env }}/HayBox-${VERSION_REF}-${{ matrix.env }}.${{ matrix.bin_ext }}" - name: Publish ${{ matrix.env }} artifacts uses: actions/upload-artifact@v3 From 0649a0a4cdd743a51521888002eb6f5f1bb4ea73 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 30 Jan 2024 00:36:41 +0000 Subject: [PATCH 075/167] build: switch back to mainline FastLED now that PRs are merged --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 45aee7b0..825241e7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -105,7 +105,7 @@ build_src_filter = ${env.build_src_filter} + platform_packages = - framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.1 + framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.3 lib_archive = no lib_deps = ${env.lib_deps} @@ -113,7 +113,7 @@ lib_deps = https://github.com/JonnyHaystack/nes-pio#b15c04f https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput#4b5617b - https://github.com/JonnyHaystack/FastLED#all_rp2040_fixes + https://github.com/FastLED/FastLED#6daa782 eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 TUCompositeHID From 0a358fbc84596feb2435858a5133dcfa411a27c9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 8 Feb 2024 20:55:29 +0000 Subject: [PATCH 076/167] feat: OLED display support --- config/glyph/include/glyph_overrides.hpp | 76 ++---- include/comms/IntegratedDisplay.hpp | 91 +++++++ src/comms/IntegratedDisplay.cpp | 305 +++++++++++++++++++++++ 3 files changed, 421 insertions(+), 51 deletions(-) create mode 100644 include/comms/IntegratedDisplay.hpp create mode 100644 src/comms/IntegratedDisplay.cpp diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 3ac883fd..9de7d968 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -1,8 +1,10 @@ #include "comms/B0XXInputViewer.hpp" +#include "comms/IntegratedDisplay.hpp" #include "comms/NeoPixelBackend.hpp" #include "core/config_utils.hpp" #include "stdlib.hpp" +#include #include #define LED_PIN 7 @@ -51,56 +53,7 @@ const Button pixel_to_button_mappings[LED_COUNT] = { // clang-format on -void usb_backend_from_4pos_switch( - CommunicationBackendConfig &backend_config, - const Config &config -) { - const uint pin2 = 8; - const uint pin3 = 9; - const uint pin4 = 10; - - pinMode(pin2, INPUT_PULLUP); - pinMode(pin3, INPUT_PULLUP); - pinMode(pin4, INPUT_PULLUP); - - uint toggle_switch_state = 0; - if (!digitalRead(pin3)) { - toggle_switch_state = 1; - } else if (!digitalRead(pin4)) { - toggle_switch_state = 4; - } else { - pinMode(pin2, OUTPUT); - digitalWrite(pin2, LOW); - - if (!digitalRead(pin4)) { - toggle_switch_state = 2; - } else { - toggle_switch_state = 3; - } - } - - CommunicationBackendId backend_id = COMMS_BACKEND_UNSPECIFIED; - - switch (toggle_switch_state) { - case 1: - backend_id = COMMS_BACKEND_XINPUT; - break; - case 2: - backend_id = COMMS_BACKEND_DINPUT; - break; - case 3: - backend_id = COMMS_BACKEND_NINTENDO_SWITCH; - break; - case 4: - break; - } - - backend_config = backend_config_from_id( - backend_id, - config.communication_backend_configs, - config.communication_backend_configs_count - ); -} +Adafruit_SSD1306 display(128, 64, &Wire1); size_t init_secondary_backends_glyph( CommunicationBackend **&backends, @@ -125,7 +78,8 @@ size_t init_secondary_backends_glyph( // Create new array containing all old backends but with length increased by 1 to make space for // NeoPixel backend. - CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 1]; + // CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 1]; + CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 2]; for (size_t i = 0; i < backend_count; i++) { new_backends[i] = backends[i]; } @@ -140,6 +94,26 @@ size_t init_secondary_backends_glyph( config.rgb_configs_count ); + Wire1.setSDA(2); + Wire1.setSCL(3); + Wire1.begin(); + Wire1.setClock(1'000'000UL); + if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { + backend_count++; + new_backends[backend_count - 1] = new IntegratedDisplay( + inputs, + input_sources, + input_source_count, + 128, + 64, + Wire1, + config, + backend_id, + new_backends, + backend_count + ); + } + // Delete the old backends array and reassign it. delete[] backends; backends = new_backends; diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp new file mode 100644 index 00000000..bcd2bba8 --- /dev/null +++ b/include/comms/IntegratedDisplay.hpp @@ -0,0 +1,91 @@ +#ifndef _COMMS_INTEGRATEDDISPLAY_HPP +#define _COMMS_INTEGRATEDDISPLAY_HPP + +#include "core/CommunicationBackend.hpp" +#include "core/Persistence.hpp" +#include "core/config_utils.hpp" +#include "core/mode_selection.hpp" +#include "reboot.hpp" + +#include +#include +#include +#include + +typedef enum _DisplayMode { + DISPLAY_MODE_VIEWER, + DISPLAY_MODE_CONFIG, +} DisplayMode; + +class IntegratedDisplay; + +typedef struct _MenuPage { + typedef struct _MenuItem { + char text[20]; + uint8_t key = 0; + void (*action)(IntegratedDisplay *instance, Config &config, uint8_t key) = nullptr; + struct _MenuPage *page = nullptr; + } MenuItem; + + struct _MenuPage *parent = nullptr; + const MenuItem *items = nullptr; + size_t items_count = 0; +} MenuPage; + +class IntegratedDisplay : public CommunicationBackend { + public: + IntegratedDisplay( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Adafruit_GFX &display, + Config &config, + CommunicationBackendId backend_id, + CommunicationBackend **backends, + size_t backends_count + ); + ~IntegratedDisplay(); + virtual void UpdateOutputs(); + virtual void SetGameMode(ControllerMode *gamemode); + virtual void SendReport(); + + protected: + static constexpr uint8_t padding = 2; + static constexpr uint32_t button_cooldown_ms = 150; + static constexpr uint8_t font_width = 6; + static constexpr uint8_t font_height = 8; + static constexpr uint8_t max_visible_lines = 6; + static constexpr char highlight_string[] = ">"; + + Adafruit_GFX _display; + Config &_config; + const CommunicationBackendId _backend_id; + DisplayMode _display_mode = DISPLAY_MODE_VIEWER; + GameModeId _gamemode = MODE_UNSPECIFIED; + char _gamemode_text[16] = ""; + + absolute_time_t _button_cooldown_end = 0; + MenuPage *_current_menu_page = &_top_level_page; + uint8_t _highlighted_menu_item = 0; + int _current_menu_offset = 0; + + private: + MenuPage _usb_backends_page; + MenuPage _gamemode_options_page; + MenuPage _top_level_page; + CommunicationBackend **_backends; + size_t _backends_count; + + static void SetDefaultMode( + IntegratedDisplay *instance, + Config &config, + uint8_t mode_config_index + ); + static void SetDefaultUsbBackend( + IntegratedDisplay *instance, + Config &config, + uint8_t backend_config_index + ); +}; + +#endif \ No newline at end of file diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp new file mode 100644 index 00000000..ddd0d81f --- /dev/null +++ b/src/comms/IntegratedDisplay.cpp @@ -0,0 +1,305 @@ +#include "comms/IntegratedDisplay.hpp" + +#include "core/Persistence.hpp" +#include "core/config_utils.hpp" + +IntegratedDisplay::IntegratedDisplay( + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Adafruit_GFX &display, + Config &config, + CommunicationBackendId backend_id, + CommunicationBackend **backends, + size_t backends_count +) + : CommunicationBackend(inputs, input_sources, input_source_count), + _display(display), + _config(config), + _backend_id(backend_id), + _backends(backends), + _backends_count(backends_count) { + _display.setTextSize(1); + _display.setTextColor(WHITE); + + /* Build default USB backends page */ + MenuPage::MenuItem *usb_backend_options = + new MenuPage::MenuItem[config.communication_backend_configs_count]; + + size_t usb_backend_options_count = 0; + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; + MenuPage::MenuItem ¤t_backend_option = usb_backend_options[usb_backend_options_count]; + + if (backend_config.backend_id != COMMS_BACKEND_XINPUT && + backend_config.backend_id != COMMS_BACKEND_DINPUT && + backend_config.backend_id != COMMS_BACKEND_NINTENDO_SWITCH) { + continue; + } + + strlcpy( + current_backend_option.text, + backend_name(backend_config.backend_id), + sizeof(current_backend_option.text) + ); + current_backend_option.key = i; + current_backend_option.action = &SetDefaultUsbBackend; + usb_backend_options_count++; + } + + _usb_backends_page = { + .items = usb_backend_options, + .items_count = usb_backend_options_count, + }; + + /* Build gamemodes page */ + MenuPage::MenuItem *gamemode_options = new MenuPage::MenuItem[config.game_mode_configs_count]; + + size_t gamemode_options_count = 0; + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + MenuPage::MenuItem ¤t_gamemode_option = gamemode_options[gamemode_options_count]; + + // Don't show keyboard modes as a gamemode option unless using DInputBackend. + if (_backend_id != COMMS_BACKEND_DINPUT && mode_config.mode_id == MODE_KEYBOARD) { + continue; + } + + if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { + strlcpy( + current_gamemode_option.text, + mode_config.name, + sizeof(current_gamemode_option.text) + ); + } else { + strlcpy( + current_gamemode_option.text, + gamemode_name(mode_config.mode_id), + sizeof(current_gamemode_option.text) + ); + } + current_gamemode_option.key = i; + current_gamemode_option.action = &SetDefaultMode; + gamemode_options_count++; + } + + _gamemode_options_page = { + .items = gamemode_options, + .items_count = gamemode_options_count, + }; + + /* Build top-level page */ + char top_level_item1_text[] = "Default Gamemode"; + char top_level_item2_text[] = "Default USB Mode"; + char top_level_item3_text[] = "Exit"; + + // clang-format off + static const MenuPage::MenuItem top_level_items[] = { + { + .text = "Gamemode", + .page = &_gamemode_options_page, + }, + { + .text = "Default USB Mode", + .page = &_usb_backends_page, + }, + { + .text = "Return", + .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { + instance->_display_mode = DISPLAY_MODE_VIEWER; + }, + }, + { + .text = "Save changes", + .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { + persistence.SaveConfig(config); + reboot_firmware(); + }, + }, + { + .text = "Discard changes", + .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { + reboot_firmware(); + }, + } + }; + // clang-format on + + _top_level_page = { + .items = top_level_items, + .items_count = sizeof(top_level_items) / sizeof(MenuPage::MenuItem), + }; + + _usb_backends_page.parent = &_top_level_page; + _gamemode_options_page.parent = &_top_level_page; +} + +IntegratedDisplay::~IntegratedDisplay() { + delete[] _usb_backends_page.items; + delete[] _gamemode_options_page.items; + + _display.clearDisplay(); + _display.display(); +} + +void IntegratedDisplay::SetGameMode(ControllerMode *gamemode) { + _gamemode = gamemode->GetConfig().mode_id; + strlcpy(_gamemode_text, gamemode_name(_gamemode), sizeof(_gamemode_text)); +} + +void IntegratedDisplay::UpdateOutputs() { + // Process inputs. + if (!time_reached(_button_cooldown_end)) { + return; + } + if (_current_menu_page == nullptr) { + _current_menu_page = &_top_level_page; + _current_menu_offset = 0; + return; + } + + if (_display_mode != DISPLAY_MODE_CONFIG) { + if (_inputs.mb7) { + _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); + _display_mode = DISPLAY_MODE_CONFIG; + } + return; + } + + // Handle Up button press. + if (_inputs.mb6) { + _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); + + _highlighted_menu_item = max(0, _highlighted_menu_item - 1); + return; + } + + // Handle Down button press. + if (_inputs.mb5) { + _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); + + _highlighted_menu_item = + min(_current_menu_page->items_count - 1, _highlighted_menu_item + 1); + return; + } + + // Handle Select button press. + if (_inputs.mb7) { + _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); + + // Bounds check. + if (_highlighted_menu_item > _current_menu_page->items_count) { + _highlighted_menu_item = 0; + return; + } + + const MenuPage::MenuItem &selected_item = _current_menu_page->items[_highlighted_menu_item]; + + // If there's an action defined, perform it. + if (selected_item.action != nullptr) { + selected_item.action(this, _config, selected_item.key); + + // Go back up a level. + if (_current_menu_page->parent != nullptr) { + _current_menu_page = _current_menu_page->parent; + _current_menu_offset = 0; + } + _highlighted_menu_item = 0; + return; + } + + // If there's a child page defined, drill into it. + if (selected_item.page != nullptr) { + _current_menu_page = selected_item.page; + _current_menu_offset = 0; + _highlighted_menu_item = 0; + return; + } + } + + // Handle Back button press. + if (_inputs.mb4) { + _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); + + if (_current_menu_page->parent == nullptr) { + _display_mode = DISPLAY_MODE_VIEWER; + return; + } + + _current_menu_page = _current_menu_page->parent; + _highlighted_menu_item = 0; + return; + } +} + +void IntegratedDisplay::SendReport() { + UpdateOutputs(); + + _display.clearDisplay(); + + if (_display_mode == DISPLAY_MODE_VIEWER) { + /* Gamemode text */ + _display.setCursor(0, 0); + _display.print(_gamemode_text); + + /* Backend text */ + const char *backend_text = backend_name(_backend_id); + _display.setCursor(_display.width() - (strlen(backend_text) * 6), 0); + _display.print(backend_name(_backend_id)); + } else if (_display_mode == DISPLAY_MODE_CONFIG) { + /* Menu */ + if (_highlighted_menu_item - _current_menu_offset > max_visible_lines - 1) { + _current_menu_offset++; + } else if (_highlighted_menu_item < _current_menu_offset) { + _current_menu_offset--; + } + uint8_t last_item_to_display = + min(_current_menu_page->items_count - _current_menu_offset, max_visible_lines + 1); + for (size_t i = 0; i < last_item_to_display; i++) { + if (i + _current_menu_offset == _highlighted_menu_item) { + _display.setCursor(0, i * (font_height + padding)); + _display.print(highlight_string); + } + _display.setCursor(font_width + padding, i * (font_height + padding)); + _display.print(_current_menu_page->items[i + _current_menu_offset].text); + } + } + + _display.display(); +} + +void IntegratedDisplay::SetDefaultMode( + IntegratedDisplay *instance, + Config &config, + uint8_t mode_config_index +) { + if (mode_config_index < 0 || mode_config_index >= config.game_mode_configs_count) { + return; + } + + // Overwrite default game mode for all backend configs. + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + config.communication_backend_configs[i].default_mode_config = mode_config_index + 1; + } + + for (size_t i = 0; i < instance->_backends_count; i++) { + set_mode( + instance->_backends[i], + config.game_mode_configs[mode_config_index], + config.keyboard_modes, + config.keyboard_modes_count + ); + } +} + +void IntegratedDisplay::SetDefaultUsbBackend( + IntegratedDisplay *instance, + Config &config, + uint8_t backend_config_index +) { + if (backend_config_index < 0 || + backend_config_index >= config.communication_backend_configs_count) { + return; + } + config.default_usb_backend_config = backend_config_index + 1; +} From 6503d84126e328694c6d538acb38374d68f549e1 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 8 Feb 2024 21:02:07 +0000 Subject: [PATCH 077/167] feat: add missing stuff for OLED support --- HAL/avr/proto/config.options | 2 +- HAL/pico/include/config_defaults.hpp | 1 - HAL/pico/include/core/Persistence.hpp | 2 + HAL/pico/src/core/Persistence.cpp | 4 +- config/glyph/config.cpp | 8 ++-- config/glyph/env.ini | 1 + config/glyph/include/glyph_overrides.hpp | 8 ++-- include/comms/IntegratedDisplay.hpp | 6 ++- include/core/CommunicationBackend.hpp | 2 +- include/core/config_utils.hpp | 48 ++++++++++++++++++++++++ include/core/state.hpp | 2 +- platformio.ini | 4 +- src/comms/IntegratedDisplay.cpp | 12 ++++-- src/core/config_utils.cpp | 17 ++++++++- 14 files changed, 96 insertions(+), 21 deletions(-) diff --git a/HAL/avr/proto/config.options b/HAL/avr/proto/config.options index d6b360c5..0df23090 100644 --- a/HAL/avr/proto/config.options +++ b/HAL/avr/proto/config.options @@ -11,6 +11,7 @@ ButtonToKeycodeMapping.keycode int_size:IS_8 ButtonToColorMapping.button int_size:IS_8 GameModeConfig.mode_id int_size:IS_8 +GameModeConfig.name max_length:17 GameModeConfig.socd_pairs max_count:10 GameModeConfig.socd_pairs type:FT_POINTER GameModeConfig.button_remapping max_count:60 @@ -20,7 +21,6 @@ GameModeConfig.activation_binding type:FT_POINTER GameModeConfig.keyboard_mode_config int_size:IS_8 KeyboardModeConfig.id int_size:IS_8 -KeyboardModeConfig.name max_length:20 KeyboardModeConfig.buttons_to_keycodes max_count:60 KeyboardModeConfig.buttons_to_keycodes type:FT_POINTER diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 459e9a12..55598ae3 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -127,7 +127,6 @@ const Config default_config = { .keyboard_modes = { KeyboardModeConfig { 0, - "Default", 22, { { BTN_LF4, HID_KEY_A }, diff --git a/HAL/pico/include/core/Persistence.hpp b/HAL/pico/include/core/Persistence.hpp index 2096c1e6..6ce5d426 100644 --- a/HAL/pico/include/core/Persistence.hpp +++ b/HAL/pico/include/core/Persistence.hpp @@ -42,4 +42,6 @@ class Persistence { static uint8_t _buffer[eeprom_size - config_offset]; }; +extern Persistence persistence; + #endif \ No newline at end of file diff --git a/HAL/pico/src/core/Persistence.cpp b/HAL/pico/src/core/Persistence.cpp index 6825485f..4cfcb638 100644 --- a/HAL/pico/src/core/Persistence.cpp +++ b/HAL/pico/src/core/Persistence.cpp @@ -103,4 +103,6 @@ size_t Persistence::LoadConfigRaw(uint8_t *buffer, size_t buffer_len) { // Return the number of bytes of config data read. return bytes_read; -} \ No newline at end of file +} + +Persistence persistence; \ No newline at end of file diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 53ea207c..4ae9c420 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -62,11 +62,9 @@ void setup() { } // Attempt to load config, or write default config to flash if failed to load config. - Persistence *persistence = new Persistence(); - if (!persistence->LoadConfig(config)) { - persistence->SaveConfig(config); + if (!persistence.LoadConfig(config)) { + persistence.SaveConfig(config); } - delete persistence; // Create array of input sources to be used. static InputSource *input_sources[] = {}; @@ -80,7 +78,7 @@ void setup() { config, pinout, get_backend_config_default, - &usb_backend_from_4pos_switch, + get_usb_backend_config_default, &detect_console, &init_secondary_backends_glyph ); diff --git a/config/glyph/env.ini b/config/glyph/env.ini index 39d2f3f0..8da252a8 100644 --- a/config/glyph/env.ini +++ b/config/glyph/env.ini @@ -3,6 +3,7 @@ extends = arduino_pico_base build_flags = ${arduino_pico_base.build_flags} -I config/glyph/include + -D SSD1306_NO_SPLASH build_src_filter = ${arduino_pico_base.build_src_filter} + diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 9de7d968..f55a881c 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -100,18 +100,20 @@ size_t init_secondary_backends_glyph( Wire1.setClock(1'000'000UL); if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { backend_count++; + // clang-format off new_backends[backend_count - 1] = new IntegratedDisplay( inputs, input_sources, input_source_count, - 128, - 64, - Wire1, + display, + []() { display.clearDisplay(); }, + []() { display.display(); }, config, backend_id, new_backends, backend_count ); + // clang-format on } // Delete the old backends array and reassign it. diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp index bcd2bba8..ff8f887c 100644 --- a/include/comms/IntegratedDisplay.hpp +++ b/include/comms/IntegratedDisplay.hpp @@ -39,6 +39,8 @@ class IntegratedDisplay : public CommunicationBackend { InputSource **input_sources, size_t input_source_count, Adafruit_GFX &display, + void (*clear_display)(), + void (*update_display)(), Config &config, CommunicationBackendId backend_id, CommunicationBackend **backends, @@ -57,7 +59,9 @@ class IntegratedDisplay : public CommunicationBackend { static constexpr uint8_t max_visible_lines = 6; static constexpr char highlight_string[] = ">"; - Adafruit_GFX _display; + Adafruit_GFX &_display; + void (*_clear_display)(); + void (*_update_display)(); Config &_config; const CommunicationBackendId _backend_id; DisplayMode _display_mode = DISPLAY_MODE_VIEWER; diff --git a/include/core/CommunicationBackend.hpp b/include/core/CommunicationBackend.hpp index f644c439..46928b75 100644 --- a/include/core/CommunicationBackend.hpp +++ b/include/core/CommunicationBackend.hpp @@ -18,7 +18,7 @@ class CommunicationBackend { void ScanInputs(); void ScanInputs(InputScanSpeed input_source_filter); - void UpdateOutputs(); + virtual void UpdateOutputs(); virtual void SetGameMode(ControllerMode *gamemode); virtual void SendReport() = 0; diff --git a/include/core/config_utils.hpp b/include/core/config_utils.hpp index 7fc1e161..c6171742 100644 --- a/include/core/config_utils.hpp +++ b/include/core/config_utils.hpp @@ -17,10 +17,58 @@ CommunicationBackendConfig backend_config_from_id( size_t backend_configs_count ); +uint8_t backend_config_id_from_backend_id( + CommunicationBackendId backend_id, + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count +); + uint8_t mode_config_id_from_mode_id( GameModeId mode_id, const GameModeConfig *mode_configs, size_t mode_configs_count ); +constexpr const char *gamemode_name(GameModeId mode_id) { + switch (mode_id) { + case MODE_MELEE: + return "Melee"; + case MODE_PROJECT_M: + return "Project M"; + case MODE_ULTIMATE: + return "Ultimate"; + case MODE_FGC: + return "FGC"; + case MODE_RIVALS_OF_AETHER: + return "Rivals"; + case MODE_KEYBOARD: + return "Keyboard"; + default: + return "Unknown"; + } +} + +constexpr const char *backend_name(CommunicationBackendId backend_id) { + switch (backend_id) { + case COMMS_BACKEND_DINPUT: + return "DInput"; + case COMMS_BACKEND_XINPUT: + return "XInput"; + case COMMS_BACKEND_GAMECUBE: + return "GameCube"; + case COMMS_BACKEND_N64: + return "N64"; + case COMMS_BACKEND_NES: + return "NES"; + case COMMS_BACKEND_SNES: + return "SNES"; + case COMMS_BACKEND_NINTENDO_SWITCH: + return "Switch"; + case COMMS_BACKEND_CONFIGURATOR: + return "Configurator"; + default: + return "Unknown"; + } +} + #endif \ No newline at end of file diff --git a/include/core/state.hpp b/include/core/state.hpp index 987a0aae..391641f7 100644 --- a/include/core/state.hpp +++ b/include/core/state.hpp @@ -101,7 +101,7 @@ typedef struct { } StickDirections; // Output state. -typedef struct outputstate { +typedef struct _OutputState { // Digital outputs. bool a = false; bool b = false; diff --git a/platformio.ini b/platformio.ini index 825241e7..147aa1a9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#ad75259 + https://github.com/JonnyHaystack/HayBox-proto#3c14f28 [avr_base] platform = atmelavr @@ -114,6 +114,8 @@ lib_deps = https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput#4b5617b https://github.com/FastLED/FastLED#6daa782 + adafruit/Adafruit SSD1306@^2.5.9 + adafruit/Adafruit GFX Library@^1.11.9 eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 TUCompositeHID diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp index ddd0d81f..d3601fd0 100644 --- a/src/comms/IntegratedDisplay.cpp +++ b/src/comms/IntegratedDisplay.cpp @@ -8,6 +8,8 @@ IntegratedDisplay::IntegratedDisplay( InputSource **input_sources, size_t input_source_count, Adafruit_GFX &display, + void (*clear_display)(), + void (*update_display)(), Config &config, CommunicationBackendId backend_id, CommunicationBackend **backends, @@ -15,6 +17,8 @@ IntegratedDisplay::IntegratedDisplay( ) : CommunicationBackend(inputs, input_sources, input_source_count), _display(display), + _clear_display(clear_display), + _update_display(update_display), _config(config), _backend_id(backend_id), _backends(backends), @@ -138,8 +142,8 @@ IntegratedDisplay::~IntegratedDisplay() { delete[] _usb_backends_page.items; delete[] _gamemode_options_page.items; - _display.clearDisplay(); - _display.display(); + _clear_display(); + _update_display(); } void IntegratedDisplay::SetGameMode(ControllerMode *gamemode) { @@ -235,7 +239,7 @@ void IntegratedDisplay::UpdateOutputs() { void IntegratedDisplay::SendReport() { UpdateOutputs(); - _display.clearDisplay(); + _clear_display(); if (_display_mode == DISPLAY_MODE_VIEWER) { /* Gamemode text */ @@ -265,7 +269,7 @@ void IntegratedDisplay::SendReport() { } } - _display.display(); + _update_display(); } void IntegratedDisplay::SetDefaultMode( diff --git a/src/core/config_utils.cpp b/src/core/config_utils.cpp index 59841deb..beeb1202 100644 --- a/src/core/config_utils.cpp +++ b/src/core/config_utils.cpp @@ -35,8 +35,6 @@ CommunicationBackendConfig backend_config_from_id( const CommunicationBackendConfig *backend_configs, size_t backend_configs_count ) { - // Find the first backend config that matches the detected console so we can check what the - // configured default gamemode is. for (size_t i = 0; i < backend_configs_count; i++) { const CommunicationBackendConfig &backend_config = backend_configs[i]; if (backend_config.backend_id == backend_id) { @@ -50,6 +48,21 @@ CommunicationBackendConfig backend_config_from_id( }; } +uint8_t backend_config_id_from_backend_id( + CommunicationBackendId backend_id, + const CommunicationBackendConfig *backend_configs, + size_t backend_configs_count +) { + for (size_t i = 0; i < backend_configs_count; i++) { + const CommunicationBackendConfig &backend_config = backend_configs[i]; + if (backend_config.backend_id == backend_id) { + return i + 1; + } + } + + return 0; +} + uint8_t mode_config_id_from_mode_id( GameModeId mode_id, const GameModeConfig *mode_configs, From a250f49db007de5ae8acd6420c8f5e0fbe60da71 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 8 Feb 2024 21:02:23 +0000 Subject: [PATCH 078/167] chore: update clang-format config --- .clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.clang-format b/.clang-format index 32c2f383..b65ffac5 100644 --- a/.clang-format +++ b/.clang-format @@ -37,7 +37,7 @@ PackConstructorInitializers: CurrentLine PenaltyReturnTypeOnItsOwnLine: 2000 PointerAlignment: Right QualifierAlignment: Custom -QualifierOrder: ['inline', 'static', 'const', 'constexpr', 'restrict', 'volatile', 'type'] +QualifierOrder: ['inline', 'static', 'constexpr', 'const', 'restrict', 'volatile', 'type'] ReferenceAlignment: Right ReflowComments: true SeparateDefinitionBlocks: Always From a97eabf67a3a66b7d9636f225e417ec5dad5c3e9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 8 Feb 2024 22:17:51 +0000 Subject: [PATCH 079/167] feat: move default RGB config to Glyph overrides --- HAL/pico/include/config_defaults.hpp | 44 ---------------------- config/glyph/config.cpp | 3 +- config/glyph/include/glyph_overrides.hpp | 48 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 55598ae3..65282faf 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -154,50 +154,6 @@ const Config default_config = { }, }, }, - .rgb_configs_count = 2, - .rgb_configs = { - RgbConfig { - .button_colors_count = 19, - .button_colors = { - { BTN_LF1, 0x0000ff }, - { BTN_LF2, 0x0000ff }, - { BTN_LF3, 0x0000ff }, - { BTN_LF4, 0x0000ff }, - { BTN_LT1, 0x0000ff }, - { BTN_LT2, 0x0000ff }, - { BTN_RF1, 0x0000ff }, - { BTN_RF2, 0x0000ff }, - { BTN_RF3, 0x0000ff }, - { BTN_RF4, 0x0000ff }, - { BTN_RF5, 0x0000ff }, - { BTN_RF6, 0x0000ff }, - { BTN_RF7, 0x0000ff }, - { BTN_RF8, 0x0000ff }, - { BTN_RT1, 0x0000ff }, - { BTN_RT2, 0x0000ff }, - { BTN_RT3, 0x0000ff }, - { BTN_RT4, 0x0000ff }, - { BTN_RT5, 0x0000ff }, - }, - }, - RgbConfig { - .button_colors_count = 12, - .button_colors = { - { BTN_LF6, 0xff0000 }, - { BTN_LF7, 0xff0000 }, - { BTN_LF8, 0xff0000 }, - { BTN_LT6, 0xff0000 }, - { BTN_RF9, 0xff0000 }, - { BTN_RF10, 0xff0000 }, - { BTN_RF11, 0xff0000 }, - { BTN_RF1, 0xff0000 }, - { BTN_RF12, 0xff0000 }, - { BTN_RF13, 0xff0000 }, - { BTN_RF14, 0xff0000 }, - { BTN_RF5, 0xff0000 }, - }, - }, - }, .default_backend_config = 1, .default_usb_backend_config = 1, }; diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 4ae9c420..790475cc 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -1,5 +1,4 @@ #include "comms/backend_init.hpp" -#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" #include "core/KeyboardMode.hpp" #include "core/Persistence.hpp" @@ -13,7 +12,7 @@ #include -Config config = default_config; +Config config = glyph_default_config(); const size_t num_rows = 4; const size_t num_cols = 11; diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index f55a881c..223f7a53 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -1,6 +1,7 @@ #include "comms/B0XXInputViewer.hpp" #include "comms/IntegratedDisplay.hpp" #include "comms/NeoPixelBackend.hpp" +#include "config_defaults.hpp" #include "core/config_utils.hpp" #include "stdlib.hpp" @@ -53,6 +54,53 @@ const Button pixel_to_button_mappings[LED_COUNT] = { // clang-format on +Config glyph_default_config() { + Config config = default_config; + config.rgb_configs_count = 2; + config.rgb_configs[0] = { + .button_colors_count = 19, + .button_colors = { + { BTN_LF1, 0x0000ff }, + { BTN_LF2, 0x0000ff }, + { BTN_LF3, 0x0000ff }, + { BTN_LF4, 0x0000ff }, + { BTN_LT1, 0x0000ff }, + { BTN_LT2, 0x0000ff }, + { BTN_RF1, 0x0000ff }, + { BTN_RF2, 0x0000ff }, + { BTN_RF3, 0x0000ff }, + { BTN_RF4, 0x0000ff }, + { BTN_RF5, 0x0000ff }, + { BTN_RF6, 0x0000ff }, + { BTN_RF7, 0x0000ff }, + { BTN_RF8, 0x0000ff }, + { BTN_RT1, 0x0000ff }, + { BTN_RT2, 0x0000ff }, + { BTN_RT3, 0x0000ff }, + { BTN_RT4, 0x0000ff }, + { BTN_RT5, 0x0000ff }, + }, + }; + config.rgb_configs[1] = { + .button_colors_count = 12, + .button_colors = { + { BTN_LF6, 0xff0000 }, + { BTN_LF7, 0xff0000 }, + { BTN_LF8, 0xff0000 }, + { BTN_LT6, 0xff0000 }, + { BTN_RF9, 0xff0000 }, + { BTN_RF10, 0xff0000 }, + { BTN_RF11, 0xff0000 }, + { BTN_RF1, 0xff0000 }, + { BTN_RF12, 0xff0000 }, + { BTN_RF13, 0xff0000 }, + { BTN_RF14, 0xff0000 }, + { BTN_RF5, 0xff0000 }, + }, + }; + return config; +} + Adafruit_SSD1306 display(128, 64, &Wire1); size_t init_secondary_backends_glyph( From 535d12a2d56486702f81101f9ecafa479a60a1da Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 8 Feb 2024 23:15:43 +0000 Subject: [PATCH 080/167] style: remove commented out code --- config/glyph/include/glyph_overrides.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 223f7a53..3a7d3c4c 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -126,7 +126,6 @@ size_t init_secondary_backends_glyph( // Create new array containing all old backends but with length increased by 1 to make space for // NeoPixel backend. - // CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 1]; CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 2]; for (size_t i = 0; i < backend_count; i++) { new_backends[i] = backends[i]; From 736aed9d5c809c117ab8a98c28e76808cb191f33 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 6 Mar 2024 02:51:19 +0000 Subject: [PATCH 081/167] feat: add SOCD menu to OLED and move to core1 --- .../avr_nousb/include/core/KeyboardMode.hpp | 2 +- HAL/avr/avr_nousb/src/core/KeyboardMode.cpp | 2 +- .../avr_usb/include/comms/DInputBackend.hpp | 1 + HAL/avr/avr_usb/include/core/KeyboardMode.hpp | 2 +- HAL/avr/avr_usb/src/comms/DInputBackend.cpp | 4 ++ HAL/avr/avr_usb/src/core/KeyboardMode.cpp | 2 +- HAL/avr/include/comms/GamecubeBackend.hpp | 1 + HAL/avr/include/comms/N64Backend.hpp | 1 + HAL/avr/src/comms/GamecubeBackend.cpp | 4 ++ HAL/avr/src/comms/N64Backend.cpp | 4 ++ .../include/comms/ConfiguratorBackend.hpp | 1 + HAL/pico/include/comms/DInputBackend.hpp | 1 + HAL/pico/include/comms/GamecubeBackend.hpp | 1 + HAL/pico/include/comms/N64Backend.hpp | 1 + HAL/pico/include/comms/NesBackend.hpp | 1 + .../include/comms/NintendoSwitchBackend.hpp | 1 + HAL/pico/include/comms/SnesBackend.hpp | 1 + HAL/pico/include/comms/XInputBackend.hpp | 1 + HAL/pico/include/core/KeyboardMode.hpp | 2 +- HAL/pico/src/comms/ConfiguratorBackend.cpp | 4 ++ HAL/pico/src/comms/DInputBackend.cpp | 4 ++ HAL/pico/src/comms/GamecubeBackend.cpp | 4 ++ HAL/pico/src/comms/N64Backend.cpp | 4 ++ HAL/pico/src/comms/NesBackend.cpp | 4 ++ HAL/pico/src/comms/NintendoSwitchBackend.cpp | 4 ++ HAL/pico/src/comms/SnesBackend.cpp | 4 ++ HAL/pico/src/comms/XInputBackend.cpp | 4 ++ HAL/pico/src/comms/backend_init.cpp | 2 +- HAL/pico/src/core/KeyboardMode.cpp | 2 +- config/glyph/config.cpp | 45 +++++++++--- config/glyph/include/glyph_overrides.hpp | 24 ------- include/comms/IntegratedDisplay.hpp | 2 +- include/core/CommunicationBackend.hpp | 2 + include/core/ControllerMode.hpp | 2 +- include/core/InputMode.hpp | 6 +- include/core/config_utils.hpp | 17 +++++ include/core/mode_selection.hpp | 6 +- include/modes/CustomKeyboardMode.hpp | 2 +- include/modes/DefaultKeyboardMode.hpp | 2 +- include/modes/FgcMode.hpp | 2 +- include/modes/Melee18Button.hpp | 2 +- include/modes/Melee20Button.hpp | 2 +- include/modes/ProjectM.hpp | 2 +- include/modes/RivalsOfAether.hpp | 2 +- include/modes/Ultimate.hpp | 2 +- include/modes/extra/DarkSouls.hpp | 2 +- include/modes/extra/HollowKnight.hpp | 2 +- include/modes/extra/MKWii.hpp | 2 +- include/modes/extra/MultiVersus.hpp | 2 +- include/modes/extra/RocketLeague.hpp | 2 +- include/modes/extra/SaltAndSanctuary.hpp | 2 +- include/modes/extra/ShovelKnight.hpp | 2 +- include/modes/extra/ToughLoveArena.hpp | 2 +- include/modes/extra/Ultimate2.hpp | 2 +- src/comms/IntegratedDisplay.cpp | 70 +++++++++++++------ src/core/CommunicationBackend.cpp | 10 +++ src/core/ControllerMode.cpp | 2 +- src/core/InputMode.cpp | 4 +- src/core/mode_selection.cpp | 10 +-- src/modes/CustomKeyboardMode.cpp | 2 +- src/modes/DefaultKeyboardMode.cpp | 2 +- src/modes/FgcMode.cpp | 2 +- src/modes/Melee18Button.cpp | 2 +- src/modes/Melee20Button.cpp | 2 +- src/modes/ProjectM.cpp | 2 +- src/modes/RivalsOfAether.cpp | 2 +- src/modes/Ultimate.cpp | 2 +- src/modes/extra/DarkSouls.cpp | 2 +- src/modes/extra/HollowKnight.cpp | 2 +- src/modes/extra/MKWii.cpp | 2 +- src/modes/extra/MultiVersus.cpp | 2 +- src/modes/extra/RocketLeague.cpp | 2 +- src/modes/extra/SaltAndSanctuary.cpp | 2 +- src/modes/extra/ShovelKnight.cpp | 2 +- src/modes/extra/ToughLoveArena.cpp | 2 +- src/modes/extra/Ultimate2.cpp | 2 +- 76 files changed, 225 insertions(+), 112 deletions(-) diff --git a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp index f8354dfc..7a9f78b8 100644 --- a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp @@ -8,7 +8,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(const GameModeConfig &config); + KeyboardMode(GameModeConfig &config); ~KeyboardMode(); void SendReport(const InputState &inputs); diff --git a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp index 0509739d..66cc370a 100644 --- a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp @@ -2,7 +2,7 @@ #include "core/InputMode.hpp" -KeyboardMode::KeyboardMode(const GameModeConfig &config) : InputMode(config) {} +KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) {} KeyboardMode::~KeyboardMode() {} diff --git a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp index e5f041b8..f0e7b785 100644 --- a/HAL/avr/avr_usb/include/comms/DInputBackend.hpp +++ b/HAL/avr/avr_usb/include/comms/DInputBackend.hpp @@ -13,6 +13,7 @@ class DInputBackend : public CommunicationBackend { public: DInputBackend(InputState &inputs, InputSource **input_sources, size_t input_source_count); ~DInputBackend(); + CommunicationBackendId BackendId(); void SendReport(); private: diff --git a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp index a9dd3148..3673c4ce 100644 --- a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp @@ -9,7 +9,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(const GameModeConfig &config); + KeyboardMode(GameModeConfig &config); ~KeyboardMode(); void SendReport(const InputState &inputs); diff --git a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp index 918a6015..72349eb4 100644 --- a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp +++ b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp @@ -18,6 +18,10 @@ DInputBackend::~DInputBackend() { _joystick.end(); } +CommunicationBackendId DInputBackend::BackendId() { + return COMMS_BACKEND_DINPUT; +} + void DInputBackend::SendReport() { // Update inputs from all sources at once. ScanInputs(); diff --git a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp index dd1c912f..5e3f5692 100644 --- a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp @@ -4,7 +4,7 @@ #include -KeyboardMode::KeyboardMode(const GameModeConfig &config) : InputMode(config) {} +KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) {} KeyboardMode::~KeyboardMode() { _keyboard.releaseAll(); diff --git a/HAL/avr/include/comms/GamecubeBackend.hpp b/HAL/avr/include/comms/GamecubeBackend.hpp index 7127a620..2780d774 100644 --- a/HAL/avr/include/comms/GamecubeBackend.hpp +++ b/HAL/avr/include/comms/GamecubeBackend.hpp @@ -15,6 +15,7 @@ class GamecubeBackend : public CommunicationBackend { int polling_rate, int data_pin ); + CommunicationBackendId BackendId(); void SendReport(); private: diff --git a/HAL/avr/include/comms/N64Backend.hpp b/HAL/avr/include/comms/N64Backend.hpp index 6c90197b..34a141fa 100644 --- a/HAL/avr/include/comms/N64Backend.hpp +++ b/HAL/avr/include/comms/N64Backend.hpp @@ -15,6 +15,7 @@ class N64Backend : public CommunicationBackend { int polling_rate, int data_pin ); + CommunicationBackendId BackendId(); void SendReport(); private: diff --git a/HAL/avr/src/comms/GamecubeBackend.cpp b/HAL/avr/src/comms/GamecubeBackend.cpp index 11c29745..370d6f71 100644 --- a/HAL/avr/src/comms/GamecubeBackend.cpp +++ b/HAL/avr/src/comms/GamecubeBackend.cpp @@ -26,6 +26,10 @@ GamecubeBackend::GamecubeBackend( } } +CommunicationBackendId GamecubeBackend::BackendId() { + return COMMS_BACKEND_GAMECUBE; +} + void GamecubeBackend::SendReport() { // Update inputs from all sources at once. ScanInputs(); diff --git a/HAL/avr/src/comms/N64Backend.cpp b/HAL/avr/src/comms/N64Backend.cpp index 98e88deb..fbda0868 100644 --- a/HAL/avr/src/comms/N64Backend.cpp +++ b/HAL/avr/src/comms/N64Backend.cpp @@ -23,6 +23,10 @@ N64Backend::N64Backend( } } +CommunicationBackendId N64Backend::BackendId() { + return COMMS_BACKEND_N64; +} + void N64Backend::SendReport() { // Update inputs from all sources at once. ScanInputs(); diff --git a/HAL/pico/include/comms/ConfiguratorBackend.hpp b/HAL/pico/include/comms/ConfiguratorBackend.hpp index 58f84040..46c505fb 100644 --- a/HAL/pico/include/comms/ConfiguratorBackend.hpp +++ b/HAL/pico/include/comms/ConfiguratorBackend.hpp @@ -34,6 +34,7 @@ class ConfiguratorBackend : public CommunicationBackend { Config &config ); ~ConfiguratorBackend(); + CommunicationBackendId BackendId(); void SendReport(); private: diff --git a/HAL/pico/include/comms/DInputBackend.hpp b/HAL/pico/include/comms/DInputBackend.hpp index 6f890f8a..1758c361 100644 --- a/HAL/pico/include/comms/DInputBackend.hpp +++ b/HAL/pico/include/comms/DInputBackend.hpp @@ -11,6 +11,7 @@ class DInputBackend : public CommunicationBackend { public: DInputBackend(InputState &inputs, InputSource **input_sources, size_t input_source_count); ~DInputBackend(); + CommunicationBackendId BackendId(); void SendReport(); private: diff --git a/HAL/pico/include/comms/GamecubeBackend.hpp b/HAL/pico/include/comms/GamecubeBackend.hpp index ad3ee553..c08c3e7e 100644 --- a/HAL/pico/include/comms/GamecubeBackend.hpp +++ b/HAL/pico/include/comms/GamecubeBackend.hpp @@ -17,6 +17,7 @@ class GamecubeBackend : public CommunicationBackend { int sm = -1, int offset = -1 ); + CommunicationBackendId BackendId(); void SendReport(); int GetOffset(); diff --git a/HAL/pico/include/comms/N64Backend.hpp b/HAL/pico/include/comms/N64Backend.hpp index 7266cf6d..f82c676b 100644 --- a/HAL/pico/include/comms/N64Backend.hpp +++ b/HAL/pico/include/comms/N64Backend.hpp @@ -17,6 +17,7 @@ class N64Backend : public CommunicationBackend { int sm = -1, int offset = -1 ); + CommunicationBackendId BackendId(); void SendReport(); int GetOffset(); diff --git a/HAL/pico/include/comms/NesBackend.hpp b/HAL/pico/include/comms/NesBackend.hpp index 816a9ce2..83378a88 100644 --- a/HAL/pico/include/comms/NesBackend.hpp +++ b/HAL/pico/include/comms/NesBackend.hpp @@ -18,6 +18,7 @@ class NesBackend : public CommunicationBackend { int sm = -1, int offset = -1 ); + CommunicationBackendId BackendId(); void SendReport(); int GetOffset(); diff --git a/HAL/pico/include/comms/NintendoSwitchBackend.hpp b/HAL/pico/include/comms/NintendoSwitchBackend.hpp index c8b5eed0..0d16ac39 100644 --- a/HAL/pico/include/comms/NintendoSwitchBackend.hpp +++ b/HAL/pico/include/comms/NintendoSwitchBackend.hpp @@ -50,6 +50,7 @@ class NintendoSwitchBackend : public CommunicationBackend { static void RegisterDescriptor(); + CommunicationBackendId BackendId(); void SendReport(); protected: diff --git a/HAL/pico/include/comms/SnesBackend.hpp b/HAL/pico/include/comms/SnesBackend.hpp index 45eb2ae7..aca980c9 100644 --- a/HAL/pico/include/comms/SnesBackend.hpp +++ b/HAL/pico/include/comms/SnesBackend.hpp @@ -18,6 +18,7 @@ class SnesBackend : public CommunicationBackend { int sm = -1, int offset = -1 ); + CommunicationBackendId BackendId(); void SendReport(); int GetOffset(); diff --git a/HAL/pico/include/comms/XInputBackend.hpp b/HAL/pico/include/comms/XInputBackend.hpp index 72140782..d0f884c9 100644 --- a/HAL/pico/include/comms/XInputBackend.hpp +++ b/HAL/pico/include/comms/XInputBackend.hpp @@ -10,6 +10,7 @@ class XInputBackend : public CommunicationBackend { public: XInputBackend(InputState &inputs, InputSource **input_sources, size_t input_source_count); + CommunicationBackendId BackendId(); void SendReport(); private: diff --git a/HAL/pico/include/core/KeyboardMode.hpp b/HAL/pico/include/core/KeyboardMode.hpp index ab11ebfe..b6a3cd0b 100644 --- a/HAL/pico/include/core/KeyboardMode.hpp +++ b/HAL/pico/include/core/KeyboardMode.hpp @@ -10,7 +10,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(const GameModeConfig &config); + KeyboardMode(GameModeConfig &config); ~KeyboardMode(); void SendReport(const InputState &inputs); diff --git a/HAL/pico/src/comms/ConfiguratorBackend.cpp b/HAL/pico/src/comms/ConfiguratorBackend.cpp index 8216e03e..661932c0 100644 --- a/HAL/pico/src/comms/ConfiguratorBackend.cpp +++ b/HAL/pico/src/comms/ConfiguratorBackend.cpp @@ -43,6 +43,10 @@ ConfiguratorBackend::~ConfiguratorBackend() { delete _persistence; } +CommunicationBackendId ConfiguratorBackend::BackendId() { + return COMMS_BACKEND_CONFIGURATOR; +} + void ConfiguratorBackend::SendReport() { size_t packet_len = ReadPacket(_cmd_buffer, sizeof(_cmd_buffer)); Command command = (Command)_cmd_buffer[0]; diff --git a/HAL/pico/src/comms/DInputBackend.cpp b/HAL/pico/src/comms/DInputBackend.cpp index 0b5204d6..e1941c55 100644 --- a/HAL/pico/src/comms/DInputBackend.cpp +++ b/HAL/pico/src/comms/DInputBackend.cpp @@ -18,6 +18,10 @@ DInputBackend::~DInputBackend() { _gamepad.resetInputs(); } +CommunicationBackendId DInputBackend::BackendId() { + return COMMS_BACKEND_DINPUT; +} + void DInputBackend::SendReport() { ScanInputs(InputScanSpeed::SLOW); ScanInputs(InputScanSpeed::MEDIUM); diff --git a/HAL/pico/src/comms/GamecubeBackend.cpp b/HAL/pico/src/comms/GamecubeBackend.cpp index b5d7aa9d..2c8ee35a 100644 --- a/HAL/pico/src/comms/GamecubeBackend.cpp +++ b/HAL/pico/src/comms/GamecubeBackend.cpp @@ -20,6 +20,10 @@ GamecubeBackend::GamecubeBackend( _report = default_gc_report; } +CommunicationBackendId GamecubeBackend::BackendId() { + return COMMS_BACKEND_GAMECUBE; +} + void GamecubeBackend::SendReport() { // Update slower inputs before we start waiting for poll. ScanInputs(InputScanSpeed::SLOW); diff --git a/HAL/pico/src/comms/N64Backend.cpp b/HAL/pico/src/comms/N64Backend.cpp index d01018d7..f45d2032 100644 --- a/HAL/pico/src/comms/N64Backend.cpp +++ b/HAL/pico/src/comms/N64Backend.cpp @@ -19,6 +19,10 @@ N64Backend::N64Backend( _report = default_n64_report; } +CommunicationBackendId N64Backend::BackendId() { + return COMMS_BACKEND_N64; +} + void N64Backend::SendReport() { // Update slower inputs before we start waiting for poll. ScanInputs(InputScanSpeed::SLOW); diff --git a/HAL/pico/src/comms/NesBackend.cpp b/HAL/pico/src/comms/NesBackend.cpp index 832724ea..c59063e0 100644 --- a/HAL/pico/src/comms/NesBackend.cpp +++ b/HAL/pico/src/comms/NesBackend.cpp @@ -14,6 +14,10 @@ NesBackend::NesBackend( : CommunicationBackend(inputs, input_sources, input_source_count), _nes(data_pin, clock_pin, latch_pin, pio, sm, offset) {} +CommunicationBackendId NesBackend::BackendId() { + return COMMS_BACKEND_NES; +} + void NesBackend::SendReport() { ScanInputs(); diff --git a/HAL/pico/src/comms/NintendoSwitchBackend.cpp b/HAL/pico/src/comms/NintendoSwitchBackend.cpp index 0c92edae..c4aab389 100644 --- a/HAL/pico/src/comms/NintendoSwitchBackend.cpp +++ b/HAL/pico/src/comms/NintendoSwitchBackend.cpp @@ -107,6 +107,10 @@ void NintendoSwitchBackend::RegisterDescriptor() { TUCompositeHID::addDescriptor(_descriptor, sizeof(_descriptor)); } +CommunicationBackendId NintendoSwitchBackend::BackendId() { + return COMMS_BACKEND_NINTENDO_SWITCH; +} + void NintendoSwitchBackend::SendReport() { ScanInputs(InputScanSpeed::SLOW); ScanInputs(InputScanSpeed::MEDIUM); diff --git a/HAL/pico/src/comms/SnesBackend.cpp b/HAL/pico/src/comms/SnesBackend.cpp index 1643bc6e..fab8bbfa 100644 --- a/HAL/pico/src/comms/SnesBackend.cpp +++ b/HAL/pico/src/comms/SnesBackend.cpp @@ -14,6 +14,10 @@ SnesBackend::SnesBackend( : CommunicationBackend(inputs, input_sources, input_source_count), _snes(data_pin, clock_pin, latch_pin, pio, sm, offset) {} +CommunicationBackendId SnesBackend::BackendId() { + return COMMS_BACKEND_SNES; +} + void SnesBackend::SendReport() { ScanInputs(); diff --git a/HAL/pico/src/comms/XInputBackend.cpp b/HAL/pico/src/comms/XInputBackend.cpp index 343eac38..068b7296 100644 --- a/HAL/pico/src/comms/XInputBackend.cpp +++ b/HAL/pico/src/comms/XInputBackend.cpp @@ -19,6 +19,10 @@ XInputBackend::XInputBackend( TinyUSBDevice.setID(0x0738, 0x4726); } +CommunicationBackendId XInputBackend::BackendId() { + return COMMS_BACKEND_XINPUT; +} + void XInputBackend::SendReport() { ScanInputs(InputScanSpeed::SLOW); ScanInputs(InputScanSpeed::MEDIUM); diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index d6cc9d08..9b0b8aab 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -99,7 +99,7 @@ size_t initialize_backends( } if (backend_config.default_mode_config > 0) { - const GameModeConfig &mode_config = + GameModeConfig &mode_config = config.game_mode_configs[backend_config.default_mode_config - 1]; for (size_t i = 0; i < backend_count; i++) { set_mode(backends[i], mode_config, config.keyboard_modes, config.keyboard_modes_count); diff --git a/HAL/pico/src/core/KeyboardMode.cpp b/HAL/pico/src/core/KeyboardMode.cpp index 126fba6f..c06b1bf9 100644 --- a/HAL/pico/src/core/KeyboardMode.cpp +++ b/HAL/pico/src/core/KeyboardMode.cpp @@ -4,7 +4,7 @@ #include -KeyboardMode::KeyboardMode(const GameModeConfig &config) : InputMode(config) { +KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) { _keyboard = new TUKeyboard(); _keyboard->begin(); } diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 790475cc..f539253a 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -49,9 +49,12 @@ CommunicationBackend **backends = nullptr; size_t backend_count; KeyboardMode *current_kb_mode = nullptr; -void setup() { - static InputState inputs; +InputState inputs; + +InputSource *input_sources[] = { &matrix_input }; +size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); +void setup() { // Create GPIO input source and use it to read button states for checking button holds. matrix_input.UpdateInputs(inputs); @@ -66,9 +69,6 @@ void setup() { } // Create array of input sources to be used. - static InputSource *input_sources[] = {}; - size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - backend_count = initialize_backends( backends, inputs, @@ -97,16 +97,41 @@ void loop() { } } -/* Button inputs are read from the second core */ +/* Second core handles OLED display */ +Adafruit_SSD1306 display(128, 64, &Wire1); +IntegratedDisplay *display_backend = nullptr; void setup1() { - while (backends == nullptr) { - tight_loop_contents(); + while (!backend_count || backends == nullptr) { + delay(1); + } + Wire1.setSDA(2); + Wire1.setSCL(3); + Wire1.setClock(1'000'000UL); + Wire1.begin(); + if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { + // clang-format off + display_backend = new IntegratedDisplay( + inputs, + input_sources, + input_source_count, + display, + []() { display.clearDisplay(); }, + []() { display.display(); }, + config, + backends[0]->BackendId(), + backends, + backend_count + ); + // clang-format on } } void loop1() { - if (backends != nullptr) { - matrix_input.UpdateInputs(backends[0]->GetInputs()); + if (display_backend != nullptr) { + if (display_backend->CurrentGameMode() != backends[0]->CurrentGameMode()) { + display_backend->SetGameMode(backends[0]->CurrentGameMode()); + } + display_backend->SendReport(); } } diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 3a7d3c4c..49de71c5 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -101,8 +101,6 @@ Config glyph_default_config() { return config; } -Adafruit_SSD1306 display(128, 64, &Wire1); - size_t init_secondary_backends_glyph( CommunicationBackend **&backends, CommunicationBackend *&primary_backend, @@ -141,28 +139,6 @@ size_t init_secondary_backends_glyph( config.rgb_configs_count ); - Wire1.setSDA(2); - Wire1.setSCL(3); - Wire1.begin(); - Wire1.setClock(1'000'000UL); - if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { - backend_count++; - // clang-format off - new_backends[backend_count - 1] = new IntegratedDisplay( - inputs, - input_sources, - input_source_count, - display, - []() { display.clearDisplay(); }, - []() { display.display(); }, - config, - backend_id, - new_backends, - backend_count - ); - // clang-format on - } - // Delete the old backends array and reassign it. delete[] backends; backends = new_backends; diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp index ff8f887c..d79467a0 100644 --- a/include/comms/IntegratedDisplay.hpp +++ b/include/comms/IntegratedDisplay.hpp @@ -65,7 +65,6 @@ class IntegratedDisplay : public CommunicationBackend { Config &_config; const CommunicationBackendId _backend_id; DisplayMode _display_mode = DISPLAY_MODE_VIEWER; - GameModeId _gamemode = MODE_UNSPECIFIED; char _gamemode_text[16] = ""; absolute_time_t _button_cooldown_end = 0; @@ -90,6 +89,7 @@ class IntegratedDisplay : public CommunicationBackend { Config &config, uint8_t backend_config_index ); + static void SetSocdType(IntegratedDisplay *instance, Config &config, uint8_t socd_type); }; #endif \ No newline at end of file diff --git a/include/core/CommunicationBackend.hpp b/include/core/CommunicationBackend.hpp index 46928b75..cad38b78 100644 --- a/include/core/CommunicationBackend.hpp +++ b/include/core/CommunicationBackend.hpp @@ -19,7 +19,9 @@ class CommunicationBackend { void ScanInputs(InputScanSpeed input_source_filter); virtual void UpdateOutputs(); + virtual CommunicationBackendId BackendId(); virtual void SetGameMode(ControllerMode *gamemode); + virtual ControllerMode *CurrentGameMode(); virtual void SendReport() = 0; diff --git a/include/core/ControllerMode.hpp b/include/core/ControllerMode.hpp index a8e2ff09..fa66cd9d 100644 --- a/include/core/ControllerMode.hpp +++ b/include/core/ControllerMode.hpp @@ -9,7 +9,7 @@ class ControllerMode : public InputMode { public: - ControllerMode(const GameModeConfig &config); + ControllerMode(GameModeConfig &config); void UpdateOutputs(const InputState &inputs, OutputState &outputs); void ResetDirections(); virtual void UpdateDirections( diff --git a/include/core/InputMode.hpp b/include/core/InputMode.hpp index 95d7c5ba..7d985775 100644 --- a/include/core/InputMode.hpp +++ b/include/core/InputMode.hpp @@ -8,12 +8,12 @@ class InputMode { public: - InputMode(const GameModeConfig &config); + InputMode(GameModeConfig &config); virtual ~InputMode(); - const GameModeConfig &GetConfig(); + GameModeConfig &GetConfig(); protected: - const GameModeConfig &_config; + GameModeConfig &_config; virtual void HandleSocd(InputState &inputs); virtual void HandleRemap(const InputState &original_inputs, InputState &remapped_inputs); diff --git a/include/core/config_utils.hpp b/include/core/config_utils.hpp index c6171742..31b95581 100644 --- a/include/core/config_utils.hpp +++ b/include/core/config_utils.hpp @@ -71,4 +71,21 @@ constexpr const char *backend_name(CommunicationBackendId backend_id) { } } +constexpr const char *socd_name(SocdType socd_type) { + switch (socd_type) { + case SOCD_NEUTRAL: + return "Neutral"; + case SOCD_2IP: + return "2IP"; + case SOCD_2IP_NO_REAC: + return "2IP No Reactivation"; + case SOCD_DIR1_PRIORITY: + return "Dir 1 priority"; + case SOCD_DIR2_PRIORITY: + return "Dir 2 priority"; + default: + return "Unknown"; + } +} + #endif \ No newline at end of file diff --git a/include/core/mode_selection.hpp b/include/core/mode_selection.hpp index e0e92efb..a2fe7648 100644 --- a/include/core/mode_selection.hpp +++ b/include/core/mode_selection.hpp @@ -13,19 +13,19 @@ void set_mode(CommunicationBackend *backend, ControllerMode *mode); void set_mode(CommunicationBackend *backend, KeyboardMode *mode); void set_mode( CommunicationBackend *backend, - const GameModeConfig &mode_config, + GameModeConfig &mode_config, const KeyboardModeConfig *keyboard_modes, size_t keyboard_modes_count ); void set_mode( CommunicationBackend *backend, GameModeId mode_id, - const GameModeConfig *mode_configs, + GameModeConfig *mode_configs, size_t mode_configs_count, const KeyboardModeConfig *keyboard_modes, size_t keyboard_modes_count ); -void select_mode(CommunicationBackend **backends, size_t backends_count, const Config &config); +void select_mode(CommunicationBackend **backends, size_t backends_count, Config &config); void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count); #endif diff --git a/include/modes/CustomKeyboardMode.hpp b/include/modes/CustomKeyboardMode.hpp index 25f34d5c..ca5e2e80 100644 --- a/include/modes/CustomKeyboardMode.hpp +++ b/include/modes/CustomKeyboardMode.hpp @@ -8,7 +8,7 @@ class CustomKeyboardMode : public KeyboardMode { public: - CustomKeyboardMode(const GameModeConfig &config, const KeyboardModeConfig &keyboard_config); + CustomKeyboardMode(GameModeConfig &config, const KeyboardModeConfig &keyboard_config); private: const KeyboardModeConfig &_keyboard_config; diff --git a/include/modes/DefaultKeyboardMode.hpp b/include/modes/DefaultKeyboardMode.hpp index b5ca9836..3439b8fe 100644 --- a/include/modes/DefaultKeyboardMode.hpp +++ b/include/modes/DefaultKeyboardMode.hpp @@ -6,7 +6,7 @@ class DefaultKeyboardMode : public KeyboardMode { public: - DefaultKeyboardMode(const GameModeConfig &config); + DefaultKeyboardMode(GameModeConfig &config); private: void UpdateKeys(const InputState &inputs); diff --git a/include/modes/FgcMode.hpp b/include/modes/FgcMode.hpp index 10b14af6..6293d6b4 100644 --- a/include/modes/FgcMode.hpp +++ b/include/modes/FgcMode.hpp @@ -6,7 +6,7 @@ class FgcMode : public ControllerMode { public: - FgcMode(const GameModeConfig &config); + FgcMode(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/Melee18Button.hpp b/include/modes/Melee18Button.hpp index 15cb1c19..3d4f6527 100644 --- a/include/modes/Melee18Button.hpp +++ b/include/modes/Melee18Button.hpp @@ -10,7 +10,7 @@ typedef struct { class Melee18Button : public ControllerMode { public: - Melee18Button(const GameModeConfig &config, Melee18ButtonOptions options = {}); + Melee18Button(GameModeConfig &config, Melee18ButtonOptions options = {}); private: Melee18ButtonOptions _options; diff --git a/include/modes/Melee20Button.hpp b/include/modes/Melee20Button.hpp index 0bb3ffea..fb088367 100644 --- a/include/modes/Melee20Button.hpp +++ b/include/modes/Melee20Button.hpp @@ -12,7 +12,7 @@ typedef struct { class Melee20Button : public ControllerMode { public: - Melee20Button(const GameModeConfig &config, Melee20ButtonOptions options = {}); + Melee20Button(GameModeConfig &config, Melee20ButtonOptions options = {}); protected: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/ProjectM.hpp b/include/modes/ProjectM.hpp index cd373768..aacf3370 100644 --- a/include/modes/ProjectM.hpp +++ b/include/modes/ProjectM.hpp @@ -11,7 +11,7 @@ typedef struct { class ProjectM : public ControllerMode { public: - ProjectM(const GameModeConfig &config, ProjectMOptions options = {}); + ProjectM(GameModeConfig &config, ProjectMOptions options = {}); private: ProjectMOptions _options; diff --git a/include/modes/RivalsOfAether.hpp b/include/modes/RivalsOfAether.hpp index f929c49f..f37f6544 100644 --- a/include/modes/RivalsOfAether.hpp +++ b/include/modes/RivalsOfAether.hpp @@ -6,7 +6,7 @@ class RivalsOfAether : public ControllerMode { public: - RivalsOfAether(const GameModeConfig &config); + RivalsOfAether(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/Ultimate.hpp b/include/modes/Ultimate.hpp index 111c5939..d8c07018 100644 --- a/include/modes/Ultimate.hpp +++ b/include/modes/Ultimate.hpp @@ -6,7 +6,7 @@ class Ultimate : public ControllerMode { public: - Ultimate(const GameModeConfig &config); + Ultimate(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/DarkSouls.hpp b/include/modes/extra/DarkSouls.hpp index 3dc157f8..c3dffe52 100644 --- a/include/modes/extra/DarkSouls.hpp +++ b/include/modes/extra/DarkSouls.hpp @@ -7,7 +7,7 @@ class DarkSouls : public ControllerMode { public: - DarkSouls(const GameModeConfig &config); + DarkSouls(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/HollowKnight.hpp b/include/modes/extra/HollowKnight.hpp index 3cf8ea1f..4e257e09 100644 --- a/include/modes/extra/HollowKnight.hpp +++ b/include/modes/extra/HollowKnight.hpp @@ -8,7 +8,7 @@ class HollowKnight : public ControllerMode { public: - HollowKnight(const GameModeConfig &config); + HollowKnight(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/MKWii.hpp b/include/modes/extra/MKWii.hpp index 5c8c0ab0..5c13800d 100644 --- a/include/modes/extra/MKWii.hpp +++ b/include/modes/extra/MKWii.hpp @@ -7,7 +7,7 @@ class MKWii : public ControllerMode { public: - MKWii(const GameModeConfig &config); + MKWii(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/MultiVersus.hpp b/include/modes/extra/MultiVersus.hpp index 4f1b0c27..7469f4d8 100644 --- a/include/modes/extra/MultiVersus.hpp +++ b/include/modes/extra/MultiVersus.hpp @@ -7,7 +7,7 @@ class MultiVersus : public ControllerMode { public: - MultiVersus(const GameModeConfig &config); + MultiVersus(GameModeConfig &config); protected: virtual void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/RocketLeague.hpp b/include/modes/extra/RocketLeague.hpp index 615bafdc..cc73199f 100644 --- a/include/modes/extra/RocketLeague.hpp +++ b/include/modes/extra/RocketLeague.hpp @@ -7,7 +7,7 @@ class RocketLeague : public ControllerMode { public: - RocketLeague(const GameModeConfig &config); + RocketLeague(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/SaltAndSanctuary.hpp b/include/modes/extra/SaltAndSanctuary.hpp index daae968b..790d1016 100644 --- a/include/modes/extra/SaltAndSanctuary.hpp +++ b/include/modes/extra/SaltAndSanctuary.hpp @@ -7,7 +7,7 @@ class SaltAndSanctuary : public ControllerMode { public: - SaltAndSanctuary(const GameModeConfig &config); + SaltAndSanctuary(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/ShovelKnight.hpp b/include/modes/extra/ShovelKnight.hpp index 601c00d9..b3d33525 100644 --- a/include/modes/extra/ShovelKnight.hpp +++ b/include/modes/extra/ShovelKnight.hpp @@ -7,7 +7,7 @@ class ShovelKnight : public ControllerMode { public: - ShovelKnight(const GameModeConfig &config); + ShovelKnight(GameModeConfig &config); private: virtual void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/ToughLoveArena.hpp b/include/modes/extra/ToughLoveArena.hpp index f00a0cbc..b0781fa9 100644 --- a/include/modes/extra/ToughLoveArena.hpp +++ b/include/modes/extra/ToughLoveArena.hpp @@ -7,7 +7,7 @@ class ToughLoveArena : public KeyboardMode { public: - ToughLoveArena(const GameModeConfig &config); + ToughLoveArena(GameModeConfig &config); private: void UpdateKeys(const InputState &inputs); diff --git a/include/modes/extra/Ultimate2.hpp b/include/modes/extra/Ultimate2.hpp index 9f619df6..7f2d781f 100644 --- a/include/modes/extra/Ultimate2.hpp +++ b/include/modes/extra/Ultimate2.hpp @@ -7,7 +7,7 @@ class Ultimate2 : public ControllerMode { public: - Ultimate2(const GameModeConfig &config); + Ultimate2(GameModeConfig &config); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp index d3601fd0..875a90f4 100644 --- a/src/comms/IntegratedDisplay.cpp +++ b/src/comms/IntegratedDisplay.cpp @@ -33,7 +33,7 @@ IntegratedDisplay::IntegratedDisplay( size_t usb_backend_options_count = 0; for (size_t i = 0; i < config.communication_backend_configs_count; i++) { CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; - MenuPage::MenuItem ¤t_backend_option = usb_backend_options[usb_backend_options_count]; + MenuPage::MenuItem ¤t_option = usb_backend_options[usb_backend_options_count]; if (backend_config.backend_id != COMMS_BACKEND_XINPUT && backend_config.backend_id != COMMS_BACKEND_DINPUT && @@ -42,12 +42,12 @@ IntegratedDisplay::IntegratedDisplay( } strlcpy( - current_backend_option.text, + current_option.text, backend_name(backend_config.backend_id), - sizeof(current_backend_option.text) + sizeof(current_option.text) ); - current_backend_option.key = i; - current_backend_option.action = &SetDefaultUsbBackend; + current_option.key = i; + current_option.action = &SetDefaultUsbBackend; usb_backend_options_count++; } @@ -62,7 +62,7 @@ IntegratedDisplay::IntegratedDisplay( size_t gamemode_options_count = 0; for (size_t i = 0; i < config.game_mode_configs_count; i++) { GameModeConfig &mode_config = config.game_mode_configs[i]; - MenuPage::MenuItem ¤t_gamemode_option = gamemode_options[gamemode_options_count]; + MenuPage::MenuItem ¤t_option = gamemode_options[gamemode_options_count]; // Don't show keyboard modes as a gamemode option unless using DInputBackend. if (_backend_id != COMMS_BACKEND_DINPUT && mode_config.mode_id == MODE_KEYBOARD) { @@ -70,20 +70,16 @@ IntegratedDisplay::IntegratedDisplay( } if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { - strlcpy( - current_gamemode_option.text, - mode_config.name, - sizeof(current_gamemode_option.text) - ); + strlcpy(current_option.text, mode_config.name, sizeof(current_option.text)); } else { strlcpy( - current_gamemode_option.text, + current_option.text, gamemode_name(mode_config.mode_id), - sizeof(current_gamemode_option.text) + sizeof(current_option.text) ); } - current_gamemode_option.key = i; - current_gamemode_option.action = &SetDefaultMode; + current_option.key = i; + current_option.action = &SetDefaultMode; gamemode_options_count++; } @@ -92,11 +88,21 @@ IntegratedDisplay::IntegratedDisplay( .items_count = gamemode_options_count, }; - /* Build top-level page */ - char top_level_item1_text[] = "Default Gamemode"; - char top_level_item2_text[] = "Default USB Mode"; - char top_level_item3_text[] = "Exit"; + /* Build SOCD types page */ + static MenuPage::MenuItem socd_options[_SocdType_MAX] = {}; + for (uint8_t socd_type = SOCD_NEUTRAL; socd_type < _SocdType_ARRAYSIZE; socd_type++) { + MenuPage::MenuItem ¤t_option = socd_options[socd_type - 1]; + strlcpy(current_option.text, socd_name((SocdType)socd_type), sizeof(current_option.text)); + current_option.key = socd_type; + current_option.action = &SetSocdType; + } + static MenuPage socd_page = { + .items = socd_options, + .items_count = sizeof(socd_options) / sizeof(MenuPage::MenuItem), + }; + + /* Build top-level page */ // clang-format off static const MenuPage::MenuItem top_level_items[] = { { @@ -107,6 +113,10 @@ IntegratedDisplay::IntegratedDisplay( .text = "Default USB Mode", .page = &_usb_backends_page, }, + { + .text = "SOCD Mode", + .page = &socd_page, + }, { .text = "Return", .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { @@ -136,6 +146,7 @@ IntegratedDisplay::IntegratedDisplay( _usb_backends_page.parent = &_top_level_page; _gamemode_options_page.parent = &_top_level_page; + socd_page.parent = &_top_level_page; } IntegratedDisplay::~IntegratedDisplay() { @@ -147,8 +158,9 @@ IntegratedDisplay::~IntegratedDisplay() { } void IntegratedDisplay::SetGameMode(ControllerMode *gamemode) { - _gamemode = gamemode->GetConfig().mode_id; - strlcpy(_gamemode_text, gamemode_name(_gamemode), sizeof(_gamemode_text)); + GameModeId mode_id = gamemode->GetConfig().mode_id; + strlcpy(_gamemode_text, gamemode_name(mode_id), sizeof(_gamemode_text)); + CommunicationBackend::SetGameMode(gamemode); } void IntegratedDisplay::UpdateOutputs() { @@ -307,3 +319,19 @@ void IntegratedDisplay::SetDefaultUsbBackend( } config.default_usb_backend_config = backend_config_index + 1; } + +void IntegratedDisplay::SetSocdType( + IntegratedDisplay *instance, + Config &config, + uint8_t socd_type +) { + if (socd_type <= SOCD_UNSPECIFIED || socd_type > _SocdType_MAX) { + return; + } + + // Overwrite SOCD type for all SOCD pairs of current gamemode's config. + GameModeConfig &mode_config = instance->_gamemode->GetConfig(); + for (size_t i = 0; i < mode_config.socd_pairs_count; i++) { + mode_config.socd_pairs[i].socd_type = (SocdType)socd_type; + } +} diff --git a/src/core/CommunicationBackend.cpp b/src/core/CommunicationBackend.cpp index b6df57ce..0f20844d 100644 --- a/src/core/CommunicationBackend.cpp +++ b/src/core/CommunicationBackend.cpp @@ -4,6 +4,8 @@ #include "core/InputSource.hpp" #include "core/state.hpp" +#include + CommunicationBackend::CommunicationBackend( InputState &inputs, InputSource **input_sources, @@ -45,7 +47,15 @@ void CommunicationBackend::UpdateOutputs() { } } +CommunicationBackendId CommunicationBackend::BackendId() { + return COMMS_BACKEND_UNSPECIFIED; +} + void CommunicationBackend::SetGameMode(ControllerMode *gamemode) { delete _gamemode; _gamemode = gamemode; } + +ControllerMode *CommunicationBackend::CurrentGameMode() { + return _gamemode; +} diff --git a/src/core/ControllerMode.cpp b/src/core/ControllerMode.cpp index 11f9bd24..448acbd4 100644 --- a/src/core/ControllerMode.cpp +++ b/src/core/ControllerMode.cpp @@ -1,6 +1,6 @@ #include "core/ControllerMode.hpp" -ControllerMode::ControllerMode(const GameModeConfig &config) : InputMode(config) { +ControllerMode::ControllerMode(GameModeConfig &config) : InputMode(config) { // Set up initial state. ResetDirections(); } diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index 5261c152..e5dba376 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -4,7 +4,7 @@ #include "core/state.hpp" #include "util/state_util.hpp" -InputMode::InputMode(const GameModeConfig &config) : _config(config) { +InputMode::InputMode(GameModeConfig &config) : _config(config) { _socd_states = new socd::SocdState[_config.socd_pairs_count]; } @@ -12,7 +12,7 @@ InputMode::~InputMode() { delete[] _socd_states; } -const GameModeConfig &InputMode::GetConfig() { +GameModeConfig &InputMode::GetConfig() { return _config; } diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 3e354eb7..213be7da 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -36,7 +36,7 @@ void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { void set_mode( CommunicationBackend *backend, - const GameModeConfig &mode_config, + GameModeConfig &mode_config, const KeyboardModeConfig *keyboard_modes, size_t keyboard_modes_count ) { @@ -86,7 +86,7 @@ void set_mode( void set_mode( CommunicationBackend *backend, GameModeId mode_id, - const GameModeConfig *mode_configs, + GameModeConfig *mode_configs, size_t mode_configs_count, const KeyboardModeConfig *keyboard_modes, size_t keyboard_modes_count @@ -94,7 +94,7 @@ void set_mode( // In this overload we only know the mode id so we need to find a mode config that matches this // ID. for (size_t i = 0; i < mode_configs_count; i++) { - const GameModeConfig &mode = mode_configs[i]; + GameModeConfig &mode = mode_configs[i]; if (mode.mode_id == mode_id) { set_mode(backend, mode, keyboard_modes, keyboard_modes_count); return; @@ -102,14 +102,14 @@ void set_mode( } } -void select_mode(CommunicationBackend **backends, size_t backends_count, const Config &config) { +void select_mode(CommunicationBackend **backends, size_t backends_count, Config &config) { // TODO: Use a counter variable to only run the contents of this function every x iterations // rather than on every single poll. InputState &inputs = backends[0]->GetInputs(); for (size_t i = 0; i < config.game_mode_configs_count; i++) { - const GameModeConfig &mode_config = config.game_mode_configs[i]; + GameModeConfig &mode_config = config.game_mode_configs[i]; if (all_buttons_held(inputs.buttons, mode_activation_masks[i]) && i != current_mode_index) { current_mode_index = i; for (size_t i = 0; i < backends_count; i++) { diff --git a/src/modes/CustomKeyboardMode.cpp b/src/modes/CustomKeyboardMode.cpp index 400025ce..cd88ac82 100644 --- a/src/modes/CustomKeyboardMode.cpp +++ b/src/modes/CustomKeyboardMode.cpp @@ -6,7 +6,7 @@ #include CustomKeyboardMode::CustomKeyboardMode( - const GameModeConfig &config, + GameModeConfig &config, const KeyboardModeConfig &keyboard_config ) : KeyboardMode(config), diff --git a/src/modes/DefaultKeyboardMode.cpp b/src/modes/DefaultKeyboardMode.cpp index d7c9ef77..ec87975c 100644 --- a/src/modes/DefaultKeyboardMode.cpp +++ b/src/modes/DefaultKeyboardMode.cpp @@ -3,7 +3,7 @@ #include "core/socd.hpp" #include "core/state.hpp" -DefaultKeyboardMode::DefaultKeyboardMode(const GameModeConfig &config) : KeyboardMode(config) {} +DefaultKeyboardMode::DefaultKeyboardMode(GameModeConfig &config) : KeyboardMode(config) {} void DefaultKeyboardMode::UpdateKeys(const InputState &inputs) { Press(HID_KEY_A, inputs.lf4); diff --git a/src/modes/FgcMode.cpp b/src/modes/FgcMode.cpp index 0fea6781..3f8776b3 100644 --- a/src/modes/FgcMode.cpp +++ b/src/modes/FgcMode.cpp @@ -1,6 +1,6 @@ #include "modes/FgcMode.hpp" -FgcMode::FgcMode(const GameModeConfig &config) : ControllerMode(config) {} +FgcMode::FgcMode(GameModeConfig &config) : ControllerMode(config) {} void FgcMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Directions diff --git a/src/modes/Melee18Button.cpp b/src/modes/Melee18Button.cpp index d6cdcbde..14f21ca8 100644 --- a/src/modes/Melee18Button.cpp +++ b/src/modes/Melee18Button.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee18Button::Melee18Button(const GameModeConfig &config, Melee18ButtonOptions options) +Melee18Button::Melee18Button(GameModeConfig &config, Melee18ButtonOptions options) : ControllerMode(config) { _options = options; horizontal_socd = false; diff --git a/src/modes/Melee20Button.cpp b/src/modes/Melee20Button.cpp index 38747f63..1c32b778 100644 --- a/src/modes/Melee20Button.cpp +++ b/src/modes/Melee20Button.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee20Button::Melee20Button(const GameModeConfig &config, Melee20ButtonOptions options) +Melee20Button::Melee20Button(GameModeConfig &config, Melee20ButtonOptions options) : ControllerMode(config) { _options = options; _horizontal_socd = false; diff --git a/src/modes/ProjectM.cpp b/src/modes/ProjectM.cpp index 833bb0f3..341181dc 100644 --- a/src/modes/ProjectM.cpp +++ b/src/modes/ProjectM.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -ProjectM::ProjectM(const GameModeConfig &config, ProjectMOptions options) : ControllerMode(config) { +ProjectM::ProjectM(GameModeConfig &config, ProjectMOptions options) : ControllerMode(config) { _options = options; _horizontal_socd = false; } diff --git a/src/modes/RivalsOfAether.cpp b/src/modes/RivalsOfAether.cpp index 977544ff..35961a0f 100644 --- a/src/modes/RivalsOfAether.cpp +++ b/src/modes/RivalsOfAether.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -RivalsOfAether::RivalsOfAether(const GameModeConfig &config) : ControllerMode(config) {} +RivalsOfAether::RivalsOfAether(GameModeConfig &config) : ControllerMode(config) {} void RivalsOfAether::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; diff --git a/src/modes/Ultimate.cpp b/src/modes/Ultimate.cpp index 19545570..822dd67d 100644 --- a/src/modes/Ultimate.cpp +++ b/src/modes/Ultimate.cpp @@ -5,7 +5,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate::Ultimate(const GameModeConfig &config) : ControllerMode(config) {} +Ultimate::Ultimate(GameModeConfig &config) : ControllerMode(config) {} void Ultimate::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; diff --git a/src/modes/extra/DarkSouls.cpp b/src/modes/extra/DarkSouls.cpp index 7392afee..5dab4f05 100644 --- a/src/modes/extra/DarkSouls.cpp +++ b/src/modes/extra/DarkSouls.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -DarkSouls::DarkSouls(const GameModeConfig &config) : ControllerMode(config) {} +DarkSouls::DarkSouls(GameModeConfig &config) : ControllerMode(config) {} void DarkSouls::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.y = inputs.rf6; diff --git a/src/modes/extra/HollowKnight.cpp b/src/modes/extra/HollowKnight.cpp index 8a9af817..bb270617 100644 --- a/src/modes/extra/HollowKnight.cpp +++ b/src/modes/extra/HollowKnight.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -HollowKnight::HollowKnight(const GameModeConfig &config) : ControllerMode(config) {} +HollowKnight::HollowKnight(GameModeConfig &config) : ControllerMode(config) {} void HollowKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; // Attack diff --git a/src/modes/extra/MKWii.cpp b/src/modes/extra/MKWii.cpp index 2ab4d97a..122b1cac 100644 --- a/src/modes/extra/MKWii.cpp +++ b/src/modes/extra/MKWii.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MKWii::MKWii(const GameModeConfig &config) : ControllerMode(config) {} +MKWii::MKWii(GameModeConfig &config) : ControllerMode(config) {} void MKWii::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rf1; diff --git a/src/modes/extra/MultiVersus.cpp b/src/modes/extra/MultiVersus.cpp index ea4a2510..145207de 100644 --- a/src/modes/extra/MultiVersus.cpp +++ b/src/modes/extra/MultiVersus.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MultiVersus::MultiVersus(const GameModeConfig &config) : ControllerMode(config) {} +MultiVersus::MultiVersus(GameModeConfig &config) : ControllerMode(config) {} void MultiVersus::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Bind X and Y to "jump" in-game. diff --git a/src/modes/extra/RocketLeague.cpp b/src/modes/extra/RocketLeague.cpp index be3b801e..b5ec4125 100644 --- a/src/modes/extra/RocketLeague.cpp +++ b/src/modes/extra/RocketLeague.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -RocketLeague::RocketLeague(const GameModeConfig &config) : ControllerMode(config) {} +RocketLeague::RocketLeague(GameModeConfig &config) : ControllerMode(config) {} void RocketLeague::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; diff --git a/src/modes/extra/SaltAndSanctuary.cpp b/src/modes/extra/SaltAndSanctuary.cpp index 0f244ea6..79712fd9 100644 --- a/src/modes/extra/SaltAndSanctuary.cpp +++ b/src/modes/extra/SaltAndSanctuary.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -SaltAndSanctuary::SaltAndSanctuary(const GameModeConfig &config) : ControllerMode(config) {} +SaltAndSanctuary::SaltAndSanctuary(GameModeConfig &config) : ControllerMode(config) {} void SaltAndSanctuary::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.dpadRight = inputs.lf4; // Block diff --git a/src/modes/extra/ShovelKnight.cpp b/src/modes/extra/ShovelKnight.cpp index 2d05c1de..8cd72043 100644 --- a/src/modes/extra/ShovelKnight.cpp +++ b/src/modes/extra/ShovelKnight.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -ShovelKnight::ShovelKnight(const GameModeConfig &config) : ControllerMode(config) {} +ShovelKnight::ShovelKnight(GameModeConfig &config) : ControllerMode(config) {} void ShovelKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.dpadLeft = inputs.lf3; diff --git a/src/modes/extra/ToughLoveArena.cpp b/src/modes/extra/ToughLoveArena.cpp index 0f9c8a4b..9ebd0d94 100644 --- a/src/modes/extra/ToughLoveArena.cpp +++ b/src/modes/extra/ToughLoveArena.cpp @@ -1,6 +1,6 @@ #include "modes/extra/ToughLoveArena.hpp" -ToughLoveArena::ToughLoveArena(const GameModeConfig &config) : KeyboardMode(config) {} +ToughLoveArena::ToughLoveArena(GameModeConfig &config) : KeyboardMode(config) {} void ToughLoveArena::UpdateKeys(const InputState &inputs) { Press(HID_KEY_S, inputs.lf3); diff --git a/src/modes/extra/Ultimate2.cpp b/src/modes/extra/Ultimate2.cpp index 44ae066a..d828d498 100644 --- a/src/modes/extra/Ultimate2.cpp +++ b/src/modes/extra/Ultimate2.cpp @@ -5,7 +5,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate2::Ultimate2(const GameModeConfig &config) : ControllerMode(config) {} +Ultimate2::Ultimate2(GameModeConfig &config) : ControllerMode(config) {} void Ultimate2::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; From 45b5d8d8859ac7ef0344a0202a1e0b6469013f85 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 6 Mar 2024 20:03:10 +0000 Subject: [PATCH 082/167] feat: add RGB brightness menu and refactor display control handling --- HAL/pico/include/comms/NeoPixelBackend.hpp | 8 +- config/glyph/config.cpp | 1 + config/glyph/include/glyph_overrides.hpp | 3 +- include/comms/IntegratedDisplay.hpp | 15 ++++ platformio.ini | 2 +- src/comms/IntegratedDisplay.cpp | 93 ++++++++++++++-------- 6 files changed, 85 insertions(+), 37 deletions(-) diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index 567413c3..f149d33c 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -14,12 +14,14 @@ template class NeoPixelBackend : public Commun size_t input_source_count, const Button *button_mappings, const RgbConfig *rgb_configs, - size_t rgb_configs_count + const size_t rgb_configs_count, + const uint8_t &brightness ) : CommunicationBackend(inputs, input_sources, input_source_count), _button_mappings(button_mappings), _rgb_configs(rgb_configs), - _rgb_configs_count(rgb_configs_count) { + _rgb_configs_count(rgb_configs_count), + _brightness(brightness) { FastLED.addLeds(_leds, led_count); FastLED.setMaxPowerInVoltsAndMilliamps(5, 200); } @@ -54,6 +56,7 @@ template class NeoPixelBackend : public Commun Button button = this->_button_mappings[i]; _leds[i] = _button_colors[max(0, button - 1)]; } + FastLED.setBrightness(_brightness); FastLED.show(); } @@ -65,6 +68,7 @@ template class NeoPixelBackend : public Commun const RgbConfig *_rgb_configs; const size_t _rgb_configs_count; const RgbConfig *_config = nullptr; + const uint8_t &_brightness; CRGB _leds[led_count]; uint32_t _button_colors[button_colors_count]; diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index f539253a..7cfc7f65 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -118,6 +118,7 @@ void setup1() { display, []() { display.clearDisplay(); }, []() { display.display(); }, + DisplayControls{ .back = BTN_MB4, .down = BTN_MB5, .up = BTN_MB6, .enter = BTN_MB7 }, config, backends[0]->BackendId(), backends, diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 49de71c5..bc361852 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -136,7 +136,8 @@ size_t init_secondary_backends_glyph( input_source_count, pixel_to_button_mappings, config.rgb_configs, - config.rgb_configs_count + config.rgb_configs_count, + config.rgb_brightness ); // Delete the old backends array and reassign it. diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp index d79467a0..b8c3c292 100644 --- a/include/comms/IntegratedDisplay.hpp +++ b/include/comms/IntegratedDisplay.hpp @@ -15,8 +15,16 @@ typedef enum _DisplayMode { DISPLAY_MODE_VIEWER, DISPLAY_MODE_CONFIG, + DISPLAY_MODE_RGB_BRIGHTNESS, } DisplayMode; +typedef struct _DisplayControls { + Button back; + Button down; + Button up; + Button enter; +} DisplayControls; + class IntegratedDisplay; typedef struct _MenuPage { @@ -41,6 +49,7 @@ class IntegratedDisplay : public CommunicationBackend { Adafruit_GFX &display, void (*clear_display)(), void (*update_display)(), + DisplayControls controls, Config &config, CommunicationBackendId backend_id, CommunicationBackend **backends, @@ -62,6 +71,8 @@ class IntegratedDisplay : public CommunicationBackend { Adafruit_GFX &_display; void (*_clear_display)(); void (*_update_display)(); + const DisplayControls _controls; + const Button _controls_array[4]; Config &_config; const CommunicationBackendId _backend_id; DisplayMode _display_mode = DISPLAY_MODE_VIEWER; @@ -90,6 +101,10 @@ class IntegratedDisplay : public CommunicationBackend { uint8_t backend_config_index ); static void SetSocdType(IntegratedDisplay *instance, Config &config, uint8_t socd_type); + + void HandleControlsViewerMode(Button button); + void HandleControlsConfigMode(Button button); + void HandleControlsRgbBrightnessMode(Button button); }; #endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 147aa1a9..c35043b3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#3c14f28 + https://github.com/JonnyHaystack/HayBox-proto#7cf3883 [avr_base] platform = atmelavr diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp index 875a90f4..1e71153d 100644 --- a/src/comms/IntegratedDisplay.cpp +++ b/src/comms/IntegratedDisplay.cpp @@ -2,6 +2,7 @@ #include "core/Persistence.hpp" #include "core/config_utils.hpp" +#include "util/state_util.hpp" IntegratedDisplay::IntegratedDisplay( InputState &inputs, @@ -10,6 +11,7 @@ IntegratedDisplay::IntegratedDisplay( Adafruit_GFX &display, void (*clear_display)(), void (*update_display)(), + const DisplayControls controls, Config &config, CommunicationBackendId backend_id, CommunicationBackend **backends, @@ -19,6 +21,8 @@ IntegratedDisplay::IntegratedDisplay( _display(display), _clear_display(clear_display), _update_display(update_display), + _controls(controls), + _controls_array{ controls.back, controls.down, controls.up, controls.enter }, _config(config), _backend_id(backend_id), _backends(backends), @@ -117,6 +121,12 @@ IntegratedDisplay::IntegratedDisplay( .text = "SOCD Mode", .page = &socd_page, }, + { + .text = "RGB Brightness", + .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { + instance->_display_mode = DISPLAY_MODE_RGB_BRIGHTNESS; + }, + }, { .text = "Return", .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { @@ -164,45 +174,45 @@ void IntegratedDisplay::SetGameMode(ControllerMode *gamemode) { } void IntegratedDisplay::UpdateOutputs() { - // Process inputs. if (!time_reached(_button_cooldown_end)) { return; } - if (_current_menu_page == nullptr) { - _current_menu_page = &_top_level_page; - _current_menu_offset = 0; - return; - } - if (_display_mode != DISPLAY_MODE_CONFIG) { - if (_inputs.mb7) { + for (uint8_t i = 0; i < sizeof(_controls_array); i++) { + Button button = _controls_array[i]; + if (get_button(_inputs.buttons, button)) { _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); - _display_mode = DISPLAY_MODE_CONFIG; + switch (_display_mode) { + case DISPLAY_MODE_VIEWER: + return HandleControlsViewerMode(button); + case DISPLAY_MODE_CONFIG: + return HandleControlsConfigMode(button); + case DISPLAY_MODE_RGB_BRIGHTNESS: + return HandleControlsRgbBrightnessMode(button); + } } - return; } +} - // Handle Up button press. - if (_inputs.mb6) { - _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); +void IntegratedDisplay::HandleControlsViewerMode(Button button) { + if (button == _controls.enter) { + _display_mode = DISPLAY_MODE_CONFIG; + } +} - _highlighted_menu_item = max(0, _highlighted_menu_item - 1); +void IntegratedDisplay::HandleControlsConfigMode(Button button) { + if (_current_menu_page == nullptr) { + _current_menu_page = &_top_level_page; + _current_menu_offset = 0; return; } - // Handle Down button press. - if (_inputs.mb5) { - _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); - + if (button == _controls.up) { + _highlighted_menu_item = max(0, _highlighted_menu_item - 1); + } else if (button == _controls.down) { _highlighted_menu_item = min(_current_menu_page->items_count - 1, _highlighted_menu_item + 1); - return; - } - - // Handle Select button press. - if (_inputs.mb7) { - _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); - + } else if (button == _controls.enter) { // Bounds check. if (_highlighted_menu_item > _current_menu_page->items_count) { _highlighted_menu_item = 0; @@ -231,12 +241,8 @@ void IntegratedDisplay::UpdateOutputs() { _highlighted_menu_item = 0; return; } - } - - // Handle Back button press. - if (_inputs.mb4) { - _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); - + } else if (button == _controls.back) { + // If at top-level page, go back to input viewer. if (_current_menu_page->parent == nullptr) { _display_mode = DISPLAY_MODE_VIEWER; return; @@ -244,7 +250,16 @@ void IntegratedDisplay::UpdateOutputs() { _current_menu_page = _current_menu_page->parent; _highlighted_menu_item = 0; - return; + } +} + +void IntegratedDisplay::HandleControlsRgbBrightnessMode(Button button) { + if (button == _controls.up) { + _config.rgb_brightness++; + } else if (button == _controls.down) { + _config.rgb_brightness--; + } else if (button == _controls.back) { + _display_mode = DISPLAY_MODE_CONFIG; } } @@ -260,7 +275,7 @@ void IntegratedDisplay::SendReport() { /* Backend text */ const char *backend_text = backend_name(_backend_id); - _display.setCursor(_display.width() - (strlen(backend_text) * 6), 0); + _display.setCursor(_display.width() - (strlen(backend_text) * font_width), 0); _display.print(backend_name(_backend_id)); } else if (_display_mode == DISPLAY_MODE_CONFIG) { /* Menu */ @@ -279,6 +294,18 @@ void IntegratedDisplay::SendReport() { _display.setCursor(font_width + padding, i * (font_height + padding)); _display.print(_current_menu_page->items[i + _current_menu_offset].text); } + } else if (_display_mode == DISPLAY_MODE_RGB_BRIGHTNESS) { + // Current brightness value. + _display.setCursor(_display.width() / 2 - (font_width * 3) / 2, _display.height() / 2); + _display.printf("%3d", _config.rgb_brightness); + + // Display control hints. + _display.setCursor(5, _display.height() - font_height); + _display.print("Back"); + _display.setCursor(45, _display.getCursorY()); + _display.print("-"); + _display.setCursor(_display.width() - 45 - font_width, _display.getCursorY()); + _display.print("+"); } _update_display(); From 19cc1c2443c0b457ea9422c87b2955f6e6c6822d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 6 Mar 2024 20:09:27 +0000 Subject: [PATCH 083/167] feat: set default RGB brightness to 255 for Glyph --- config/glyph/include/glyph_overrides.hpp | 1 + src/comms/IntegratedDisplay.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index bc361852..69091c98 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -98,6 +98,7 @@ Config glyph_default_config() { { BTN_RF5, 0xff0000 }, }, }; + config.rgb_brightness = 255; return config; } diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp index 1e71153d..ea2ef93b 100644 --- a/src/comms/IntegratedDisplay.cpp +++ b/src/comms/IntegratedDisplay.cpp @@ -325,6 +325,7 @@ void IntegratedDisplay::SetDefaultMode( config.communication_backend_configs[i].default_mode_config = mode_config_index + 1; } + // Update mode for all backends. for (size_t i = 0; i < instance->_backends_count; i++) { set_mode( instance->_backends[i], From 7f7c6397fcfc7979c39d5000788d806a0279e5b9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 6 Mar 2024 23:00:40 +0000 Subject: [PATCH 084/167] feat: add input display to OLED --- config/glyph/config.cpp | 47 +++++++++++++++++++++++++++-- include/comms/IntegratedDisplay.hpp | 17 ++++++++--- src/comms/IntegratedDisplay.cpp | 26 +++++++++++++--- 3 files changed, 78 insertions(+), 12 deletions(-) diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 7cfc7f65..22ab3920 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -10,6 +10,7 @@ #include "reboot.hpp" #include "stdlib.hpp" +#include #include Config config = glyph_default_config(); @@ -97,6 +98,45 @@ void loop() { } } +#define MENU_BUTTON_RADIUS 2 +#define NORMAL_BUTTON_RADIUS 4 +#define LARGE_BUTTON_RADIUS 5 + +InputViewerButton input_viewer_buttons[] = { + // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, + + {BTN_LF4, 6, 29, NORMAL_BUTTON_RADIUS}, + { BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, + { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, + { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, + + { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, + { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, + { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, + { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, + + { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, + { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, + { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, + { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, + + { BTN_LT1, 38, 52, NORMAL_BUTTON_RADIUS}, + { BTN_LT2, 46, 58, NORMAL_BUTTON_RADIUS}, + + { BTN_RT1, 90, 52, NORMAL_BUTTON_RADIUS}, + { BTN_RT2, 82, 58, NORMAL_BUTTON_RADIUS}, + { BTN_RT3, 82, 46, NORMAL_BUTTON_RADIUS}, + { BTN_RT4, 90, 40, NORMAL_BUTTON_RADIUS}, + { BTN_RT5, 98, 46, NORMAL_BUTTON_RADIUS}, +}; +size_t input_viewer_buttons_count = count_of(input_viewer_buttons); + /* Second core handles OLED display */ Adafruit_SSD1306 display(128, 64, &Wire1); IntegratedDisplay *display_backend = nullptr; @@ -110,17 +150,18 @@ void setup1() { Wire1.setClock(1'000'000UL); Wire1.begin(); if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { + CommunicationBackendId primary_backend_id = backends[0]->BackendId(); // clang-format off display_backend = new IntegratedDisplay( inputs, - input_sources, - input_source_count, display, []() { display.clearDisplay(); }, []() { display.display(); }, DisplayControls{ .back = BTN_MB4, .down = BTN_MB5, .up = BTN_MB6, .enter = BTN_MB7 }, + input_viewer_buttons, + input_viewer_buttons_count, config, - backends[0]->BackendId(), + primary_backend_id, backends, backend_count ); diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp index b8c3c292..be46a37c 100644 --- a/include/comms/IntegratedDisplay.hpp +++ b/include/comms/IntegratedDisplay.hpp @@ -8,7 +8,6 @@ #include "reboot.hpp" #include -#include #include #include @@ -25,6 +24,13 @@ typedef struct _DisplayControls { Button enter; } DisplayControls; +typedef struct _InputViewerButton { + Button button; + uint8_t center_x; + uint8_t center_y; + uint8_t radius; +} InputViewerButton; + class IntegratedDisplay; typedef struct _MenuPage { @@ -44,12 +50,12 @@ class IntegratedDisplay : public CommunicationBackend { public: IntegratedDisplay( InputState &inputs, - InputSource **input_sources, - size_t input_source_count, Adafruit_GFX &display, void (*clear_display)(), void (*update_display)(), DisplayControls controls, + const InputViewerButton *input_viewer_buttons, + const size_t input_viewer_buttons_count, Config &config, CommunicationBackendId backend_id, CommunicationBackend **backends, @@ -61,6 +67,7 @@ class IntegratedDisplay : public CommunicationBackend { virtual void SendReport(); protected: + static constexpr uint8_t controls_count = 4; static constexpr uint8_t padding = 2; static constexpr uint32_t button_cooldown_ms = 150; static constexpr uint8_t font_width = 6; @@ -72,7 +79,9 @@ class IntegratedDisplay : public CommunicationBackend { void (*_clear_display)(); void (*_update_display)(); const DisplayControls _controls; - const Button _controls_array[4]; + const Button _controls_array[controls_count]; + const InputViewerButton *_input_viewer_buttons; + const size_t _input_viewer_buttons_count; Config &_config; const CommunicationBackendId _backend_id; DisplayMode _display_mode = DISPLAY_MODE_VIEWER; diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp index ea2ef93b..489ea982 100644 --- a/src/comms/IntegratedDisplay.cpp +++ b/src/comms/IntegratedDisplay.cpp @@ -4,31 +4,35 @@ #include "core/config_utils.hpp" #include "util/state_util.hpp" +#define DEFAULT_COLOR 1 + IntegratedDisplay::IntegratedDisplay( InputState &inputs, - InputSource **input_sources, - size_t input_source_count, Adafruit_GFX &display, void (*clear_display)(), void (*update_display)(), const DisplayControls controls, + const InputViewerButton *input_viewer_buttons, + const size_t input_viewer_buttons_count, Config &config, CommunicationBackendId backend_id, CommunicationBackend **backends, size_t backends_count ) - : CommunicationBackend(inputs, input_sources, input_source_count), + : CommunicationBackend(inputs, nullptr, 0), _display(display), _clear_display(clear_display), _update_display(update_display), _controls(controls), _controls_array{ controls.back, controls.down, controls.up, controls.enter }, + _input_viewer_buttons(input_viewer_buttons), + _input_viewer_buttons_count(input_viewer_buttons_count), _config(config), _backend_id(backend_id), _backends(backends), _backends_count(backends_count) { _display.setTextSize(1); - _display.setTextColor(WHITE); + _display.setTextColor(DEFAULT_COLOR); /* Build default USB backends page */ MenuPage::MenuItem *usb_backend_options = @@ -178,7 +182,7 @@ void IntegratedDisplay::UpdateOutputs() { return; } - for (uint8_t i = 0; i < sizeof(_controls_array); i++) { + for (uint8_t i = 0; i < controls_count; i++) { Button button = _controls_array[i]; if (get_button(_inputs.buttons, button)) { _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); @@ -277,6 +281,18 @@ void IntegratedDisplay::SendReport() { const char *backend_text = backend_name(_backend_id); _display.setCursor(_display.width() - (strlen(backend_text) * font_width), 0); _display.print(backend_name(_backend_id)); + + /* Input display */ + for (size_t i = 0; i < _input_viewer_buttons_count; i++) { + InputViewerButton mapping = _input_viewer_buttons[i]; + if (get_button(_inputs.buttons, mapping.button)) { + _display + .fillCircle(mapping.center_x, mapping.center_y, mapping.radius, DEFAULT_COLOR); + } else { + _display + .drawCircle(mapping.center_x, mapping.center_y, mapping.radius, DEFAULT_COLOR); + } + } } else if (_display_mode == DISPLAY_MODE_CONFIG) { /* Menu */ if (_highlighted_menu_item - _current_menu_offset > max_visible_lines - 1) { From b184d8d9e5d59e19832247ee9994757f50fa9abe Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 8 Mar 2024 16:36:05 +0000 Subject: [PATCH 085/167] chore: update some copyright headers --- HAL/pico/include/comms/ConfiguratorBackend.hpp | 2 +- HAL/pico/include/core/Persistence.hpp | 2 +- HAL/pico/src/comms/ConfiguratorBackend.cpp | 2 +- HAL/pico/src/core/Persistence.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/HAL/pico/include/comms/ConfiguratorBackend.hpp b/HAL/pico/include/comms/ConfiguratorBackend.hpp index 46c505fb..8cb95a01 100644 --- a/HAL/pico/include/comms/ConfiguratorBackend.hpp +++ b/HAL/pico/include/comms/ConfiguratorBackend.hpp @@ -1,6 +1,6 @@ /* * This file is part of HayBox - * Copyright (C) 2023 Jonathan Haylett + * Copyright (C) 2024 Jonathan Haylett * * HayBox is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as diff --git a/HAL/pico/include/core/Persistence.hpp b/HAL/pico/include/core/Persistence.hpp index 6ce5d426..0206e627 100644 --- a/HAL/pico/include/core/Persistence.hpp +++ b/HAL/pico/include/core/Persistence.hpp @@ -1,6 +1,6 @@ /* * This file is part of HayBox - * Copyright (C) 2023 Jonathan Haylett + * Copyright (C) 2024 Jonathan Haylett * * HayBox is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as diff --git a/HAL/pico/src/comms/ConfiguratorBackend.cpp b/HAL/pico/src/comms/ConfiguratorBackend.cpp index 661932c0..9469e2cb 100644 --- a/HAL/pico/src/comms/ConfiguratorBackend.cpp +++ b/HAL/pico/src/comms/ConfiguratorBackend.cpp @@ -1,6 +1,6 @@ /* * This file is part of HayBox - * Copyright (C) 2023 Jonathan Haylett + * Copyright (C) 2024 Jonathan Haylett * * HayBox is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as diff --git a/HAL/pico/src/core/Persistence.cpp b/HAL/pico/src/core/Persistence.cpp index 4cfcb638..4700a956 100644 --- a/HAL/pico/src/core/Persistence.cpp +++ b/HAL/pico/src/core/Persistence.cpp @@ -1,6 +1,6 @@ /* * This file is part of HayBox - * Copyright (C) 2023 Jonathan Haylett + * Copyright (C) 2024 Jonathan Haylett * * HayBox is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as From 5d664a1f97c222c5098a12a51b50d73ff8837a8b Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 8 Mar 2024 17:06:17 +0000 Subject: [PATCH 086/167] refactor: introduce DisplayMode, refactor IntegratedDisplay --- HAL/pico/include/display/ConfigMenu.hpp | 82 ++++ HAL/pico/include/display/DisplayMode.hpp | 31 ++ HAL/pico/include/display/InputDisplay.hpp | 34 ++ .../include/display/RgbBrightnessMenu.hpp | 21 + HAL/pico/src/display/ConfigMenu.cpp | 306 +++++++++++++++ HAL/pico/src/display/InputDisplay.cpp | 54 +++ HAL/pico/src/display/RgbBrightnessMenu.cpp | 41 ++ config/glyph/config.cpp | 28 +- include/comms/IntegratedDisplay.hpp | 95 +---- src/comms/IntegratedDisplay.cpp | 359 ++---------------- 10 files changed, 628 insertions(+), 423 deletions(-) create mode 100644 HAL/pico/include/display/ConfigMenu.hpp create mode 100644 HAL/pico/include/display/DisplayMode.hpp create mode 100644 HAL/pico/include/display/InputDisplay.hpp create mode 100644 HAL/pico/include/display/RgbBrightnessMenu.hpp create mode 100644 HAL/pico/src/display/ConfigMenu.cpp create mode 100644 HAL/pico/src/display/InputDisplay.cpp create mode 100644 HAL/pico/src/display/RgbBrightnessMenu.cpp diff --git a/HAL/pico/include/display/ConfigMenu.hpp b/HAL/pico/include/display/ConfigMenu.hpp new file mode 100644 index 00000000..e69d7f89 --- /dev/null +++ b/HAL/pico/include/display/ConfigMenu.hpp @@ -0,0 +1,82 @@ +#ifndef _DISPLAY_CONFIGMENU_HPP +#define _DISPLAY_CONFIGMENU_HPP + +#include "comms/IntegratedDisplay.hpp" +#include "display/DisplayMode.hpp" + +#include + +class ConfigMenu; + +// clang-format off + +typedef struct _MenuPage { + typedef struct _MenuItem { + char text[20]; + uint8_t key = 0; + void (*action)( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t key + ) = nullptr; + struct _MenuPage *page = nullptr; + } MenuItem; + + struct _MenuPage *parent = nullptr; + const MenuItem *items = nullptr; + size_t items_count = 0; +} MenuPage; + +// clang-format on + +class ConfigMenu : public DisplayMode { + public: + ConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count); + ~ConfigMenu(); + DisplayModeId GetId(); + virtual void HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button + ); + virtual void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); + + private: + static constexpr uint8_t padding = 2; + static constexpr uint8_t max_visible_lines = 6; + static constexpr char highlight_string[] = ">"; + + Config &_config; + CommunicationBackend **_backends; + size_t _backends_count; + + MenuPage _usb_backends_page; + MenuPage _gamemode_options_page; + MenuPage _top_level_page; + + MenuPage *_current_menu_page = &_top_level_page; + uint8_t _highlighted_menu_item = 0; + int _current_menu_offset = 0; + + static void SetDefaultMode( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t mode_config_index + ); + static void SetDefaultUsbBackend( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t backend_config_index + ); + static void SetSocdType( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t socd_type + ); +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/include/display/DisplayMode.hpp b/HAL/pico/include/display/DisplayMode.hpp new file mode 100644 index 00000000..003b8537 --- /dev/null +++ b/HAL/pico/include/display/DisplayMode.hpp @@ -0,0 +1,31 @@ +#ifndef _DISPLAY_DISPLAYMODE_HPP +#define _DISPLAY_DISPLAYMODE_HPP + +#include +#include + +// struct _DisplayControls; +typedef struct _DisplayControls DisplayControls; +class IntegratedDisplay; + +typedef enum _DisplayModeId { + DISPLAY_MODE_VIEWER, + DISPLAY_MODE_CONFIG, + DISPLAY_MODE_RGB_BRIGHTNESS, +} DisplayModeId; + +class DisplayMode { + public: + DisplayMode(){}; + virtual ~DisplayMode(){}; + + virtual DisplayModeId GetId() = 0; + virtual void HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button + ) = 0; + virtual void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display) = 0; +}; + +#endif diff --git a/HAL/pico/include/display/InputDisplay.hpp b/HAL/pico/include/display/InputDisplay.hpp new file mode 100644 index 00000000..d2e03cd5 --- /dev/null +++ b/HAL/pico/include/display/InputDisplay.hpp @@ -0,0 +1,34 @@ +#ifndef _DISPLAY_INPUTDISPLAY_HPP +#define _DISPLAY_INPUTDISPLAY_HPP + +#include "display/DisplayMode.hpp" + +typedef struct _InputViewerButton { + Button button; + uint8_t center_x; + uint8_t center_y; + uint8_t radius; +} InputViewerButton; + +class InputDisplay : public DisplayMode { + public: + InputDisplay( + InputViewerButton *input_viewer_buttons, + size_t input_viewer_buttons_count, + CommunicationBackendId backend_id + ); + DisplayModeId GetId(); + void HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button + ); + void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); + + protected: + InputViewerButton *_input_viewer_buttons; + size_t _input_viewer_buttons_count; + CommunicationBackendId _backend_id; +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/include/display/RgbBrightnessMenu.hpp b/HAL/pico/include/display/RgbBrightnessMenu.hpp new file mode 100644 index 00000000..d44ee328 --- /dev/null +++ b/HAL/pico/include/display/RgbBrightnessMenu.hpp @@ -0,0 +1,21 @@ +#ifndef _DISPLAY_RGBBRIGHTNESSMENU_HPP +#define _DISPLAY_RGBBRIGHTNESSMENU_HPP + +#include "display/DisplayMode.hpp" + +class RgbBrightnessMenu : public DisplayMode { + public: + RgbBrightnessMenu(Config &config); + DisplayModeId GetId(); + void HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button + ); + void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); + + private: + Config &_config; +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp new file mode 100644 index 00000000..a7272ddc --- /dev/null +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -0,0 +1,306 @@ +#include "display/ConfigMenu.hpp" + +#include "core/Persistence.hpp" +#include "core/config_utils.hpp" +#include "core/mode_selection.hpp" +#include "reboot.hpp" + +ConfigMenu::ConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count) + : _config(config), + _backends(backends), + _backends_count(backends_count) { + /* Build default USB backends page */ + MenuPage::MenuItem *usb_backend_options = + new MenuPage::MenuItem[config.communication_backend_configs_count]; + + size_t usb_backend_options_count = 0; + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; + MenuPage::MenuItem ¤t_option = usb_backend_options[usb_backend_options_count]; + + if (backend_config.backend_id != COMMS_BACKEND_XINPUT && + backend_config.backend_id != COMMS_BACKEND_DINPUT && + backend_config.backend_id != COMMS_BACKEND_NINTENDO_SWITCH) { + continue; + } + + strlcpy( + current_option.text, + backend_name(backend_config.backend_id), + sizeof(current_option.text) + ); + current_option.key = i; + current_option.action = &SetDefaultUsbBackend; + usb_backend_options_count++; + } + + _usb_backends_page = { + .items = usb_backend_options, + .items_count = usb_backend_options_count, + }; + + /* Build gamemodes page */ + MenuPage::MenuItem *gamemode_options = new MenuPage::MenuItem[config.game_mode_configs_count]; + + size_t gamemode_options_count = 0; + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + MenuPage::MenuItem ¤t_option = gamemode_options[gamemode_options_count]; + + // Don't show keyboard modes as a gamemode option unless using DInputBackend. + if (_backends_count > 0 && _backends[0] != nullptr) { + CommunicationBackendId primary_backend_id = _backends[0]->BackendId(); + if (primary_backend_id != COMMS_BACKEND_DINPUT && + mode_config.mode_id == MODE_KEYBOARD) { + continue; + } + } + + if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { + strlcpy(current_option.text, mode_config.name, sizeof(current_option.text)); + } else { + strlcpy( + current_option.text, + gamemode_name(mode_config.mode_id), + sizeof(current_option.text) + ); + } + current_option.key = i; + current_option.action = &SetDefaultMode; + gamemode_options_count++; + } + + _gamemode_options_page = { + .items = gamemode_options, + .items_count = gamemode_options_count, + }; + + /* Build SOCD types page */ + static MenuPage::MenuItem socd_options[_SocdType_MAX] = {}; + for (uint8_t socd_type = SOCD_NEUTRAL; socd_type < _SocdType_ARRAYSIZE; socd_type++) { + MenuPage::MenuItem ¤t_option = socd_options[socd_type - 1]; + strlcpy(current_option.text, socd_name((SocdType)socd_type), sizeof(current_option.text)); + current_option.key = socd_type; + current_option.action = &SetSocdType; + } + + static MenuPage socd_page = { + .items = socd_options, + .items_count = sizeof(socd_options) / sizeof(MenuPage::MenuItem), + }; + + /* Build top-level page */ + // clang-format off + static const MenuPage::MenuItem top_level_items[] = { + { + .text = "Gamemode", + .page = &_gamemode_options_page, + }, + { + .text = "Default USB Mode", + .page = &_usb_backends_page, + }, + { + .text = "SOCD Mode", + .page = &socd_page, + }, + { + .text = "RGB Brightness", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + display_backend->SetDisplayMode(DISPLAY_MODE_RGB_BRIGHTNESS); + }, + }, + { + .text = "Return", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + display_backend->SetDisplayMode(DISPLAY_MODE_VIEWER); + }, + }, + { + .text = "Save changes", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + persistence.SaveConfig(config); + reboot_firmware(); + }, + }, + { + .text = "Discard changes", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + reboot_firmware(); + }, + } + }; + // clang-format on + + _top_level_page = { + .items = top_level_items, + .items_count = sizeof(top_level_items) / sizeof(MenuPage::MenuItem), + }; + + _usb_backends_page.parent = &_top_level_page; + _gamemode_options_page.parent = &_top_level_page; + socd_page.parent = &_top_level_page; +} + +ConfigMenu::~ConfigMenu() { + delete[] _usb_backends_page.items; + delete[] _gamemode_options_page.items; +} + +DisplayModeId ConfigMenu::GetId() { + return DISPLAY_MODE_CONFIG; +} + +void ConfigMenu::HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button +) { + if (_current_menu_page == nullptr) { + _current_menu_page = &_top_level_page; + _current_menu_offset = 0; + return; + } + + if (button == controls.up) { + _highlighted_menu_item = max(0, _highlighted_menu_item - 1); + } else if (button == controls.down) { + _highlighted_menu_item = + min(_current_menu_page->items_count - 1, _highlighted_menu_item + 1); + } else if (button == controls.enter) { + // Bounds check. + if (_highlighted_menu_item > _current_menu_page->items_count) { + _highlighted_menu_item = 0; + return; + } + + const MenuPage::MenuItem &selected_item = _current_menu_page->items[_highlighted_menu_item]; + + // If there's an action defined, perform it. + if (selected_item.action != nullptr) { + selected_item.action(instance, this, _config, selected_item.key); + + // Go back up a level. + if (_current_menu_page->parent != nullptr) { + _current_menu_page = _current_menu_page->parent; + _current_menu_offset = 0; + } + _highlighted_menu_item = 0; + return; + } + + // If there's a child page defined, drill into it. + if (selected_item.page != nullptr) { + _current_menu_page = selected_item.page; + _current_menu_offset = 0; + _highlighted_menu_item = 0; + return; + } + } else if (button == controls.back) { + // If at top-level page, go back to input viewer. + if (_current_menu_page->parent == nullptr) { + instance->SetDisplayMode(DISPLAY_MODE_VIEWER); + return; + } + + _current_menu_page = _current_menu_page->parent; + _highlighted_menu_item = 0; + } +} + +void ConfigMenu::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display) { + uint8_t font_width = instance->font_width; + uint8_t font_height = instance->font_height; + + if (_highlighted_menu_item - _current_menu_offset > max_visible_lines - 1) { + _current_menu_offset++; + } else if (_highlighted_menu_item < _current_menu_offset) { + _current_menu_offset--; + } + uint8_t last_item_to_display = + min(_current_menu_page->items_count - _current_menu_offset, max_visible_lines + 1); + for (size_t i = 0; i < last_item_to_display; i++) { + if (i + _current_menu_offset == _highlighted_menu_item) { + display.setCursor(0, i * (font_height + padding)); + display.print(highlight_string); + } + display.setCursor(font_width + padding, i * (font_height + padding)); + display.print(_current_menu_page->items[i + _current_menu_offset].text); + } +} + +void ConfigMenu::SetDefaultMode( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t mode_config_index +) { + if (mode_config_index < 0 || mode_config_index >= config.game_mode_configs_count) { + return; + } + + // Overwrite default game mode for all backend configs. + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + config.communication_backend_configs[i].default_mode_config = mode_config_index + 1; + } + + // Update mode for all backends. + for (size_t i = 0; i < menu->_backends_count; i++) { + set_mode( + menu->_backends[i], + config.game_mode_configs[mode_config_index], + config.keyboard_modes, + config.keyboard_modes_count + ); + } +} + +void ConfigMenu::SetDefaultUsbBackend( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t backend_config_index +) { + if (backend_config_index < 0 || + backend_config_index >= config.communication_backend_configs_count) { + return; + } + config.default_usb_backend_config = backend_config_index + 1; +} + +void ConfigMenu::SetSocdType( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t socd_type +) { + if (socd_type <= SOCD_UNSPECIFIED || socd_type > _SocdType_MAX) { + return; + } + + // Overwrite SOCD type for all SOCD pairs of current gamemode's config. + GameModeConfig &mode_config = display_backend->CurrentGameMode()->GetConfig(); + for (size_t i = 0; i < mode_config.socd_pairs_count; i++) { + mode_config.socd_pairs[i].socd_type = (SocdType)socd_type; + } +} \ No newline at end of file diff --git a/HAL/pico/src/display/InputDisplay.cpp b/HAL/pico/src/display/InputDisplay.cpp new file mode 100644 index 00000000..e9188bb7 --- /dev/null +++ b/HAL/pico/src/display/InputDisplay.cpp @@ -0,0 +1,54 @@ +#include "display/InputDisplay.hpp" + +#include "comms/IntegratedDisplay.hpp" +#include "core/config_utils.hpp" +#include "util/state_util.hpp" + +InputDisplay::InputDisplay( + InputViewerButton *input_viewer_buttons, + size_t input_viewer_buttons_count, + const CommunicationBackendId backend_id +) + : _input_viewer_buttons(input_viewer_buttons), + _input_viewer_buttons_count(input_viewer_buttons_count), + _backend_id(backend_id) {} + +DisplayModeId InputDisplay::GetId() { + return DISPLAY_MODE_VIEWER; +} + +void InputDisplay::HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button +) { + if (button == controls.enter) { + instance->SetDisplayMode(DISPLAY_MODE_CONFIG); + } +} + +void InputDisplay::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display) { + InputState &inputs = instance->GetInputs(); + uint8_t font_width = instance->font_width; + uint8_t color = instance->default_color; + + /* Gamemode text */ + const char *gamemode_text = gamemode_name(instance->CurrentGameMode()->GetConfig().mode_id); + display.setCursor(0, 0); + display.print(gamemode_text); + + /* Backend text */ + const char *backend_text = backend_name(_backend_id); + display.setCursor(display.width() - (strlen(backend_text) * font_width), 0); + display.print(backend_name(_backend_id)); + + /* Input display */ + for (size_t i = 0; i < _input_viewer_buttons_count; i++) { + InputViewerButton mapping = _input_viewer_buttons[i]; + if (get_button(inputs.buttons, mapping.button)) { + display.fillCircle(mapping.center_x, mapping.center_y, mapping.radius, color); + } else { + display.drawCircle(mapping.center_x, mapping.center_y, mapping.radius, color); + } + } +} \ No newline at end of file diff --git a/HAL/pico/src/display/RgbBrightnessMenu.cpp b/HAL/pico/src/display/RgbBrightnessMenu.cpp new file mode 100644 index 00000000..a4545f73 --- /dev/null +++ b/HAL/pico/src/display/RgbBrightnessMenu.cpp @@ -0,0 +1,41 @@ +#include "display/RgbBrightnessMenu.hpp" + +#include "comms/IntegratedDisplay.hpp" + +RgbBrightnessMenu::RgbBrightnessMenu(Config &config) : _config(config) {} + +DisplayModeId RgbBrightnessMenu::GetId() { + return DISPLAY_MODE_RGB_BRIGHTNESS; +} + +void RgbBrightnessMenu::HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button +) { + // const DisplayControls &controls = instance->_controls; + if (button == controls.up) { + _config.rgb_brightness++; + } else if (button == controls.down) { + _config.rgb_brightness--; + } else if (button == controls.back) { + instance->SetDisplayMode(DISPLAY_MODE_CONFIG); + } +} + +void RgbBrightnessMenu::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display) { + uint8_t font_width = instance->font_width; + uint8_t font_height = instance->font_height; + + // Current brightness value. + display.setCursor(display.width() / 2 - (font_width * 3) / 2, display.height() / 2); + display.printf("%3d", _config.rgb_brightness); + + // Display control hints. + display.setCursor(5, display.height() - font_height); + display.print("Back"); + display.setCursor(45, display.getCursorY()); + display.print("-"); + display.setCursor(display.width() - 45 - font_width, display.getCursorY()); + display.print("+"); +} \ No newline at end of file diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 22ab3920..31417772 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -5,6 +5,10 @@ #include "core/mode_selection.hpp" #include "core/pinout.hpp" #include "core/state.hpp" +#include "display/ConfigMenu.hpp" +#include "display/DisplayMode.hpp" +#include "display/InputDisplay.hpp" +#include "display/RgbBrightnessMenu.hpp" #include "glyph_overrides.hpp" #include "input/DebouncedSwitchMatrixInput.hpp" #include "reboot.hpp" @@ -141,16 +145,30 @@ size_t input_viewer_buttons_count = count_of(input_viewer_buttons); Adafruit_SSD1306 display(128, 64, &Wire1); IntegratedDisplay *display_backend = nullptr; +RgbBrightnessMenu rgb_brightness_menu(config); + void setup1() { while (!backend_count || backends == nullptr) { delay(1); } + + // These have to be initialized after backends. + CommunicationBackendId primary_backend_id = backends[0]->BackendId(); + static InputDisplay input_display( + input_viewer_buttons, + input_viewer_buttons_count, + primary_backend_id + ); + static ConfigMenu config_menu(config, backends, backend_count); + + static DisplayMode *display_modes[] = { &input_display, &config_menu, &rgb_brightness_menu }; + size_t display_modes_count = count_of(display_modes); + Wire1.setSDA(2); Wire1.setSCL(3); Wire1.setClock(1'000'000UL); Wire1.begin(); if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { - CommunicationBackendId primary_backend_id = backends[0]->BackendId(); // clang-format off display_backend = new IntegratedDisplay( inputs, @@ -158,12 +176,8 @@ void setup1() { []() { display.clearDisplay(); }, []() { display.display(); }, DisplayControls{ .back = BTN_MB4, .down = BTN_MB5, .up = BTN_MB6, .enter = BTN_MB7 }, - input_viewer_buttons, - input_viewer_buttons_count, - config, - primary_backend_id, - backends, - backend_count + display_modes, + display_modes_count ); // clang-format on } diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp index be46a37c..76d9113d 100644 --- a/include/comms/IntegratedDisplay.hpp +++ b/include/comms/IntegratedDisplay.hpp @@ -2,21 +2,11 @@ #define _COMMS_INTEGRATEDDISPLAY_HPP #include "core/CommunicationBackend.hpp" -#include "core/Persistence.hpp" -#include "core/config_utils.hpp" -#include "core/mode_selection.hpp" -#include "reboot.hpp" +#include "display/DisplayMode.hpp" #include -#include #include -typedef enum _DisplayMode { - DISPLAY_MODE_VIEWER, - DISPLAY_MODE_CONFIG, - DISPLAY_MODE_RGB_BRIGHTNESS, -} DisplayMode; - typedef struct _DisplayControls { Button back; Button down; @@ -24,96 +14,41 @@ typedef struct _DisplayControls { Button enter; } DisplayControls; -typedef struct _InputViewerButton { - Button button; - uint8_t center_x; - uint8_t center_y; - uint8_t radius; -} InputViewerButton; - -class IntegratedDisplay; - -typedef struct _MenuPage { - typedef struct _MenuItem { - char text[20]; - uint8_t key = 0; - void (*action)(IntegratedDisplay *instance, Config &config, uint8_t key) = nullptr; - struct _MenuPage *page = nullptr; - } MenuItem; - - struct _MenuPage *parent = nullptr; - const MenuItem *items = nullptr; - size_t items_count = 0; -} MenuPage; - class IntegratedDisplay : public CommunicationBackend { public: + static constexpr uint8_t controls_count = 4; + static constexpr uint32_t button_cooldown_ms = 150; + static constexpr uint8_t font_width = 6; + static constexpr uint8_t font_height = 8; + static constexpr uint8_t default_color = 1; + IntegratedDisplay( InputState &inputs, Adafruit_GFX &display, void (*clear_display)(), void (*update_display)(), - DisplayControls controls, - const InputViewerButton *input_viewer_buttons, - const size_t input_viewer_buttons_count, - Config &config, - CommunicationBackendId backend_id, - CommunicationBackend **backends, - size_t backends_count + const DisplayControls controls, + DisplayMode **display_modes, + size_t display_modes_count ); ~IntegratedDisplay(); - virtual void UpdateOutputs(); - virtual void SetGameMode(ControllerMode *gamemode); virtual void SendReport(); + void SetDisplayMode(DisplayModeId display_mode); protected: - static constexpr uint8_t controls_count = 4; - static constexpr uint8_t padding = 2; - static constexpr uint32_t button_cooldown_ms = 150; - static constexpr uint8_t font_width = 6; - static constexpr uint8_t font_height = 8; - static constexpr uint8_t max_visible_lines = 6; - static constexpr char highlight_string[] = ">"; - Adafruit_GFX &_display; void (*_clear_display)(); void (*_update_display)(); const DisplayControls _controls; const Button _controls_array[controls_count]; - const InputViewerButton *_input_viewer_buttons; - const size_t _input_viewer_buttons_count; - Config &_config; - const CommunicationBackendId _backend_id; - DisplayMode _display_mode = DISPLAY_MODE_VIEWER; - char _gamemode_text[16] = ""; - + DisplayModeId _display_mode = DISPLAY_MODE_VIEWER; absolute_time_t _button_cooldown_end = 0; - MenuPage *_current_menu_page = &_top_level_page; - uint8_t _highlighted_menu_item = 0; - int _current_menu_offset = 0; private: - MenuPage _usb_backends_page; - MenuPage _gamemode_options_page; - MenuPage _top_level_page; - CommunicationBackend **_backends; - size_t _backends_count; - - static void SetDefaultMode( - IntegratedDisplay *instance, - Config &config, - uint8_t mode_config_index - ); - static void SetDefaultUsbBackend( - IntegratedDisplay *instance, - Config &config, - uint8_t backend_config_index - ); - static void SetSocdType(IntegratedDisplay *instance, Config &config, uint8_t socd_type); + DisplayMode **_display_modes; + size_t _display_modes_count; - void HandleControlsViewerMode(Button button); - void HandleControlsConfigMode(Button button); - void HandleControlsRgbBrightnessMode(Button button); + DisplayMode *GetActiveDisplayMode(); }; #endif \ No newline at end of file diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp index 489ea982..9e529472 100644 --- a/src/comms/IntegratedDisplay.cpp +++ b/src/comms/IntegratedDisplay.cpp @@ -4,20 +4,14 @@ #include "core/config_utils.hpp" #include "util/state_util.hpp" -#define DEFAULT_COLOR 1 - IntegratedDisplay::IntegratedDisplay( InputState &inputs, Adafruit_GFX &display, void (*clear_display)(), void (*update_display)(), const DisplayControls controls, - const InputViewerButton *input_viewer_buttons, - const size_t input_viewer_buttons_count, - Config &config, - CommunicationBackendId backend_id, - CommunicationBackend **backends, - size_t backends_count + DisplayMode **display_modes, + size_t display_modes_count ) : CommunicationBackend(inputs, nullptr, 0), _display(display), @@ -25,357 +19,50 @@ IntegratedDisplay::IntegratedDisplay( _update_display(update_display), _controls(controls), _controls_array{ controls.back, controls.down, controls.up, controls.enter }, - _input_viewer_buttons(input_viewer_buttons), - _input_viewer_buttons_count(input_viewer_buttons_count), - _config(config), - _backend_id(backend_id), - _backends(backends), - _backends_count(backends_count) { + _display_modes(display_modes), + _display_modes_count(display_modes_count) { _display.setTextSize(1); - _display.setTextColor(DEFAULT_COLOR); - - /* Build default USB backends page */ - MenuPage::MenuItem *usb_backend_options = - new MenuPage::MenuItem[config.communication_backend_configs_count]; - - size_t usb_backend_options_count = 0; - for (size_t i = 0; i < config.communication_backend_configs_count; i++) { - CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; - MenuPage::MenuItem ¤t_option = usb_backend_options[usb_backend_options_count]; - - if (backend_config.backend_id != COMMS_BACKEND_XINPUT && - backend_config.backend_id != COMMS_BACKEND_DINPUT && - backend_config.backend_id != COMMS_BACKEND_NINTENDO_SWITCH) { - continue; - } - - strlcpy( - current_option.text, - backend_name(backend_config.backend_id), - sizeof(current_option.text) - ); - current_option.key = i; - current_option.action = &SetDefaultUsbBackend; - usb_backend_options_count++; - } - - _usb_backends_page = { - .items = usb_backend_options, - .items_count = usb_backend_options_count, - }; - - /* Build gamemodes page */ - MenuPage::MenuItem *gamemode_options = new MenuPage::MenuItem[config.game_mode_configs_count]; - - size_t gamemode_options_count = 0; - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode_config = config.game_mode_configs[i]; - MenuPage::MenuItem ¤t_option = gamemode_options[gamemode_options_count]; - - // Don't show keyboard modes as a gamemode option unless using DInputBackend. - if (_backend_id != COMMS_BACKEND_DINPUT && mode_config.mode_id == MODE_KEYBOARD) { - continue; - } - - if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { - strlcpy(current_option.text, mode_config.name, sizeof(current_option.text)); - } else { - strlcpy( - current_option.text, - gamemode_name(mode_config.mode_id), - sizeof(current_option.text) - ); - } - current_option.key = i; - current_option.action = &SetDefaultMode; - gamemode_options_count++; - } - - _gamemode_options_page = { - .items = gamemode_options, - .items_count = gamemode_options_count, - }; - - /* Build SOCD types page */ - static MenuPage::MenuItem socd_options[_SocdType_MAX] = {}; - for (uint8_t socd_type = SOCD_NEUTRAL; socd_type < _SocdType_ARRAYSIZE; socd_type++) { - MenuPage::MenuItem ¤t_option = socd_options[socd_type - 1]; - strlcpy(current_option.text, socd_name((SocdType)socd_type), sizeof(current_option.text)); - current_option.key = socd_type; - current_option.action = &SetSocdType; - } - - static MenuPage socd_page = { - .items = socd_options, - .items_count = sizeof(socd_options) / sizeof(MenuPage::MenuItem), - }; - - /* Build top-level page */ - // clang-format off - static const MenuPage::MenuItem top_level_items[] = { - { - .text = "Gamemode", - .page = &_gamemode_options_page, - }, - { - .text = "Default USB Mode", - .page = &_usb_backends_page, - }, - { - .text = "SOCD Mode", - .page = &socd_page, - }, - { - .text = "RGB Brightness", - .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { - instance->_display_mode = DISPLAY_MODE_RGB_BRIGHTNESS; - }, - }, - { - .text = "Return", - .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { - instance->_display_mode = DISPLAY_MODE_VIEWER; - }, - }, - { - .text = "Save changes", - .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { - persistence.SaveConfig(config); - reboot_firmware(); - }, - }, - { - .text = "Discard changes", - .action = [](IntegratedDisplay *instance, Config &config, uint8_t key) { - reboot_firmware(); - }, - } - }; - // clang-format on - - _top_level_page = { - .items = top_level_items, - .items_count = sizeof(top_level_items) / sizeof(MenuPage::MenuItem), - }; - - _usb_backends_page.parent = &_top_level_page; - _gamemode_options_page.parent = &_top_level_page; - socd_page.parent = &_top_level_page; + _display.setTextColor(default_color); } IntegratedDisplay::~IntegratedDisplay() { - delete[] _usb_backends_page.items; - delete[] _gamemode_options_page.items; - _clear_display(); _update_display(); } -void IntegratedDisplay::SetGameMode(ControllerMode *gamemode) { - GameModeId mode_id = gamemode->GetConfig().mode_id; - strlcpy(_gamemode_text, gamemode_name(mode_id), sizeof(_gamemode_text)); - CommunicationBackend::SetGameMode(gamemode); -} - -void IntegratedDisplay::UpdateOutputs() { +void IntegratedDisplay::SendReport() { if (!time_reached(_button_cooldown_end)) { return; } + DisplayMode *active_mode = GetActiveDisplayMode(); + if (active_mode == nullptr) { + return; + } + for (uint8_t i = 0; i < controls_count; i++) { Button button = _controls_array[i]; if (get_button(_inputs.buttons, button)) { _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); - switch (_display_mode) { - case DISPLAY_MODE_VIEWER: - return HandleControlsViewerMode(button); - case DISPLAY_MODE_CONFIG: - return HandleControlsConfigMode(button); - case DISPLAY_MODE_RGB_BRIGHTNESS: - return HandleControlsRgbBrightnessMode(button); - } - } - } -} - -void IntegratedDisplay::HandleControlsViewerMode(Button button) { - if (button == _controls.enter) { - _display_mode = DISPLAY_MODE_CONFIG; - } -} - -void IntegratedDisplay::HandleControlsConfigMode(Button button) { - if (_current_menu_page == nullptr) { - _current_menu_page = &_top_level_page; - _current_menu_offset = 0; - return; - } - - if (button == _controls.up) { - _highlighted_menu_item = max(0, _highlighted_menu_item - 1); - } else if (button == _controls.down) { - _highlighted_menu_item = - min(_current_menu_page->items_count - 1, _highlighted_menu_item + 1); - } else if (button == _controls.enter) { - // Bounds check. - if (_highlighted_menu_item > _current_menu_page->items_count) { - _highlighted_menu_item = 0; - return; - } - - const MenuPage::MenuItem &selected_item = _current_menu_page->items[_highlighted_menu_item]; - - // If there's an action defined, perform it. - if (selected_item.action != nullptr) { - selected_item.action(this, _config, selected_item.key); - - // Go back up a level. - if (_current_menu_page->parent != nullptr) { - _current_menu_page = _current_menu_page->parent; - _current_menu_offset = 0; - } - _highlighted_menu_item = 0; - return; + active_mode->HandleControls(this, _controls, button); + break; } - - // If there's a child page defined, drill into it. - if (selected_item.page != nullptr) { - _current_menu_page = selected_item.page; - _current_menu_offset = 0; - _highlighted_menu_item = 0; - return; - } - } else if (button == _controls.back) { - // If at top-level page, go back to input viewer. - if (_current_menu_page->parent == nullptr) { - _display_mode = DISPLAY_MODE_VIEWER; - return; - } - - _current_menu_page = _current_menu_page->parent; - _highlighted_menu_item = 0; - } -} - -void IntegratedDisplay::HandleControlsRgbBrightnessMode(Button button) { - if (button == _controls.up) { - _config.rgb_brightness++; - } else if (button == _controls.down) { - _config.rgb_brightness--; - } else if (button == _controls.back) { - _display_mode = DISPLAY_MODE_CONFIG; } -} - -void IntegratedDisplay::SendReport() { - UpdateOutputs(); _clear_display(); - - if (_display_mode == DISPLAY_MODE_VIEWER) { - /* Gamemode text */ - _display.setCursor(0, 0); - _display.print(_gamemode_text); - - /* Backend text */ - const char *backend_text = backend_name(_backend_id); - _display.setCursor(_display.width() - (strlen(backend_text) * font_width), 0); - _display.print(backend_name(_backend_id)); - - /* Input display */ - for (size_t i = 0; i < _input_viewer_buttons_count; i++) { - InputViewerButton mapping = _input_viewer_buttons[i]; - if (get_button(_inputs.buttons, mapping.button)) { - _display - .fillCircle(mapping.center_x, mapping.center_y, mapping.radius, DEFAULT_COLOR); - } else { - _display - .drawCircle(mapping.center_x, mapping.center_y, mapping.radius, DEFAULT_COLOR); - } - } - } else if (_display_mode == DISPLAY_MODE_CONFIG) { - /* Menu */ - if (_highlighted_menu_item - _current_menu_offset > max_visible_lines - 1) { - _current_menu_offset++; - } else if (_highlighted_menu_item < _current_menu_offset) { - _current_menu_offset--; - } - uint8_t last_item_to_display = - min(_current_menu_page->items_count - _current_menu_offset, max_visible_lines + 1); - for (size_t i = 0; i < last_item_to_display; i++) { - if (i + _current_menu_offset == _highlighted_menu_item) { - _display.setCursor(0, i * (font_height + padding)); - _display.print(highlight_string); - } - _display.setCursor(font_width + padding, i * (font_height + padding)); - _display.print(_current_menu_page->items[i + _current_menu_offset].text); - } - } else if (_display_mode == DISPLAY_MODE_RGB_BRIGHTNESS) { - // Current brightness value. - _display.setCursor(_display.width() / 2 - (font_width * 3) / 2, _display.height() / 2); - _display.printf("%3d", _config.rgb_brightness); - - // Display control hints. - _display.setCursor(5, _display.height() - font_height); - _display.print("Back"); - _display.setCursor(45, _display.getCursorY()); - _display.print("-"); - _display.setCursor(_display.width() - 45 - font_width, _display.getCursorY()); - _display.print("+"); - } - + active_mode->UpdateDisplay(this, _display); _update_display(); } -void IntegratedDisplay::SetDefaultMode( - IntegratedDisplay *instance, - Config &config, - uint8_t mode_config_index -) { - if (mode_config_index < 0 || mode_config_index >= config.game_mode_configs_count) { - return; - } - - // Overwrite default game mode for all backend configs. - for (size_t i = 0; i < config.communication_backend_configs_count; i++) { - config.communication_backend_configs[i].default_mode_config = mode_config_index + 1; - } - - // Update mode for all backends. - for (size_t i = 0; i < instance->_backends_count; i++) { - set_mode( - instance->_backends[i], - config.game_mode_configs[mode_config_index], - config.keyboard_modes, - config.keyboard_modes_count - ); - } +void IntegratedDisplay::SetDisplayMode(DisplayModeId display_mode) { + _display_mode = display_mode; } -void IntegratedDisplay::SetDefaultUsbBackend( - IntegratedDisplay *instance, - Config &config, - uint8_t backend_config_index -) { - if (backend_config_index < 0 || - backend_config_index >= config.communication_backend_configs_count) { - return; - } - config.default_usb_backend_config = backend_config_index + 1; -} - -void IntegratedDisplay::SetSocdType( - IntegratedDisplay *instance, - Config &config, - uint8_t socd_type -) { - if (socd_type <= SOCD_UNSPECIFIED || socd_type > _SocdType_MAX) { - return; - } - - // Overwrite SOCD type for all SOCD pairs of current gamemode's config. - GameModeConfig &mode_config = instance->_gamemode->GetConfig(); - for (size_t i = 0; i < mode_config.socd_pairs_count; i++) { - mode_config.socd_pairs[i].socd_type = (SocdType)socd_type; +DisplayMode *IntegratedDisplay::GetActiveDisplayMode() { + for (size_t i = 0; i < _display_modes_count; i++) { + if (_display_modes[i]->GetId() == _display_mode) { + return _display_modes[i]; + } } -} + return nullptr; +} \ No newline at end of file From f3e7ba00960ce125a616e7a0955acfd667eb4b40 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 8 Mar 2024 17:35:19 +0000 Subject: [PATCH 087/167] fix: minor visual bugs due to order of operations --- include/comms/IntegratedDisplay.hpp | 1 + src/comms/IntegratedDisplay.cpp | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp index 76d9113d..41af87bd 100644 --- a/include/comms/IntegratedDisplay.hpp +++ b/include/comms/IntegratedDisplay.hpp @@ -48,6 +48,7 @@ class IntegratedDisplay : public CommunicationBackend { DisplayMode **_display_modes; size_t _display_modes_count; + void HandleControls(DisplayMode *active_mode); DisplayMode *GetActiveDisplayMode(); }; diff --git a/src/comms/IntegratedDisplay.cpp b/src/comms/IntegratedDisplay.cpp index 9e529472..1274ba6c 100644 --- a/src/comms/IntegratedDisplay.cpp +++ b/src/comms/IntegratedDisplay.cpp @@ -31,12 +31,22 @@ IntegratedDisplay::~IntegratedDisplay() { } void IntegratedDisplay::SendReport() { - if (!time_reached(_button_cooldown_end)) { + DisplayMode *active_mode = GetActiveDisplayMode(); + if (active_mode == nullptr) { return; } - DisplayMode *active_mode = GetActiveDisplayMode(); - if (active_mode == nullptr) { + _clear_display(); + active_mode->UpdateDisplay(this, _display); + _update_display(); + + // This is done *after* display update so any side effects of HandleControls are not shown + // without active_mode also being up-to-date. + HandleControls(active_mode); +} + +void IntegratedDisplay::HandleControls(DisplayMode *active_mode) { + if (!time_reached(_button_cooldown_end)) { return; } @@ -45,13 +55,9 @@ void IntegratedDisplay::SendReport() { if (get_button(_inputs.buttons, button)) { _button_cooldown_end = make_timeout_time_ms(button_cooldown_ms); active_mode->HandleControls(this, _controls, button); - break; + return; } } - - _clear_display(); - active_mode->UpdateDisplay(this, _display); - _update_display(); } void IntegratedDisplay::SetDisplayMode(DisplayModeId display_mode) { From 674aa15d861cef334494eea362fb6c6b8f04edd4 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 8 Mar 2024 23:34:10 +0000 Subject: [PATCH 088/167] build: update nes-pio --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index c35043b3..941ca9b8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -110,7 +110,7 @@ lib_archive = no lib_deps = ${env.lib_deps} https://github.com/JonnyHaystack/joybus-pio/archive/refs/tags/v1.2.3.zip - https://github.com/JonnyHaystack/nes-pio#b15c04f + https://github.com/JonnyHaystack/nes-pio#73417ba https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput#4b5617b https://github.com/FastLED/FastLED#6daa782 From 41be1c858126c7875e599da8e13449b5973e0522 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 10 Mar 2024 01:22:01 +0000 Subject: [PATCH 089/167] feat: add CustomControllerMode --- HAL/pico/include/util/state_util.hpp | 36 +++++++++++ HAL/pico/src/comms/ConfiguratorBackend.cpp | 15 +++++ HAL/pico/src/comms/backend_init.cpp | 2 +- HAL/pico/src/display/ConfigMenu.cpp | 7 +- HAL/pico/src/display/InputDisplay.cpp | 10 ++- include/core/mode_selection.hpp | 16 +---- include/core/state.hpp | 41 +++++++----- include/modes/CustomControllerMode.hpp | 23 +++++++ platformio.ini | 2 +- src/core/mode_selection.cpp | 46 ++++++-------- src/modes/CustomControllerMode.cpp | 74 ++++++++++++++++++++++ 11 files changed, 206 insertions(+), 66 deletions(-) create mode 100644 include/modes/CustomControllerMode.hpp create mode 100644 src/modes/CustomControllerMode.cpp diff --git a/HAL/pico/include/util/state_util.hpp b/HAL/pico/include/util/state_util.hpp index 7ff0bcaf..9f898d6f 100644 --- a/HAL/pico/include/util/state_util.hpp +++ b/HAL/pico/include/util/state_util.hpp @@ -5,6 +5,8 @@ #include +/* InputState utils */ + inline void set_button(uint64_t &buttons, Button button_index, bool pressed) { if (button_index == BTN_UNSPECIFIED) { return; @@ -33,4 +35,38 @@ inline bool all_buttons_held(const uint64_t &buttons, uint64_t button_mask) { return button_mask != 0 && (buttons & button_mask) == button_mask; } +inline bool any_button_held(const uint64_t &buttons, uint64_t button_mask) { + return button_mask != 0 && (buttons & button_mask); +} + +/* OutputState utils */ + +inline void set_output(uint32_t &buttons, DigitalOutput output_index, bool pressed) { + if (output_index == GP_UNSPECIFIED) { + return; + } + DigitalOutput output_index_adjusted = (DigitalOutput)(output_index - 1); + buttons = + (buttons & ~(1UL << output_index_adjusted)) | ((uint32_t)pressed << output_index_adjusted); +} + +inline uint8_t OutputState::*axis_pointer(AnalogAxis axis) { + switch (axis) { + case AXIS_LSTICK_X: + return &OutputState::leftStickX; + case AXIS_LSTICK_Y: + return &OutputState::leftStickY; + case AXIS_RSTICK_X: + return &OutputState::rightStickX; + case AXIS_RSTICK_Y: + return &OutputState::rightStickY; + case AXIS_LTRIGGER: + return &OutputState::triggerLAnalog; + case AXIS_RTRIGGER: + return &OutputState::triggerRAnalog; + default: + return nullptr; + } +} + #endif \ No newline at end of file diff --git a/HAL/pico/src/comms/ConfiguratorBackend.cpp b/HAL/pico/src/comms/ConfiguratorBackend.cpp index 9469e2cb..5d2de279 100644 --- a/HAL/pico/src/comms/ConfiguratorBackend.cpp +++ b/HAL/pico/src/comms/ConfiguratorBackend.cpp @@ -183,6 +183,21 @@ bool ConfiguratorBackend::HandleSetConfig(uint8_t *buffer, size_t len) { WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); return false; } + + uint8_t custom_mode_id = _config.game_mode_configs[i].custom_mode_config; + if (custom_mode_id > _config.custom_modes_count) { + char errmsg[85]; + size_t errmsg_len = snprintf( + errmsg, + sizeof(errmsg), + "Custom mode ID %d is for game mode config %d but only %d custom modes are defined", + (uint8_t)custom_mode_id, + (uint8_t)i + 1, + (uint8_t)_config.custom_modes_count + ); + WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); + return false; + } } if (!_persistence->SaveConfig(_config)) { diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 9b0b8aab..493e7a4f 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -102,7 +102,7 @@ size_t initialize_backends( GameModeConfig &mode_config = config.game_mode_configs[backend_config.default_mode_config - 1]; for (size_t i = 0; i < backend_count; i++) { - set_mode(backends[i], mode_config, config.keyboard_modes, config.keyboard_modes_count); + set_mode(backends[i], mode_config, config); } } diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp index a7272ddc..18bfb2a7 100644 --- a/HAL/pico/src/display/ConfigMenu.cpp +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -266,12 +266,7 @@ void ConfigMenu::SetDefaultMode( // Update mode for all backends. for (size_t i = 0; i < menu->_backends_count; i++) { - set_mode( - menu->_backends[i], - config.game_mode_configs[mode_config_index], - config.keyboard_modes, - config.keyboard_modes_count - ); + set_mode(menu->_backends[i], config.game_mode_configs[mode_config_index], config); } } diff --git a/HAL/pico/src/display/InputDisplay.cpp b/HAL/pico/src/display/InputDisplay.cpp index e9188bb7..f85bebb7 100644 --- a/HAL/pico/src/display/InputDisplay.cpp +++ b/HAL/pico/src/display/InputDisplay.cpp @@ -33,9 +33,15 @@ void InputDisplay::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &disp uint8_t color = instance->default_color; /* Gamemode text */ - const char *gamemode_text = gamemode_name(instance->CurrentGameMode()->GetConfig().mode_id); display.setCursor(0, 0); - display.print(gamemode_text); + if (instance->CurrentGameMode() != nullptr) { + const GameModeConfig &mode_config = instance->CurrentGameMode()->GetConfig(); + if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { + display.print(mode_config.name); + } else { + display.print(gamemode_name(instance->CurrentGameMode()->GetConfig().mode_id)); + } + } /* Backend text */ const char *backend_text = backend_name(_backend_id); diff --git a/include/core/mode_selection.hpp b/include/core/mode_selection.hpp index a2fe7648..79ee24de 100644 --- a/include/core/mode_selection.hpp +++ b/include/core/mode_selection.hpp @@ -11,20 +11,8 @@ extern KeyboardMode *current_kb_mode; void set_mode(CommunicationBackend *backend, ControllerMode *mode); void set_mode(CommunicationBackend *backend, KeyboardMode *mode); -void set_mode( - CommunicationBackend *backend, - GameModeConfig &mode_config, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count -); -void set_mode( - CommunicationBackend *backend, - GameModeId mode_id, - GameModeConfig *mode_configs, - size_t mode_configs_count, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count -); +void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config); +void set_mode(CommunicationBackend *backend, GameModeId mode_id, Config &config); void select_mode(CommunicationBackend **backends, size_t backends_count, Config &config); void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count); diff --git a/include/core/state.hpp b/include/core/state.hpp index 391641f7..315199d1 100644 --- a/include/core/state.hpp +++ b/include/core/state.hpp @@ -103,23 +103,30 @@ typedef struct { // Output state. typedef struct _OutputState { // Digital outputs. - bool a = false; - bool b = false; - bool x = false; - bool y = false; - bool buttonL = false; - bool buttonR = false; - bool triggerLDigital = false; - bool triggerRDigital = false; - bool start = false; - bool select = false; - bool home = false; - bool dpadUp = false; - bool dpadDown = false; - bool dpadLeft = false; - bool dpadRight = false; - bool leftStickClick = false; - bool rightStickClick = false; + union { + uint32_t buttons = 0; + + struct { + bool a : 1; + bool b : 1; + bool x : 1; + bool y : 1; + bool buttonL : 1; + bool buttonR : 1; + bool triggerLDigital : 1; + bool triggerRDigital : 1; + bool start : 1; + bool select : 1; + bool home : 1; + bool capture : 1; + bool dpadUp : 1; + bool dpadDown : 1; + bool dpadLeft : 1; + bool dpadRight : 1; + bool leftStickClick : 1; + bool rightStickClick : 1; + }; + }; // Analog outputs. uint8_t leftStickX = 128; diff --git a/include/modes/CustomControllerMode.hpp b/include/modes/CustomControllerMode.hpp new file mode 100644 index 00000000..dbfd6e8d --- /dev/null +++ b/include/modes/CustomControllerMode.hpp @@ -0,0 +1,23 @@ +#ifndef _MODES_CUSTOMCONTROLLERMODE_HPP +#define _MODES_CUSTOMCONTROLLERMODE_HPP + +#include "core/ControllerMode.hpp" +#include "core/state.hpp" + +#include + +class CustomControllerMode : public ControllerMode { + public: + CustomControllerMode(GameModeConfig &config, const CustomModeConfig &custom_mode_config); + + protected: + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); + + private: + const CustomModeConfig &_custom_mode_config; + + Button GetDirectionButton(const Button *direction_buttons, StickDirectionButton direction); +}; + +#endif diff --git a/platformio.ini b/platformio.ini index 941ca9b8..053cb94b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#7cf3883 + https://github.com/JonnyHaystack/HayBox-proto#994f2cb [avr_base] platform = atmelavr diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 213be7da..d9c0ae18 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -1,6 +1,7 @@ #include "core/mode_selection.hpp" #include "core/state.hpp" +#include "modes/CustomControllerMode.hpp" #include "modes/CustomKeyboardMode.hpp" #include "modes/FgcMode.hpp" #include "modes/Melee20Button.hpp" @@ -34,12 +35,7 @@ void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { backend->SetGameMode(nullptr); } -void set_mode( - CommunicationBackend *backend, - GameModeConfig &mode_config, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count -) { +void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config) { switch (mode_config.mode_id) { case MODE_MELEE: set_mode(backend, new Melee20Button(mode_config, { .crouch_walk_os = false })); @@ -64,17 +60,29 @@ void set_mode( break; case MODE_KEYBOARD: if (mode_config.keyboard_mode_config < 1 || - mode_config.keyboard_mode_config > keyboard_modes_count) { + mode_config.keyboard_mode_config > config.keyboard_modes_count) { break; } set_mode( backend, new CustomKeyboardMode( mode_config, - keyboard_modes[mode_config.keyboard_mode_config - 1] + config.keyboard_modes[mode_config.keyboard_mode_config - 1] ) ); break; + case MODE_CUSTOM: + if (mode_config.custom_mode_config < 1 || + mode_config.custom_mode_config > config.custom_modes_count) { + break; + } + set_mode( + backend, + new CustomControllerMode( + mode_config, + config.custom_modes[mode_config.custom_mode_config - 1] + ) + ); case MODE_UNSPECIFIED: default: break; @@ -83,20 +91,13 @@ void set_mode( // TODO: Maybe remove this overload in favour of looking up the gamemode outside of here using a // config_utils function. -void set_mode( - CommunicationBackend *backend, - GameModeId mode_id, - GameModeConfig *mode_configs, - size_t mode_configs_count, - const KeyboardModeConfig *keyboard_modes, - size_t keyboard_modes_count -) { +void set_mode(CommunicationBackend *backend, GameModeId mode_id, Config &config) { // In this overload we only know the mode id so we need to find a mode config that matches this // ID. - for (size_t i = 0; i < mode_configs_count; i++) { - GameModeConfig &mode = mode_configs[i]; + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode = config.game_mode_configs[i]; if (mode.mode_id == mode_id) { - set_mode(backend, mode, keyboard_modes, keyboard_modes_count); + set_mode(backend, mode, config); return; } } @@ -113,12 +114,7 @@ void select_mode(CommunicationBackend **backends, size_t backends_count, Config if (all_buttons_held(inputs.buttons, mode_activation_masks[i]) && i != current_mode_index) { current_mode_index = i; for (size_t i = 0; i < backends_count; i++) { - set_mode( - backends[i], - mode_config, - config.keyboard_modes, - config.keyboard_modes_count - ); + set_mode(backends[i], mode_config, config); } return; } diff --git a/src/modes/CustomControllerMode.cpp b/src/modes/CustomControllerMode.cpp new file mode 100644 index 00000000..20d956ec --- /dev/null +++ b/src/modes/CustomControllerMode.cpp @@ -0,0 +1,74 @@ +#include "modes/CustomControllerMode.hpp" + +#include "util/state_util.hpp" + +#define ANALOG_STICK_NEUTRAL 128 + +CustomControllerMode::CustomControllerMode( + GameModeConfig &config, + const CustomModeConfig &custom_mode_config +) + : ControllerMode(config), + _custom_mode_config(custom_mode_config) {} + +void CustomControllerMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { + for (size_t output = 0; output < _custom_mode_config.digital_button_mappings_count; output++) { + Button input = _custom_mode_config.digital_button_mappings[output]; + set_output(outputs.buttons, (DigitalOutput)(output + 1), get_button(inputs.buttons, input)); + } + + if (inputs.nunchuk_connected) { + outputs.triggerLDigital |= inputs.nunchuk_z; + } +} + +void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { + const Button *direction_buttons = _custom_mode_config.stick_direction_mappings; + UpdateDirections( + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_LEFT)), + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_RIGHT)), + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_DOWN)), + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_UP)), + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_LEFT)), + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_RIGHT)), + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_DOWN)), + get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_UP)), + ANALOG_STICK_NEUTRAL - _custom_mode_config.stick_range, + ANALOG_STICK_NEUTRAL, + ANALOG_STICK_NEUTRAL + _custom_mode_config.stick_range, + outputs + ); + + const AnalogModifier *modifiers = _custom_mode_config.modifiers; + for (size_t i = 0; i < _custom_mode_config.modifiers_count; i++) { + const AnalogModifier &modifier = modifiers[i]; + if (modifier.axis == AXIS_UNSPECIFIED || modifier.axis > _AnalogAxis_MAX) { + continue; + } + if (!get_button(inputs.buttons, modifier.button)) { + continue; + } + + uint8_t OutputState::*axis = axis_pointer(modifier.axis); + if (axis != nullptr) { + outputs.*axis = + ANALOG_STICK_NEUTRAL + (outputs.*axis - ANALOG_STICK_NEUTRAL) * modifier.multiplier; + } + } + + // Nunchuk overrides left stick. + if (inputs.nunchuk_connected) { + outputs.leftStickX = inputs.nunchuk_x; + outputs.leftStickY = inputs.nunchuk_y; + } +} + +Button CustomControllerMode::GetDirectionButton( + const Button *direction_buttons, + StickDirectionButton direction +) { + if (direction == SD_UNSPECIFIED || direction > _StickDirectionButton_MAX) { + return BTN_UNSPECIFIED; + } + return direction_buttons[direction - 1]; +} \ No newline at end of file From 06d4714eff9aa02929b760008da027b996c2a8a5 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 10 Mar 2024 01:42:34 +0000 Subject: [PATCH 090/167] feat: implement analog triggers in CustomControllerMode --- src/modes/CustomControllerMode.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/modes/CustomControllerMode.cpp b/src/modes/CustomControllerMode.cpp index 20d956ec..36b27358 100644 --- a/src/modes/CustomControllerMode.cpp +++ b/src/modes/CustomControllerMode.cpp @@ -56,6 +56,29 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS } } + const AnalogTriggerMapping *analog_trigger_mappings = + _custom_mode_config.analog_trigger_mappings; + for (size_t i = 0; i < _custom_mode_config.analog_trigger_mappings_count; i++) { + const AnalogTriggerMapping &mapping = analog_trigger_mappings[i]; + if (get_button(inputs.buttons, mapping.button)) { + switch (mapping.trigger) { + case TRIGGER_LT: + outputs.triggerLAnalog = mapping.value; + break; + case TRIGGER_RT: + outputs.triggerRAnalog = mapping.value; + break; + } + } + } + + if (outputs.triggerLDigital) { + outputs.triggerLAnalog = 255; + } + if (outputs.triggerRDigital) { + outputs.triggerRAnalog = 255; + } + // Nunchuk overrides left stick. if (inputs.nunchuk_connected) { outputs.leftStickX = inputs.nunchuk_x; From f2b400c5e2352f7e4a9466b22b5784996b2f3f23 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 10 Mar 2024 17:45:15 +0000 Subject: [PATCH 091/167] refactor: statically allocate gamemodes --- HAL/pico/include/comms/NeoPixelBackend.hpp | 7 ++- HAL/pico/include/core/KeyboardMode.hpp | 2 +- HAL/pico/src/core/KeyboardMode.cpp | 2 +- HAL/pico/src/display/ConfigMenu.cpp | 8 ++-- HAL/pico/src/display/InputDisplay.cpp | 4 +- include/core/CommunicationBackend.hpp | 2 +- include/core/ControllerMode.hpp | 2 +- include/core/InputMode.hpp | 10 ++--- include/modes/CustomControllerMode.hpp | 5 ++- include/modes/CustomKeyboardMode.hpp | 5 ++- include/modes/DefaultKeyboardMode.hpp | 2 +- include/modes/FgcMode.hpp | 2 +- include/modes/Melee18Button.hpp | 2 +- include/modes/Melee20Button.hpp | 2 +- include/modes/ProjectM.hpp | 2 +- include/modes/RivalsOfAether.hpp | 2 +- include/modes/Ultimate.hpp | 2 +- include/modes/extra/DarkSouls.hpp | 2 +- include/modes/extra/HollowKnight.hpp | 2 +- include/modes/extra/MKWii.hpp | 2 +- include/modes/extra/MultiVersus.hpp | 2 +- include/modes/extra/RocketLeague.hpp | 2 +- include/modes/extra/SaltAndSanctuary.hpp | 2 +- include/modes/extra/ShovelKnight.hpp | 2 +- include/modes/extra/ToughLoveArena.hpp | 2 +- include/modes/extra/Ultimate2.hpp | 2 +- src/core/CommunicationBackend.cpp | 1 - src/core/ControllerMode.cpp | 2 +- src/core/InputMode.cpp | 27 ++++++----- src/core/mode_selection.cpp | 52 +++++++++++----------- src/modes/CustomControllerMode.cpp | 40 +++++++++++------ src/modes/CustomKeyboardMode.cpp | 19 +++++--- src/modes/DefaultKeyboardMode.cpp | 2 +- src/modes/FgcMode.cpp | 2 +- src/modes/Melee18Button.cpp | 3 +- src/modes/Melee20Button.cpp | 3 +- src/modes/ProjectM.cpp | 2 +- src/modes/RivalsOfAether.cpp | 2 +- src/modes/Ultimate.cpp | 2 +- src/modes/extra/DarkSouls.cpp | 2 +- src/modes/extra/HollowKnight.cpp | 2 +- src/modes/extra/MKWii.cpp | 2 +- src/modes/extra/MultiVersus.cpp | 2 +- src/modes/extra/RocketLeague.cpp | 2 +- src/modes/extra/SaltAndSanctuary.cpp | 2 +- src/modes/extra/ShovelKnight.cpp | 2 +- src/modes/extra/ToughLoveArena.cpp | 2 +- src/modes/extra/Ultimate2.cpp | 2 +- 48 files changed, 144 insertions(+), 110 deletions(-) diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index f149d33c..651c9356 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -34,7 +34,12 @@ template class NeoPixelBackend : public Commun _button_colors[i] = 0; } - uint8_t rgb_config_id = gamemode->GetConfig().rgb_config; + if (gamemode == nullptr || gamemode->GetConfig() == nullptr) { + _config = nullptr; + return; + } + + uint8_t rgb_config_id = gamemode->GetConfig()->rgb_config; if (rgb_config_id == 0 || rgb_config_id > _rgb_configs_count) { _config = nullptr; return; diff --git a/HAL/pico/include/core/KeyboardMode.hpp b/HAL/pico/include/core/KeyboardMode.hpp index b6a3cd0b..8d978279 100644 --- a/HAL/pico/include/core/KeyboardMode.hpp +++ b/HAL/pico/include/core/KeyboardMode.hpp @@ -10,7 +10,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(GameModeConfig &config); + KeyboardMode(); ~KeyboardMode(); void SendReport(const InputState &inputs); diff --git a/HAL/pico/src/core/KeyboardMode.cpp b/HAL/pico/src/core/KeyboardMode.cpp index c06b1bf9..a14f01d0 100644 --- a/HAL/pico/src/core/KeyboardMode.cpp +++ b/HAL/pico/src/core/KeyboardMode.cpp @@ -4,7 +4,7 @@ #include -KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) { +KeyboardMode::KeyboardMode() : InputMode() { _keyboard = new TUKeyboard(); _keyboard->begin(); } diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp index 18bfb2a7..22a566ca 100644 --- a/HAL/pico/src/display/ConfigMenu.cpp +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -294,8 +294,10 @@ void ConfigMenu::SetSocdType( } // Overwrite SOCD type for all SOCD pairs of current gamemode's config. - GameModeConfig &mode_config = display_backend->CurrentGameMode()->GetConfig(); - for (size_t i = 0; i < mode_config.socd_pairs_count; i++) { - mode_config.socd_pairs[i].socd_type = (SocdType)socd_type; + GameModeConfig *mode_config = display_backend->CurrentGameMode()->GetConfig(); + if (mode_config != nullptr) { + for (size_t i = 0; i < mode_config->socd_pairs_count; i++) { + mode_config->socd_pairs[i].socd_type = (SocdType)socd_type; + } } } \ No newline at end of file diff --git a/HAL/pico/src/display/InputDisplay.cpp b/HAL/pico/src/display/InputDisplay.cpp index f85bebb7..016b2a2c 100644 --- a/HAL/pico/src/display/InputDisplay.cpp +++ b/HAL/pico/src/display/InputDisplay.cpp @@ -35,11 +35,11 @@ void InputDisplay::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &disp /* Gamemode text */ display.setCursor(0, 0); if (instance->CurrentGameMode() != nullptr) { - const GameModeConfig &mode_config = instance->CurrentGameMode()->GetConfig(); + const GameModeConfig &mode_config = *instance->CurrentGameMode()->GetConfig(); if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { display.print(mode_config.name); } else { - display.print(gamemode_name(instance->CurrentGameMode()->GetConfig().mode_id)); + display.print(gamemode_name(mode_config.mode_id)); } } diff --git a/include/core/CommunicationBackend.hpp b/include/core/CommunicationBackend.hpp index cad38b78..fc1a971c 100644 --- a/include/core/CommunicationBackend.hpp +++ b/include/core/CommunicationBackend.hpp @@ -31,7 +31,7 @@ class CommunicationBackend { size_t _input_source_count; OutputState _outputs; - ControllerMode *_gamemode; + ControllerMode *_gamemode = nullptr; private: void ResetOutputs(); diff --git a/include/core/ControllerMode.hpp b/include/core/ControllerMode.hpp index fa66cd9d..8d3a927d 100644 --- a/include/core/ControllerMode.hpp +++ b/include/core/ControllerMode.hpp @@ -9,7 +9,7 @@ class ControllerMode : public InputMode { public: - ControllerMode(GameModeConfig &config); + ControllerMode(); void UpdateOutputs(const InputState &inputs, OutputState &outputs); void ResetDirections(); virtual void UpdateDirections( diff --git a/include/core/InputMode.hpp b/include/core/InputMode.hpp index 7d985775..f7af0bdf 100644 --- a/include/core/InputMode.hpp +++ b/include/core/InputMode.hpp @@ -8,18 +8,18 @@ class InputMode { public: - InputMode(GameModeConfig &config); - virtual ~InputMode(); - GameModeConfig &GetConfig(); + InputMode(); + GameModeConfig *GetConfig(); + void SetConfig(GameModeConfig &config); protected: - GameModeConfig &_config; + GameModeConfig *_config = nullptr; virtual void HandleSocd(InputState &inputs); virtual void HandleRemap(const InputState &original_inputs, InputState &remapped_inputs); private: - socd::SocdState *_socd_states = nullptr; + socd::SocdState _socd_states[10] = {}; }; #endif diff --git a/include/modes/CustomControllerMode.hpp b/include/modes/CustomControllerMode.hpp index dbfd6e8d..756bc8c4 100644 --- a/include/modes/CustomControllerMode.hpp +++ b/include/modes/CustomControllerMode.hpp @@ -8,14 +8,15 @@ class CustomControllerMode : public ControllerMode { public: - CustomControllerMode(GameModeConfig &config, const CustomModeConfig &custom_mode_config); + CustomControllerMode(); + void SetConfig(GameModeConfig &config, const CustomModeConfig &custom_mode_config); protected: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); private: - const CustomModeConfig &_custom_mode_config; + const CustomModeConfig *_custom_mode_config; Button GetDirectionButton(const Button *direction_buttons, StickDirectionButton direction); }; diff --git a/include/modes/CustomKeyboardMode.hpp b/include/modes/CustomKeyboardMode.hpp index ca5e2e80..79a2725c 100644 --- a/include/modes/CustomKeyboardMode.hpp +++ b/include/modes/CustomKeyboardMode.hpp @@ -8,10 +8,11 @@ class CustomKeyboardMode : public KeyboardMode { public: - CustomKeyboardMode(GameModeConfig &config, const KeyboardModeConfig &keyboard_config); + CustomKeyboardMode(); + void SetConfig(GameModeConfig &config, const KeyboardModeConfig &keyboard_config); private: - const KeyboardModeConfig &_keyboard_config; + const KeyboardModeConfig *_keyboard_config; void UpdateKeys(const InputState &inputs); }; diff --git a/include/modes/DefaultKeyboardMode.hpp b/include/modes/DefaultKeyboardMode.hpp index 3439b8fe..cf1a0b3e 100644 --- a/include/modes/DefaultKeyboardMode.hpp +++ b/include/modes/DefaultKeyboardMode.hpp @@ -6,7 +6,7 @@ class DefaultKeyboardMode : public KeyboardMode { public: - DefaultKeyboardMode(GameModeConfig &config); + DefaultKeyboardMode(); private: void UpdateKeys(const InputState &inputs); diff --git a/include/modes/FgcMode.hpp b/include/modes/FgcMode.hpp index 6293d6b4..d0bca9dd 100644 --- a/include/modes/FgcMode.hpp +++ b/include/modes/FgcMode.hpp @@ -6,7 +6,7 @@ class FgcMode : public ControllerMode { public: - FgcMode(GameModeConfig &config); + FgcMode(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/Melee18Button.hpp b/include/modes/Melee18Button.hpp index 3d4f6527..3095e5a7 100644 --- a/include/modes/Melee18Button.hpp +++ b/include/modes/Melee18Button.hpp @@ -10,7 +10,7 @@ typedef struct { class Melee18Button : public ControllerMode { public: - Melee18Button(GameModeConfig &config, Melee18ButtonOptions options = {}); + Melee18Button(Melee18ButtonOptions options = {}); private: Melee18ButtonOptions _options; diff --git a/include/modes/Melee20Button.hpp b/include/modes/Melee20Button.hpp index fb088367..71518a42 100644 --- a/include/modes/Melee20Button.hpp +++ b/include/modes/Melee20Button.hpp @@ -12,7 +12,7 @@ typedef struct { class Melee20Button : public ControllerMode { public: - Melee20Button(GameModeConfig &config, Melee20ButtonOptions options = {}); + Melee20Button(Melee20ButtonOptions options = {}); protected: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/ProjectM.hpp b/include/modes/ProjectM.hpp index aacf3370..ed75856c 100644 --- a/include/modes/ProjectM.hpp +++ b/include/modes/ProjectM.hpp @@ -11,7 +11,7 @@ typedef struct { class ProjectM : public ControllerMode { public: - ProjectM(GameModeConfig &config, ProjectMOptions options = {}); + ProjectM(ProjectMOptions options = {}); private: ProjectMOptions _options; diff --git a/include/modes/RivalsOfAether.hpp b/include/modes/RivalsOfAether.hpp index f37f6544..69c832ae 100644 --- a/include/modes/RivalsOfAether.hpp +++ b/include/modes/RivalsOfAether.hpp @@ -6,7 +6,7 @@ class RivalsOfAether : public ControllerMode { public: - RivalsOfAether(GameModeConfig &config); + RivalsOfAether(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/Ultimate.hpp b/include/modes/Ultimate.hpp index d8c07018..f02eb50d 100644 --- a/include/modes/Ultimate.hpp +++ b/include/modes/Ultimate.hpp @@ -6,7 +6,7 @@ class Ultimate : public ControllerMode { public: - Ultimate(GameModeConfig &config); + Ultimate(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/DarkSouls.hpp b/include/modes/extra/DarkSouls.hpp index c3dffe52..5ff2722b 100644 --- a/include/modes/extra/DarkSouls.hpp +++ b/include/modes/extra/DarkSouls.hpp @@ -7,7 +7,7 @@ class DarkSouls : public ControllerMode { public: - DarkSouls(GameModeConfig &config); + DarkSouls(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/HollowKnight.hpp b/include/modes/extra/HollowKnight.hpp index 4e257e09..7b395ffb 100644 --- a/include/modes/extra/HollowKnight.hpp +++ b/include/modes/extra/HollowKnight.hpp @@ -8,7 +8,7 @@ class HollowKnight : public ControllerMode { public: - HollowKnight(GameModeConfig &config); + HollowKnight(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/MKWii.hpp b/include/modes/extra/MKWii.hpp index 5c13800d..7bc12a8e 100644 --- a/include/modes/extra/MKWii.hpp +++ b/include/modes/extra/MKWii.hpp @@ -7,7 +7,7 @@ class MKWii : public ControllerMode { public: - MKWii(GameModeConfig &config); + MKWii(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/MultiVersus.hpp b/include/modes/extra/MultiVersus.hpp index 7469f4d8..4dca8f9e 100644 --- a/include/modes/extra/MultiVersus.hpp +++ b/include/modes/extra/MultiVersus.hpp @@ -7,7 +7,7 @@ class MultiVersus : public ControllerMode { public: - MultiVersus(GameModeConfig &config); + MultiVersus(); protected: virtual void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/RocketLeague.hpp b/include/modes/extra/RocketLeague.hpp index cc73199f..bd4e6013 100644 --- a/include/modes/extra/RocketLeague.hpp +++ b/include/modes/extra/RocketLeague.hpp @@ -7,7 +7,7 @@ class RocketLeague : public ControllerMode { public: - RocketLeague(GameModeConfig &config); + RocketLeague(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/SaltAndSanctuary.hpp b/include/modes/extra/SaltAndSanctuary.hpp index 790d1016..42466669 100644 --- a/include/modes/extra/SaltAndSanctuary.hpp +++ b/include/modes/extra/SaltAndSanctuary.hpp @@ -7,7 +7,7 @@ class SaltAndSanctuary : public ControllerMode { public: - SaltAndSanctuary(GameModeConfig &config); + SaltAndSanctuary(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/ShovelKnight.hpp b/include/modes/extra/ShovelKnight.hpp index b3d33525..b1ca38e6 100644 --- a/include/modes/extra/ShovelKnight.hpp +++ b/include/modes/extra/ShovelKnight.hpp @@ -7,7 +7,7 @@ class ShovelKnight : public ControllerMode { public: - ShovelKnight(GameModeConfig &config); + ShovelKnight(); private: virtual void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/include/modes/extra/ToughLoveArena.hpp b/include/modes/extra/ToughLoveArena.hpp index b0781fa9..7f5d0fd0 100644 --- a/include/modes/extra/ToughLoveArena.hpp +++ b/include/modes/extra/ToughLoveArena.hpp @@ -7,7 +7,7 @@ class ToughLoveArena : public KeyboardMode { public: - ToughLoveArena(GameModeConfig &config); + ToughLoveArena(); private: void UpdateKeys(const InputState &inputs); diff --git a/include/modes/extra/Ultimate2.hpp b/include/modes/extra/Ultimate2.hpp index 7f2d781f..14640e74 100644 --- a/include/modes/extra/Ultimate2.hpp +++ b/include/modes/extra/Ultimate2.hpp @@ -7,7 +7,7 @@ class Ultimate2 : public ControllerMode { public: - Ultimate2(GameModeConfig &config); + Ultimate2(); private: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); diff --git a/src/core/CommunicationBackend.cpp b/src/core/CommunicationBackend.cpp index 0f20844d..f1cbcd6d 100644 --- a/src/core/CommunicationBackend.cpp +++ b/src/core/CommunicationBackend.cpp @@ -52,7 +52,6 @@ CommunicationBackendId CommunicationBackend::BackendId() { } void CommunicationBackend::SetGameMode(ControllerMode *gamemode) { - delete _gamemode; _gamemode = gamemode; } diff --git a/src/core/ControllerMode.cpp b/src/core/ControllerMode.cpp index 448acbd4..6cb60552 100644 --- a/src/core/ControllerMode.cpp +++ b/src/core/ControllerMode.cpp @@ -1,6 +1,6 @@ #include "core/ControllerMode.hpp" -ControllerMode::ControllerMode(GameModeConfig &config) : InputMode(config) { +ControllerMode::ControllerMode() : InputMode() { // Set up initial state. ResetDirections(); } diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index e5dba376..bb732218 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -4,22 +4,23 @@ #include "core/state.hpp" #include "util/state_util.hpp" -InputMode::InputMode(GameModeConfig &config) : _config(config) { - _socd_states = new socd::SocdState[_config.socd_pairs_count]; -} +InputMode::InputMode() {} -InputMode::~InputMode() { - delete[] _socd_states; +GameModeConfig *InputMode::GetConfig() { + return _config; } -GameModeConfig &InputMode::GetConfig() { - return _config; +void InputMode::SetConfig(GameModeConfig &config) { + _config = &config; } void InputMode::HandleSocd(InputState &inputs) { + if (_config == nullptr) { + return; + } // Handle SOCD resolution for each SOCD button pair. - for (size_t i = 0; i < _config.socd_pairs_count; i++) { - const SocdPair &pair = _config.socd_pairs[i]; + for (size_t i = 0; i < _config->socd_pairs_count; i++) { + const SocdPair &pair = _config->socd_pairs[i]; switch (pair.socd_type) { case SOCD_NEUTRAL: socd::neutral(inputs, pair.button_dir1, pair.button_dir2); @@ -54,12 +55,16 @@ void InputMode::HandleSocd(InputState &inputs) { } void InputMode::HandleRemap(const InputState &original_inputs, InputState &remapped_inputs) { + if (_config == nullptr) { + return; + } + // Keep track of which buttons have been remapped so that we can avoid conflicts for buttons // that are remapped to multiple buttons and prevent macro remapping. uint64_t physical_buttons_already_remapped = 0; uint64_t buttons_already_mapped_to = 0; - for (size_t i = 0; i < _config.button_remapping_count; i++) { - const ButtonRemap &remapping = _config.button_remapping[i]; + for (size_t i = 0; i < _config->button_remapping_count; i++) { + const ButtonRemap &remapping = _config->button_remapping[i]; // If this physical button was already mapped to something else, ignore this remapping. This // is to prevent creating macro behaviour through remapping. if (get_button(physical_buttons_already_remapped, remapping.physical_button)) { diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index d9c0ae18..c6027dd5 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -12,6 +12,14 @@ #include +Melee20Button melee_mode({ .crouch_walk_os = false }); +ProjectM projectm_mode({ .true_z_press = false, .ledgedash_max_jump_traj = true }); +Ultimate ultimate_mode; +FgcMode fgc_mode; +RivalsOfAether rivals_mode; +CustomKeyboardMode keyboard_mode; +CustomControllerMode custom_mode; + uint64_t mode_activation_masks[10]; size_t current_mode_index = SIZE_MAX; @@ -19,7 +27,6 @@ size_t current_mode_index = SIZE_MAX; void set_mode(CommunicationBackend *backend, ControllerMode *mode) { // Delete keyboard mode in case one is set, so we don't end up getting both controller and // keyboard inputs. - delete current_kb_mode; current_kb_mode = nullptr; // Set new controller mode. @@ -28,7 +35,6 @@ void set_mode(CommunicationBackend *backend, ControllerMode *mode) { void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { // Delete and reassign current keyboard mode. - delete current_kb_mode; current_kb_mode = mode; // Unset the current controller mode so backend only gives neutral inputs. @@ -38,51 +44,47 @@ void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config) { switch (mode_config.mode_id) { case MODE_MELEE: - set_mode(backend, new Melee20Button(mode_config, { .crouch_walk_os = false })); + melee_mode.SetConfig(mode_config); + set_mode(backend, &melee_mode); break; case MODE_PROJECT_M: - set_mode( - backend, - new ProjectM( - mode_config, - { .true_z_press = false, .ledgedash_max_jump_traj = true } - ) - ); + projectm_mode.SetConfig(mode_config); + set_mode(backend, &projectm_mode); break; case MODE_ULTIMATE: - set_mode(backend, new Ultimate(mode_config)); + ultimate_mode.SetConfig(mode_config); + set_mode(backend, &ultimate_mode); break; case MODE_FGC: - set_mode(backend, new FgcMode(mode_config)); + fgc_mode.SetConfig(mode_config); + set_mode(backend, &fgc_mode); break; case MODE_RIVALS_OF_AETHER: - set_mode(backend, new RivalsOfAether(mode_config)); + rivals_mode.SetConfig(mode_config); + set_mode(backend, &rivals_mode); break; case MODE_KEYBOARD: if (mode_config.keyboard_mode_config < 1 || mode_config.keyboard_mode_config > config.keyboard_modes_count) { break; } - set_mode( - backend, - new CustomKeyboardMode( - mode_config, - config.keyboard_modes[mode_config.keyboard_mode_config - 1] - ) + keyboard_mode.SetConfig( + mode_config, + config.keyboard_modes[mode_config.keyboard_mode_config - 1] ); + set_mode(backend, &keyboard_mode); break; case MODE_CUSTOM: if (mode_config.custom_mode_config < 1 || mode_config.custom_mode_config > config.custom_modes_count) { break; } - set_mode( - backend, - new CustomControllerMode( - mode_config, - config.custom_modes[mode_config.custom_mode_config - 1] - ) + custom_mode.SetConfig( + mode_config, + config.custom_modes[mode_config.custom_mode_config - 1] ); + set_mode(backend, &custom_mode); + break; case MODE_UNSPECIFIED: default: break; diff --git a/src/modes/CustomControllerMode.cpp b/src/modes/CustomControllerMode.cpp index 36b27358..97a24164 100644 --- a/src/modes/CustomControllerMode.cpp +++ b/src/modes/CustomControllerMode.cpp @@ -4,16 +4,23 @@ #define ANALOG_STICK_NEUTRAL 128 -CustomControllerMode::CustomControllerMode( +CustomControllerMode::CustomControllerMode() : ControllerMode() {} + +void CustomControllerMode::SetConfig( GameModeConfig &config, const CustomModeConfig &custom_mode_config -) - : ControllerMode(config), - _custom_mode_config(custom_mode_config) {} +) { + InputMode::SetConfig(config); + _custom_mode_config = &custom_mode_config; +} void CustomControllerMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { - for (size_t output = 0; output < _custom_mode_config.digital_button_mappings_count; output++) { - Button input = _custom_mode_config.digital_button_mappings[output]; + if (_custom_mode_config == nullptr) { + return; + } + + for (size_t output = 0; output < _custom_mode_config->digital_button_mappings_count; output++) { + Button input = _custom_mode_config->digital_button_mappings[output]; set_output(outputs.buttons, (DigitalOutput)(output + 1), get_button(inputs.buttons, input)); } @@ -23,7 +30,12 @@ void CustomControllerMode::UpdateDigitalOutputs(const InputState &inputs, Output } void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { - const Button *direction_buttons = _custom_mode_config.stick_direction_mappings; + if (_custom_mode_config == nullptr) { + return; + } + + const Button *direction_buttons = _custom_mode_config->stick_direction_mappings; + uint8_t stick_range = _custom_mode_config->stick_range; UpdateDirections( get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_LEFT)), get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_RIGHT)), @@ -33,14 +45,14 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_RIGHT)), get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_DOWN)), get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_UP)), - ANALOG_STICK_NEUTRAL - _custom_mode_config.stick_range, + ANALOG_STICK_NEUTRAL - stick_range, ANALOG_STICK_NEUTRAL, - ANALOG_STICK_NEUTRAL + _custom_mode_config.stick_range, + ANALOG_STICK_NEUTRAL + stick_range, outputs ); - const AnalogModifier *modifiers = _custom_mode_config.modifiers; - for (size_t i = 0; i < _custom_mode_config.modifiers_count; i++) { + const AnalogModifier *modifiers = _custom_mode_config->modifiers; + for (size_t i = 0; i < _custom_mode_config->modifiers_count; i++) { const AnalogModifier &modifier = modifiers[i]; if (modifier.axis == AXIS_UNSPECIFIED || modifier.axis > _AnalogAxis_MAX) { continue; @@ -57,8 +69,8 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS } const AnalogTriggerMapping *analog_trigger_mappings = - _custom_mode_config.analog_trigger_mappings; - for (size_t i = 0; i < _custom_mode_config.analog_trigger_mappings_count; i++) { + _custom_mode_config->analog_trigger_mappings; + for (size_t i = 0; i < _custom_mode_config->analog_trigger_mappings_count; i++) { const AnalogTriggerMapping &mapping = analog_trigger_mappings[i]; if (get_button(inputs.buttons, mapping.button)) { switch (mapping.trigger) { @@ -68,6 +80,8 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS case TRIGGER_RT: outputs.triggerRAnalog = mapping.value; break; + default: + break; } } } diff --git a/src/modes/CustomKeyboardMode.cpp b/src/modes/CustomKeyboardMode.cpp index cd88ac82..60c7c69a 100644 --- a/src/modes/CustomKeyboardMode.cpp +++ b/src/modes/CustomKeyboardMode.cpp @@ -5,16 +5,23 @@ #include -CustomKeyboardMode::CustomKeyboardMode( +CustomKeyboardMode::CustomKeyboardMode() : KeyboardMode() {} + +void CustomKeyboardMode::SetConfig( GameModeConfig &config, const KeyboardModeConfig &keyboard_config -) - : KeyboardMode(config), - _keyboard_config(keyboard_config) {} +) { + InputMode::SetConfig(config); + _keyboard_config = &keyboard_config; +} void CustomKeyboardMode::UpdateKeys(const InputState &inputs) { - const ButtonToKeycodeMapping *keymap = _keyboard_config.buttons_to_keycodes; - size_t key_count = _keyboard_config.buttons_to_keycodes_count; + if (_keyboard_config == nullptr) { + return; + } + + const ButtonToKeycodeMapping *keymap = _keyboard_config->buttons_to_keycodes; + size_t key_count = _keyboard_config->buttons_to_keycodes_count; for (size_t i = 0; i < key_count; i++) { if (keymap[i].button == BTN_UNSPECIFIED) { continue; diff --git a/src/modes/DefaultKeyboardMode.cpp b/src/modes/DefaultKeyboardMode.cpp index ec87975c..c016527a 100644 --- a/src/modes/DefaultKeyboardMode.cpp +++ b/src/modes/DefaultKeyboardMode.cpp @@ -3,7 +3,7 @@ #include "core/socd.hpp" #include "core/state.hpp" -DefaultKeyboardMode::DefaultKeyboardMode(GameModeConfig &config) : KeyboardMode(config) {} +DefaultKeyboardMode::DefaultKeyboardMode() : KeyboardMode() {} void DefaultKeyboardMode::UpdateKeys(const InputState &inputs) { Press(HID_KEY_A, inputs.lf4); diff --git a/src/modes/FgcMode.cpp b/src/modes/FgcMode.cpp index 3f8776b3..85d366c6 100644 --- a/src/modes/FgcMode.cpp +++ b/src/modes/FgcMode.cpp @@ -1,6 +1,6 @@ #include "modes/FgcMode.hpp" -FgcMode::FgcMode(GameModeConfig &config) : ControllerMode(config) {} +FgcMode::FgcMode() : ControllerMode() {} void FgcMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Directions diff --git a/src/modes/Melee18Button.cpp b/src/modes/Melee18Button.cpp index 14f21ca8..cb74101a 100644 --- a/src/modes/Melee18Button.cpp +++ b/src/modes/Melee18Button.cpp @@ -4,8 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee18Button::Melee18Button(GameModeConfig &config, Melee18ButtonOptions options) - : ControllerMode(config) { +Melee18Button::Melee18Button(Melee18ButtonOptions options) : ControllerMode() { _options = options; horizontal_socd = false; } diff --git a/src/modes/Melee20Button.cpp b/src/modes/Melee20Button.cpp index 1c32b778..04da2bc7 100644 --- a/src/modes/Melee20Button.cpp +++ b/src/modes/Melee20Button.cpp @@ -4,8 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee20Button::Melee20Button(GameModeConfig &config, Melee20ButtonOptions options) - : ControllerMode(config) { +Melee20Button::Melee20Button(Melee20ButtonOptions options) : ControllerMode() { _options = options; _horizontal_socd = false; } diff --git a/src/modes/ProjectM.cpp b/src/modes/ProjectM.cpp index 341181dc..5556c31c 100644 --- a/src/modes/ProjectM.cpp +++ b/src/modes/ProjectM.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -ProjectM::ProjectM(GameModeConfig &config, ProjectMOptions options) : ControllerMode(config) { +ProjectM::ProjectM(ProjectMOptions options) : ControllerMode() { _options = options; _horizontal_socd = false; } diff --git a/src/modes/RivalsOfAether.cpp b/src/modes/RivalsOfAether.cpp index 35961a0f..172d6607 100644 --- a/src/modes/RivalsOfAether.cpp +++ b/src/modes/RivalsOfAether.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -RivalsOfAether::RivalsOfAether(GameModeConfig &config) : ControllerMode(config) {} +RivalsOfAether::RivalsOfAether() : ControllerMode() {} void RivalsOfAether::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; diff --git a/src/modes/Ultimate.cpp b/src/modes/Ultimate.cpp index 822dd67d..13b3f64a 100644 --- a/src/modes/Ultimate.cpp +++ b/src/modes/Ultimate.cpp @@ -5,7 +5,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate::Ultimate(GameModeConfig &config) : ControllerMode(config) {} +Ultimate::Ultimate() : ControllerMode() {} void Ultimate::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; diff --git a/src/modes/extra/DarkSouls.cpp b/src/modes/extra/DarkSouls.cpp index 5dab4f05..62298aa3 100644 --- a/src/modes/extra/DarkSouls.cpp +++ b/src/modes/extra/DarkSouls.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -DarkSouls::DarkSouls(GameModeConfig &config) : ControllerMode(config) {} +DarkSouls::DarkSouls() : ControllerMode() {} void DarkSouls::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.y = inputs.rf6; diff --git a/src/modes/extra/HollowKnight.cpp b/src/modes/extra/HollowKnight.cpp index bb270617..ef339b9b 100644 --- a/src/modes/extra/HollowKnight.cpp +++ b/src/modes/extra/HollowKnight.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -HollowKnight::HollowKnight(GameModeConfig &config) : ControllerMode(config) {} +HollowKnight::HollowKnight() : ControllerMode() {} void HollowKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; // Attack diff --git a/src/modes/extra/MKWii.cpp b/src/modes/extra/MKWii.cpp index 122b1cac..ca8bd31b 100644 --- a/src/modes/extra/MKWii.cpp +++ b/src/modes/extra/MKWii.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MKWii::MKWii(GameModeConfig &config) : ControllerMode(config) {} +MKWii::MKWii() : ControllerMode() {} void MKWii::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rf1; diff --git a/src/modes/extra/MultiVersus.cpp b/src/modes/extra/MultiVersus.cpp index 145207de..3fe3b8df 100644 --- a/src/modes/extra/MultiVersus.cpp +++ b/src/modes/extra/MultiVersus.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -MultiVersus::MultiVersus(GameModeConfig &config) : ControllerMode(config) {} +MultiVersus::MultiVersus() : ControllerMode() {} void MultiVersus::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { // Bind X and Y to "jump" in-game. diff --git a/src/modes/extra/RocketLeague.cpp b/src/modes/extra/RocketLeague.cpp index b5ec4125..0706f22d 100644 --- a/src/modes/extra/RocketLeague.cpp +++ b/src/modes/extra/RocketLeague.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -RocketLeague::RocketLeague(GameModeConfig &config) : ControllerMode(config) {} +RocketLeague::RocketLeague() : ControllerMode() {} void RocketLeague::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; diff --git a/src/modes/extra/SaltAndSanctuary.cpp b/src/modes/extra/SaltAndSanctuary.cpp index 79712fd9..5e6f1ccc 100644 --- a/src/modes/extra/SaltAndSanctuary.cpp +++ b/src/modes/extra/SaltAndSanctuary.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -SaltAndSanctuary::SaltAndSanctuary(GameModeConfig &config) : ControllerMode(config) {} +SaltAndSanctuary::SaltAndSanctuary() : ControllerMode() {} void SaltAndSanctuary::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.dpadRight = inputs.lf4; // Block diff --git a/src/modes/extra/ShovelKnight.cpp b/src/modes/extra/ShovelKnight.cpp index 8cd72043..14ebd16f 100644 --- a/src/modes/extra/ShovelKnight.cpp +++ b/src/modes/extra/ShovelKnight.cpp @@ -4,7 +4,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 255 -ShovelKnight::ShovelKnight(GameModeConfig &config) : ControllerMode(config) {} +ShovelKnight::ShovelKnight() : ControllerMode() {} void ShovelKnight::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.dpadLeft = inputs.lf3; diff --git a/src/modes/extra/ToughLoveArena.cpp b/src/modes/extra/ToughLoveArena.cpp index 9ebd0d94..3e20768a 100644 --- a/src/modes/extra/ToughLoveArena.cpp +++ b/src/modes/extra/ToughLoveArena.cpp @@ -1,6 +1,6 @@ #include "modes/extra/ToughLoveArena.hpp" -ToughLoveArena::ToughLoveArena(GameModeConfig &config) : KeyboardMode(config) {} +ToughLoveArena::ToughLoveArena() : KeyboardMode() {} void ToughLoveArena::UpdateKeys(const InputState &inputs) { Press(HID_KEY_S, inputs.lf3); diff --git a/src/modes/extra/Ultimate2.cpp b/src/modes/extra/Ultimate2.cpp index d828d498..c48b9bcb 100644 --- a/src/modes/extra/Ultimate2.cpp +++ b/src/modes/extra/Ultimate2.cpp @@ -5,7 +5,7 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -Ultimate2::Ultimate2(GameModeConfig &config) : ControllerMode(config) {} +Ultimate2::Ultimate2() : ControllerMode() {} void Ultimate2::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { outputs.a = inputs.rt1; From bbd5f5967b1ee6a0cbdaee21f1969b42ee2bec86 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 10 Mar 2024 17:45:45 +0000 Subject: [PATCH 092/167] fix: if no RGB config then LEDs should be off --- HAL/pico/include/comms/NeoPixelBackend.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index 651c9356..b853a992 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -54,12 +54,9 @@ template class NeoPixelBackend : public Commun } virtual void SendReport() { - if (_config == nullptr) { - return; - } for (int i = 0; i < led_count; i++) { Button button = this->_button_mappings[i]; - _leds[i] = _button_colors[max(0, button - 1)]; + _leds[i] = _config != nullptr ? _button_colors[max(0, button - 1)] : 0; } FastLED.setBrightness(_brightness); FastLED.show(); From 1797beaf017a2ce052ba61a181c6e727eabcb4ea Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 11 Mar 2024 12:23:41 +0000 Subject: [PATCH 093/167] feat: add MenuButtonHints display mode --- HAL/pico/include/display/DisplayMode.hpp | 1 + HAL/pico/src/display/ConfigMenu.cpp | 15 +++++++++++++++ config/glyph/config.cpp | 22 ++++++++++++++++------ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/HAL/pico/include/display/DisplayMode.hpp b/HAL/pico/include/display/DisplayMode.hpp index 003b8537..23ace4e2 100644 --- a/HAL/pico/include/display/DisplayMode.hpp +++ b/HAL/pico/include/display/DisplayMode.hpp @@ -12,6 +12,7 @@ typedef enum _DisplayModeId { DISPLAY_MODE_VIEWER, DISPLAY_MODE_CONFIG, DISPLAY_MODE_RGB_BRIGHTNESS, + DISPLAY_MODE_BUTTON_HINTS } DisplayModeId; class DisplayMode { diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp index 22a566ca..32548596 100644 --- a/HAL/pico/src/display/ConfigMenu.cpp +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -123,6 +123,10 @@ ConfigMenu::ConfigMenu(Config &config, CommunicationBackend **backends, size_t b Config &config, uint8_t key ) { + // Restore gamemode. + if (menu->_backends[0] != nullptr) { + menu->_backends[0]->SetGameMode(display_backend->CurrentGameMode()); + } display_backend->SetDisplayMode(DISPLAY_MODE_VIEWER); }, }, @@ -219,6 +223,10 @@ void ConfigMenu::HandleControls( } else if (button == controls.back) { // If at top-level page, go back to input viewer. if (_current_menu_page->parent == nullptr) { + // Restore gamemode. + if (_backends[0] != nullptr) { + _backends[0]->SetGameMode(instance->CurrentGameMode()); + } instance->SetDisplayMode(DISPLAY_MODE_VIEWER); return; } @@ -229,6 +237,12 @@ void ConfigMenu::HandleControls( } void ConfigMenu::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display) { + // Unset gamemode to prevent menu button presses being sent to console. + if (_backends[0] != nullptr && _backends[0]->CurrentGameMode() != nullptr) { + instance->SetGameMode(_backends[0]->CurrentGameMode()); + _backends[0]->SetGameMode(nullptr); + } + uint8_t font_width = instance->font_width; uint8_t font_height = instance->font_height; @@ -268,6 +282,7 @@ void ConfigMenu::SetDefaultMode( for (size_t i = 0; i < menu->_backends_count; i++) { set_mode(menu->_backends[i], config.game_mode_configs[mode_config_index], config); } + set_mode(display_backend, config.game_mode_configs[mode_config_index], config); } void ConfigMenu::SetDefaultUsbBackend( diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 31417772..7370eec6 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -8,6 +8,7 @@ #include "display/ConfigMenu.hpp" #include "display/DisplayMode.hpp" #include "display/InputDisplay.hpp" +#include "display/MenuButtonHints.hpp" #include "display/RgbBrightnessMenu.hpp" #include "glyph_overrides.hpp" #include "input/DebouncedSwitchMatrixInput.hpp" @@ -154,6 +155,7 @@ void setup1() { // These have to be initialized after backends. CommunicationBackendId primary_backend_id = backends[0]->BackendId(); + static MenuButtonHints menu_button_hints(primary_backend_id); static InputDisplay input_display( input_viewer_buttons, input_viewer_buttons_count, @@ -161,7 +163,12 @@ void setup1() { ); static ConfigMenu config_menu(config, backends, backend_count); - static DisplayMode *display_modes[] = { &input_display, &config_menu, &rgb_brightness_menu }; + static DisplayMode *display_modes[] = { + &menu_button_hints, + &input_display, + &config_menu, + &rgb_brightness_menu, + }; size_t display_modes_count = count_of(display_modes); Wire1.setSDA(2); @@ -180,14 +187,17 @@ void setup1() { display_modes_count ); // clang-format on + display_backend->SetDisplayMode(DISPLAY_MODE_BUTTON_HINTS); } } void loop1() { - if (display_backend != nullptr) { - if (display_backend->CurrentGameMode() != backends[0]->CurrentGameMode()) { - display_backend->SetGameMode(backends[0]->CurrentGameMode()); - } - display_backend->SendReport(); + if (display_backend == nullptr) { + return; } + if (backends[0] != nullptr && backends[0]->CurrentGameMode() != nullptr && + display_backend->CurrentGameMode() != backends[0]->CurrentGameMode()) { + display_backend->SetGameMode(backends[0]->CurrentGameMode()); + } + display_backend->SendReport(); } From 7cf8f23dbea6b4e67aef14dd1313a89be90bec77 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 11 Mar 2024 16:02:22 +0000 Subject: [PATCH 094/167] feat: reorganise display mode transitions --- HAL/pico/src/display/ConfigMenu.cpp | 4 ++-- HAL/pico/src/display/InputDisplay.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp index 32548596..901adb2f 100644 --- a/HAL/pico/src/display/ConfigMenu.cpp +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -116,7 +116,7 @@ ConfigMenu::ConfigMenu(Config &config, CommunicationBackend **backends, size_t b }, }, { - .text = "Return", + .text = "Input Viewer", .action = []( IntegratedDisplay *display_backend, ConfigMenu *menu, @@ -227,7 +227,7 @@ void ConfigMenu::HandleControls( if (_backends[0] != nullptr) { _backends[0]->SetGameMode(instance->CurrentGameMode()); } - instance->SetDisplayMode(DISPLAY_MODE_VIEWER); + instance->SetDisplayMode(DISPLAY_MODE_BUTTON_HINTS); return; } diff --git a/HAL/pico/src/display/InputDisplay.cpp b/HAL/pico/src/display/InputDisplay.cpp index 016b2a2c..0922da9f 100644 --- a/HAL/pico/src/display/InputDisplay.cpp +++ b/HAL/pico/src/display/InputDisplay.cpp @@ -22,7 +22,7 @@ void InputDisplay::HandleControls( const DisplayControls &controls, Button button ) { - if (button == controls.enter) { + if (button == controls.back) { instance->SetDisplayMode(DISPLAY_MODE_CONFIG); } } From 07ca07393e09707b32a42921593e56782fc74431 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 22 Mar 2024 10:15:18 +0000 Subject: [PATCH 095/167] feat: Glyph-specific proto and display menu --- HAL/avr/proto/config.options | 1 + HAL/pico/include/display/ConfigMenu.hpp | 37 ++--- HAL/pico/include/display/InputDisplay.hpp | 4 + HAL/pico/src/display/ConfigMenu.cpp | 2 +- HAL/pico/src/display/InputDisplay.cpp | 11 ++ config/glyph/config.cpp | 74 ++++----- config/glyph/env.ini | 6 + config/glyph/include/button_positions.hpp | 149 ++++++++++++++++++ .../glyph/include/display/GlyphConfigMenu.hpp | 11 ++ .../glyph/include/display/MenuButtonHints.hpp | 21 +++ config/glyph/include/glyph_overrides.hpp | 39 ++++- config/glyph/src/display/GlyphConfigMenu.cpp | 50 ++++++ config/glyph/src/display/MenuButtonHints.cpp | 60 +++++++ 13 files changed, 402 insertions(+), 63 deletions(-) create mode 100644 config/glyph/include/button_positions.hpp create mode 100644 config/glyph/include/display/GlyphConfigMenu.hpp create mode 100644 config/glyph/include/display/MenuButtonHints.hpp create mode 100644 config/glyph/src/display/GlyphConfigMenu.cpp create mode 100644 config/glyph/src/display/MenuButtonHints.cpp diff --git a/HAL/avr/proto/config.options b/HAL/avr/proto/config.options index 0df23090..dfaf43e5 100644 --- a/HAL/avr/proto/config.options +++ b/HAL/avr/proto/config.options @@ -44,6 +44,7 @@ Config.rgb_configs max_count:10 Config.rgb_configs type:FT_POINTER Config.default_backend_config int_size:IS_8 Config.default_usb_backend_config int_size:IS_8 +Config.rgb_brightness int_size:IS_8 DeviceInfo.firmware_name max_length:25 DeviceInfo.firmware_version max_length:8 diff --git a/HAL/pico/include/display/ConfigMenu.hpp b/HAL/pico/include/display/ConfigMenu.hpp index e69d7f89..07ed086e 100644 --- a/HAL/pico/include/display/ConfigMenu.hpp +++ b/HAL/pico/include/display/ConfigMenu.hpp @@ -24,7 +24,7 @@ typedef struct _MenuPage { } MenuItem; struct _MenuPage *parent = nullptr; - const MenuItem *items = nullptr; + MenuItem *items = nullptr; size_t items_count = 0; } MenuPage; @@ -42,23 +42,7 @@ class ConfigMenu : public DisplayMode { ); virtual void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); - private: - static constexpr uint8_t padding = 2; - static constexpr uint8_t max_visible_lines = 6; - static constexpr char highlight_string[] = ">"; - - Config &_config; - CommunicationBackend **_backends; - size_t _backends_count; - - MenuPage _usb_backends_page; - MenuPage _gamemode_options_page; - MenuPage _top_level_page; - - MenuPage *_current_menu_page = &_top_level_page; - uint8_t _highlighted_menu_item = 0; - int _current_menu_offset = 0; - + protected: static void SetDefaultMode( IntegratedDisplay *instance, ConfigMenu *menu, @@ -77,6 +61,23 @@ class ConfigMenu : public DisplayMode { Config &config, uint8_t socd_type ); + + Config &_config; + CommunicationBackend **_backends; + size_t _backends_count; + + MenuPage _usb_backends_page; + MenuPage _gamemode_options_page; + MenuPage _top_level_page; + + MenuPage *_current_menu_page = &_top_level_page; + uint8_t _highlighted_menu_item = 0; + int _current_menu_offset = 0; + + private: + static constexpr uint8_t padding = 2; + static constexpr uint8_t max_visible_lines = 6; + static constexpr char highlight_string[] = ">"; }; #endif \ No newline at end of file diff --git a/HAL/pico/include/display/InputDisplay.hpp b/HAL/pico/include/display/InputDisplay.hpp index d2e03cd5..641dc7e6 100644 --- a/HAL/pico/include/display/InputDisplay.hpp +++ b/HAL/pico/include/display/InputDisplay.hpp @@ -24,6 +24,10 @@ class InputDisplay : public DisplayMode { Button button ); void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); + void UpdateButtonLayout( + InputViewerButton *input_viewer_buttons, + size_t input_viewer_buttons_count + ); protected: InputViewerButton *_input_viewer_buttons; diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp index 901adb2f..910459d2 100644 --- a/HAL/pico/src/display/ConfigMenu.cpp +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -91,7 +91,7 @@ ConfigMenu::ConfigMenu(Config &config, CommunicationBackend **backends, size_t b /* Build top-level page */ // clang-format off - static const MenuPage::MenuItem top_level_items[] = { + static MenuPage::MenuItem top_level_items[] = { { .text = "Gamemode", .page = &_gamemode_options_page, diff --git a/HAL/pico/src/display/InputDisplay.cpp b/HAL/pico/src/display/InputDisplay.cpp index 0922da9f..c3ccd582 100644 --- a/HAL/pico/src/display/InputDisplay.cpp +++ b/HAL/pico/src/display/InputDisplay.cpp @@ -49,6 +49,9 @@ void InputDisplay::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &disp display.print(backend_name(_backend_id)); /* Input display */ + if (_input_viewer_buttons == nullptr) { + return; + } for (size_t i = 0; i < _input_viewer_buttons_count; i++) { InputViewerButton mapping = _input_viewer_buttons[i]; if (get_button(inputs.buttons, mapping.button)) { @@ -57,4 +60,12 @@ void InputDisplay::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &disp display.drawCircle(mapping.center_x, mapping.center_y, mapping.radius, color); } } +} + +void InputDisplay::UpdateButtonLayout( + InputViewerButton *input_viewer_buttons, + size_t input_viewer_buttons_count +) { + _input_viewer_buttons = input_viewer_buttons; + _input_viewer_buttons_count = input_viewer_buttons_count; } \ No newline at end of file diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index 7370eec6..e79a4d97 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -1,3 +1,4 @@ +#include "button_positions.hpp" #include "comms/backend_init.hpp" #include "core/CommunicationBackend.hpp" #include "core/KeyboardMode.hpp" @@ -5,8 +6,8 @@ #include "core/mode_selection.hpp" #include "core/pinout.hpp" #include "core/state.hpp" -#include "display/ConfigMenu.hpp" #include "display/DisplayMode.hpp" +#include "display/GlyphConfigMenu.hpp" #include "display/InputDisplay.hpp" #include "display/MenuButtonHints.hpp" #include "display/RgbBrightnessMenu.hpp" @@ -103,51 +104,14 @@ void loop() { } } -#define MENU_BUTTON_RADIUS 2 -#define NORMAL_BUTTON_RADIUS 4 -#define LARGE_BUTTON_RADIUS 5 - -InputViewerButton input_viewer_buttons[] = { - // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, - - {BTN_LF4, 6, 29, NORMAL_BUTTON_RADIUS}, - { BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, - { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, - { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, - - { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, - { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, - { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, - { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, - - { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, - { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, - { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, - { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, - - { BTN_LT1, 38, 52, NORMAL_BUTTON_RADIUS}, - { BTN_LT2, 46, 58, NORMAL_BUTTON_RADIUS}, - - { BTN_RT1, 90, 52, NORMAL_BUTTON_RADIUS}, - { BTN_RT2, 82, 58, NORMAL_BUTTON_RADIUS}, - { BTN_RT3, 82, 46, NORMAL_BUTTON_RADIUS}, - { BTN_RT4, 90, 40, NORMAL_BUTTON_RADIUS}, - { BTN_RT5, 98, 46, NORMAL_BUTTON_RADIUS}, -}; -size_t input_viewer_buttons_count = count_of(input_viewer_buttons); - /* Second core handles OLED display */ Adafruit_SSD1306 display(128, 64, &Wire1); IntegratedDisplay *display_backend = nullptr; RgbBrightnessMenu rgb_brightness_menu(config); +InputDisplay *input_viewer = nullptr; + void setup1() { while (!backend_count || backends == nullptr) { delay(1); @@ -157,11 +121,11 @@ void setup1() { CommunicationBackendId primary_backend_id = backends[0]->BackendId(); static MenuButtonHints menu_button_hints(primary_backend_id); static InputDisplay input_display( - input_viewer_buttons, - input_viewer_buttons_count, + platform_fighter_buttons, + platform_fighter_buttons_count, primary_backend_id ); - static ConfigMenu config_menu(config, backends, backend_count); + static GlyphConfigMenu config_menu(config, backends, backend_count); static DisplayMode *display_modes[] = { &menu_button_hints, @@ -171,6 +135,8 @@ void setup1() { }; size_t display_modes_count = count_of(display_modes); + input_viewer = &input_display; + Wire1.setSDA(2); Wire1.setSCL(3); Wire1.setClock(1'000'000UL); @@ -199,5 +165,27 @@ void loop1() { display_backend->CurrentGameMode() != backends[0]->CurrentGameMode()) { display_backend->SetGameMode(backends[0]->CurrentGameMode()); } + // Update input display layout. + if (display_backend->CurrentGameMode() != nullptr) { + GameModeConfig *mode_config = display_backend->CurrentGameMode()->GetConfig(); + switch (mode_config->layout_plate) { + case LAYOUT_PLATE_UNSPECIFIED: + case LAYOUT_PLATE_EVERYTHING: + input_viewer->UpdateButtonLayout(full_layout_buttons, full_layout_buttons_count); + break; + case LAYOUT_PLATE_FGC: + input_viewer->UpdateButtonLayout(fgc_buttons, fgc_buttons_count); + break; + case LAYOUT_PLATE_SPLIT_FGC: + input_viewer->UpdateButtonLayout(split_fgc_buttons, split_fgc_buttons_count); + break; + case LAYOUT_PLATE_PLATFORM_FIGHTER: + input_viewer->UpdateButtonLayout( + platform_fighter_buttons, + platform_fighter_buttons_count + ); + break; + } + } display_backend->SendReport(); } diff --git a/config/glyph/env.ini b/config/glyph/env.ini index 8da252a8..da31d6e7 100644 --- a/config/glyph/env.ini +++ b/config/glyph/env.ini @@ -7,3 +7,9 @@ build_flags = build_src_filter = ${arduino_pico_base.build_src_filter} + +lib_ignore = + ${env.lib_ignore} + https://github.com/JonnyHaystack/HayBox-proto +lib_deps = + ${arduino_pico_base.lib_deps} + https://github.com/LimitLabs/HayBox-proto#e87f4b2 \ No newline at end of file diff --git a/config/glyph/include/button_positions.hpp b/config/glyph/include/button_positions.hpp new file mode 100644 index 00000000..340f2883 --- /dev/null +++ b/config/glyph/include/button_positions.hpp @@ -0,0 +1,149 @@ +#ifndef _BUTTON_POSITIONS_HPP +#define _BUTTON_POSITIONS_HPP + +#define MENU_BUTTON_RADIUS 2 +#define NORMAL_BUTTON_RADIUS 4 +#define LARGE_BUTTON_RADIUS 5 + +#include "display/InputDisplay.hpp" + +InputViewerButton full_layout_buttons[] = { + // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, + + {BTN_LF4, 6, 29, NORMAL_BUTTON_RADIUS}, + { BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, + { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, + { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, + { BTN_LF5, 24, 32, NORMAL_BUTTON_RADIUS}, + + { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, + { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, + { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, + { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, + + { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, + { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, + { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, + { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, + + { BTN_LT1, 38, 52, NORMAL_BUTTON_RADIUS}, + { BTN_LT2, 46, 58, NORMAL_BUTTON_RADIUS}, + { BTN_LT3, 46, 46, NORMAL_BUTTON_RADIUS}, + { BTN_LT4, 38, 40, NORMAL_BUTTON_RADIUS}, + { BTN_LT5, 30, 46, NORMAL_BUTTON_RADIUS}, + { BTN_LT6, 59, 50, LARGE_BUTTON_RADIUS }, + + { BTN_RT1, 90, 52, NORMAL_BUTTON_RADIUS}, + { BTN_RT2, 82, 58, NORMAL_BUTTON_RADIUS}, + { BTN_RT3, 82, 46, NORMAL_BUTTON_RADIUS}, + { BTN_RT4, 90, 40, NORMAL_BUTTON_RADIUS}, + { BTN_RT5, 98, 46, NORMAL_BUTTON_RADIUS}, + + { BTN_LF6, 35, 17, NORMAL_BUTTON_RADIUS}, + { BTN_LF7, 46, 19, NORMAL_BUTTON_RADIUS}, + { BTN_LF8, 55, 25, NORMAL_BUTTON_RADIUS}, + + { BTN_RF9, 64, 30, NORMAL_BUTTON_RADIUS}, + { BTN_RF10, 74, 25, NORMAL_BUTTON_RADIUS}, + { BTN_RF11, 84, 25, NORMAL_BUTTON_RADIUS}, + + { BTN_RF12, 64, 20, NORMAL_BUTTON_RADIUS}, + { BTN_RF13, 74, 15, NORMAL_BUTTON_RADIUS}, + { BTN_RF14, 84, 15, NORMAL_BUTTON_RADIUS}, +}; +size_t full_layout_buttons_count = count_of(full_layout_buttons); + +InputViewerButton platform_fighter_buttons[] = { + // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, + + {BTN_LF4, 6, 29, NORMAL_BUTTON_RADIUS}, + { BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, + { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, + { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, + { BTN_LF5, 24, 32, NORMAL_BUTTON_RADIUS}, + + { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, + { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, + { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, + { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, + + { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, + { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, + { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, + { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, + + { BTN_LT1, 38, 52, NORMAL_BUTTON_RADIUS}, + { BTN_LT2, 46, 58, NORMAL_BUTTON_RADIUS}, + { BTN_LT3, 46, 46, NORMAL_BUTTON_RADIUS}, + { BTN_LT4, 38, 40, NORMAL_BUTTON_RADIUS}, + { BTN_LT5, 30, 46, NORMAL_BUTTON_RADIUS}, + + { BTN_RT1, 90, 52, NORMAL_BUTTON_RADIUS}, + { BTN_RT2, 82, 58, NORMAL_BUTTON_RADIUS}, + { BTN_RT3, 82, 46, NORMAL_BUTTON_RADIUS}, + { BTN_RT4, 90, 40, NORMAL_BUTTON_RADIUS}, + { BTN_RT5, 98, 46, NORMAL_BUTTON_RADIUS}, +}; +size_t platform_fighter_buttons_count = count_of(platform_fighter_buttons); + +InputViewerButton split_fgc_buttons[] = { + // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, + // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, + + {BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, + { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, + { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, + { BTN_LF5, 24, 32, NORMAL_BUTTON_RADIUS}, + + { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, + { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, + { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, + { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, + + { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, + { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, + { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, + { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, + + { BTN_LT1, 38, 52, LARGE_BUTTON_RADIUS }, + { BTN_RT1, 90, 52, LARGE_BUTTON_RADIUS }, +}; +size_t split_fgc_buttons_count = count_of(split_fgc_buttons); + +InputViewerButton fgc_buttons[] = { + {BTN_LF6, 35, 17, NORMAL_BUTTON_RADIUS}, + { BTN_LF7, 46, 19, NORMAL_BUTTON_RADIUS}, + { BTN_LF8, 55, 25, NORMAL_BUTTON_RADIUS}, + + { BTN_RF9, 64, 30, NORMAL_BUTTON_RADIUS}, + { BTN_RF10, 74, 25, NORMAL_BUTTON_RADIUS}, + { BTN_RF11, 84, 25, NORMAL_BUTTON_RADIUS}, + { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, + + { BTN_RF12, 64, 20, NORMAL_BUTTON_RADIUS}, + { BTN_RF13, 74, 15, NORMAL_BUTTON_RADIUS}, + { BTN_RF14, 84, 15, NORMAL_BUTTON_RADIUS}, + { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, + + { BTN_LT6, 59, 50, LARGE_BUTTON_RADIUS } +}; +size_t fgc_buttons_count = count_of(fgc_buttons); + +#endif \ No newline at end of file diff --git a/config/glyph/include/display/GlyphConfigMenu.hpp b/config/glyph/include/display/GlyphConfigMenu.hpp new file mode 100644 index 00000000..c8af67b1 --- /dev/null +++ b/config/glyph/include/display/GlyphConfigMenu.hpp @@ -0,0 +1,11 @@ +#ifndef _DISPLAY_GLYPHCONFIGMENU_HPP +#define _DISPLAY_GLYPHCONFIGMENU_HPP + +#include "display/ConfigMenu.hpp" + +class GlyphConfigMenu : public ConfigMenu { + public: + GlyphConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count); +}; + +#endif \ No newline at end of file diff --git a/config/glyph/include/display/MenuButtonHints.hpp b/config/glyph/include/display/MenuButtonHints.hpp new file mode 100644 index 00000000..52dc9c39 --- /dev/null +++ b/config/glyph/include/display/MenuButtonHints.hpp @@ -0,0 +1,21 @@ +#ifndef _DISPLAY_MENUBUTTONHINTS_HPP +#define _DISPLAY_MENUBUTTONHINTS_HPP + +#include "display/DisplayMode.hpp" + +class MenuButtonHints : public DisplayMode { + public: + MenuButtonHints(CommunicationBackendId backend_id); + DisplayModeId GetId(); + void HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button + ); + void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); + + protected: + CommunicationBackendId _backend_id; +}; + +#endif \ No newline at end of file diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 69091c98..1827c342 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -1,3 +1,6 @@ +#ifndef _GLYPH_OVERRIDES_HPP +#define _GLYPH_OVERRIDES_HPP + #include "comms/B0XXInputViewer.hpp" #include "comms/IntegratedDisplay.hpp" #include "comms/NeoPixelBackend.hpp" @@ -99,6 +102,38 @@ Config glyph_default_config() { }, }; config.rgb_brightness = 255; + + // Assign layout plates and applicable backends for default gamemode configs. + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + switch (mode_config.mode_id) { + case MODE_FGC: + if (mode_config.button_remapping_count > 0) { + mode_config.layout_plate = LAYOUT_PLATE_FGC; + } else { + mode_config.layout_plate = LAYOUT_PLATE_SPLIT_FGC; + } + mode_config.applicable_backends[0] = COMMS_BACKEND_XINPUT; + mode_config.applicable_backends[1] = COMMS_BACKEND_DINPUT; + mode_config.applicable_backends[2] = COMMS_BACKEND_NINTENDO_SWITCH; + mode_config.applicable_backends_count = 3; + break; + case MODE_MELEE: + case MODE_PROJECT_M: + case MODE_ULTIMATE: + case MODE_RIVALS_OF_AETHER: + mode_config.layout_plate = LAYOUT_PLATE_PLATFORM_FIGHTER; + mode_config.applicable_backends[0] = COMMS_BACKEND_XINPUT; + mode_config.applicable_backends[1] = COMMS_BACKEND_DINPUT; + mode_config.applicable_backends[2] = COMMS_BACKEND_NINTENDO_SWITCH; + mode_config.applicable_backends[3] = COMMS_BACKEND_GAMECUBE; + mode_config.applicable_backends_count = 4; + break; + default: + mode_config.layout_plate = LAYOUT_PLATE_EVERYTHING; + } + } + return config; } @@ -146,4 +181,6 @@ size_t init_secondary_backends_glyph( backends = new_backends; return backend_count; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/config/glyph/src/display/GlyphConfigMenu.cpp b/config/glyph/src/display/GlyphConfigMenu.cpp new file mode 100644 index 00000000..b02950ec --- /dev/null +++ b/config/glyph/src/display/GlyphConfigMenu.cpp @@ -0,0 +1,50 @@ +#include "display/GlyphConfigMenu.hpp" + +#include "core/Persistence.hpp" +#include "core/config_utils.hpp" +#include "core/mode_selection.hpp" +#include "reboot.hpp" + +GlyphConfigMenu::GlyphConfigMenu( + Config &config, + CommunicationBackend **backends, + size_t backends_count +) + : ConfigMenu(config, backends, backends_count) { + /* Build gamemodes page */ + size_t gamemode_options_count = 0; + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + MenuPage::MenuItem ¤t_option = _gamemode_options_page.items[gamemode_options_count]; + + // Only show gamemodes that are applicable to the current comms backend. + if (mode_config.applicable_backends_count > 0 && _backends_count > 0 && + _backends[0] != nullptr) { + CommunicationBackendId primary_backend_id = _backends[0]->BackendId(); + bool applicable = false; + for (size_t i = 0; i < mode_config.applicable_backends_count; i++) { + if (primary_backend_id == mode_config.applicable_backends[i]) { + applicable = true; + break; + } + } + if (!applicable) { + continue; + } + } + + if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { + strlcpy(current_option.text, mode_config.name, sizeof(current_option.text)); + } else { + strlcpy( + current_option.text, + gamemode_name(mode_config.mode_id), + sizeof(current_option.text) + ); + } + current_option.key = i; + current_option.action = &SetDefaultMode; + gamemode_options_count++; + } + _gamemode_options_page.items_count = gamemode_options_count; +} \ No newline at end of file diff --git a/config/glyph/src/display/MenuButtonHints.cpp b/config/glyph/src/display/MenuButtonHints.cpp new file mode 100644 index 00000000..75a54482 --- /dev/null +++ b/config/glyph/src/display/MenuButtonHints.cpp @@ -0,0 +1,60 @@ +#include "display/MenuButtonHints.hpp" + +#include "comms/IntegratedDisplay.hpp" +#include "core/config_utils.hpp" +#include "util/state_util.hpp" + +MenuButtonHints::MenuButtonHints(const CommunicationBackendId backend_id) + : _backend_id(backend_id) {} + +DisplayModeId MenuButtonHints::GetId() { + return DISPLAY_MODE_BUTTON_HINTS; +} + +void MenuButtonHints::HandleControls( + IntegratedDisplay *instance, + const DisplayControls &controls, + Button button +) { + if (button == controls.enter) { + instance->SetDisplayMode(DISPLAY_MODE_CONFIG); + } +} + +void MenuButtonHints::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display) { + InputState &inputs = instance->GetInputs(); + uint8_t font_width = instance->font_width; + uint8_t color = instance->default_color; + + /* Gamemode text */ + display.setCursor(0, 0); + if (instance->CurrentGameMode() != nullptr) { + const GameModeConfig &mode_config = *instance->CurrentGameMode()->GetConfig(); + if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { + display.print(mode_config.name); + } else { + display.print(gamemode_name(mode_config.mode_id)); + } + } + + /* Backend text */ + const char *backend_text = backend_name(_backend_id); + display.setCursor(display.width() - (strlen(backend_text) * font_width), 0); + display.print(backend_name(_backend_id)); + + /* Button hints */ + uint8_t old_rotation = display.getRotation(); + display.setRotation(3); + + display.setCursor(0, 0); + + display.println("Menu\n"); + display.println("Start\n"); + display.println("Back\n"); + display.println("Home\n"); + display.println("Capt.\n"); + display.println("L3\n"); + display.println("R3\n"); + + display.setRotation(old_rotation); +} \ No newline at end of file From 4cf43318109a55b01ed68e60f9e35b4bb36ec0cd Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 23 Mar 2024 22:12:24 +0000 Subject: [PATCH 096/167] feat: use streams and LittleFS instead of buffers and EEPROM --- .../include/comms/ConfiguratorBackend.hpp | 12 +- HAL/pico/include/core/Persistence.hpp | 10 +- HAL/pico/src/comms/ConfiguratorBackend.cpp | 90 +++++++--- HAL/pico/src/comms/backend_init.cpp | 3 +- HAL/pico/src/core/Persistence.cpp | 165 +++++++++++++----- platformio.ini | 2 + 6 files changed, 197 insertions(+), 85 deletions(-) diff --git a/HAL/pico/include/comms/ConfiguratorBackend.hpp b/HAL/pico/include/comms/ConfiguratorBackend.hpp index 8cb95a01..28f4f61a 100644 --- a/HAL/pico/include/comms/ConfiguratorBackend.hpp +++ b/HAL/pico/include/comms/ConfiguratorBackend.hpp @@ -21,7 +21,6 @@ #include "cobs/Print.h" #include "cobs/Stream.h" #include "core/CommunicationBackend.hpp" -#include "core/Persistence.hpp" #include @@ -31,24 +30,25 @@ class ConfiguratorBackend : public CommunicationBackend { InputState &inputs, InputSource **input_sources, size_t input_source_count, - Config &config + Config &config, + Stream &stream ); - ~ConfiguratorBackend(); CommunicationBackendId BackendId(); void SendReport(); private: size_t ReadPacket(uint8_t *buffer, size_t max_len); + int ReadByte(); + void SkipToNextPacket(); bool WritePacket(Command command_id, uint8_t *buffer, size_t len); bool HandleUnknownCommand(Command command); bool HandleGetDeviceInfo(); bool HandleGetConfig(); - bool HandleSetConfig(uint8_t *buffer, size_t len); + bool HandleSetConfig(); packetio::COBSStream _in; packetio::COBSPrint _out; - Persistence *_persistence; - uint8_t _cmd_buffer[Persistence::eeprom_size - Persistence::config_offset]; + Stream &_base_stream; Config &_config; }; diff --git a/HAL/pico/include/core/Persistence.hpp b/HAL/pico/include/core/Persistence.hpp index 0206e627..43cbd3f3 100644 --- a/HAL/pico/include/core/Persistence.hpp +++ b/HAL/pico/include/core/Persistence.hpp @@ -18,6 +18,7 @@ #ifndef _CORE_PERSISTENCE_HPP #define _CORE_PERSISTENCE_HPP +#include #include class Persistence { @@ -32,14 +33,15 @@ class Persistence { bool SaveConfig(Config &config); bool LoadConfig(Config &config); - size_t LoadConfigRaw(uint8_t *buffer, size_t buffer_len); + bool CheckSavedConfig(); + size_t LoadConfigRaw(Print &out, bool validate = true); - static constexpr size_t eeprom_size = 4096; static constexpr size_t config_offset = sizeof(ConfigHeader); private: - static Config _config; - static uint8_t _buffer[eeprom_size - config_offset]; + static constexpr char config_filename[] = "config.bin"; + + bool CheckSavedConfig(File &config_file); }; extern Persistence persistence; diff --git a/HAL/pico/src/comms/ConfiguratorBackend.cpp b/HAL/pico/src/comms/ConfiguratorBackend.cpp index 5d2de279..a0016f7c 100644 --- a/HAL/pico/src/comms/ConfiguratorBackend.cpp +++ b/HAL/pico/src/comms/ConfiguratorBackend.cpp @@ -18,9 +18,10 @@ #include "comms/ConfiguratorBackend.hpp" #include "core/InputSource.hpp" +#include "core/Persistence.hpp" #include "reboot.hpp" -#include "serial.hpp" +#include #include #include @@ -28,28 +29,29 @@ ConfiguratorBackend::ConfiguratorBackend( InputState &inputs, InputSource **input_sources, size_t input_source_count, - Config &config + Config &config, + Stream &stream ) : CommunicationBackend(inputs, input_sources, input_source_count), - _in(Serial), - _out(Serial), - _config(config) { - serial::init(115200); - _persistence = new Persistence(); -} - -ConfiguratorBackend::~ConfiguratorBackend() { - serial::close(); - delete _persistence; -} + _in(stream), + _out(stream), + _base_stream(stream), + _config(config) {} CommunicationBackendId ConfiguratorBackend::BackendId() { return COMMS_BACKEND_CONFIGURATOR; } void ConfiguratorBackend::SendReport() { - size_t packet_len = ReadPacket(_cmd_buffer, sizeof(_cmd_buffer)); - Command command = (Command)_cmd_buffer[0]; + int data = ReadByte(); + if (data < 0) { + if (data == _in.EOP) { + SkipToNextPacket(); + } + return; + } + + Command command = (Command)data; switch (command) { case CMD_GET_DEVICE_INFO: HandleGetDeviceInfo(); @@ -58,7 +60,7 @@ void ConfiguratorBackend::SendReport() { HandleGetConfig(); break; case CMD_SET_CONFIG: - HandleSetConfig(_cmd_buffer, packet_len); + HandleSetConfig(); break; case CMD_REBOOT_FIRMWARE: reboot_firmware(); @@ -71,11 +73,13 @@ void ConfiguratorBackend::SendReport() { HandleUnknownCommand(command); break; } + + SkipToNextPacket(); } size_t ConfiguratorBackend::ReadPacket(uint8_t *buffer, size_t max_len) { size_t bytes_read = 0; - while (!Serial.available()) { + while (!_in.available()) { delay(1); } while (true) { @@ -97,6 +101,17 @@ size_t ConfiguratorBackend::ReadPacket(uint8_t *buffer, size_t max_len) { return bytes_read; } +int ConfiguratorBackend::ReadByte() { + if (!_base_stream.available()) { + return -1; + } + return _in.read(); +} + +void ConfiguratorBackend::SkipToNextPacket() { + _in.next(); +} + bool ConfiguratorBackend::WritePacket(Command command_id, uint8_t *buffer, size_t len) { _out.write((uint8_t)command_id); for (size_t i = 0; i < len; i++) { @@ -112,29 +127,46 @@ bool ConfiguratorBackend::HandleGetDeviceInfo() { DEVICE_NAME, }; - uint8_t buffer[sizeof(DeviceInfo)]; - pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer)); - - if (!pb_encode(&ostream, DeviceInfo_fields, &device_info)) { + // Ensure device info encodes correctly. + size_t size; + if (!pb_get_encoded_size(&size, DeviceInfo_fields, &device_info)) { char errmsg[] = "Failed to encode device info"; WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); return false; } - return WritePacket(CMD_SET_DEVICE_INFO, buffer, ostream.bytes_written); + _out.write(CMD_SET_DEVICE_INFO); + pb_ostream_t ostream = as_pb_ostream(_out); + pb_encode(&ostream, DeviceInfo_fields, &device_info); + return _out.end(); } bool ConfiguratorBackend::HandleGetConfig() { - size_t config_size = _persistence->LoadConfigRaw(_cmd_buffer, sizeof(_cmd_buffer)); - return WritePacket(CMD_SET_CONFIG, _cmd_buffer, config_size); + if (!persistence.CheckSavedConfig()) { + char errmsg[] = "Config file is invalid"; + WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); + return false; + } + + // Write raw config data to output stream. + _out.write(CMD_SET_CONFIG); + persistence.LoadConfigRaw(_out, false); + return _out.end(); } -bool ConfiguratorBackend::HandleSetConfig(uint8_t *buffer, size_t len) { - pb_istream_t istream = pb_istream_from_buffer(&buffer[1], len - 1); +bool ConfiguratorBackend::HandleSetConfig() { + // Reset config defaults first, so config is completely replaced rather than merged. + _config = Config_init_default; + pb_istream_t istream = as_pb_istream(_in); if (!pb_decode(&istream, Config_fields, &_config)) { - char errmsg[] = "Failed to decode config"; - WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); + char errmsg[100]; + size_t errmsg_len = + snprintf(errmsg, sizeof(errmsg), "Failed to decode config: %s", istream.errmsg); + WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); + + // Restore old config. + persistence.LoadConfig(_config); return false; } @@ -200,7 +232,7 @@ bool ConfiguratorBackend::HandleSetConfig(uint8_t *buffer, size_t len) { } } - if (!_persistence->SaveConfig(_config)) { + if (!persistence.SaveConfig(_config)) { char errmsg[] = "Failed to save config to memory"; WritePacket(CMD_ERROR, (uint8_t *)errmsg, sizeof(errmsg)); return false; diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 493e7a4f..23212798 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -174,8 +174,9 @@ void init_primary_backend( case COMMS_BACKEND_CONFIGURATOR: default: delete primary_backend; + Serial.begin(115200); primary_backend = - new ConfiguratorBackend(inputs, input_sources, input_source_count, config); + new ConfiguratorBackend(inputs, input_sources, input_source_count, config, Serial); } } diff --git a/HAL/pico/src/core/Persistence.cpp b/HAL/pico/src/core/Persistence.cpp index 4700a956..907e6ca3 100644 --- a/HAL/pico/src/core/Persistence.cpp +++ b/HAL/pico/src/core/Persistence.cpp @@ -20,89 +20,164 @@ #include "stdlib.hpp" #include -#include +#include +#include #include #include -Config Persistence::_config; -uint8_t Persistence::_buffer[eeprom_size - config_offset]; - Persistence::Persistence() { - EEPROM.begin(eeprom_size); + LittleFS.begin(); } Persistence::~Persistence() { - EEPROM.end(); + LittleFS.end(); } bool Persistence::SaveConfig(Config &config) { - pb_ostream_t ostream = pb_ostream_from_buffer(_buffer, sizeof(_buffer)); + // Make sure config encodes correctly. + size_t encoded_size; + if (!pb_get_encoded_size(&encoded_size, Config_fields, &config)) { + return false; + } - if (!pb_encode(&ostream, Config_fields, &config)) { + // Open file to store config data in. + File config_file = LittleFS.open(config_filename, "w+"); + if (!config_file) { return false; } - ConfigHeader header = { - .config_size = ostream.bytes_written, - .config_crc = CRC32::calculate(_buffer, ostream.bytes_written), - }; + // Write empty header to start with. + ConfigHeader header = { .config_size = 0, .config_crc = 0 }; + config_file.write((uint8_t *)&header, sizeof(ConfigHeader)); - // Store number of bytes of configuration data at offset 0. - EEPROM.put(0, header); + // Encode Protobuf data directly into file body. + pb_ostream_t ostream = as_pb_ostream(config_file); + if (!pb_encode(&ostream, Config_fields, &config)) { + config_file.close(); + return false; + } - // Store the rest of the data directly after that. - for (size_t i = 0; i < header.config_size; i++) { - EEPROM.write(config_offset + i, _buffer[i]); + // Calculate checksum. + config_file.seek(config_offset); + CRC32 crc; + int value; + while ((value = config_file.read()) != -1) { + crc.update((uint8_t)value); } - EEPROM.commit(); + + // Update header. + header.config_size = ostream.bytes_written; + header.config_crc = crc.finalize(); + config_file.seek(0); + config_file.write((uint8_t *)&header, sizeof(ConfigHeader)); + + // Persist changes. + config_file.close(); return true; } bool Persistence::LoadConfig(Config &config) { - size_t config_size = LoadConfigRaw(_buffer, sizeof(_buffer)); + // Open file to load config data from. + File config_file = LittleFS.open(config_filename, "r"); + if (!config_file) { + return false; + } - // No valid config found. - if (config_size == 0) { + if (!CheckSavedConfig(config_file)) { + config_file.close(); return false; } - pb_istream_t istream = pb_istream_from_buffer(_buffer, config_size); + // Seek to start of Protobuf data. + if (!config_file.seek(config_offset)) { + config_file.close(); + return false; + } + + // Reset config defaults first, so config is completely replaced rather than merged with + // defaults. + config = Config_init_default; - // Return true if successfully decoded. - if (pb_decode(&istream, Config_fields, &_config)) { - config = _config; - return true; + // Decode streamed Protobuf data into config struct. + pb_istream_t istream = as_pb_istream(config_file, (size_t)config_file.available()); + if (!pb_decode(&istream, Config_fields, &config)) { + config_file.close(); + return false; } - // Otherwise reset back to original config. - return false; + config_file.close(); + return true; } -size_t Persistence::LoadConfigRaw(uint8_t *buffer, size_t buffer_len) { - // Get config header containing CRC32 checksum and number of stored bytes of config data from - // offset 0 of EEPROM. - ConfigHeader header; - EEPROM.get(0, header); +bool Persistence::CheckSavedConfig() { + // Open file to load config data from. + File config_file = LittleFS.open(config_filename, "r"); + if (!config_file) { + return false; + } + + bool is_valid = CheckSavedConfig(config_file); + config_file.close(); + return is_valid; +} - // Buffer can't be less than the size we expect to read. - if (buffer_len < header.config_size) { - return 0; +size_t Persistence::LoadConfigRaw(Print &out, bool validate) { + // Open file to load config data from. + File config_file = LittleFS.open(config_filename, "r"); + if (!config_file) { + return false; + } + + // Optionally perform validation. + if (validate && !CheckSavedConfig(config_file)) { + config_file.close(); + return false; } - // Read config data from EEPROM into the buffer. - size_t bytes_read; - for (bytes_read = 0; bytes_read < header.config_size; bytes_read++) { - buffer[bytes_read] = EEPROM.read(config_offset + bytes_read); + // Seek to start of Protobuf data. + if (!config_file.seek(config_offset)) { + config_file.close(); + return false; } - // If CRC32 checksum does not match, consider it as having failed to read. - if (CRC32::calculate(buffer, bytes_read) != header.config_crc) { - return 0; + // Write raw Protobuf encoded data to output stream. + int value; + while ((value = config_file.read()) != -1) { + out.write((uint8_t)value); } - // Return the number of bytes of config data read. - return bytes_read; + config_file.close(); + return true; +} + +bool Persistence::CheckSavedConfig(File &config_file) { + size_t file_size = config_file.size(); + + // Read file header. + ConfigHeader header; + size_t bytes_read = config_file.read((uint8_t *)&header, sizeof(ConfigHeader)); + if (bytes_read < sizeof(ConfigHeader)) { + return false; + } + + // Validate config length. + size_t config_size = file_size - config_offset; + if (config_size != header.config_size) { + return false; + } + + // Calculate CRC for file contents and compare with CRC in header. + CRC32 crc; + int value; + while ((value = config_file.read()) != -1) { + crc.update((uint8_t)value); + } + if (crc.finalize() != header.config_crc) { + return false; + } + + return true; } Persistence persistence; \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 053cb94b..357239d6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -89,6 +89,7 @@ debug_tool = cmsis-dap monitor_speed = 115200 board_build.core = earlephilhower board_build.f_cpu = 130000000L +board_build.filesystem_size = 0.5m build_unflags = -Os build_flags = ${env.build_flags} @@ -114,6 +115,7 @@ lib_deps = https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput#4b5617b https://github.com/FastLED/FastLED#6daa782 + https://github.com/JonnyHaystack/nanopb-arduino/archive/refs/tags/v1.1.1.zip adafruit/Adafruit SSD1306@^2.5.9 adafruit/Adafruit GFX Library@^1.11.9 eric-wieser/PacketIO@^0.3.0 From 933cd8a0e90387170b91234b57bfe3ad7e448449 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 23 Mar 2024 22:13:46 +0000 Subject: [PATCH 097/167] fix: prevent busy wait in FastLED --- HAL/pico/include/comms/NeoPixelBackend.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index b853a992..4692aec8 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -5,6 +5,7 @@ #include #include +#include template class NeoPixelBackend : public CommunicationBackend { public: @@ -24,6 +25,7 @@ template class NeoPixelBackend : public Commun _brightness(brightness) { FastLED.addLeds(_leds, led_count); FastLED.setMaxPowerInVoltsAndMilliamps(5, 200); + FastLED.setMaxRefreshRate(0); } ~NeoPixelBackend() { FastLED.clear(true); } @@ -54,6 +56,12 @@ template class NeoPixelBackend : public Commun } virtual void SendReport() { + // Use timeout to avoid refreshing too fast which results in FastLED library blocking. + if (!time_reached(_refresh_timeout)) { + return; + } + _refresh_timeout = make_timeout_time_ms(refresh_interval_ms); + for (int i = 0; i < led_count; i++) { Button button = this->_button_mappings[i]; _leds[i] = _config != nullptr ? _button_colors[max(0, button - 1)] : 0; @@ -65,6 +73,7 @@ template class NeoPixelBackend : public Commun protected: static constexpr size_t button_colors_count = sizeof(RgbConfig::button_colors) / sizeof(ButtonToColorMapping); + static constexpr uint64_t refresh_interval_ms = 4; // 250Hz refresh rate const Button *_button_mappings; const RgbConfig *_rgb_configs; @@ -74,6 +83,7 @@ template class NeoPixelBackend : public Commun CRGB _leds[led_count]; uint32_t _button_colors[button_colors_count]; + absolute_time_t _refresh_timeout; }; #endif \ No newline at end of file From 1ae1c4f338a864805e6dedc8c2b275977661b070 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 16 Apr 2024 19:03:09 +0100 Subject: [PATCH 098/167] feat: add Schism config and PCA9671 input source --- HAL/pico/include/input/Pca9671Input.hpp | 37 +++++++ HAL/pico/src/input/Pca9671Input.cpp | 47 +++++++++ config/schism/config.cpp | 132 ++++++++++++++++++++++++ config/schism/env.ini | 11 ++ 4 files changed, 227 insertions(+) create mode 100644 HAL/pico/include/input/Pca9671Input.hpp create mode 100644 HAL/pico/src/input/Pca9671Input.cpp create mode 100644 config/schism/config.cpp create mode 100644 config/schism/env.ini diff --git a/HAL/pico/include/input/Pca9671Input.hpp b/HAL/pico/include/input/Pca9671Input.hpp new file mode 100644 index 00000000..1ed9d404 --- /dev/null +++ b/HAL/pico/include/input/Pca9671Input.hpp @@ -0,0 +1,37 @@ +#ifndef _INPUT_PCA9671INPUT_HPP +#define _INPUT_PCA9671INPUT_HPP + +#include "core/InputSource.hpp" + +#include +#include +#include + +typedef struct { + Button button; + uint8_t bit; +} Pca9671ButtonMapping; + +class Pca9671Input : public InputSource { + public: + Pca9671Input( + const Pca9671ButtonMapping *button_mappings, + size_t button_count, + TwoWire &wire = Wire, + int sda_pin = -1, + int scl_pin = -1, + uint8_t i2c_addr = 0x20 + ); + InputScanSpeed ScanSpeed(); + void UpdateInputs(InputState &inputs); + + protected: + const Pca9671ButtonMapping *_button_mappings; + size_t _button_count; + PCF8575 _pcf; + + private: + virtual void UpdateButtonState(InputState &inputs, size_t button_mapping_index, bool pressed); +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/src/input/Pca9671Input.cpp b/HAL/pico/src/input/Pca9671Input.cpp new file mode 100644 index 00000000..fd501853 --- /dev/null +++ b/HAL/pico/src/input/Pca9671Input.cpp @@ -0,0 +1,47 @@ +#include "input/Pca9671Input.hpp" + +#include "util/state_util.hpp" + +Pca9671Input::Pca9671Input( + const Pca9671ButtonMapping *button_mappings, + size_t button_count, + TwoWire &wire, + int sda_pin, + int scl_pin, + uint8_t i2c_addr +) + : _pcf(i2c_addr, &wire) { + _button_mappings = button_mappings; + _button_count = button_count; + +#ifdef ARDUINO_PICO_REVISION + wire.setClock(3'000'000); + if (sda_pin > 0 && scl_pin > 0) { + wire.setSDA(sda_pin); + wire.setSCL(scl_pin); + } +#endif + + wire.begin(); + _pcf.begin(); +} + +InputScanSpeed Pca9671Input::ScanSpeed() { + return InputScanSpeed::FAST; +} + +void Pca9671Input::UpdateInputs(InputState &inputs) { + uint16_t pin_values = _pcf.read16(); + + for (size_t i = 0; i < _button_count; i++) { + UpdateButtonState(inputs, i, !(pin_values & (1 << _button_mappings[i].bit))); + } +} + +void Pca9671Input::UpdateButtonState( + InputState &inputs, + size_t button_mapping_index, + bool pressed +) { + set_button(inputs.buttons, _button_mappings[button_mapping_index].button, pressed); +} \ No newline at end of file diff --git a/config/schism/config.cpp b/config/schism/config.cpp new file mode 100644 index 00000000..7b66c3ca --- /dev/null +++ b/config/schism/config.cpp @@ -0,0 +1,132 @@ +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" +#include "core/CommunicationBackend.hpp" +#include "core/KeyboardMode.hpp" +#include "core/Persistence.hpp" +#include "core/mode_selection.hpp" +#include "core/pinout.hpp" +#include "core/state.hpp" +#include "input/DebouncedGpioButtonInput.hpp" +#include "input/Mcp23Input.hpp" +#include "input/Pca9671Input.hpp" +#include "reboot.hpp" +#include "stdlib.hpp" + +#include + +Config config = default_config; + +GpioButtonMapping button_mappings[] = { + {BTN_LF1, 27}, + { BTN_LF2, 26}, + { BTN_LF3, 19}, + { BTN_LF4, 18}, + + { BTN_LT1, 3 }, + { BTN_LT2, 2 }, + { BTN_LT3, 0 }, + + { BTN_MB1, 1 }, +}; +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); + +Pca9671ButtonMapping expander_button_mappings[] = { + {BTN_RT1, 14}, + { BTN_RT2, 15}, + { BTN_RT3, 13}, + { BTN_RT4, 11}, + { BTN_RT5, 12}, + + { BTN_RF1, 7 }, + { BTN_RF2, 3 }, + { BTN_RF3, 4 }, + { BTN_RF4, 6 }, + + { BTN_RF5, 0 }, + { BTN_RF6, 1 }, + { BTN_RF7, 2 }, + { BTN_RF8, 5 }, +}; +const size_t expander_button_count = + sizeof(expander_button_mappings) / sizeof(Pca9671ButtonMapping); + +DebouncedGpioButtonInput gpio_input(button_mappings); +// Mcp23Input *expander_input = nullptr; +Pca9671Input expander_input(expander_button_mappings, expander_button_count, Wire, 20, 21); + +const Pinout pinout = { + .joybus_data = 28, + .mux = -1, + .nunchuk_detect = -1, + .nunchuk_sda = -1, + .nunchuk_scl = -1, +}; + +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + +void setup() { + static InputState inputs; + + // Create GPIO input source and use it to read button states for checking button holds. + gpio_input.UpdateInputs(inputs); + + // Check bootsel button hold as early as possible for safety. + if (inputs.mb1) { + reboot_bootloader(); + } + + // Turn on LED to indicate firmware booted. + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + gpio_put(PICO_DEFAULT_LED_PIN, 1); + + // Attempt to load config, or write default config to flash if failed to load config. + Persistence *persistence = new Persistence(); + if (!persistence->LoadConfig(config)) { + persistence->SaveConfig(config); + } + delete persistence; + + // Create array of input sources to be used. + static InputSource *input_sources[] = {}; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); + + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); +} + +void loop() { + select_mode(backends, backend_count, config); + + for (size_t i = 0; i < backend_count; i++) { + backends[i]->SendReport(); + } + + if (current_kb_mode != nullptr) { + current_kb_mode->SendReport(backends[0]->GetInputs()); + } +} + +/* Button inputs are read from the second core */ + +void setup1() { + while (backends == nullptr) { + tight_loop_contents(); + } + // Wire.setSDA(20); + // Wire.setSCL(21); + // Wire.begin(); + // expander_input = new Pca9671Input(expander_button_mappings, expander_button_count, Wire); +} + +void loop1() { + if (backends != nullptr) { + InputState &inputs = backends[0]->GetInputs(); + gpio_input.UpdateInputs(inputs); + expander_input.UpdateInputs(inputs); + } +} diff --git a/config/schism/env.ini b/config/schism/env.ini new file mode 100644 index 00000000..7d5f4568 --- /dev/null +++ b/config/schism/env.ini @@ -0,0 +1,11 @@ +[env:schism] +extends = arduino_pico_base +build_flags = + ${arduino_pico_base.build_flags} + -I config/schism/include +build_src_filter = + ${arduino_pico_base.build_src_filter} + + +lib_deps = + ${arduino_pico_base.lib_deps} + adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 From 15621511914a40c9d787204ee7974172acc64cff Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 23 Apr 2024 17:46:32 +0100 Subject: [PATCH 099/167] build: add missing dependency --- config/schism/env.ini | 6 ------ platformio.ini | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/config/schism/env.ini b/config/schism/env.ini index 7d5f4568..7fa0a0aa 100644 --- a/config/schism/env.ini +++ b/config/schism/env.ini @@ -1,11 +1,5 @@ [env:schism] extends = arduino_pico_base -build_flags = - ${arduino_pico_base.build_flags} - -I config/schism/include build_src_filter = ${arduino_pico_base.build_src_filter} + -lib_deps = - ${arduino_pico_base.lib_deps} - adafruit/Adafruit MCP23017 Arduino Library@^2.3.2 diff --git a/platformio.ini b/platformio.ini index 357239d6..5f3f154d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -120,4 +120,5 @@ lib_deps = adafruit/Adafruit GFX Library@^1.11.9 eric-wieser/PacketIO@^0.3.0 bakercp/CRC32@^2.0.0 + robtillaart/PCF8575@^0.2.2 TUCompositeHID From 175f00e114c7d9876a9da1f21fce8e7bedab364a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 14 May 2024 18:48:13 +0100 Subject: [PATCH 100/167] fix: Glyph default config missing RGB mode assignments --- config/glyph/include/glyph_overrides.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 1827c342..35d71549 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -108,6 +108,7 @@ Config glyph_default_config() { GameModeConfig &mode_config = config.game_mode_configs[i]; switch (mode_config.mode_id) { case MODE_FGC: + mode_config.rgb_config = 2; if (mode_config.button_remapping_count > 0) { mode_config.layout_plate = LAYOUT_PLATE_FGC; } else { @@ -122,6 +123,7 @@ Config glyph_default_config() { case MODE_PROJECT_M: case MODE_ULTIMATE: case MODE_RIVALS_OF_AETHER: + mode_config.rgb_config = 1; mode_config.layout_plate = LAYOUT_PLATE_PLATFORM_FIGHTER; mode_config.applicable_backends[0] = COMMS_BACKEND_XINPUT; mode_config.applicable_backends[1] = COMMS_BACKEND_DINPUT; From 97d4fcfc6a825f4cdbd221279b5b2360f749ffbc Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 17 May 2024 20:52:09 +0100 Subject: [PATCH 101/167] fix: RGB refresh timeout not initialized --- HAL/pico/include/comms/NeoPixelBackend.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index 4692aec8..0c68575d 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -83,7 +83,7 @@ template class NeoPixelBackend : public Commun CRGB _leds[led_count]; uint32_t _button_colors[button_colors_count]; - absolute_time_t _refresh_timeout; + absolute_time_t _refresh_timeout = 0; }; #endif \ No newline at end of file From 0fa222e74c339a4bed355e9cb5c484940b24ff1d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:21:27 +0100 Subject: [PATCH 102/167] fix: remapping bug allows macro creation --- src/core/InputMode.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index bb732218..0059b903 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -58,11 +58,10 @@ void InputMode::HandleRemap(const InputState &original_inputs, InputState &remap if (_config == nullptr) { return; } + remapped_inputs.buttons = 0; - // Keep track of which buttons have been remapped so that we can avoid conflicts for buttons - // that are remapped to multiple buttons and prevent macro remapping. + // Keep track of which buttons have been remapped so that we can prevent macro remapping. uint64_t physical_buttons_already_remapped = 0; - uint64_t buttons_already_mapped_to = 0; for (size_t i = 0; i < _config->button_remapping_count; i++) { const ButtonRemap &remapping = _config->button_remapping[i]; // If this physical button was already mapped to something else, ignore this remapping. This @@ -70,11 +69,6 @@ void InputMode::HandleRemap(const InputState &original_inputs, InputState &remap if (get_button(physical_buttons_already_remapped, remapping.physical_button)) { continue; } - // If physical button has not been mapped to yet, set it to false. This too is intended to - // prevent creating macro behaviour through remapping. - if (!get_button(buttons_already_mapped_to, remapping.physical_button)) { - set_button(remapped_inputs.buttons, remapping.physical_button, false); - } // Either use the value of the physical button, or if the physical button is not pressed, // but the target button has another physical button remapped to it, and is considered to be @@ -85,6 +79,19 @@ void InputMode::HandleRemap(const InputState &original_inputs, InputState &remap // Track which buttons have been mapped from/to. set_button(physical_buttons_already_remapped, remapping.physical_button, true); - set_button(buttons_already_mapped_to, remapping.activates, true); + } + + // Copy over original button states for buttons that were not remapped. + for (uint8_t i = BTN_LF1; i < _Button_MAX; i++) { + Button button = (Button)i; + if (!get_button(physical_buttons_already_remapped, button)) { + bool original_button_pressed = get_button(original_inputs.buttons, button); + bool remapped_button_pressed = get_button(remapped_inputs.buttons, button); + set_button( + remapped_inputs.buttons, + button, + original_button_pressed || remapped_button_pressed + ); + } } } From 3fd35358a1f418c8d0bf1f86b39a3e8bb0ac9b5a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:33:58 +0100 Subject: [PATCH 103/167] perf: optimize remapping with bitwise operations --- src/core/InputMode.cpp | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/core/InputMode.cpp b/src/core/InputMode.cpp index 0059b903..f1388a19 100644 --- a/src/core/InputMode.cpp +++ b/src/core/InputMode.cpp @@ -64,8 +64,8 @@ void InputMode::HandleRemap(const InputState &original_inputs, InputState &remap uint64_t physical_buttons_already_remapped = 0; for (size_t i = 0; i < _config->button_remapping_count; i++) { const ButtonRemap &remapping = _config->button_remapping[i]; - // If this physical button was already mapped to something else, ignore this remapping. This - // is to prevent creating macro behaviour through remapping. + // If this physical button was already remapped to something else, ignore this remapping. + // This is to prevent creating macro behaviour through remapping. if (get_button(physical_buttons_already_remapped, remapping.physical_button)) { continue; } @@ -77,21 +77,10 @@ void InputMode::HandleRemap(const InputState &original_inputs, InputState &remap get_button(remapped_inputs.buttons, remapping.activates); set_button(remapped_inputs.buttons, remapping.activates, should_be_pressed); - // Track which buttons have been mapped from/to. + // Track which buttons have been remapped. set_button(physical_buttons_already_remapped, remapping.physical_button, true); } // Copy over original button states for buttons that were not remapped. - for (uint8_t i = BTN_LF1; i < _Button_MAX; i++) { - Button button = (Button)i; - if (!get_button(physical_buttons_already_remapped, button)) { - bool original_button_pressed = get_button(original_inputs.buttons, button); - bool remapped_button_pressed = get_button(remapped_inputs.buttons, button); - set_button( - remapped_inputs.buttons, - button, - original_button_pressed || remapped_button_pressed - ); - } - } + remapped_inputs.buttons |= original_inputs.buttons & ~physical_buttons_already_remapped; } From f493fbde978dd828ad791144736b4c3aa195f3d8 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:38:10 +0100 Subject: [PATCH 104/167] style: cleanup Schism config --- config/schism/config.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/schism/config.cpp b/config/schism/config.cpp index 7b66c3ca..202f0f51 100644 --- a/config/schism/config.cpp +++ b/config/schism/config.cpp @@ -7,7 +7,6 @@ #include "core/pinout.hpp" #include "core/state.hpp" #include "input/DebouncedGpioButtonInput.hpp" -#include "input/Mcp23Input.hpp" #include "input/Pca9671Input.hpp" #include "reboot.hpp" #include "stdlib.hpp" @@ -51,7 +50,6 @@ const size_t expander_button_count = sizeof(expander_button_mappings) / sizeof(Pca9671ButtonMapping); DebouncedGpioButtonInput gpio_input(button_mappings); -// Mcp23Input *expander_input = nullptr; Pca9671Input expander_input(expander_button_mappings, expander_button_count, Wire, 20, 21); const Pinout pinout = { From e49ada04df32b27237d46c7b020b6b107fe525e8 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:40:51 +0100 Subject: [PATCH 105/167] feat: update OLED menu item text --- HAL/pico/src/display/ConfigMenu.cpp | 4 ++-- config/glyph/include/display/GlyphConfigMenu.hpp | 4 ++++ include/comms/IntegratedDisplay.hpp | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp index 910459d2..0b2a687f 100644 --- a/HAL/pico/src/display/ConfigMenu.cpp +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -93,7 +93,7 @@ ConfigMenu::ConfigMenu(Config &config, CommunicationBackend **backends, size_t b // clang-format off static MenuPage::MenuItem top_level_items[] = { { - .text = "Gamemode", + .text = "Profile", .page = &_gamemode_options_page, }, { @@ -101,7 +101,7 @@ ConfigMenu::ConfigMenu(Config &config, CommunicationBackend **backends, size_t b .page = &_usb_backends_page, }, { - .text = "SOCD Mode", + .text = "SOCD Option", .page = &socd_page, }, { diff --git a/config/glyph/include/display/GlyphConfigMenu.hpp b/config/glyph/include/display/GlyphConfigMenu.hpp index c8af67b1..340e7bc9 100644 --- a/config/glyph/include/display/GlyphConfigMenu.hpp +++ b/config/glyph/include/display/GlyphConfigMenu.hpp @@ -3,6 +3,10 @@ #include "display/ConfigMenu.hpp" +/** + * @brief Modified version of ConfigMenu that only shows gamemodes marked as applicable for current + * CommunicationBackend. + */ class GlyphConfigMenu : public ConfigMenu { public: GlyphConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count); diff --git a/include/comms/IntegratedDisplay.hpp b/include/comms/IntegratedDisplay.hpp index 41af87bd..1441ce74 100644 --- a/include/comms/IntegratedDisplay.hpp +++ b/include/comms/IntegratedDisplay.hpp @@ -49,6 +49,13 @@ class IntegratedDisplay : public CommunicationBackend { size_t _display_modes_count; void HandleControls(DisplayMode *active_mode); + + /** + * @brief Get the current active DisplayMode instance. + * + * @return A pointer to the first DisplayMode instance in the _display_modes array whose + * DisplayModeId is the same as the current value of _display_mode in this class. + */ DisplayMode *GetActiveDisplayMode(); }; From cbf6f5a7ac7d0784c9f737ff1927d7a4c31537f5 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:41:41 +0100 Subject: [PATCH 106/167] feat: add Glyph button remapping for FGC mode --- config/glyph/include/glyph_overrides.hpp | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 35d71549..1c4e0566 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -118,6 +118,44 @@ Config glyph_default_config() { mode_config.applicable_backends[1] = COMMS_BACKEND_DINPUT; mode_config.applicable_backends[2] = COMMS_BACKEND_NINTENDO_SWITCH; mode_config.applicable_backends_count = 3; + + // Right hand bottom row + mode_config.button_remapping[0] = { BTN_RF9, BTN_RF1 }; + mode_config.button_remapping[1] = { BTN_RF10, BTN_RF2 }; + mode_config.button_remapping[2] = { BTN_RF11, BTN_RF3 }; + mode_config.button_remapping[3] = { BTN_RF1, BTN_RF4 }; + // Right hand top row + mode_config.button_remapping[4] = { BTN_RF12, BTN_RF5 }; + mode_config.button_remapping[5] = { BTN_RF13, BTN_RF6 }; + mode_config.button_remapping[6] = { BTN_RF14, BTN_RF7 }; + mode_config.button_remapping[7] = { BTN_RF5, BTN_RF8 }; + // Left hand row + mode_config.button_remapping[8] = { BTN_LF8, BTN_LF1 }; + mode_config.button_remapping[9] = { BTN_LF7, BTN_LF2 }; + mode_config.button_remapping[10] = { BTN_LF6, BTN_LF3 }; + // Up button + mode_config.button_remapping[11] = { BTN_LT6, BTN_LT1 }; + // Menu buttons + mode_config.button_remapping[12] = { BTN_MB3, BTN_RT3 }; + mode_config.button_remapping[13] = { BTN_MB4, BTN_RT2 }; + mode_config.button_remapping[14] = { BTN_MB2, BTN_MB1 }; + + // Unmap the old buttons + mode_config.button_remapping[15] = { BTN_RF2, BTN_UNSPECIFIED }; + mode_config.button_remapping[16] = { BTN_RF3, BTN_UNSPECIFIED }; + mode_config.button_remapping[17] = { BTN_RF4, BTN_UNSPECIFIED }; + mode_config.button_remapping[18] = { BTN_RF6, BTN_UNSPECIFIED }; + mode_config.button_remapping[19] = { BTN_RF7, BTN_UNSPECIFIED }; + mode_config.button_remapping[20] = { BTN_RF8, BTN_UNSPECIFIED }; + mode_config.button_remapping[21] = { BTN_LF1, BTN_UNSPECIFIED }; + mode_config.button_remapping[22] = { BTN_LF2, BTN_UNSPECIFIED }; + mode_config.button_remapping[23] = { BTN_LF3, BTN_UNSPECIFIED }; + mode_config.button_remapping[24] = { BTN_LT1, BTN_UNSPECIFIED }; + mode_config.button_remapping[25] = { BTN_RT2, BTN_UNSPECIFIED }; + mode_config.button_remapping[26] = { BTN_RT3, BTN_UNSPECIFIED }; + mode_config.button_remapping[27] = { BTN_MB1, BTN_UNSPECIFIED }; + + mode_config.button_remapping_count = 28; break; case MODE_MELEE: case MODE_PROJECT_M: From 3247d301f31b558d19269ca1fde05e5c1dd9fde0 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:44:01 +0100 Subject: [PATCH 107/167] fix: keyboard modes should only be visible when using DInputBackend --- config/glyph/include/glyph_overrides.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 1c4e0566..bf283f96 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -169,6 +169,9 @@ Config glyph_default_config() { mode_config.applicable_backends[3] = COMMS_BACKEND_GAMECUBE; mode_config.applicable_backends_count = 4; break; + case MODE_KEYBOARD: + mode_config.applicable_backends[0] = COMMS_BACKEND_DINPUT; + mode_config.applicable_backends_count = 1; default: mode_config.layout_plate = LAYOUT_PLATE_EVERYTHING; } From 06e70909c2511dec4c7ac792b5e4344dff8e9040 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:53:34 +0100 Subject: [PATCH 108/167] feat: CustomControllerMode support multi-button modifiers --- config/glyph/env.ini | 2 +- include/modes/CustomControllerMode.hpp | 1 + platformio.ini | 248 ++++++++++++------------- src/modes/CustomControllerMode.cpp | 25 ++- 4 files changed, 148 insertions(+), 128 deletions(-) diff --git a/config/glyph/env.ini b/config/glyph/env.ini index da31d6e7..3290c926 100644 --- a/config/glyph/env.ini +++ b/config/glyph/env.ini @@ -12,4 +12,4 @@ lib_ignore = https://github.com/JonnyHaystack/HayBox-proto lib_deps = ${arduino_pico_base.lib_deps} - https://github.com/LimitLabs/HayBox-proto#e87f4b2 \ No newline at end of file + https://github.com/LimitLabs/HayBox-proto#bec35e5 \ No newline at end of file diff --git a/include/modes/CustomControllerMode.hpp b/include/modes/CustomControllerMode.hpp index 756bc8c4..a18976e8 100644 --- a/include/modes/CustomControllerMode.hpp +++ b/include/modes/CustomControllerMode.hpp @@ -17,6 +17,7 @@ class CustomControllerMode : public ControllerMode { private: const CustomModeConfig *_custom_mode_config; + uint64_t _modifier_button_masks[10]; Button GetDirectionButton(const Button *direction_buttons, StickDirectionButton direction); }; diff --git a/platformio.ini b/platformio.ini index 5f3f154d..1aec6b16 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1,124 +1,124 @@ -[platformio] -name = HayBox -default_envs = pico -extra_configs = config/*/env.ini -src_dir = ./ - -[env] -build_type = release -custom_firmware_version = 3.0.0 -lib_ldf_mode = chain+ -build_flags = - -I src/ - -I include/ - -D 'DEVICE_NAME="${PIOENV}"' - -D 'FIRMWARE_NAME="${platformio.name}"' - -D 'FIRMWARE_VERSION="${this.custom_firmware_version}"' -build_src_filter = - + -custom_nanopb_protos = - +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> -custom_nanopb_options = - --error-on-unmatched -lib_deps = - nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#994f2cb - -[avr_base] -platform = atmelavr -framework = arduino -build_unflags = - -std=gnu++11 -build_flags = - ${env.build_flags} - -std=gnu++17 - -Os - -fdata-sections - -ffunction-sections - -fno-sized-deallocation - -flto - -fshort-enums - -Wl,--gc-sections - -Wno-unused-variable - -I HAL/avr/include - -D PB_BUFFER_ONLY - -D PB_WITHOUT_64BIT - -D PB_NO_ERRMSG - -D PB_CONVERT_DOUBLE_FLOAT -build_src_filter = - ${env.build_src_filter} - + -custom_nanopb_options = - ${env.custom_nanopb_options} - --options-file ../../../../HAL/avr/proto/config.options -lib_deps = - ${env.lib_deps} - nicohood/Nintendo@^1.4.0 - Wire - https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip - -[avr_nousb] -extends = avr_base -build_flags = - ${avr_base.build_flags} - -I HAL/avr/avr_nousb/include -build_src_filter = - ${avr_base.build_src_filter} - + - -[avr_usb] -extends = avr_base -build_flags = - ${avr_base.build_flags} - -I HAL/avr/avr_usb/include -build_src_filter = - ${avr_base.build_src_filter} - + -lib_deps = - ${avr_base.lib_deps} - https://github.com/JonnyHaystack/ArduinoJoystickLibrary/archive/refs/tags/v0.0.1.zip - https://github.com/JonnyHaystack/ArduinoKeyboard/archive/refs/tags/1.0.5.zip - -[arduino_pico_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi -framework = arduino -board = pico -extra_scripts = pre:builder_scripts/arduino_pico.py -debug_tool = cmsis-dap -; upload_protocol = cmsis-dap -monitor_speed = 115200 -board_build.core = earlephilhower -board_build.f_cpu = 130000000L -board_build.filesystem_size = 0.5m -build_unflags = -Os -build_flags = - ${env.build_flags} - -O3 - -D USE_TINYUSB - -D CFG_TUSB_CONFIG_FILE=\"tusb_config_pico.h\" - -D NDEBUG - -D FASTLED_RP2040_CLOCKLESS_M0_FALLBACK=0 - -Wall - -Wstack-usage=1024 - -Wno-unused-variable - -I HAL/pico/include -build_src_filter = - ${env.build_src_filter} - + -platform_packages = - framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.3 -lib_archive = no -lib_deps = - ${env.lib_deps} - https://github.com/JonnyHaystack/joybus-pio/archive/refs/tags/v1.2.3.zip - https://github.com/JonnyHaystack/nes-pio#73417ba - https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip - https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput#4b5617b - https://github.com/FastLED/FastLED#6daa782 - https://github.com/JonnyHaystack/nanopb-arduino/archive/refs/tags/v1.1.1.zip - adafruit/Adafruit SSD1306@^2.5.9 - adafruit/Adafruit GFX Library@^1.11.9 - eric-wieser/PacketIO@^0.3.0 - bakercp/CRC32@^2.0.0 - robtillaart/PCF8575@^0.2.2 - TUCompositeHID +[platformio] +name = HayBox +default_envs = pico +extra_configs = config/*/env.ini +src_dir = ./ + +[env] +build_type = release +custom_firmware_version = 3.0.0 +lib_ldf_mode = chain+ +build_flags = + -I src/ + -I include/ + -D 'DEVICE_NAME="${PIOENV}"' + -D 'FIRMWARE_NAME="${platformio.name}"' + -D 'FIRMWARE_VERSION="${this.custom_firmware_version}"' +build_src_filter = + + +custom_nanopb_protos = + +<.pio/libdeps/${PIOENV}/HayBox-proto/config.proto> +custom_nanopb_options = + --error-on-unmatched +lib_deps = + nanopb/Nanopb@^0.4.8 + https://github.com/JonnyHaystack/HayBox-proto#703e11f + +[avr_base] +platform = atmelavr +framework = arduino +build_unflags = + -std=gnu++11 +build_flags = + ${env.build_flags} + -std=gnu++17 + -Os + -fdata-sections + -ffunction-sections + -fno-sized-deallocation + -flto + -fshort-enums + -Wl,--gc-sections + -Wno-unused-variable + -I HAL/avr/include + -D PB_BUFFER_ONLY + -D PB_WITHOUT_64BIT + -D PB_NO_ERRMSG + -D PB_CONVERT_DOUBLE_FLOAT +build_src_filter = + ${env.build_src_filter} + + +custom_nanopb_options = + ${env.custom_nanopb_options} + --options-file ../../../../HAL/avr/proto/config.options +lib_deps = + ${env.lib_deps} + nicohood/Nintendo@^1.4.0 + Wire + https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip + +[avr_nousb] +extends = avr_base +build_flags = + ${avr_base.build_flags} + -I HAL/avr/avr_nousb/include +build_src_filter = + ${avr_base.build_src_filter} + + + +[avr_usb] +extends = avr_base +build_flags = + ${avr_base.build_flags} + -I HAL/avr/avr_usb/include +build_src_filter = + ${avr_base.build_src_filter} + + +lib_deps = + ${avr_base.lib_deps} + https://github.com/JonnyHaystack/ArduinoJoystickLibrary/archive/refs/tags/v0.0.1.zip + https://github.com/JonnyHaystack/ArduinoKeyboard/archive/refs/tags/1.0.5.zip + +[arduino_pico_base] +platform = https://github.com/maxgerhardt/platform-raspberrypi +framework = arduino +board = pico +extra_scripts = pre:builder_scripts/arduino_pico.py +debug_tool = cmsis-dap +; upload_protocol = cmsis-dap +monitor_speed = 115200 +board_build.core = earlephilhower +board_build.f_cpu = 130000000L +board_build.filesystem_size = 0.5m +build_unflags = -Os +build_flags = + ${env.build_flags} + -O3 + -D USE_TINYUSB + -D CFG_TUSB_CONFIG_FILE=\"tusb_config_pico.h\" + -D NDEBUG + -D FASTLED_RP2040_CLOCKLESS_M0_FALLBACK=0 + -Wall + -Wstack-usage=1024 + -Wno-unused-variable + -I HAL/pico/include +build_src_filter = + ${env.build_src_filter} + + +platform_packages = + framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.6.3 +lib_archive = no +lib_deps = + ${env.lib_deps} + https://github.com/JonnyHaystack/joybus-pio/archive/refs/tags/v1.2.3.zip + https://github.com/JonnyHaystack/nes-pio#73417ba + https://github.com/JonnyHaystack/arduino-nunchuk/archive/refs/tags/v1.0.1.zip + https://github.com/JonnyHaystack/Adafruit_TinyUSB_XInput#4b5617b + https://github.com/FastLED/FastLED#6daa782 + https://github.com/JonnyHaystack/nanopb-arduino/archive/refs/tags/v1.1.1.zip + adafruit/Adafruit SSD1306@^2.5.9 + adafruit/Adafruit GFX Library@^1.11.9 + eric-wieser/PacketIO@^0.3.0 + bakercp/CRC32@^2.0.0 + robtillaart/PCF8575@^0.2.2 + TUCompositeHID diff --git a/src/modes/CustomControllerMode.cpp b/src/modes/CustomControllerMode.cpp index 97a24164..12ecd130 100644 --- a/src/modes/CustomControllerMode.cpp +++ b/src/modes/CustomControllerMode.cpp @@ -2,6 +2,7 @@ #include "util/state_util.hpp" +#define SIGNUM(x) ((x > 0) - (x < 0)) #define ANALOG_STICK_NEUTRAL 128 CustomControllerMode::CustomControllerMode() : ControllerMode() {} @@ -12,6 +13,12 @@ void CustomControllerMode::SetConfig( ) { InputMode::SetConfig(config); _custom_mode_config = &custom_mode_config; + for (size_t i = 0; i < custom_mode_config.modifiers_count; i++) { + _modifier_button_masks[i] = make_button_mask( + custom_mode_config.modifiers[i].buttons, + custom_mode_config.modifiers[i].buttons_count + ); + } } void CustomControllerMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { @@ -57,14 +64,26 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS if (modifier.axis == AXIS_UNSPECIFIED || modifier.axis > _AnalogAxis_MAX) { continue; } - if (!get_button(inputs.buttons, modifier.button)) { + if (!all_buttons_held(inputs.buttons, _modifier_button_masks[i])) { continue; } uint8_t OutputState::*axis = axis_pointer(modifier.axis); if (axis != nullptr) { - outputs.*axis = - ANALOG_STICK_NEUTRAL + (outputs.*axis - ANALOG_STICK_NEUTRAL) * modifier.multiplier; + int8_t sign = 0; + switch (modifier.combination_mode) { + case COMBINATION_MODE_OVERRIDE: + sign = SIGNUM(outputs.*axis); + outputs.*axis = ANALOG_STICK_NEUTRAL + + _custom_mode_config->stick_range * modifier.multiplier * sign; + break; + case COMBINATION_MODE_COMPOUND: + case COMBINATION_MODE_UNSPECIFIED: + default: + outputs.*axis = ANALOG_STICK_NEUTRAL + + (outputs.*axis - ANALOG_STICK_NEUTRAL) * modifier.multiplier; + break; + } } } From 45b6225931f5dce63f44aa7f17e2e1a815349ba8 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 22:55:30 +0100 Subject: [PATCH 109/167] style: remove commented out code --- HAL/pico/include/display/DisplayMode.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/HAL/pico/include/display/DisplayMode.hpp b/HAL/pico/include/display/DisplayMode.hpp index 23ace4e2..047398b9 100644 --- a/HAL/pico/include/display/DisplayMode.hpp +++ b/HAL/pico/include/display/DisplayMode.hpp @@ -4,7 +4,6 @@ #include #include -// struct _DisplayControls; typedef struct _DisplayControls DisplayControls; class IntegratedDisplay; From e2ac009f27901e4d7d6a136237be508faf5f4f85 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 23:08:51 +0100 Subject: [PATCH 110/167] refactor: write out Glyph config in full because the overrides are getting to be a lot --- config/glyph/include/glyph_overrides.hpp | 325 +++++++++++++++++------ 1 file changed, 238 insertions(+), 87 deletions(-) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index bf283f96..a02683e7 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -16,6 +16,244 @@ // clang-format off +const Config default_config = { + .game_mode_configs_count = 5, + .game_mode_configs = { + GameModeConfig { + .mode_id = MODE_MELEE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .rgb_config = 1, + }, + GameModeConfig { + .mode_id = MODE_PROJECT_M, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .rgb_config = 1, + }, + GameModeConfig { + .mode_id = MODE_ULTIMATE, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .rgb_config = 1, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .name = "Split FGC", + .socd_pairs_count = 2, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .rgb_config = 1, + .layout_plate = LAYOUT_PLATE_SPLIT_FGC, + }, + GameModeConfig { + .mode_id = MODE_FGC, + .socd_pairs_count = 2, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + }, + .button_remapping_count = 28, + .button_remapping = { + // Right hand bottom row + ButtonRemap { .physical_button = BTN_RF9, .activates = BTN_RF1 }, + ButtonRemap { .physical_button = BTN_RF10, .activates = BTN_RF2 }, + ButtonRemap { .physical_button = BTN_RF11, .activates = BTN_RF3 }, + ButtonRemap { .physical_button = BTN_RF1, .activates = BTN_RF4 }, + // Right hand top row + ButtonRemap { .physical_button = BTN_RF12, .activates = BTN_RF5 }, + ButtonRemap { .physical_button = BTN_RF13, .activates = BTN_RF6 }, + ButtonRemap { .physical_button = BTN_RF14, .activates = BTN_RF7 }, + ButtonRemap { .physical_button = BTN_RF5, .activates = BTN_RF8 }, + // Left hand row + ButtonRemap { .physical_button = BTN_LF8, .activates = BTN_LF1 }, + ButtonRemap { .physical_button = BTN_LF7, .activates = BTN_LF2 }, + ButtonRemap { .physical_button = BTN_LF6, .activates = BTN_LF3 }, + // Up button + ButtonRemap { .physical_button = BTN_LT6, .activates = BTN_LT1 }, + // Menu buttons + ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_RT3 }, + ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_RT2 }, + ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, + + // Unmap the old buttons + ButtonRemap { .physical_button = BTN_RF2, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RF3, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RF4, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RF6, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RF7, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RF8, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_LF1, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_LF2, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_LF3, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_LT1, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RT2, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RT3, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, + }, + .activation_binding_count = 3, + .rgb_config = 2, + .layout_plate = LAYOUT_PLATE_FGC, + }, + GameModeConfig { + .mode_id = MODE_KEYBOARD, + .socd_pairs_count = 2, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, + SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .keyboard_mode_config = 1, + }, + }, + .communication_backend_configs_count = 8, + .communication_backend_configs = { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_XINPUT, + .default_mode_config = 4, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode_config = 5, + .activation_binding_count = 1, + .activation_binding = { BTN_RF3 }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_NINTENDO_SWITCH, + .default_mode_config = 3, + .activation_binding_count = 1, + .activation_binding = { BTN_RF2 }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_GAMECUBE, + .default_mode_config = 1, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_N64, + .default_mode_config = 1, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_NES, + .default_mode_config = 1, + .activation_binding_count = 1, + .activation_binding = { BTN_LT1 }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_SNES, + .default_mode_config = 1, + .activation_binding_count = 1, + .activation_binding = { BTN_LT2 }, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_CONFIGURATOR, + .activation_binding_count = 1, + .activation_binding = { BTN_RT2 }, + } + }, + .keyboard_modes_count = 1, + .keyboard_modes = { + KeyboardModeConfig { + 0, + 22, + { + { BTN_LF4, HID_KEY_A }, + { BTN_LF3, HID_KEY_B }, + { BTN_LF2, HID_KEY_C }, + { BTN_LF1, HID_KEY_D }, + { BTN_LT1, HID_KEY_E }, + { BTN_LT2, HID_KEY_F }, + { BTN_MB3, HID_KEY_G }, + { BTN_MB1, HID_KEY_H }, + { BTN_MB2, HID_KEY_I }, + { BTN_RF5, HID_KEY_J }, + { BTN_RF6, HID_KEY_K }, + { BTN_RF7, HID_KEY_L }, + { BTN_RF8, HID_KEY_M }, + { BTN_RF1, HID_KEY_N }, + { BTN_RF2, HID_KEY_O }, + { BTN_RF3, HID_KEY_P }, + { BTN_RF4, HID_KEY_Q }, + { BTN_RT4, HID_KEY_R }, + { BTN_RT3, HID_KEY_S }, + { BTN_RT5, HID_KEY_T }, + { BTN_RT1, HID_KEY_U }, + { BTN_RT2, HID_KEY_V }, + }, + }, + }, + .rgb_configs_count = 2, + .rgb_configs = { + RgbConfig { + .button_colors_count = 19, + .button_colors = { + { BTN_LF1, 0x0000ff }, + { BTN_LF2, 0x0000ff }, + { BTN_LF3, 0x0000ff }, + { BTN_LF4, 0x0000ff }, + { BTN_LT1, 0x0000ff }, + { BTN_LT2, 0x0000ff }, + { BTN_RF1, 0x0000ff }, + { BTN_RF2, 0x0000ff }, + { BTN_RF3, 0x0000ff }, + { BTN_RF4, 0x0000ff }, + { BTN_RF5, 0x0000ff }, + { BTN_RF6, 0x0000ff }, + { BTN_RF7, 0x0000ff }, + { BTN_RF8, 0x0000ff }, + { BTN_RT1, 0x0000ff }, + { BTN_RT2, 0x0000ff }, + { BTN_RT3, 0x0000ff }, + { BTN_RT4, 0x0000ff }, + { BTN_RT5, 0x0000ff }, + }, + }, + RgbConfig { + .button_colors_count = 12, + .button_colors = { + { BTN_LF6, 0xff0000 }, + { BTN_LF7, 0xff0000 }, + { BTN_LF8, 0xff0000 }, + { BTN_LT6, 0xff0000 }, + { BTN_RF9, 0xff0000 }, + { BTN_RF10, 0xff0000 }, + { BTN_RF11, 0xff0000 }, + { BTN_RF1, 0xff0000 }, + { BTN_RF12, 0xff0000 }, + { BTN_RF13, 0xff0000 }, + { BTN_RF14, 0xff0000 }, + { BTN_RF5, 0xff0000 }, + }, + }, + }, + .default_backend_config = 1, + .default_usb_backend_config = 1, + .rgb_brightness = 255, +}; + const Button pixel_to_button_mappings[LED_COUNT] = { BTN_MB1, BTN_MB1, BTN_LF4, BTN_LF4, @@ -59,103 +297,16 @@ const Button pixel_to_button_mappings[LED_COUNT] = { Config glyph_default_config() { Config config = default_config; - config.rgb_configs_count = 2; - config.rgb_configs[0] = { - .button_colors_count = 19, - .button_colors = { - { BTN_LF1, 0x0000ff }, - { BTN_LF2, 0x0000ff }, - { BTN_LF3, 0x0000ff }, - { BTN_LF4, 0x0000ff }, - { BTN_LT1, 0x0000ff }, - { BTN_LT2, 0x0000ff }, - { BTN_RF1, 0x0000ff }, - { BTN_RF2, 0x0000ff }, - { BTN_RF3, 0x0000ff }, - { BTN_RF4, 0x0000ff }, - { BTN_RF5, 0x0000ff }, - { BTN_RF6, 0x0000ff }, - { BTN_RF7, 0x0000ff }, - { BTN_RF8, 0x0000ff }, - { BTN_RT1, 0x0000ff }, - { BTN_RT2, 0x0000ff }, - { BTN_RT3, 0x0000ff }, - { BTN_RT4, 0x0000ff }, - { BTN_RT5, 0x0000ff }, - }, - }; - config.rgb_configs[1] = { - .button_colors_count = 12, - .button_colors = { - { BTN_LF6, 0xff0000 }, - { BTN_LF7, 0xff0000 }, - { BTN_LF8, 0xff0000 }, - { BTN_LT6, 0xff0000 }, - { BTN_RF9, 0xff0000 }, - { BTN_RF10, 0xff0000 }, - { BTN_RF11, 0xff0000 }, - { BTN_RF1, 0xff0000 }, - { BTN_RF12, 0xff0000 }, - { BTN_RF13, 0xff0000 }, - { BTN_RF14, 0xff0000 }, - { BTN_RF5, 0xff0000 }, - }, - }; - config.rgb_brightness = 255; // Assign layout plates and applicable backends for default gamemode configs. for (size_t i = 0; i < config.game_mode_configs_count; i++) { GameModeConfig &mode_config = config.game_mode_configs[i]; switch (mode_config.mode_id) { case MODE_FGC: - mode_config.rgb_config = 2; - if (mode_config.button_remapping_count > 0) { - mode_config.layout_plate = LAYOUT_PLATE_FGC; - } else { - mode_config.layout_plate = LAYOUT_PLATE_SPLIT_FGC; - } mode_config.applicable_backends[0] = COMMS_BACKEND_XINPUT; mode_config.applicable_backends[1] = COMMS_BACKEND_DINPUT; mode_config.applicable_backends[2] = COMMS_BACKEND_NINTENDO_SWITCH; mode_config.applicable_backends_count = 3; - - // Right hand bottom row - mode_config.button_remapping[0] = { BTN_RF9, BTN_RF1 }; - mode_config.button_remapping[1] = { BTN_RF10, BTN_RF2 }; - mode_config.button_remapping[2] = { BTN_RF11, BTN_RF3 }; - mode_config.button_remapping[3] = { BTN_RF1, BTN_RF4 }; - // Right hand top row - mode_config.button_remapping[4] = { BTN_RF12, BTN_RF5 }; - mode_config.button_remapping[5] = { BTN_RF13, BTN_RF6 }; - mode_config.button_remapping[6] = { BTN_RF14, BTN_RF7 }; - mode_config.button_remapping[7] = { BTN_RF5, BTN_RF8 }; - // Left hand row - mode_config.button_remapping[8] = { BTN_LF8, BTN_LF1 }; - mode_config.button_remapping[9] = { BTN_LF7, BTN_LF2 }; - mode_config.button_remapping[10] = { BTN_LF6, BTN_LF3 }; - // Up button - mode_config.button_remapping[11] = { BTN_LT6, BTN_LT1 }; - // Menu buttons - mode_config.button_remapping[12] = { BTN_MB3, BTN_RT3 }; - mode_config.button_remapping[13] = { BTN_MB4, BTN_RT2 }; - mode_config.button_remapping[14] = { BTN_MB2, BTN_MB1 }; - - // Unmap the old buttons - mode_config.button_remapping[15] = { BTN_RF2, BTN_UNSPECIFIED }; - mode_config.button_remapping[16] = { BTN_RF3, BTN_UNSPECIFIED }; - mode_config.button_remapping[17] = { BTN_RF4, BTN_UNSPECIFIED }; - mode_config.button_remapping[18] = { BTN_RF6, BTN_UNSPECIFIED }; - mode_config.button_remapping[19] = { BTN_RF7, BTN_UNSPECIFIED }; - mode_config.button_remapping[20] = { BTN_RF8, BTN_UNSPECIFIED }; - mode_config.button_remapping[21] = { BTN_LF1, BTN_UNSPECIFIED }; - mode_config.button_remapping[22] = { BTN_LF2, BTN_UNSPECIFIED }; - mode_config.button_remapping[23] = { BTN_LF3, BTN_UNSPECIFIED }; - mode_config.button_remapping[24] = { BTN_LT1, BTN_UNSPECIFIED }; - mode_config.button_remapping[25] = { BTN_RT2, BTN_UNSPECIFIED }; - mode_config.button_remapping[26] = { BTN_RT3, BTN_UNSPECIFIED }; - mode_config.button_remapping[27] = { BTN_MB1, BTN_UNSPECIFIED }; - - mode_config.button_remapping_count = 28; break; case MODE_MELEE: case MODE_PROJECT_M: From d335c36fc68c85ad86866a382e76d191bc98068a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 23:12:58 +0100 Subject: [PATCH 111/167] feat: update Glyph OLED controls --- config/glyph/config.cpp | 2 +- config/glyph/src/display/MenuButtonHints.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index e79a4d97..c3c67fb0 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -148,7 +148,7 @@ void setup1() { display, []() { display.clearDisplay(); }, []() { display.display(); }, - DisplayControls{ .back = BTN_MB4, .down = BTN_MB5, .up = BTN_MB6, .enter = BTN_MB7 }, + DisplayControls{ .back = BTN_MB1, .down = BTN_MB6, .up = BTN_MB5, .enter = BTN_MB7 }, display_modes, display_modes_count ); diff --git a/config/glyph/src/display/MenuButtonHints.cpp b/config/glyph/src/display/MenuButtonHints.cpp index 75a54482..6335f44b 100644 --- a/config/glyph/src/display/MenuButtonHints.cpp +++ b/config/glyph/src/display/MenuButtonHints.cpp @@ -16,7 +16,7 @@ void MenuButtonHints::HandleControls( const DisplayControls &controls, Button button ) { - if (button == controls.enter) { + if (button == controls.back) { instance->SetDisplayMode(DISPLAY_MODE_CONFIG); } } From 505318c7e9def05e2fe18a61a4807a081e8f7260 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 23:21:13 +0100 Subject: [PATCH 112/167] fix: missing break and wrong count --- config/glyph/include/glyph_overrides.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index a02683e7..d8502a90 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -4,7 +4,6 @@ #include "comms/B0XXInputViewer.hpp" #include "comms/IntegratedDisplay.hpp" #include "comms/NeoPixelBackend.hpp" -#include "config_defaults.hpp" #include "core/config_utils.hpp" #include "stdlib.hpp" @@ -17,7 +16,7 @@ // clang-format off const Config default_config = { - .game_mode_configs_count = 5, + .game_mode_configs_count = 6, .game_mode_configs = { GameModeConfig { .mode_id = MODE_MELEE, @@ -323,6 +322,7 @@ Config glyph_default_config() { case MODE_KEYBOARD: mode_config.applicable_backends[0] = COMMS_BACKEND_DINPUT; mode_config.applicable_backends_count = 1; + break; default: mode_config.layout_plate = LAYOUT_PLATE_EVERYTHING; } From 2bfc5ac39f6ca0fe7f4fe47abfa06e5619536a15 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Thu, 23 May 2024 23:24:28 +0100 Subject: [PATCH 113/167] fix: revert test default_mode_config values --- config/glyph/include/glyph_overrides.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index d8502a90..9f7485a0 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -133,11 +133,11 @@ const Config default_config = { .communication_backend_configs = { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_XINPUT, - .default_mode_config = 4, + .default_mode_config = 1, }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_DINPUT, - .default_mode_config = 5, + .default_mode_config = 1, .activation_binding_count = 1, .activation_binding = { BTN_RF3 }, }, From bccde9c75bf65d6a6ccdb8962bc7283e07b7149d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 24 May 2024 23:51:51 +0100 Subject: [PATCH 114/167] fix: RGB mode not being applied for keyboard modes --- HAL/avr/avr_nousb/include/core/KeyboardMode.hpp | 2 ++ HAL/avr/avr_usb/include/core/KeyboardMode.hpp | 2 ++ HAL/pico/include/comms/NeoPixelBackend.hpp | 2 +- HAL/pico/include/core/KeyboardMode.hpp | 2 ++ include/core/CommunicationBackend.hpp | 6 +++--- include/core/InputMode.hpp | 1 + src/core/CommunicationBackend.cpp | 4 ++-- src/core/mode_selection.cpp | 2 +- 8 files changed, 14 insertions(+), 7 deletions(-) diff --git a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp index 7a9f78b8..738027cc 100644 --- a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp @@ -12,6 +12,8 @@ class KeyboardMode : public InputMode { ~KeyboardMode(); void SendReport(const InputState &inputs); + void UpdateOutputs(const InputState &inputs, OutputState &outputs) {} + protected: void Press(uint8_t keycode, bool press); diff --git a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp index 3673c4ce..42e5a23b 100644 --- a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp @@ -13,6 +13,8 @@ class KeyboardMode : public InputMode { ~KeyboardMode(); void SendReport(const InputState &inputs); + void UpdateOutputs(const InputState &inputs, OutputState &outputs) {} + protected: void Press(uint8_t keycode, bool press); diff --git a/HAL/pico/include/comms/NeoPixelBackend.hpp b/HAL/pico/include/comms/NeoPixelBackend.hpp index 0c68575d..0b5e348a 100644 --- a/HAL/pico/include/comms/NeoPixelBackend.hpp +++ b/HAL/pico/include/comms/NeoPixelBackend.hpp @@ -30,7 +30,7 @@ template class NeoPixelBackend : public Commun ~NeoPixelBackend() { FastLED.clear(true); } - virtual void SetGameMode(ControllerMode *gamemode) { + virtual void SetGameMode(InputMode *gamemode) { // Clear current button colors. for (size_t i = 0; i < button_colors_count; i++) { _button_colors[i] = 0; diff --git a/HAL/pico/include/core/KeyboardMode.hpp b/HAL/pico/include/core/KeyboardMode.hpp index 8d978279..b32a09db 100644 --- a/HAL/pico/include/core/KeyboardMode.hpp +++ b/HAL/pico/include/core/KeyboardMode.hpp @@ -14,6 +14,8 @@ class KeyboardMode : public InputMode { ~KeyboardMode(); void SendReport(const InputState &inputs); + void UpdateOutputs(const InputState &inputs, OutputState &outputs) {} + protected: void Press(uint8_t keycode, bool press); diff --git a/include/core/CommunicationBackend.hpp b/include/core/CommunicationBackend.hpp index fc1a971c..fdcd73aa 100644 --- a/include/core/CommunicationBackend.hpp +++ b/include/core/CommunicationBackend.hpp @@ -20,8 +20,8 @@ class CommunicationBackend { virtual void UpdateOutputs(); virtual CommunicationBackendId BackendId(); - virtual void SetGameMode(ControllerMode *gamemode); - virtual ControllerMode *CurrentGameMode(); + virtual void SetGameMode(InputMode *gamemode); + virtual InputMode *CurrentGameMode(); virtual void SendReport() = 0; @@ -31,7 +31,7 @@ class CommunicationBackend { size_t _input_source_count; OutputState _outputs; - ControllerMode *_gamemode = nullptr; + InputMode *_gamemode = nullptr; private: void ResetOutputs(); diff --git a/include/core/InputMode.hpp b/include/core/InputMode.hpp index f7af0bdf..0e4d7803 100644 --- a/include/core/InputMode.hpp +++ b/include/core/InputMode.hpp @@ -11,6 +11,7 @@ class InputMode { InputMode(); GameModeConfig *GetConfig(); void SetConfig(GameModeConfig &config); + virtual void UpdateOutputs(const InputState &inputs, OutputState &outputs) = 0; protected: GameModeConfig *_config = nullptr; diff --git a/src/core/CommunicationBackend.cpp b/src/core/CommunicationBackend.cpp index f1cbcd6d..c7a756d5 100644 --- a/src/core/CommunicationBackend.cpp +++ b/src/core/CommunicationBackend.cpp @@ -51,10 +51,10 @@ CommunicationBackendId CommunicationBackend::BackendId() { return COMMS_BACKEND_UNSPECIFIED; } -void CommunicationBackend::SetGameMode(ControllerMode *gamemode) { +void CommunicationBackend::SetGameMode(InputMode *gamemode) { _gamemode = gamemode; } -ControllerMode *CommunicationBackend::CurrentGameMode() { +InputMode *CommunicationBackend::CurrentGameMode() { return _gamemode; } diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index c6027dd5..270df100 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -38,7 +38,7 @@ void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { current_kb_mode = mode; // Unset the current controller mode so backend only gives neutral inputs. - backend->SetGameMode(nullptr); + backend->SetGameMode(mode); } void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config) { From f423ab466bcfe61d247c3ea1938325ea0ed30c6c Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 24 May 2024 23:59:54 +0100 Subject: [PATCH 115/167] feat: NES/SNES autodetection --- HAL/pico/src/comms/console_detection.cpp | 42 +++++++++++++++++++----- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/HAL/pico/src/comms/console_detection.cpp b/HAL/pico/src/comms/console_detection.cpp index eb86b968..dd30e821 100644 --- a/HAL/pico/src/comms/console_detection.cpp +++ b/HAL/pico/src/comms/console_detection.cpp @@ -7,18 +7,44 @@ #include #include +uint latch_pulses = 0; +uint clock_pulses = 0; + +void latch_irq_handler() { + latch_pulses++; +} + +void clock_irq_handler() { + clock_pulses++; +} + CommunicationBackendId detect_console(const Pinout &pinout) { + if (pinout.nes_latch > -1 && pinout.nes_clock > -1) { + attachInterrupt(pinout.nes_latch, &latch_irq_handler, PinStatus::RISING); + attachInterrupt(pinout.nes_clock, &clock_irq_handler, PinStatus::FALLING); + } + delay(500); bool usb_connected = usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS; - if (usb_connected) { - return COMMS_BACKEND_XINPUT; + if (pinout.nes_latch > -1 && pinout.nes_clock > -1) { + detachInterrupt(pinout.nes_latch); + detachInterrupt(pinout.nes_clock); } - if (GamecubeConsole(pinout.joybus_data).Detect()) { - return COMMS_BACKEND_GAMECUBE; - } - if (N64Console(pinout.joybus_data).Detect()) { - return COMMS_BACKEND_N64; + + CommunicationBackendId result = COMMS_BACKEND_UNSPECIFIED; + + if (usb_connected) { + result = COMMS_BACKEND_XINPUT; + } else if (latch_pulses && (clock_pulses / latch_pulses) > 8) { + result = COMMS_BACKEND_SNES; + } else if (latch_pulses && (clock_pulses / latch_pulses) > 1) { + result = COMMS_BACKEND_NES; + } else if (GamecubeConsole(pinout.joybus_data).Detect()) { + result = COMMS_BACKEND_GAMECUBE; + } else if (N64Console(pinout.joybus_data).Detect()) { + result = COMMS_BACKEND_N64; } - return COMMS_BACKEND_UNSPECIFIED; + + return result; } \ No newline at end of file From ff0bb2ed723af8d3cb48c97d0dd2845e5f588fe9 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 25 May 2024 00:00:24 +0100 Subject: [PATCH 116/167] feat: add RGB config for default keyboard mode --- config/glyph/include/glyph_overrides.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 9f7485a0..4912ded4 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -322,6 +322,7 @@ Config glyph_default_config() { case MODE_KEYBOARD: mode_config.applicable_backends[0] = COMMS_BACKEND_DINPUT; mode_config.applicable_backends_count = 1; + mode_config.rgb_config = 1; break; default: mode_config.layout_plate = LAYOUT_PLATE_EVERYTHING; @@ -354,7 +355,7 @@ size_t init_secondary_backends_glyph( // Create new array containing all old backends but with length increased by 1 to make space for // NeoPixel backend. - CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 2]; + CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 1]; for (size_t i = 0; i < backend_count; i++) { new_backends[i] = backends[i]; } From 9eafeb84ea016cf4c9173bfaf7a8dfb329c13971 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 25 May 2024 19:47:31 +0100 Subject: [PATCH 117/167] ci: set fail-fast = false --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index de522c60..3251d009 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,6 +10,7 @@ jobs: env: VERSION_REF: ${{ github.ref_type == 'tag' && github.ref_name || github.sha }} strategy: + fail-fast: false matrix: include: - env: c53 From 8e3aedc4c1ebdf9f305bb03cef238be87baa410a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 25 May 2024 20:32:10 +0100 Subject: [PATCH 118/167] ci: add build-device-config reusable Action --- .github/workflows/build-device-config.yaml | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .github/workflows/build-device-config.yaml diff --git a/.github/workflows/build-device-config.yaml b/.github/workflows/build-device-config.yaml new file mode 100644 index 00000000..d274d267 --- /dev/null +++ b/.github/workflows/build-device-config.yaml @@ -0,0 +1,90 @@ +name: Build device config + +on: [workflow_call] + +jobs: + metadata: + runs-on: ubuntu-latest + name: Parse config metadata + outputs: + meta_json: ${{ steps.parse_yaml.outputs.metadata }} + build_matrix: ${{ steps.parse_yaml.outputs.metadata.build }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install yaml2json + run: python3 -m pip install remarshal + + - name: Read metadata from yaml file + id: parse_yaml + run: | + echo "metadata=$(yaml2json 'meta.yaml')" >> "$GITHUB_OUTPUT" + + build: + runs-on: ubuntu-latest + permissions: + contents: write + needs: metadata + env: + HAYBOX_REPO: ${{ fromJson(needs.metadata.outputs.meta_json).repo }} + HAYBOX_REVISION: ${{ fromJson(needs.metadata.outputs.meta_json).revision }} + DEVICE_CONFIG_REVISION: ${{ github.ref_type == 'tag' && github.ref_name || github.sha }} + PIO_ENV: ${{ matrix.env }} + BIN_EXT: ${{ matrix.bin_ext }} + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(needs.metadata.outputs.meta_json).build }} + + steps: + - name: Check out HayBox repo + uses: actions/checkout@v4 + with: + repository: ${{ env.HAYBOX_REPO }} + + - name: Check out specific HayBox revision + run: | + git checkout "$HAYBOX_REVISION" + + - name: Check out config repo + uses: actions/checkout@v4 + with: + path: config/device + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + + - name: Set artifact filename environment variable + run: | + echo "ARTIFACT_NAME=HayBox-${HAYBOX_REVISION}-${PIO_ENV}-${DEVICE_CONFIG_REVISION}.${BIN_EXT}" >> "$GITHUB_ENV" + + - name: Set artifact path environment variable + run: | + echo "ARTIFACT_PATH=${PIO_ENV}/${ARTIFACT_NAME}" >> "$GITHUB_ENV" + + - name: Build ${{ matrix.env }} env + run: | + pio run -e "$PIO_ENV" + mkdir -p "$PIO_ENV" + + cp ".pio/build/${PIO_ENV}/firmware.${BIN_EXT}" "$ARTIFACT_PATH" + + - name: Publish ${{ matrix.env }} artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ env.ARTIFACT_NAME }} + path: ${{ env.ARTIFACT_PATH }} + + - name: Upload binaries to release + uses: softprops/action-gh-release@v1 + if: github.ref_type == 'tag' + with: + files: ${{ env.ARTIFACT_PATH }} From c74261c77457f360c5eebc7859c35a1e8b9e9a58 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 25 May 2024 20:34:23 +0100 Subject: [PATCH 119/167] ci: rename yaml -> yml --- .../{build-device-config.yaml => build-device-config.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{build-device-config.yaml => build-device-config.yml} (100%) diff --git a/.github/workflows/build-device-config.yaml b/.github/workflows/build-device-config.yml similarity index 100% rename from .github/workflows/build-device-config.yaml rename to .github/workflows/build-device-config.yml From e4b6956fb14907524155ead679d73d1208f20f0e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 25 May 2024 20:50:36 +0100 Subject: [PATCH 120/167] ci: update repo checkout path for device config build --- .github/workflows/build-device-config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-device-config.yml b/.github/workflows/build-device-config.yml index d274d267..d94ea463 100644 --- a/.github/workflows/build-device-config.yml +++ b/.github/workflows/build-device-config.yml @@ -42,6 +42,7 @@ jobs: uses: actions/checkout@v4 with: repository: ${{ env.HAYBOX_REPO }} + path: . - name: Check out specific HayBox revision run: | From 7d9c2be0faa36eea9b169d4e91e45e72142b0d0e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 25 May 2024 20:55:00 +0100 Subject: [PATCH 121/167] ci: revert to manual command for git clone --- .github/workflows/build-device-config.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/build-device-config.yml b/.github/workflows/build-device-config.yml index d94ea463..fe7ed52b 100644 --- a/.github/workflows/build-device-config.yml +++ b/.github/workflows/build-device-config.yml @@ -38,14 +38,9 @@ jobs: include: ${{ fromJson(needs.metadata.outputs.meta_json).build }} steps: - - name: Check out HayBox repo - uses: actions/checkout@v4 - with: - repository: ${{ env.HAYBOX_REPO }} - path: . - - name: Check out specific HayBox revision run: | + git clone "$HAYBOX_REPO" . git checkout "$HAYBOX_REVISION" - name: Check out config repo From 35b965467821a3714718e2ed0603b9c8f3bb7660 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 25 May 2024 20:56:46 +0100 Subject: [PATCH 122/167] ci: fix git clone path --- .github/workflows/build-device-config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-device-config.yml b/.github/workflows/build-device-config.yml index fe7ed52b..8f443189 100644 --- a/.github/workflows/build-device-config.yml +++ b/.github/workflows/build-device-config.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Check out specific HayBox revision run: | - git clone "$HAYBOX_REPO" . + git clone "https://github.com/$HAYBOX_REPO" . git checkout "$HAYBOX_REVISION" - name: Check out config repo From f417dc562febeb4fd27c517005ba2448d73213b6 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 26 May 2024 11:22:39 +0100 Subject: [PATCH 123/167] ci: use setup-python@v5 --- .github/workflows/build-device-config.yml | 2 +- .github/workflows/build.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-device-config.yml b/.github/workflows/build-device-config.yml index 8f443189..aea2f77d 100644 --- a/.github/workflows/build-device-config.yml +++ b/.github/workflows/build-device-config.yml @@ -49,7 +49,7 @@ jobs: path: config/device - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.10' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3251d009..99b346ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.10' From 51e9e51bbb135c9ccfed39c975ce39a86e969a12 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 May 2024 00:30:37 +0100 Subject: [PATCH 124/167] fix: use static Persistence instance in pico config --- config/pico/config.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/config/pico/config.cpp b/config/pico/config.cpp index cae924d4..68a5c754 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -77,11 +77,9 @@ void setup() { gpio_put(PICO_DEFAULT_LED_PIN, 1); // Attempt to load config, or write default config to flash if failed to load config. - Persistence *persistence = new Persistence(); - if (!persistence->LoadConfig(config)) { - persistence->SaveConfig(config); + if (!persistence.LoadConfig(config)) { + persistence.SaveConfig(config); } - delete persistence; // Create array of input sources to be used. static InputSource *input_sources[] = {}; From 7a7baa37857fa5facf853b9f2960c04116552f69 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 May 2024 16:34:28 +0100 Subject: [PATCH 125/167] chore: clean up duplicated coords in Ultimate mode --- src/modes/Ultimate.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/modes/Ultimate.cpp b/src/modes/Ultimate.cpp index 13b3f64a..b52a64a3 100644 --- a/src/modes/Ultimate.cpp +++ b/src/modes/Ultimate.cpp @@ -69,26 +69,15 @@ void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickY = 128 + (directions.y * 51); } } - if (directions.diagonal) { - // MX + q1/2/3/4 = 53 35 - outputs.leftStickX = 128 + (directions.x * 53); - outputs.leftStickY = 128 + (directions.y * 35); - if (shield_button_pressed) { - // MX + L, R, LS, and MS + q1/2/3/4 = 6375 3750 = 51 30 - outputs.leftStickX = 128 + (directions.x * 51); - outputs.leftStickY = 128 + (directions.y * 30); - } - } - - // Angled fsmash/ftilt with C-Stick + MX - if (directions.cx != 0) { - outputs.rightStickX = 128 + (directions.cx * 127); - outputs.rightStickY = 128 + (directions.y * 59); + if (directions.diagonal && shield_button_pressed) { + // MX + L, R, LS, and MS + q1/2/3/4 = 6375 3750 = 51 30 + outputs.leftStickX = 128 + (directions.x * 51); + outputs.leftStickY = 128 + (directions.y * 30); } /* Up B angles */ if (directions.diagonal && !shield_button_pressed) { - // (33.44) = 53 35 + // MX + q1/2/3/4 = 33.44 degrees | 53 35 outputs.leftStickX = 128 + (directions.x * 53); outputs.leftStickY = 128 + (directions.y * 35); // (39.05) = 53 43 @@ -139,6 +128,12 @@ void Ultimate::UpdateAnalogOutputs(const InputState &inputs, OutputState &output } } + // Angled fsmash/ftilt with C-Stick + MX + if (directions.cx != 0) { + outputs.rightStickX = 128 + (directions.cx * 127); + outputs.rightStickY = 128 + (directions.y * 59); + } + // Angled Ftilts if (inputs.rt1) { outputs.leftStickX = 128 + (directions.x * 36); From 9ebdc81792352a4c28da26a5a79c6c01a87451e3 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 May 2024 16:35:14 +0100 Subject: [PATCH 126/167] feat: only allow keyboard mode with DInputBackend --- src/core/mode_selection.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 270df100..4e8c44e0 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -34,6 +34,11 @@ void set_mode(CommunicationBackend *backend, ControllerMode *mode) { } void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { + // Only DInputBackend supports keyboard modes. + if (backend->BackendId() != COMMS_BACKEND_DINPUT) { + return; + } + // Delete and reassign current keyboard mode. current_kb_mode = mode; From 6df21d51bd292b9668d13fd1274fada0d330350d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 May 2024 18:42:30 +0100 Subject: [PATCH 127/167] feat: add dashboard option support for Glyph --- HAL/pico/include/display/ConfigMenu.hpp | 28 +-- .../include/display/DefaultConfigMenu.hpp | 40 +++ HAL/pico/src/display/ConfigMenu.cpp | 221 +---------------- HAL/pico/src/display/DefaultConfigMenu.cpp | 234 ++++++++++++++++++ config/glyph/config.cpp | 5 +- config/glyph/env.ini | 2 +- .../glyph/include/display/GlyphConfigMenu.hpp | 13 +- config/glyph/include/glyph_overrides.hpp | 38 ++- config/glyph/src/display/GlyphConfigMenu.cpp | 55 +++- 9 files changed, 382 insertions(+), 254 deletions(-) create mode 100644 HAL/pico/include/display/DefaultConfigMenu.hpp create mode 100644 HAL/pico/src/display/DefaultConfigMenu.cpp diff --git a/HAL/pico/include/display/ConfigMenu.hpp b/HAL/pico/include/display/ConfigMenu.hpp index 07ed086e..55e4b5f1 100644 --- a/HAL/pico/include/display/ConfigMenu.hpp +++ b/HAL/pico/include/display/ConfigMenu.hpp @@ -33,7 +33,6 @@ typedef struct _MenuPage { class ConfigMenu : public DisplayMode { public: ConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count); - ~ConfigMenu(); DisplayModeId GetId(); virtual void HandleControls( IntegratedDisplay *instance, @@ -41,36 +40,15 @@ class ConfigMenu : public DisplayMode { Button button ); virtual void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); + virtual void ReturnToDashboard(IntegratedDisplay *instance); protected: - static void SetDefaultMode( - IntegratedDisplay *instance, - ConfigMenu *menu, - Config &config, - uint8_t mode_config_index - ); - static void SetDefaultUsbBackend( - IntegratedDisplay *instance, - ConfigMenu *menu, - Config &config, - uint8_t backend_config_index - ); - static void SetSocdType( - IntegratedDisplay *instance, - ConfigMenu *menu, - Config &config, - uint8_t socd_type - ); - Config &_config; CommunicationBackend **_backends; size_t _backends_count; - MenuPage _usb_backends_page; - MenuPage _gamemode_options_page; - MenuPage _top_level_page; - - MenuPage *_current_menu_page = &_top_level_page; + MenuPage *_top_level_page = nullptr; + MenuPage *_current_menu_page = nullptr; uint8_t _highlighted_menu_item = 0; int _current_menu_offset = 0; diff --git a/HAL/pico/include/display/DefaultConfigMenu.hpp b/HAL/pico/include/display/DefaultConfigMenu.hpp new file mode 100644 index 00000000..5b69f124 --- /dev/null +++ b/HAL/pico/include/display/DefaultConfigMenu.hpp @@ -0,0 +1,40 @@ +#ifndef _DISPLAY_DEFAULTCONFIGMENU_HPP +#define _DISPLAY_DEFAULTCONFIGMENU_HPP + +#include "display/ConfigMenu.hpp" + +class DefaultConfigMenu : public ConfigMenu { + public: + DefaultConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count); + ~DefaultConfigMenu(); + + protected: + static void SetDefaultMode( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t mode_config_index + ); + static void SetDefaultUsbBackend( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t backend_config_index + ); + static void SetSocdType( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t socd_type + ); + + MenuPage _usb_backends_page; + MenuPage _gamemode_options_page; + + private: + static constexpr uint8_t padding = 2; + static constexpr uint8_t max_visible_lines = 6; + static constexpr char highlight_string[] = ">"; +}; + +#endif \ No newline at end of file diff --git a/HAL/pico/src/display/ConfigMenu.cpp b/HAL/pico/src/display/ConfigMenu.cpp index 0b2a687f..9fb52d1f 100644 --- a/HAL/pico/src/display/ConfigMenu.cpp +++ b/HAL/pico/src/display/ConfigMenu.cpp @@ -8,168 +8,7 @@ ConfigMenu::ConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count) : _config(config), _backends(backends), - _backends_count(backends_count) { - /* Build default USB backends page */ - MenuPage::MenuItem *usb_backend_options = - new MenuPage::MenuItem[config.communication_backend_configs_count]; - - size_t usb_backend_options_count = 0; - for (size_t i = 0; i < config.communication_backend_configs_count; i++) { - CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; - MenuPage::MenuItem ¤t_option = usb_backend_options[usb_backend_options_count]; - - if (backend_config.backend_id != COMMS_BACKEND_XINPUT && - backend_config.backend_id != COMMS_BACKEND_DINPUT && - backend_config.backend_id != COMMS_BACKEND_NINTENDO_SWITCH) { - continue; - } - - strlcpy( - current_option.text, - backend_name(backend_config.backend_id), - sizeof(current_option.text) - ); - current_option.key = i; - current_option.action = &SetDefaultUsbBackend; - usb_backend_options_count++; - } - - _usb_backends_page = { - .items = usb_backend_options, - .items_count = usb_backend_options_count, - }; - - /* Build gamemodes page */ - MenuPage::MenuItem *gamemode_options = new MenuPage::MenuItem[config.game_mode_configs_count]; - - size_t gamemode_options_count = 0; - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode_config = config.game_mode_configs[i]; - MenuPage::MenuItem ¤t_option = gamemode_options[gamemode_options_count]; - - // Don't show keyboard modes as a gamemode option unless using DInputBackend. - if (_backends_count > 0 && _backends[0] != nullptr) { - CommunicationBackendId primary_backend_id = _backends[0]->BackendId(); - if (primary_backend_id != COMMS_BACKEND_DINPUT && - mode_config.mode_id == MODE_KEYBOARD) { - continue; - } - } - - if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { - strlcpy(current_option.text, mode_config.name, sizeof(current_option.text)); - } else { - strlcpy( - current_option.text, - gamemode_name(mode_config.mode_id), - sizeof(current_option.text) - ); - } - current_option.key = i; - current_option.action = &SetDefaultMode; - gamemode_options_count++; - } - - _gamemode_options_page = { - .items = gamemode_options, - .items_count = gamemode_options_count, - }; - - /* Build SOCD types page */ - static MenuPage::MenuItem socd_options[_SocdType_MAX] = {}; - for (uint8_t socd_type = SOCD_NEUTRAL; socd_type < _SocdType_ARRAYSIZE; socd_type++) { - MenuPage::MenuItem ¤t_option = socd_options[socd_type - 1]; - strlcpy(current_option.text, socd_name((SocdType)socd_type), sizeof(current_option.text)); - current_option.key = socd_type; - current_option.action = &SetSocdType; - } - - static MenuPage socd_page = { - .items = socd_options, - .items_count = sizeof(socd_options) / sizeof(MenuPage::MenuItem), - }; - - /* Build top-level page */ - // clang-format off - static MenuPage::MenuItem top_level_items[] = { - { - .text = "Profile", - .page = &_gamemode_options_page, - }, - { - .text = "Default USB Mode", - .page = &_usb_backends_page, - }, - { - .text = "SOCD Option", - .page = &socd_page, - }, - { - .text = "RGB Brightness", - .action = []( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t key - ) { - display_backend->SetDisplayMode(DISPLAY_MODE_RGB_BRIGHTNESS); - }, - }, - { - .text = "Input Viewer", - .action = []( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t key - ) { - // Restore gamemode. - if (menu->_backends[0] != nullptr) { - menu->_backends[0]->SetGameMode(display_backend->CurrentGameMode()); - } - display_backend->SetDisplayMode(DISPLAY_MODE_VIEWER); - }, - }, - { - .text = "Save changes", - .action = []( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t key - ) { - persistence.SaveConfig(config); - reboot_firmware(); - }, - }, - { - .text = "Discard changes", - .action = []( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t key - ) { - reboot_firmware(); - }, - } - }; - // clang-format on - - _top_level_page = { - .items = top_level_items, - .items_count = sizeof(top_level_items) / sizeof(MenuPage::MenuItem), - }; - - _usb_backends_page.parent = &_top_level_page; - _gamemode_options_page.parent = &_top_level_page; - socd_page.parent = &_top_level_page; -} - -ConfigMenu::~ConfigMenu() { - delete[] _usb_backends_page.items; - delete[] _gamemode_options_page.items; -} + _backends_count(backends_count) {} DisplayModeId ConfigMenu::GetId() { return DISPLAY_MODE_CONFIG; @@ -181,7 +20,7 @@ void ConfigMenu::HandleControls( Button button ) { if (_current_menu_page == nullptr) { - _current_menu_page = &_top_level_page; + _current_menu_page = _top_level_page; _current_menu_offset = 0; return; } @@ -227,7 +66,7 @@ void ConfigMenu::HandleControls( if (_backends[0] != nullptr) { _backends[0]->SetGameMode(instance->CurrentGameMode()); } - instance->SetDisplayMode(DISPLAY_MODE_BUTTON_HINTS); + ReturnToDashboard(instance); return; } @@ -263,56 +102,6 @@ void ConfigMenu::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &displa } } -void ConfigMenu::SetDefaultMode( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t mode_config_index -) { - if (mode_config_index < 0 || mode_config_index >= config.game_mode_configs_count) { - return; - } - - // Overwrite default game mode for all backend configs. - for (size_t i = 0; i < config.communication_backend_configs_count; i++) { - config.communication_backend_configs[i].default_mode_config = mode_config_index + 1; - } - - // Update mode for all backends. - for (size_t i = 0; i < menu->_backends_count; i++) { - set_mode(menu->_backends[i], config.game_mode_configs[mode_config_index], config); - } - set_mode(display_backend, config.game_mode_configs[mode_config_index], config); -} - -void ConfigMenu::SetDefaultUsbBackend( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t backend_config_index -) { - if (backend_config_index < 0 || - backend_config_index >= config.communication_backend_configs_count) { - return; - } - config.default_usb_backend_config = backend_config_index + 1; -} - -void ConfigMenu::SetSocdType( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t socd_type -) { - if (socd_type <= SOCD_UNSPECIFIED || socd_type > _SocdType_MAX) { - return; - } - - // Overwrite SOCD type for all SOCD pairs of current gamemode's config. - GameModeConfig *mode_config = display_backend->CurrentGameMode()->GetConfig(); - if (mode_config != nullptr) { - for (size_t i = 0; i < mode_config->socd_pairs_count; i++) { - mode_config->socd_pairs[i].socd_type = (SocdType)socd_type; - } - } +void ConfigMenu::ReturnToDashboard(IntegratedDisplay *instance) { + instance->SetDisplayMode(DISPLAY_MODE_VIEWER); } \ No newline at end of file diff --git a/HAL/pico/src/display/DefaultConfigMenu.cpp b/HAL/pico/src/display/DefaultConfigMenu.cpp new file mode 100644 index 00000000..91dbf5d0 --- /dev/null +++ b/HAL/pico/src/display/DefaultConfigMenu.cpp @@ -0,0 +1,234 @@ +#include "display/DefaultConfigMenu.hpp" + +#include "core/Persistence.hpp" +#include "core/config_utils.hpp" +#include "core/mode_selection.hpp" +#include "reboot.hpp" + +DefaultConfigMenu::DefaultConfigMenu( + Config &config, + CommunicationBackend **backends, + size_t backends_count +) + : ConfigMenu(config, backends, backends_count) { + /* Build default USB backends page */ + MenuPage::MenuItem *usb_backend_options = + new MenuPage::MenuItem[config.communication_backend_configs_count]; + + size_t usb_backend_options_count = 0; + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + CommunicationBackendConfig &backend_config = config.communication_backend_configs[i]; + MenuPage::MenuItem ¤t_option = usb_backend_options[usb_backend_options_count]; + + if (backend_config.backend_id != COMMS_BACKEND_XINPUT && + backend_config.backend_id != COMMS_BACKEND_DINPUT && + backend_config.backend_id != COMMS_BACKEND_NINTENDO_SWITCH) { + continue; + } + + strlcpy( + current_option.text, + backend_name(backend_config.backend_id), + sizeof(current_option.text) + ); + current_option.key = i; + current_option.action = &SetDefaultUsbBackend; + usb_backend_options_count++; + } + + _usb_backends_page = { + .items = usb_backend_options, + .items_count = usb_backend_options_count, + }; + + /* Build gamemodes page */ + MenuPage::MenuItem *gamemode_options = new MenuPage::MenuItem[config.game_mode_configs_count]; + + size_t gamemode_options_count = 0; + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + MenuPage::MenuItem ¤t_option = gamemode_options[gamemode_options_count]; + + // Don't show keyboard modes as a gamemode option unless using DInputBackend. + if (_backends_count > 0 && _backends[0] != nullptr) { + CommunicationBackendId primary_backend_id = _backends[0]->BackendId(); + if (primary_backend_id != COMMS_BACKEND_DINPUT && + mode_config.mode_id == MODE_KEYBOARD) { + continue; + } + } + + if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { + strlcpy(current_option.text, mode_config.name, sizeof(current_option.text)); + } else { + strlcpy( + current_option.text, + gamemode_name(mode_config.mode_id), + sizeof(current_option.text) + ); + } + current_option.key = i; + current_option.action = &SetDefaultMode; + gamemode_options_count++; + } + + _gamemode_options_page = { + .items = gamemode_options, + .items_count = gamemode_options_count, + }; + + /* Build SOCD types page */ + static MenuPage::MenuItem socd_options[_SocdType_MAX] = {}; + for (uint8_t socd_type = SOCD_NEUTRAL; socd_type < _SocdType_ARRAYSIZE; socd_type++) { + MenuPage::MenuItem ¤t_option = socd_options[socd_type - 1]; + strlcpy(current_option.text, socd_name((SocdType)socd_type), sizeof(current_option.text)); + current_option.key = socd_type; + current_option.action = &SetSocdType; + } + + static MenuPage socd_page = { + .items = socd_options, + .items_count = sizeof(socd_options) / sizeof(MenuPage::MenuItem), + }; + + /* Build top-level page */ + // clang-format off + static MenuPage::MenuItem top_level_items[] = { + { + .text = "Profile", + .page = &_gamemode_options_page, + }, + { + .text = "Default USB Mode", + .page = &_usb_backends_page, + }, + { + .text = "SOCD Mode", + .page = &socd_page, + }, + { + .text = "RGB Brightness", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + display_backend->SetDisplayMode(DISPLAY_MODE_RGB_BRIGHTNESS); + }, + }, + { + .text = "Input Viewer", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + // Restore gamemode. + DefaultConfigMenu *config_menu = (DefaultConfigMenu*)menu; + if (config_menu->_backends[0] != nullptr) { + config_menu->_backends[0]->SetGameMode(display_backend->CurrentGameMode()); + } + display_backend->SetDisplayMode(DISPLAY_MODE_VIEWER); + }, + }, + { + .text = "Save changes", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + persistence.SaveConfig(config); + reboot_firmware(); + }, + }, + { + .text = "Discard changes", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + reboot_firmware(); + }, + } + }; + // clang-format on + + static MenuPage top_level_page = { + .items = top_level_items, + .items_count = sizeof(top_level_items) / sizeof(MenuPage::MenuItem), + }; + _top_level_page = &top_level_page; + + _usb_backends_page.parent = _top_level_page; + _gamemode_options_page.parent = _top_level_page; + socd_page.parent = _top_level_page; + + // Set initial page. + _current_menu_page = _top_level_page; +} + +DefaultConfigMenu::~DefaultConfigMenu() { + delete[] _usb_backends_page.items; + delete[] _gamemode_options_page.items; +} + +void DefaultConfigMenu::SetDefaultMode( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t mode_config_index +) { + if (mode_config_index < 0 || mode_config_index >= config.game_mode_configs_count) { + return; + } + + // Overwrite default game mode for all backend configs. + for (size_t i = 0; i < config.communication_backend_configs_count; i++) { + config.communication_backend_configs[i].default_mode_config = mode_config_index + 1; + } + + // Update mode for all backends. + DefaultConfigMenu *config_menu = (DefaultConfigMenu *)menu; + for (size_t i = 0; i < config_menu->_backends_count; i++) { + set_mode(config_menu->_backends[i], config.game_mode_configs[mode_config_index], config); + } + set_mode(display_backend, config.game_mode_configs[mode_config_index], config); +} + +void DefaultConfigMenu::SetDefaultUsbBackend( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t backend_config_index +) { + if (backend_config_index < 0 || + backend_config_index >= config.communication_backend_configs_count) { + return; + } + config.default_usb_backend_config = backend_config_index + 1; +} + +void DefaultConfigMenu::SetSocdType( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t socd_type +) { + if (socd_type <= SOCD_UNSPECIFIED || socd_type > _SocdType_MAX) { + return; + } + + // Overwrite SOCD type for all SOCD pairs of current gamemode's config. + GameModeConfig *mode_config = display_backend->CurrentGameMode()->GetConfig(); + if (mode_config != nullptr) { + for (size_t i = 0; i < mode_config->socd_pairs_count; i++) { + mode_config->socd_pairs[i].socd_type = (SocdType)socd_type; + } + } +} \ No newline at end of file diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp index c3c67fb0..a2cbae3b 100644 --- a/config/glyph/config.cpp +++ b/config/glyph/config.cpp @@ -153,7 +153,10 @@ void setup1() { display_modes_count ); // clang-format on - display_backend->SetDisplayMode(DISPLAY_MODE_BUTTON_HINTS); + display_backend->SetDisplayMode( + config.default_dashboard_option == DASHBOARD_INPUT_VIEWER ? DISPLAY_MODE_VIEWER + : DISPLAY_MODE_BUTTON_HINTS + ); } } diff --git a/config/glyph/env.ini b/config/glyph/env.ini index 3290c926..2e02aecc 100644 --- a/config/glyph/env.ini +++ b/config/glyph/env.ini @@ -12,4 +12,4 @@ lib_ignore = https://github.com/JonnyHaystack/HayBox-proto lib_deps = ${arduino_pico_base.lib_deps} - https://github.com/LimitLabs/HayBox-proto#bec35e5 \ No newline at end of file + https://github.com/LimitLabs/HayBox-proto#3b7abdf \ No newline at end of file diff --git a/config/glyph/include/display/GlyphConfigMenu.hpp b/config/glyph/include/display/GlyphConfigMenu.hpp index 340e7bc9..775db523 100644 --- a/config/glyph/include/display/GlyphConfigMenu.hpp +++ b/config/glyph/include/display/GlyphConfigMenu.hpp @@ -1,15 +1,24 @@ #ifndef _DISPLAY_GLYPHCONFIGMENU_HPP #define _DISPLAY_GLYPHCONFIGMENU_HPP -#include "display/ConfigMenu.hpp" +#include "display/DefaultConfigMenu.hpp" /** * @brief Modified version of ConfigMenu that only shows gamemodes marked as applicable for current * CommunicationBackend. */ -class GlyphConfigMenu : public ConfigMenu { +class GlyphConfigMenu : public DefaultConfigMenu { public: GlyphConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count); + void ReturnToDashboard(IntegratedDisplay *instance); + + private: + static void SetDashboardOption( + IntegratedDisplay *instance, + ConfigMenu *menu, + Config &config, + uint8_t mode_config_index + ); }; #endif \ No newline at end of file diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 4912ded4..91f7fa2e 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -27,8 +27,13 @@ const Config default_config = { SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, }, - .button_remapping_count = 0, - .activation_binding_count = 3, + .button_remapping_count = 4, + .button_remapping = { + ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, // Menu + ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, // Start + ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_MB3 }, // Back + ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_MB2 }, // Home + }, .rgb_config = 1, }, GameModeConfig { @@ -40,8 +45,13 @@ const Config default_config = { SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, }, - .button_remapping_count = 0, - .activation_binding_count = 3, + .button_remapping_count = 4, + .button_remapping = { + ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, // Menu + ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, // Start + ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_MB3 }, // Back + ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_MB2 }, // Home + }, .rgb_config = 1, }, GameModeConfig { @@ -53,8 +63,13 @@ const Config default_config = { SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, }, - .button_remapping_count = 0, - .activation_binding_count = 3, + .button_remapping_count = 4, + .button_remapping = { + ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, // Menu + ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, // Start + ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_MB3 }, // Back + ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_MB2 }, // Home + }, .rgb_config = 1, }, GameModeConfig { @@ -65,6 +80,15 @@ const Config default_config = { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, }, + .button_remapping_count = 6, + .button_remapping = { + ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_RT3 }, + ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_RT2 }, + ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, + ButtonRemap { .physical_button = BTN_RT2, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_RT3, .activates = BTN_UNSPECIFIED }, + ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, + }, .rgb_config = 1, .layout_plate = LAYOUT_PLATE_SPLIT_FGC, }, @@ -113,7 +137,6 @@ const Config default_config = { ButtonRemap { .physical_button = BTN_RT3, .activates = BTN_UNSPECIFIED }, ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, }, - .activation_binding_count = 3, .rgb_config = 2, .layout_plate = LAYOUT_PLATE_FGC, }, @@ -125,7 +148,6 @@ const Config default_config = { SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, }, .button_remapping_count = 0, - .activation_binding_count = 3, .keyboard_mode_config = 1, }, }, diff --git a/config/glyph/src/display/GlyphConfigMenu.cpp b/config/glyph/src/display/GlyphConfigMenu.cpp index b02950ec..cf91f7bb 100644 --- a/config/glyph/src/display/GlyphConfigMenu.cpp +++ b/config/glyph/src/display/GlyphConfigMenu.cpp @@ -10,7 +10,7 @@ GlyphConfigMenu::GlyphConfigMenu( CommunicationBackend **backends, size_t backends_count ) - : ConfigMenu(config, backends, backends_count) { + : DefaultConfigMenu(config, backends, backends_count) { /* Build gamemodes page */ size_t gamemode_options_count = 0; for (size_t i = 0; i < config.game_mode_configs_count; i++) { @@ -47,4 +47,57 @@ GlyphConfigMenu::GlyphConfigMenu( gamemode_options_count++; } _gamemode_options_page.items_count = gamemode_options_count; + + /* Add new page for dashboard option */ + // clang-format off + size_t dashboard_options_count = 2; + static MenuPage::MenuItem dashboard_options[] = { + { + .text = "Dashboard Menu", + .key = DASHBOARD_MENU_BUTTON_HINTS, + .action = &SetDashboardOption, + }, + { + .text = "Input Viewer", + .key = DASHBOARD_INPUT_VIEWER, + .action = &SetDashboardOption, + }, + }; + // clang-format on + + static MenuPage dashboard_options_page = { + .parent = _top_level_page, + .items = dashboard_options, + .items_count = sizeof(dashboard_options) / sizeof(MenuPage::MenuItem), + }; + + /* Overrides for top-level page */ + strlcpy(_top_level_page->items[2].text, "SOCD Option", sizeof(_top_level_page->items[2].text)); + _top_level_page->items[4] = { + .text = "Dashboard Option", + .page = &dashboard_options_page, + }; +} + +void GlyphConfigMenu::ReturnToDashboard(IntegratedDisplay *instance) { + instance->SetDisplayMode( + _config.default_dashboard_option == DASHBOARD_INPUT_VIEWER ? DISPLAY_MODE_VIEWER + : DISPLAY_MODE_BUTTON_HINTS + ); +} + +void GlyphConfigMenu::SetDashboardOption( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t dashboard_option +) { + // Restore gamemode. + GlyphConfigMenu *config_menu = (GlyphConfigMenu *)menu; + if (config_menu->_backends[0] != nullptr) { + config_menu->_backends[0]->SetGameMode(display_backend->CurrentGameMode()); + } + + config.default_dashboard_option = (DashboardOption)dashboard_option; + config_menu->ReturnToDashboard(display_backend); } \ No newline at end of file From 3fbe2c9c9f13954e37b6e8e0f4acad2c49fa6e1e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 May 2024 18:42:55 +0100 Subject: [PATCH 128/167] chore: clean up default Pico config --- HAL/pico/include/config_defaults.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 65282faf..21859a8e 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -21,7 +21,6 @@ const Config default_config = { .button_remapping_count = 0, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, - .rgb_config = 1, }, GameModeConfig { .mode_id = MODE_PROJECT_M, @@ -35,7 +34,6 @@ const Config default_config = { .button_remapping_count = 0, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF3 }, - .rgb_config = 1, }, GameModeConfig { .mode_id = MODE_ULTIMATE, @@ -49,7 +47,6 @@ const Config default_config = { .button_remapping_count = 0, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF2 }, - .rgb_config = 1, }, GameModeConfig { .mode_id = MODE_FGC, @@ -64,7 +61,6 @@ const Config default_config = { }, .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, - .rgb_config = 2, }, GameModeConfig { .mode_id = MODE_KEYBOARD, @@ -87,7 +83,7 @@ const Config default_config = { }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_DINPUT, - .default_mode_config = 5, + .default_mode_config = 1, .activation_binding_count = 1, .activation_binding = { BTN_RF3 }, }, From 296a34fb63ef64227c7f7d2cfb20beb209b01827 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 7 Jun 2024 00:49:06 +0100 Subject: [PATCH 129/167] fix: incorrect SOCD pairs for FgcMode --- HAL/pico/include/config_defaults.hpp | 2 +- config/glyph/include/glyph_overrides.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 21859a8e..bddea8c2 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -53,7 +53,7 @@ const Config default_config = { .socd_pairs_count = 2, .socd_pairs = { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_LT1, .socd_type = SOCD_NEUTRAL }, }, .button_remapping_count = 1, .button_remapping = { diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 91f7fa2e..691b81af 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -78,7 +78,7 @@ const Config default_config = { .socd_pairs_count = 2, .socd_pairs = { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_LT1, .socd_type = SOCD_NEUTRAL }, }, .button_remapping_count = 6, .button_remapping = { @@ -97,7 +97,7 @@ const Config default_config = { .socd_pairs_count = 2, .socd_pairs = { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_LT1, .socd_type = SOCD_NEUTRAL }, }, .button_remapping_count = 28, .button_remapping = { From 43f03a330d1c1b027edb5a15c29a705b5f79570a Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 7 Jun 2024 00:49:27 +0100 Subject: [PATCH 130/167] fix: add missing remap for split FGC mode --- config/glyph/include/glyph_overrides.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index 691b81af..ee4a44c6 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -80,8 +80,9 @@ const Config default_config = { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_LT1, .socd_type = SOCD_NEUTRAL }, }, - .button_remapping_count = 6, + .button_remapping_count = 7, .button_remapping = { + ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_RT3 }, ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_RT2 }, ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, From 38ccfa9a743ac6de3a6c2c655c0aa46a8ebc6eec Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 8 Jun 2024 21:52:11 +0100 Subject: [PATCH 131/167] fix: incorrect button remap for Glyph split FGC --- config/glyph/include/glyph_overrides.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp index ee4a44c6..13511145 100644 --- a/config/glyph/include/glyph_overrides.hpp +++ b/config/glyph/include/glyph_overrides.hpp @@ -82,7 +82,7 @@ const Config default_config = { }, .button_remapping_count = 7, .button_remapping = { - ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, + ButtonRemap { .physical_button = BTN_RT1, .activates = BTN_LT1 }, ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_RT3 }, ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_RT2 }, ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, From 42bc7c0b768dcc3ae963bad412d0d608220180a3 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 8 Jun 2024 22:04:57 +0100 Subject: [PATCH 132/167] feat: add B0XX R4 config --- .github/workflows/build.yml | 2 + config/b0xx_r4/config.cpp | 120 ++++++++++++++++++++++++++++++++++++ config/b0xx_r4/env.ini | 5 ++ 3 files changed, 127 insertions(+) create mode 100644 config/b0xx_r4/config.cpp create mode 100644 config/b0xx_r4/env.ini diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 99b346ef..861fba76 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,8 @@ jobs: bin_ext: uf2 - env: pico bin_ext: uf2 + - env: b0xx_r4 + bin_ext: uf2 - env: arduino_uno bin_ext: hex - env: arduino_nano diff --git a/config/b0xx_r4/config.cpp b/config/b0xx_r4/config.cpp new file mode 100644 index 00000000..6fa7df61 --- /dev/null +++ b/config/b0xx_r4/config.cpp @@ -0,0 +1,120 @@ +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" +#include "core/CommunicationBackend.hpp" +#include "core/KeyboardMode.hpp" +#include "core/Persistence.hpp" +#include "core/mode_selection.hpp" +#include "core/pinout.hpp" +#include "core/state.hpp" +#include "input/DebouncedGpioButtonInput.hpp" +#include "input/NunchukInput.hpp" +#include "reboot.hpp" +#include "stdlib.hpp" + +#include + +Config config = default_config; + +GpioButtonMapping button_mappings[] = { + {BTN_LF1, 9 }, + { BTN_LF2, 8 }, + { BTN_LF3, 7 }, + { BTN_LF4, 6 }, + + { BTN_LT1, 10}, + { BTN_LT2, 11}, + + { BTN_MB1, 12}, + + { BTN_RT1, 28}, + { BTN_RT2, 27}, + { BTN_RT3, 14}, + { BTN_RT4, 13}, + { BTN_RT5, 15}, + + { BTN_RF1, 19}, + { BTN_RF2, 18}, + { BTN_RF3, 17}, + { BTN_RF4, 16}, + + { BTN_RF5, 26}, + { BTN_RF6, 22}, + { BTN_RF7, 21}, + { BTN_RF8, 20}, +}; +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); + +const Pinout pinout = { + .joybus_data = 2, + .mux = -1, + .nunchuk_detect = 3, + .nunchuk_sda = 4, + .nunchuk_scl = 5, +}; + +DebouncedGpioButtonInput gpio_input(button_mappings); +NunchukInput *nunchuk = nullptr; + +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + +void setup() { + static InputState inputs; + + // Create GPIO input source and use it to read button states for checking button holds. + gpio_input.UpdateInputs(inputs); + + // Check bootsel button hold as early as possible for safety. + if (inputs.mb1) { + reboot_bootloader(); + } + + // Turn on LED to indicate firmware booted. + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + gpio_put(PICO_DEFAULT_LED_PIN, 1); + + // Attempt to load config, or write default config to flash if failed to load config. + if (!persistence.LoadConfig(config)) { + persistence.SaveConfig(config); + } + + // Create Nunchuk input source. + nunchuk = new NunchukInput(Wire, pinout.nunchuk_detect, pinout.nunchuk_sda, pinout.nunchuk_scl); + + // Create array of input sources to be used. + static InputSource *input_sources[] = { nunchuk }; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); + + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); +} + +void loop() { + select_mode(backends, backend_count, config); + + for (size_t i = 0; i < backend_count; i++) { + backends[i]->SendReport(); + } + + if (current_kb_mode != nullptr) { + current_kb_mode->SendReport(backends[0]->GetInputs()); + } +} + +/* Button inputs are read from the second core */ + +void setup1() { + while (backends == nullptr) { + tight_loop_contents(); + } +} + +void loop1() { + if (backends != nullptr) { + gpio_input.UpdateInputs(backends[0]->GetInputs()); + } +} diff --git a/config/b0xx_r4/env.ini b/config/b0xx_r4/env.ini new file mode 100644 index 00000000..8b6d2ea8 --- /dev/null +++ b/config/b0xx_r4/env.ini @@ -0,0 +1,5 @@ +[env:b0xx_r4] +extends = arduino_pico_base +build_src_filter = + ${arduino_pico_base.build_src_filter} + + From 40c118a47a8d83f59d071854243aaac131d19069 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 8 Jun 2024 23:59:55 +0100 Subject: [PATCH 133/167] ci: add schism build --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 861fba76..4cf3a239 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,11 +15,13 @@ jobs: include: - env: c53 bin_ext: uf2 + - env: b0xx_r4 + bin_ext: uf2 - env: glyph bin_ext: uf2 - env: pico bin_ext: uf2 - - env: b0xx_r4 + - env: schism bin_ext: uf2 - env: arduino_uno bin_ext: hex From b743868e8fb13db382e8f7a2d9783afd88b52b29 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 9 Jun 2024 00:26:45 +0100 Subject: [PATCH 134/167] fix: schism should scan expander_input before checking button holds --- config/schism/config.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/config/schism/config.cpp b/config/schism/config.cpp index 202f0f51..9d237e92 100644 --- a/config/schism/config.cpp +++ b/config/schism/config.cpp @@ -75,6 +75,9 @@ void setup() { reboot_bootloader(); } + // Also scan I/O expander for inputs, but after the bootloader check in case it causes a crash. + expander_input.UpdateInputs(inputs); + // Turn on LED to indicate firmware booted. gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); @@ -115,10 +118,6 @@ void setup1() { while (backends == nullptr) { tight_loop_contents(); } - // Wire.setSDA(20); - // Wire.setSCL(21); - // Wire.begin(); - // expander_input = new Pca9671Input(expander_button_mappings, expander_button_count, Wire); } void loop1() { From a1ccfc4aa7d41d0721aced03ef89c74225dcac41 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 9 Jun 2024 00:36:43 +0100 Subject: [PATCH 135/167] ci: update deprecated actions --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4cf3a239..cf4cb592 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: steps: - name: Check out source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 @@ -69,7 +69,7 @@ jobs: cp ".pio/build/${{ matrix.env }}/firmware.${{ matrix.bin_ext }}" "${{ matrix.env }}/HayBox-${VERSION_REF}-${{ matrix.env }}.${{ matrix.bin_ext }}" - name: Publish ${{ matrix.env }} artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} path: ${{ matrix.env }}/HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} From ac0e9b319605be8ad8d29d9fd3c9db98a7be093c Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 9 Jun 2024 00:45:06 +0100 Subject: [PATCH 136/167] fix: use global Persistence instance in schism config --- config/schism/config.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/config/schism/config.cpp b/config/schism/config.cpp index 9d237e92..7fa11bd6 100644 --- a/config/schism/config.cpp +++ b/config/schism/config.cpp @@ -84,11 +84,9 @@ void setup() { gpio_put(PICO_DEFAULT_LED_PIN, 1); // Attempt to load config, or write default config to flash if failed to load config. - Persistence *persistence = new Persistence(); - if (!persistence->LoadConfig(config)) { - persistence->SaveConfig(config); + if (!persistence.LoadConfig(config)) { + persistence.SaveConfig(config); } - delete persistence; // Create array of input sources to be used. static InputSource *input_sources[] = {}; From 374f91282fb407a3ab8e6221162ef0dde32f597e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 9 Jun 2024 17:42:15 +0100 Subject: [PATCH 137/167] feat: add Melee and PM mode config options --- HAL/pico/include/config_defaults.hpp | 8 ++++++++ include/modes/Melee20Button.hpp | 9 +++------ include/modes/ProjectM.hpp | 13 ++++++++----- platformio.ini | 2 +- src/core/mode_selection.cpp | 8 ++++---- src/modes/Melee20Button.cpp | 24 ++++++++++++++++++------ src/modes/ProjectM.cpp | 23 ++++++++++++++++++----- 7 files changed, 60 insertions(+), 27 deletions(-) diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index bddea8c2..e0fcc6ed 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -152,6 +152,14 @@ const Config default_config = { }, .default_backend_config = 1, .default_usb_backend_config = 1, + .melee_options = { + .crouch_walk_os = false, + .disable_ledgedash_socd_override = false, + }, + .project_m_options = { + .true_z_press = false, + .disable_ledgedash_socd_override = false, + }, }; // clang-format on diff --git a/include/modes/Melee20Button.hpp b/include/modes/Melee20Button.hpp index 71518a42..54f904f2 100644 --- a/include/modes/Melee20Button.hpp +++ b/include/modes/Melee20Button.hpp @@ -6,20 +6,17 @@ #include -typedef struct { - bool crouch_walk_os = false; -} Melee20ButtonOptions; - class Melee20Button : public ControllerMode { public: - Melee20Button(Melee20ButtonOptions options = {}); + Melee20Button(); + void SetConfig(GameModeConfig &config, const MeleeOptions options); protected: void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); private: - Melee20ButtonOptions _options; + MeleeOptions _options; bool _horizontal_socd; void HandleSocd(InputState &inputs); diff --git a/include/modes/ProjectM.hpp b/include/modes/ProjectM.hpp index ed75856c..580fd544 100644 --- a/include/modes/ProjectM.hpp +++ b/include/modes/ProjectM.hpp @@ -4,14 +4,17 @@ #include "core/ControllerMode.hpp" #include "core/state.hpp" -typedef struct { - bool true_z_press = false; - bool ledgedash_max_jump_traj = true; -} ProjectMOptions; +#include + +// typedef struct { +// bool true_z_press = false; +// bool ledgedash_max_jump_traj = true; +// } ProjectMOptions; class ProjectM : public ControllerMode { public: - ProjectM(ProjectMOptions options = {}); + ProjectM(); + void SetConfig(GameModeConfig &config, const ProjectMOptions options); private: ProjectMOptions _options; diff --git a/platformio.ini b/platformio.ini index 1aec6b16..0672291d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#703e11f + https://github.com/JonnyHaystack/HayBox-proto#f37657b [avr_base] platform = atmelavr diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 4e8c44e0..a5b98822 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -12,8 +12,8 @@ #include -Melee20Button melee_mode({ .crouch_walk_os = false }); -ProjectM projectm_mode({ .true_z_press = false, .ledgedash_max_jump_traj = true }); +Melee20Button melee_mode; +ProjectM projectm_mode; Ultimate ultimate_mode; FgcMode fgc_mode; RivalsOfAether rivals_mode; @@ -49,11 +49,11 @@ void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config) { switch (mode_config.mode_id) { case MODE_MELEE: - melee_mode.SetConfig(mode_config); + melee_mode.SetConfig(mode_config, config.melee_options); set_mode(backend, &melee_mode); break; case MODE_PROJECT_M: - projectm_mode.SetConfig(mode_config); + projectm_mode.SetConfig(mode_config, config.project_m_options); set_mode(backend, &projectm_mode); break; case MODE_ULTIMATE: diff --git a/src/modes/Melee20Button.cpp b/src/modes/Melee20Button.cpp index 04da2bc7..766e609d 100644 --- a/src/modes/Melee20Button.cpp +++ b/src/modes/Melee20Button.cpp @@ -4,11 +4,15 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 208 -Melee20Button::Melee20Button(Melee20ButtonOptions options) : ControllerMode() { - _options = options; +Melee20Button::Melee20Button() : ControllerMode() { _horizontal_socd = false; } +void Melee20Button::SetConfig(GameModeConfig &config, const MeleeOptions options) { + InputMode::SetConfig(config); + _options = options; +} + void Melee20Button::HandleSocd(InputState &inputs) { _horizontal_socd = inputs.lf3 && inputs.lf1; InputMode::HandleSocd(inputs); @@ -73,6 +77,7 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } } + /* Mod X */ if (inputs.lt1) { // MX + Horizontal (even if shield is held) = 6625 = 53 if (directions.horizontal) { @@ -83,9 +88,15 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o outputs.leftStickY = 128 + (directions.y * 43); } if (directions.diagonal && shield_button_pressed) { - // MX + L, R, LS, and MS + q1/2/3/4 = 6375 3750 = 51 30 - outputs.leftStickX = 128 + (directions.x * 51); - outputs.leftStickY = 128 + (directions.y * 30); + // Use custom airdodge angle if set, otherwise B0XX standard default. + if (_options.has_custom_airdodge) { + outputs.leftStickX = 128 + (directions.x * _options.custom_airdodge.x); + outputs.leftStickY = 128 + (directions.y * _options.custom_airdodge.y); + } else { + // MX + L, R, LS, and MS + q1/2/3/4 = 6375 3750 = 51 30 + outputs.leftStickX = 128 + (directions.x * 51); + outputs.leftStickY = 128 + (directions.y * 30); + } } /* Up B angles */ @@ -150,6 +161,7 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o } } + /* Mod Y */ if (inputs.lt2) { // MY + Horizontal (even if shield is held) = 3375 = 27 if (directions.horizontal) { @@ -240,7 +252,7 @@ void Melee20Button::UpdateAnalogOutputs(const InputState &inputs, OutputState &o // Horizontal SOCD overrides X-axis modifiers (for ledgedash maximum jump // trajectory). - if (_horizontal_socd && !directions.vertical) { + if (!_options.disable_ledgedash_socd_override && _horizontal_socd && !directions.vertical) { outputs.leftStickX = 128 + (directions.x * 80); } diff --git a/src/modes/ProjectM.cpp b/src/modes/ProjectM.cpp index 5556c31c..5246bbca 100644 --- a/src/modes/ProjectM.cpp +++ b/src/modes/ProjectM.cpp @@ -4,11 +4,15 @@ #define ANALOG_STICK_NEUTRAL 128 #define ANALOG_STICK_MAX 228 -ProjectM::ProjectM(ProjectMOptions options) : ControllerMode() { - _options = options; +ProjectM::ProjectM() : ControllerMode() { _horizontal_socd = false; } +void ProjectM::SetConfig(GameModeConfig &config, const ProjectMOptions options) { + InputMode::SetConfig(config); + _options = options; +} + void ProjectM::HandleSocd(InputState &inputs) { _horizontal_socd = inputs.lf3 && inputs.lf1; InputMode::HandleSocd(inputs); @@ -76,6 +80,7 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output } } + /* Mod X */ if (inputs.lt1) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 70); @@ -90,6 +95,7 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output } if (directions.diagonal) { + // Default MX Diagonal outputs.leftStickX = 128 + (directions.x * 70); outputs.leftStickY = 128 + (directions.y * 34); @@ -98,9 +104,15 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output outputs.leftStickY = 128 + (directions.y * 31); } + // Airdodge angle if (inputs.rf5) { - outputs.leftStickX = 128 + (directions.x * 82); - outputs.leftStickY = 128 + (directions.y * 35); + if (_options.has_custom_airdodge) { + outputs.leftStickX = 128 + (directions.x * _options.custom_airdodge.x); + outputs.leftStickY = 128 + (directions.y * _options.custom_airdodge.y); + } else { + outputs.leftStickX = 128 + (directions.x * 82); + outputs.leftStickY = 128 + (directions.y * 35); + } } if (inputs.rt4) { @@ -125,6 +137,7 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output } } + /* Mod Y */ if (inputs.lt2) { if (directions.horizontal) { outputs.leftStickX = 128 + (directions.x * 35); @@ -181,7 +194,7 @@ void ProjectM::UpdateAnalogOutputs(const InputState &inputs, OutputState &output // Horizontal SOCD overrides X-axis modifiers (for ledgedash maximum jump // trajectory). - if (_options.ledgedash_max_jump_traj && _horizontal_socd && !directions.vertical && + if (!_options.disable_ledgedash_socd_override && _horizontal_socd && !directions.vertical && !shield_button_pressed) { outputs.leftStickX = 128 + (directions.x * 100); } From 8b5124428134112247cb548bc0dfe9907f2809a3 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 11 Jun 2024 20:57:51 +0100 Subject: [PATCH 138/167] feat: add more validation checks for config update --- HAL/pico/src/comms/ConfiguratorBackend.cpp | 30 ++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/HAL/pico/src/comms/ConfiguratorBackend.cpp b/HAL/pico/src/comms/ConfiguratorBackend.cpp index a0016f7c..96c3cc91 100644 --- a/HAL/pico/src/comms/ConfiguratorBackend.cpp +++ b/HAL/pico/src/comms/ConfiguratorBackend.cpp @@ -201,7 +201,34 @@ bool ConfiguratorBackend::HandleSetConfig() { } for (size_t i = 0; i < _config.game_mode_configs_count; i++) { - uint8_t keyboard_mode_id = _config.game_mode_configs[i].keyboard_mode_config; + const GameModeConfig &gamemode_config = _config.game_mode_configs[i]; + uint8_t keyboard_mode_id = gamemode_config.keyboard_mode_config; + uint8_t custom_mode_id = gamemode_config.custom_mode_config; + + if (keyboard_mode_id > 0 && gamemode_config.mode_id != MODE_KEYBOARD) { + char errmsg[80]; + size_t errmsg_len = snprintf( + errmsg, + sizeof(errmsg), + "keyboard_mode_id is set for game mode %d but mode_id is not MODE_KEYBOARD", + (uint8_t)i + 1 + ); + WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); + return false; + } + + if (custom_mode_id > 0 && gamemode_config.mode_id != MODE_CUSTOM) { + char errmsg[75]; + size_t errmsg_len = snprintf( + errmsg, + sizeof(errmsg), + "custom_mode_id is set for game mode %d but mode_id is not MODE_CUSTOM", + (uint8_t)i + 1 + ); + WritePacket(CMD_ERROR, (uint8_t *)errmsg, errmsg_len); + return false; + } + if (keyboard_mode_id > _config.keyboard_modes_count) { char errmsg[85]; size_t errmsg_len = snprintf( @@ -216,7 +243,6 @@ bool ConfiguratorBackend::HandleSetConfig() { return false; } - uint8_t custom_mode_id = _config.game_mode_configs[i].custom_mode_config; if (custom_mode_id > _config.custom_modes_count) { char errmsg[85]; size_t errmsg_len = snprintf( From d80420c9d1ca74cff6d018e197bf26c71d34cf42 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 11 Jun 2024 20:58:10 +0100 Subject: [PATCH 139/167] feat: add default mappings for L3 and R3 in FgcMode --- src/modes/FgcMode.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modes/FgcMode.cpp b/src/modes/FgcMode.cpp index 85d366c6..84a64818 100644 --- a/src/modes/FgcMode.cpp +++ b/src/modes/FgcMode.cpp @@ -13,6 +13,8 @@ void FgcMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &output outputs.start = inputs.mb1; outputs.select = inputs.rt3; outputs.home = inputs.rt2; + outputs.leftStickClick = inputs.rt1; + outputs.rightStickClick = inputs.rt5; // Right hand bottom row outputs.a = inputs.rf1; From c5da94415442f483efa2d65784cb353ce52e91fa Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 11 Jun 2024 21:20:17 +0100 Subject: [PATCH 140/167] feat: update default mappings for L3 and R3 in FgcMode --- src/modes/FgcMode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modes/FgcMode.cpp b/src/modes/FgcMode.cpp index 84a64818..c51f0eb1 100644 --- a/src/modes/FgcMode.cpp +++ b/src/modes/FgcMode.cpp @@ -13,8 +13,8 @@ void FgcMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &output outputs.start = inputs.mb1; outputs.select = inputs.rt3; outputs.home = inputs.rt2; - outputs.leftStickClick = inputs.rt1; - outputs.rightStickClick = inputs.rt5; + outputs.leftStickClick = inputs.lt2; + outputs.rightStickClick = inputs.rt1; // Right hand bottom row outputs.a = inputs.rf1; From 6f522b0cda962e3fe753650aa223885094ea0af2 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Tue, 11 Jun 2024 22:28:34 +0100 Subject: [PATCH 141/167] feat: add button combo mapping support --- include/modes/CustomControllerMode.hpp | 3 ++ platformio.ini | 2 +- src/modes/CustomControllerMode.cpp | 47 ++++++++++++++++++++------ 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/include/modes/CustomControllerMode.hpp b/include/modes/CustomControllerMode.hpp index a18976e8..c322f0e0 100644 --- a/include/modes/CustomControllerMode.hpp +++ b/include/modes/CustomControllerMode.hpp @@ -18,6 +18,9 @@ class CustomControllerMode : public ControllerMode { private: const CustomModeConfig *_custom_mode_config; uint64_t _modifier_button_masks[10]; + uint64_t _button_combo_mappings_masks[5]; + uint64_t _buttons_to_ignore = 0; + uint64_t _filtered_buttons = 0; Button GetDirectionButton(const Button *direction_buttons, StickDirectionButton direction); }; diff --git a/platformio.ini b/platformio.ini index 0672291d..447587b2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#f37657b + https://github.com/JonnyHaystack/HayBox-proto#5b2bb5d [avr_base] platform = atmelavr diff --git a/src/modes/CustomControllerMode.cpp b/src/modes/CustomControllerMode.cpp index 12ecd130..fd6fe0c6 100644 --- a/src/modes/CustomControllerMode.cpp +++ b/src/modes/CustomControllerMode.cpp @@ -19,6 +19,12 @@ void CustomControllerMode::SetConfig( custom_mode_config.modifiers[i].buttons_count ); } + for (size_t i = 0; i < custom_mode_config.button_combo_mappings_count; i++) { + _button_combo_mappings_masks[i] = make_button_mask( + custom_mode_config.button_combo_mappings[i].buttons, + custom_mode_config.button_combo_mappings[i].buttons_count + ); + } } void CustomControllerMode::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { @@ -26,9 +32,28 @@ void CustomControllerMode::UpdateDigitalOutputs(const InputState &inputs, Output return; } + // First check for button combo -> single output mappings, and lock out the normal function of + // the buttons in any buttons combos that are activated. + _buttons_to_ignore = 0; + const ButtonComboMapping *button_combo_mappings = _custom_mode_config->button_combo_mappings; + for (size_t i = 0; i < _custom_mode_config->button_combo_mappings_count; i++) { + const ButtonComboMapping &button_combo_mapping = button_combo_mappings[i]; + if (!all_buttons_held(inputs.buttons, _button_combo_mappings_masks[i])) { + continue; + } + + set_output(outputs.buttons, button_combo_mapping.digital_output, true); + _buttons_to_ignore |= _button_combo_mappings_masks[i]; + } + _filtered_buttons = inputs.buttons & ~_buttons_to_ignore; + for (size_t output = 0; output < _custom_mode_config->digital_button_mappings_count; output++) { Button input = _custom_mode_config->digital_button_mappings[output]; - set_output(outputs.buttons, (DigitalOutput)(output + 1), get_button(inputs.buttons, input)); + set_output( + outputs.buttons, + (DigitalOutput)(output + 1), + get_button(_filtered_buttons, input) + ); } if (inputs.nunchuk_connected) { @@ -44,14 +69,14 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS const Button *direction_buttons = _custom_mode_config->stick_direction_mappings; uint8_t stick_range = _custom_mode_config->stick_range; UpdateDirections( - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_LEFT)), - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_RIGHT)), - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_DOWN)), - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_LSTICK_UP)), - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_LEFT)), - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_RIGHT)), - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_DOWN)), - get_button(inputs.buttons, GetDirectionButton(direction_buttons, SD_RSTICK_UP)), + get_button(_filtered_buttons, SD_LSTICK_LEFT)), + get_button(_filtered_buttons, SD_LSTICK_RIGHT)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_LSTICK_DOWN)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_LSTICK_UP)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_RSTICK_LEFT)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_RSTICK_RIGHT)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_RSTICK_DOWN)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_RSTICK_UP)), ANALOG_STICK_NEUTRAL - stick_range, ANALOG_STICK_NEUTRAL, ANALOG_STICK_NEUTRAL + stick_range, @@ -64,7 +89,7 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS if (modifier.axis == AXIS_UNSPECIFIED || modifier.axis > _AnalogAxis_MAX) { continue; } - if (!all_buttons_held(inputs.buttons, _modifier_button_masks[i])) { + if (!all_buttons_held(_filtered_buttons, _modifier_button_masks[i])) { continue; } @@ -91,7 +116,7 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS _custom_mode_config->analog_trigger_mappings; for (size_t i = 0; i < _custom_mode_config->analog_trigger_mappings_count; i++) { const AnalogTriggerMapping &mapping = analog_trigger_mappings[i]; - if (get_button(inputs.buttons, mapping.button)) { + if (get_button(_filtered_buttons, mapping.button)) { switch (mapping.trigger) { case TRIGGER_LT: outputs.triggerLAnalog = mapping.value; From 491b5172d41c12c89d3c26670210e29a33f9e245 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 12 Jun 2024 13:45:48 +0100 Subject: [PATCH 142/167] fix: add back code that got removed by VS Code... --- src/modes/CustomControllerMode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modes/CustomControllerMode.cpp b/src/modes/CustomControllerMode.cpp index fd6fe0c6..f3599398 100644 --- a/src/modes/CustomControllerMode.cpp +++ b/src/modes/CustomControllerMode.cpp @@ -69,8 +69,8 @@ void CustomControllerMode::UpdateAnalogOutputs(const InputState &inputs, OutputS const Button *direction_buttons = _custom_mode_config->stick_direction_mappings; uint8_t stick_range = _custom_mode_config->stick_range; UpdateDirections( - get_button(_filtered_buttons, SD_LSTICK_LEFT)), - get_button(_filtered_buttons, SD_LSTICK_RIGHT)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_LSTICK_LEFT)), + get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_LSTICK_RIGHT)), get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_LSTICK_DOWN)), get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_LSTICK_UP)), get_button(_filtered_buttons, GetDirectionButton(direction_buttons, SD_RSTICK_LEFT)), From dead2a666fa91202669da32820fdfce66d217781 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 12 Jun 2024 13:47:16 +0100 Subject: [PATCH 143/167] feat: config menu instantly USB backend switching Selecting a USB mode via the OLED display config menu now uses the watchdog SCRATCH0 register to store a backend index and then reboot, thus effectively changing the backend immediately, and also updating the default in RAM which can then be manually saved. Also added the option to switch to ConfiguratorBackend via the config menu, and another option at the top level to reboot to bootloader for firmware updates. --- HAL/pico/include/comms/backend_init.hpp | 2 +- .../include/display/DefaultConfigMenu.hpp | 2 +- HAL/pico/src/comms/backend_init.cpp | 19 ++++++++++----- HAL/pico/src/display/DefaultConfigMenu.cpp | 24 +++++++++++++++---- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/HAL/pico/include/comms/backend_init.hpp b/HAL/pico/include/comms/backend_init.hpp index 2ee95d25..783cb54e 100644 --- a/HAL/pico/include/comms/backend_init.hpp +++ b/HAL/pico/include/comms/backend_init.hpp @@ -24,7 +24,7 @@ typedef void (*backend_config_selector_t)( CommunicationBackendConfig &backend_config, const InputState &inputs, - const Config &config + Config &config ); /** diff --git a/HAL/pico/include/display/DefaultConfigMenu.hpp b/HAL/pico/include/display/DefaultConfigMenu.hpp index 5b69f124..49a6e628 100644 --- a/HAL/pico/include/display/DefaultConfigMenu.hpp +++ b/HAL/pico/include/display/DefaultConfigMenu.hpp @@ -15,7 +15,7 @@ class DefaultConfigMenu : public ConfigMenu { Config &config, uint8_t mode_config_index ); - static void SetDefaultUsbBackend( + static void SetUsbBackend( IntegratedDisplay *instance, ConfigMenu *menu, Config &config, diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 23212798..1eb778d3 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -214,13 +214,20 @@ size_t init_secondary_backends( backend_config_selector_t get_backend_config_default = []( CommunicationBackendConfig &backend_config, const InputState &inputs, - const Config &config + Config &config ) { - backend_config = backend_config_from_buttons( - inputs, - config.communication_backend_configs, - config.communication_backend_configs_count - ); + // Check watchdog SCRATCH0 register for temporarily set backend config index. + uint8_t temp_backend_index = watchdog_hw->scratch[0]; + if (temp_backend_index > 0 && temp_backend_index <= config.communication_backend_configs_count) { + backend_config = config.communication_backend_configs[temp_backend_index - 1]; + config.default_usb_backend_config = config.default_usb_backend_config = temp_backend_index; + } else { + backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + } }; /* Default is to get default USB backend from config. */ diff --git a/HAL/pico/src/display/DefaultConfigMenu.cpp b/HAL/pico/src/display/DefaultConfigMenu.cpp index 91dbf5d0..aa783fcf 100644 --- a/HAL/pico/src/display/DefaultConfigMenu.cpp +++ b/HAL/pico/src/display/DefaultConfigMenu.cpp @@ -22,7 +22,8 @@ DefaultConfigMenu::DefaultConfigMenu( if (backend_config.backend_id != COMMS_BACKEND_XINPUT && backend_config.backend_id != COMMS_BACKEND_DINPUT && - backend_config.backend_id != COMMS_BACKEND_NINTENDO_SWITCH) { + backend_config.backend_id != COMMS_BACKEND_NINTENDO_SWITCH && + backend_config.backend_id != COMMS_BACKEND_CONFIGURATOR) { continue; } @@ -32,7 +33,7 @@ DefaultConfigMenu::DefaultConfigMenu( sizeof(current_option.text) ); current_option.key = i; - current_option.action = &SetDefaultUsbBackend; + current_option.action = &SetUsbBackend; usb_backend_options_count++; } @@ -99,7 +100,7 @@ DefaultConfigMenu::DefaultConfigMenu( .page = &_gamemode_options_page, }, { - .text = "Default USB Mode", + .text = "USB Mode", .page = &_usb_backends_page, }, { @@ -155,6 +156,17 @@ DefaultConfigMenu::DefaultConfigMenu( ) { reboot_firmware(); }, + }, + { + .text = "Firmware update", + .action = []( + IntegratedDisplay *display_backend, + ConfigMenu *menu, + Config &config, + uint8_t key + ) { + reboot_bootloader(); + } } }; // clang-format on @@ -201,7 +213,7 @@ void DefaultConfigMenu::SetDefaultMode( set_mode(display_backend, config.game_mode_configs[mode_config_index], config); } -void DefaultConfigMenu::SetDefaultUsbBackend( +void DefaultConfigMenu::SetUsbBackend( IntegratedDisplay *display_backend, ConfigMenu *menu, Config &config, @@ -211,7 +223,9 @@ void DefaultConfigMenu::SetDefaultUsbBackend( backend_config_index >= config.communication_backend_configs_count) { return; } - config.default_usb_backend_config = backend_config_index + 1; + // Set backend in watchdog SCRATCH0 register and reboot. + watchdog_hw->scratch[0] = backend_config_index + 1; + reboot_firmware(); } void DefaultConfigMenu::SetSocdType( From c75527c885764af2ac4a741a998e9b68e8a6a8b4 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 12 Jun 2024 13:54:40 +0100 Subject: [PATCH 144/167] fix: fix typo and add watchdog reboot check --- HAL/pico/src/comms/backend_init.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/HAL/pico/src/comms/backend_init.cpp b/HAL/pico/src/comms/backend_init.cpp index 1eb778d3..f7b65d11 100644 --- a/HAL/pico/src/comms/backend_init.cpp +++ b/HAL/pico/src/comms/backend_init.cpp @@ -216,18 +216,22 @@ backend_config_selector_t get_backend_config_default = []( const InputState &inputs, Config &config ) { - // Check watchdog SCRATCH0 register for temporarily set backend config index. - uint8_t temp_backend_index = watchdog_hw->scratch[0]; - if (temp_backend_index > 0 && temp_backend_index <= config.communication_backend_configs_count) { - backend_config = config.communication_backend_configs[temp_backend_index - 1]; - config.default_usb_backend_config = config.default_usb_backend_config = temp_backend_index; - } else { - backend_config = backend_config_from_buttons( - inputs, - config.communication_backend_configs, - config.communication_backend_configs_count - ); + if (watchdog_caused_reboot()) { + // Check watchdog SCRATCH0 register for temporarily set backend config index. + uint8_t temp_backend_index = watchdog_hw->scratch[0]; + if (temp_backend_index > 0 && + temp_backend_index <= config.communication_backend_configs_count) { + backend_config = config.communication_backend_configs[temp_backend_index - 1]; + config.default_usb_backend_config = temp_backend_index; + return; + } } + + backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); }; /* Default is to get default USB backend from config. */ From 5031aba54a23980053483929bd39865141ebe946 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 12 Jun 2024 13:57:42 +0100 Subject: [PATCH 145/167] refactor: remove glyph config (has been moved to LimitLabs/HayBox-config-Glyph) --- config/glyph/config.cpp | 194 --------- config/glyph/env.ini | 15 - config/glyph/include/button_positions.hpp | 149 ------- .../glyph/include/display/GlyphConfigMenu.hpp | 24 -- .../glyph/include/display/MenuButtonHints.hpp | 21 - config/glyph/include/glyph_overrides.hpp | 404 ------------------ config/glyph/src/display/GlyphConfigMenu.cpp | 103 ----- config/glyph/src/display/MenuButtonHints.cpp | 60 --- 8 files changed, 970 deletions(-) delete mode 100644 config/glyph/config.cpp delete mode 100644 config/glyph/env.ini delete mode 100644 config/glyph/include/button_positions.hpp delete mode 100644 config/glyph/include/display/GlyphConfigMenu.hpp delete mode 100644 config/glyph/include/display/MenuButtonHints.hpp delete mode 100644 config/glyph/include/glyph_overrides.hpp delete mode 100644 config/glyph/src/display/GlyphConfigMenu.cpp delete mode 100644 config/glyph/src/display/MenuButtonHints.cpp diff --git a/config/glyph/config.cpp b/config/glyph/config.cpp deleted file mode 100644 index a2cbae3b..00000000 --- a/config/glyph/config.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "button_positions.hpp" -#include "comms/backend_init.hpp" -#include "core/CommunicationBackend.hpp" -#include "core/KeyboardMode.hpp" -#include "core/Persistence.hpp" -#include "core/mode_selection.hpp" -#include "core/pinout.hpp" -#include "core/state.hpp" -#include "display/DisplayMode.hpp" -#include "display/GlyphConfigMenu.hpp" -#include "display/InputDisplay.hpp" -#include "display/MenuButtonHints.hpp" -#include "display/RgbBrightnessMenu.hpp" -#include "glyph_overrides.hpp" -#include "input/DebouncedSwitchMatrixInput.hpp" -#include "reboot.hpp" -#include "stdlib.hpp" - -#include -#include - -Config config = glyph_default_config(); - -const size_t num_rows = 4; -const size_t num_cols = 11; -const uint row_pins[num_rows] = { 26, 25, 24, 23 }; -const uint col_pins[num_cols] = { 15, 14, 13, 12, 16, 17, 21, 20, 19, 18, 22 }; -// clang-format off -const Button matrix[num_rows][num_cols] = { - {BTN_MB1, BTN_MB2, BTN_MB3, BTN_MB4, BTN_MB5, BTN_MB6, BTN_MB7, NA, NA, NA, NA }, - { BTN_LF3, BTN_LF2, BTN_LF6, BTN_LF7, BTN_RF12, BTN_RF13, BTN_RF14, BTN_RF5, BTN_RF6, BTN_RF7, BTN_RF8}, - { BTN_LF4, BTN_LF5, BTN_LF1, BTN_LF8, BTN_RF9, BTN_RF10, BTN_RF11, BTN_RF1, BTN_RF2, BTN_RF3, BTN_RF4}, - { BTN_LT5, BTN_LT4, BTN_LT1, BTN_LT3, BTN_LT2, BTN_LT6, BTN_RT2, BTN_RT3, BTN_RT1, BTN_RT4, BTN_RT5}, -}; -// clang-format on - -DebouncedSwitchMatrixInput matrix_input( - row_pins, - col_pins, - matrix, - DiodeDirection::COL2ROW -); - -const Pinout pinout = { - .joybus_data = 4, - .nes_data = 4, - .nes_clock = 5, - .nes_latch = 6, - .mux = -1, - .nunchuk_detect = -1, - .nunchuk_sda = -1, - .nunchuk_scl = -1, -}; - -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; - -InputState inputs; - -InputSource *input_sources[] = { &matrix_input }; -size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - -void setup() { - // Create GPIO input source and use it to read button states for checking button holds. - matrix_input.UpdateInputs(inputs); - - // Check bootsel button hold as early as possible for safety. - if (inputs.mb1) { - reboot_bootloader(); - } - - // Attempt to load config, or write default config to flash if failed to load config. - if (!persistence.LoadConfig(config)) { - persistence.SaveConfig(config); - } - - // Create array of input sources to be used. - backend_count = initialize_backends( - backends, - inputs, - input_sources, - input_source_count, - config, - pinout, - get_backend_config_default, - get_usb_backend_config_default, - &detect_console, - &init_secondary_backends_glyph - ); - - setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); -} - -void loop() { - select_mode(backends, backend_count, config); - - for (size_t i = 0; i < backend_count; i++) { - backends[i]->SendReport(); - } - - if (current_kb_mode != nullptr) { - current_kb_mode->SendReport(backends[0]->GetInputs()); - } -} - -/* Second core handles OLED display */ -Adafruit_SSD1306 display(128, 64, &Wire1); -IntegratedDisplay *display_backend = nullptr; - -RgbBrightnessMenu rgb_brightness_menu(config); - -InputDisplay *input_viewer = nullptr; - -void setup1() { - while (!backend_count || backends == nullptr) { - delay(1); - } - - // These have to be initialized after backends. - CommunicationBackendId primary_backend_id = backends[0]->BackendId(); - static MenuButtonHints menu_button_hints(primary_backend_id); - static InputDisplay input_display( - platform_fighter_buttons, - platform_fighter_buttons_count, - primary_backend_id - ); - static GlyphConfigMenu config_menu(config, backends, backend_count); - - static DisplayMode *display_modes[] = { - &menu_button_hints, - &input_display, - &config_menu, - &rgb_brightness_menu, - }; - size_t display_modes_count = count_of(display_modes); - - input_viewer = &input_display; - - Wire1.setSDA(2); - Wire1.setSCL(3); - Wire1.setClock(1'000'000UL); - Wire1.begin(); - if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) { - // clang-format off - display_backend = new IntegratedDisplay( - inputs, - display, - []() { display.clearDisplay(); }, - []() { display.display(); }, - DisplayControls{ .back = BTN_MB1, .down = BTN_MB6, .up = BTN_MB5, .enter = BTN_MB7 }, - display_modes, - display_modes_count - ); - // clang-format on - display_backend->SetDisplayMode( - config.default_dashboard_option == DASHBOARD_INPUT_VIEWER ? DISPLAY_MODE_VIEWER - : DISPLAY_MODE_BUTTON_HINTS - ); - } -} - -void loop1() { - if (display_backend == nullptr) { - return; - } - if (backends[0] != nullptr && backends[0]->CurrentGameMode() != nullptr && - display_backend->CurrentGameMode() != backends[0]->CurrentGameMode()) { - display_backend->SetGameMode(backends[0]->CurrentGameMode()); - } - // Update input display layout. - if (display_backend->CurrentGameMode() != nullptr) { - GameModeConfig *mode_config = display_backend->CurrentGameMode()->GetConfig(); - switch (mode_config->layout_plate) { - case LAYOUT_PLATE_UNSPECIFIED: - case LAYOUT_PLATE_EVERYTHING: - input_viewer->UpdateButtonLayout(full_layout_buttons, full_layout_buttons_count); - break; - case LAYOUT_PLATE_FGC: - input_viewer->UpdateButtonLayout(fgc_buttons, fgc_buttons_count); - break; - case LAYOUT_PLATE_SPLIT_FGC: - input_viewer->UpdateButtonLayout(split_fgc_buttons, split_fgc_buttons_count); - break; - case LAYOUT_PLATE_PLATFORM_FIGHTER: - input_viewer->UpdateButtonLayout( - platform_fighter_buttons, - platform_fighter_buttons_count - ); - break; - } - } - display_backend->SendReport(); -} diff --git a/config/glyph/env.ini b/config/glyph/env.ini deleted file mode 100644 index 2e02aecc..00000000 --- a/config/glyph/env.ini +++ /dev/null @@ -1,15 +0,0 @@ -[env:glyph] -extends = arduino_pico_base -build_flags = - ${arduino_pico_base.build_flags} - -I config/glyph/include - -D SSD1306_NO_SPLASH -build_src_filter = - ${arduino_pico_base.build_src_filter} - + -lib_ignore = - ${env.lib_ignore} - https://github.com/JonnyHaystack/HayBox-proto -lib_deps = - ${arduino_pico_base.lib_deps} - https://github.com/LimitLabs/HayBox-proto#3b7abdf \ No newline at end of file diff --git a/config/glyph/include/button_positions.hpp b/config/glyph/include/button_positions.hpp deleted file mode 100644 index 340f2883..00000000 --- a/config/glyph/include/button_positions.hpp +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef _BUTTON_POSITIONS_HPP -#define _BUTTON_POSITIONS_HPP - -#define MENU_BUTTON_RADIUS 2 -#define NORMAL_BUTTON_RADIUS 4 -#define LARGE_BUTTON_RADIUS 5 - -#include "display/InputDisplay.hpp" - -InputViewerButton full_layout_buttons[] = { - // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, - - {BTN_LF4, 6, 29, NORMAL_BUTTON_RADIUS}, - { BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, - { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, - { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, - { BTN_LF5, 24, 32, NORMAL_BUTTON_RADIUS}, - - { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, - { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, - { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, - { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, - - { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, - { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, - { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, - { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, - - { BTN_LT1, 38, 52, NORMAL_BUTTON_RADIUS}, - { BTN_LT2, 46, 58, NORMAL_BUTTON_RADIUS}, - { BTN_LT3, 46, 46, NORMAL_BUTTON_RADIUS}, - { BTN_LT4, 38, 40, NORMAL_BUTTON_RADIUS}, - { BTN_LT5, 30, 46, NORMAL_BUTTON_RADIUS}, - { BTN_LT6, 59, 50, LARGE_BUTTON_RADIUS }, - - { BTN_RT1, 90, 52, NORMAL_BUTTON_RADIUS}, - { BTN_RT2, 82, 58, NORMAL_BUTTON_RADIUS}, - { BTN_RT3, 82, 46, NORMAL_BUTTON_RADIUS}, - { BTN_RT4, 90, 40, NORMAL_BUTTON_RADIUS}, - { BTN_RT5, 98, 46, NORMAL_BUTTON_RADIUS}, - - { BTN_LF6, 35, 17, NORMAL_BUTTON_RADIUS}, - { BTN_LF7, 46, 19, NORMAL_BUTTON_RADIUS}, - { BTN_LF8, 55, 25, NORMAL_BUTTON_RADIUS}, - - { BTN_RF9, 64, 30, NORMAL_BUTTON_RADIUS}, - { BTN_RF10, 74, 25, NORMAL_BUTTON_RADIUS}, - { BTN_RF11, 84, 25, NORMAL_BUTTON_RADIUS}, - - { BTN_RF12, 64, 20, NORMAL_BUTTON_RADIUS}, - { BTN_RF13, 74, 15, NORMAL_BUTTON_RADIUS}, - { BTN_RF14, 84, 15, NORMAL_BUTTON_RADIUS}, -}; -size_t full_layout_buttons_count = count_of(full_layout_buttons); - -InputViewerButton platform_fighter_buttons[] = { - // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, - - {BTN_LF4, 6, 29, NORMAL_BUTTON_RADIUS}, - { BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, - { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, - { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, - { BTN_LF5, 24, 32, NORMAL_BUTTON_RADIUS}, - - { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, - { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, - { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, - { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, - - { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, - { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, - { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, - { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, - - { BTN_LT1, 38, 52, NORMAL_BUTTON_RADIUS}, - { BTN_LT2, 46, 58, NORMAL_BUTTON_RADIUS}, - { BTN_LT3, 46, 46, NORMAL_BUTTON_RADIUS}, - { BTN_LT4, 38, 40, NORMAL_BUTTON_RADIUS}, - { BTN_LT5, 30, 46, NORMAL_BUTTON_RADIUS}, - - { BTN_RT1, 90, 52, NORMAL_BUTTON_RADIUS}, - { BTN_RT2, 82, 58, NORMAL_BUTTON_RADIUS}, - { BTN_RT3, 82, 46, NORMAL_BUTTON_RADIUS}, - { BTN_RT4, 90, 40, NORMAL_BUTTON_RADIUS}, - { BTN_RT5, 98, 46, NORMAL_BUTTON_RADIUS}, -}; -size_t platform_fighter_buttons_count = count_of(platform_fighter_buttons); - -InputViewerButton split_fgc_buttons[] = { - // {BTN_MB1, 2, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB2, 8, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB3, 14, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB4, 20, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB5, 26, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB6, 32, 3, MENU_BUTTON_RADIUS }, - // { BTN_MB7, 38, 3, MENU_BUTTON_RADIUS }, - - {BTN_LF3, 15, 23, NORMAL_BUTTON_RADIUS}, - { BTN_LF2, 25, 22, NORMAL_BUTTON_RADIUS}, - { BTN_LF1, 35, 27, NORMAL_BUTTON_RADIUS}, - { BTN_LF5, 24, 32, NORMAL_BUTTON_RADIUS}, - - { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, - { BTN_RF2, 102, 23, NORMAL_BUTTON_RADIUS}, - { BTN_RF3, 112, 24, NORMAL_BUTTON_RADIUS}, - { BTN_RF4, 122, 29, NORMAL_BUTTON_RADIUS}, - - { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, - { BTN_RF6, 102, 13, NORMAL_BUTTON_RADIUS}, - { BTN_RF7, 112, 14, NORMAL_BUTTON_RADIUS}, - { BTN_RF8, 122, 19, NORMAL_BUTTON_RADIUS}, - - { BTN_LT1, 38, 52, LARGE_BUTTON_RADIUS }, - { BTN_RT1, 90, 52, LARGE_BUTTON_RADIUS }, -}; -size_t split_fgc_buttons_count = count_of(split_fgc_buttons); - -InputViewerButton fgc_buttons[] = { - {BTN_LF6, 35, 17, NORMAL_BUTTON_RADIUS}, - { BTN_LF7, 46, 19, NORMAL_BUTTON_RADIUS}, - { BTN_LF8, 55, 25, NORMAL_BUTTON_RADIUS}, - - { BTN_RF9, 64, 30, NORMAL_BUTTON_RADIUS}, - { BTN_RF10, 74, 25, NORMAL_BUTTON_RADIUS}, - { BTN_RF11, 84, 25, NORMAL_BUTTON_RADIUS}, - { BTN_RF1, 93, 27, NORMAL_BUTTON_RADIUS}, - - { BTN_RF12, 64, 20, NORMAL_BUTTON_RADIUS}, - { BTN_RF13, 74, 15, NORMAL_BUTTON_RADIUS}, - { BTN_RF14, 84, 15, NORMAL_BUTTON_RADIUS}, - { BTN_RF5, 93, 17, NORMAL_BUTTON_RADIUS}, - - { BTN_LT6, 59, 50, LARGE_BUTTON_RADIUS } -}; -size_t fgc_buttons_count = count_of(fgc_buttons); - -#endif \ No newline at end of file diff --git a/config/glyph/include/display/GlyphConfigMenu.hpp b/config/glyph/include/display/GlyphConfigMenu.hpp deleted file mode 100644 index 775db523..00000000 --- a/config/glyph/include/display/GlyphConfigMenu.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _DISPLAY_GLYPHCONFIGMENU_HPP -#define _DISPLAY_GLYPHCONFIGMENU_HPP - -#include "display/DefaultConfigMenu.hpp" - -/** - * @brief Modified version of ConfigMenu that only shows gamemodes marked as applicable for current - * CommunicationBackend. - */ -class GlyphConfigMenu : public DefaultConfigMenu { - public: - GlyphConfigMenu(Config &config, CommunicationBackend **backends, size_t backends_count); - void ReturnToDashboard(IntegratedDisplay *instance); - - private: - static void SetDashboardOption( - IntegratedDisplay *instance, - ConfigMenu *menu, - Config &config, - uint8_t mode_config_index - ); -}; - -#endif \ No newline at end of file diff --git a/config/glyph/include/display/MenuButtonHints.hpp b/config/glyph/include/display/MenuButtonHints.hpp deleted file mode 100644 index 52dc9c39..00000000 --- a/config/glyph/include/display/MenuButtonHints.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _DISPLAY_MENUBUTTONHINTS_HPP -#define _DISPLAY_MENUBUTTONHINTS_HPP - -#include "display/DisplayMode.hpp" - -class MenuButtonHints : public DisplayMode { - public: - MenuButtonHints(CommunicationBackendId backend_id); - DisplayModeId GetId(); - void HandleControls( - IntegratedDisplay *instance, - const DisplayControls &controls, - Button button - ); - void UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display); - - protected: - CommunicationBackendId _backend_id; -}; - -#endif \ No newline at end of file diff --git a/config/glyph/include/glyph_overrides.hpp b/config/glyph/include/glyph_overrides.hpp deleted file mode 100644 index 13511145..00000000 --- a/config/glyph/include/glyph_overrides.hpp +++ /dev/null @@ -1,404 +0,0 @@ -#ifndef _GLYPH_OVERRIDES_HPP -#define _GLYPH_OVERRIDES_HPP - -#include "comms/B0XXInputViewer.hpp" -#include "comms/IntegratedDisplay.hpp" -#include "comms/NeoPixelBackend.hpp" -#include "core/config_utils.hpp" -#include "stdlib.hpp" - -#include -#include - -#define LED_PIN 7 -#define LED_COUNT 72 - -// clang-format off - -const Config default_config = { - .game_mode_configs_count = 6, - .game_mode_configs = { - GameModeConfig { - .mode_id = MODE_MELEE, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 4, - .button_remapping = { - ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, // Menu - ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, // Start - ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_MB3 }, // Back - ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_MB2 }, // Home - }, - .rgb_config = 1, - }, - GameModeConfig { - .mode_id = MODE_PROJECT_M, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 4, - .button_remapping = { - ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, // Menu - ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, // Start - ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_MB3 }, // Back - ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_MB2 }, // Home - }, - .rgb_config = 1, - }, - GameModeConfig { - .mode_id = MODE_ULTIMATE, - .socd_pairs_count = 4, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 4, - .button_remapping = { - ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, // Menu - ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, // Start - ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_MB3 }, // Back - ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_MB2 }, // Home - }, - .rgb_config = 1, - }, - GameModeConfig { - .mode_id = MODE_FGC, - .name = "Split FGC", - .socd_pairs_count = 2, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_LT1, .socd_type = SOCD_NEUTRAL }, - }, - .button_remapping_count = 7, - .button_remapping = { - ButtonRemap { .physical_button = BTN_RT1, .activates = BTN_LT1 }, - ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_RT3 }, - ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_RT2 }, - ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, - ButtonRemap { .physical_button = BTN_RT2, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RT3, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, - }, - .rgb_config = 1, - .layout_plate = LAYOUT_PLATE_SPLIT_FGC, - }, - GameModeConfig { - .mode_id = MODE_FGC, - .socd_pairs_count = 2, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_LT1, .socd_type = SOCD_NEUTRAL }, - }, - .button_remapping_count = 28, - .button_remapping = { - // Right hand bottom row - ButtonRemap { .physical_button = BTN_RF9, .activates = BTN_RF1 }, - ButtonRemap { .physical_button = BTN_RF10, .activates = BTN_RF2 }, - ButtonRemap { .physical_button = BTN_RF11, .activates = BTN_RF3 }, - ButtonRemap { .physical_button = BTN_RF1, .activates = BTN_RF4 }, - // Right hand top row - ButtonRemap { .physical_button = BTN_RF12, .activates = BTN_RF5 }, - ButtonRemap { .physical_button = BTN_RF13, .activates = BTN_RF6 }, - ButtonRemap { .physical_button = BTN_RF14, .activates = BTN_RF7 }, - ButtonRemap { .physical_button = BTN_RF5, .activates = BTN_RF8 }, - // Left hand row - ButtonRemap { .physical_button = BTN_LF8, .activates = BTN_LF1 }, - ButtonRemap { .physical_button = BTN_LF7, .activates = BTN_LF2 }, - ButtonRemap { .physical_button = BTN_LF6, .activates = BTN_LF3 }, - // Up button - ButtonRemap { .physical_button = BTN_LT6, .activates = BTN_LT1 }, - // Menu buttons - ButtonRemap { .physical_button = BTN_MB3, .activates = BTN_RT3 }, - ButtonRemap { .physical_button = BTN_MB4, .activates = BTN_RT2 }, - ButtonRemap { .physical_button = BTN_MB2, .activates = BTN_MB1 }, - - // Unmap the old buttons - ButtonRemap { .physical_button = BTN_RF2, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RF3, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RF4, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RF6, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RF7, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RF8, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_LF1, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_LF2, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_LF3, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_LT1, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RT2, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_RT3, .activates = BTN_UNSPECIFIED }, - ButtonRemap { .physical_button = BTN_MB1, .activates = BTN_UNSPECIFIED }, - }, - .rgb_config = 2, - .layout_plate = LAYOUT_PLATE_FGC, - }, - GameModeConfig { - .mode_id = MODE_KEYBOARD, - .socd_pairs_count = 2, - .socd_pairs = { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .keyboard_mode_config = 1, - }, - }, - .communication_backend_configs_count = 8, - .communication_backend_configs = { - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_XINPUT, - .default_mode_config = 1, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_DINPUT, - .default_mode_config = 1, - .activation_binding_count = 1, - .activation_binding = { BTN_RF3 }, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_NINTENDO_SWITCH, - .default_mode_config = 3, - .activation_binding_count = 1, - .activation_binding = { BTN_RF2 }, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_GAMECUBE, - .default_mode_config = 1, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_N64, - .default_mode_config = 1, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_NES, - .default_mode_config = 1, - .activation_binding_count = 1, - .activation_binding = { BTN_LT1 }, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_SNES, - .default_mode_config = 1, - .activation_binding_count = 1, - .activation_binding = { BTN_LT2 }, - }, - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_CONFIGURATOR, - .activation_binding_count = 1, - .activation_binding = { BTN_RT2 }, - } - }, - .keyboard_modes_count = 1, - .keyboard_modes = { - KeyboardModeConfig { - 0, - 22, - { - { BTN_LF4, HID_KEY_A }, - { BTN_LF3, HID_KEY_B }, - { BTN_LF2, HID_KEY_C }, - { BTN_LF1, HID_KEY_D }, - { BTN_LT1, HID_KEY_E }, - { BTN_LT2, HID_KEY_F }, - { BTN_MB3, HID_KEY_G }, - { BTN_MB1, HID_KEY_H }, - { BTN_MB2, HID_KEY_I }, - { BTN_RF5, HID_KEY_J }, - { BTN_RF6, HID_KEY_K }, - { BTN_RF7, HID_KEY_L }, - { BTN_RF8, HID_KEY_M }, - { BTN_RF1, HID_KEY_N }, - { BTN_RF2, HID_KEY_O }, - { BTN_RF3, HID_KEY_P }, - { BTN_RF4, HID_KEY_Q }, - { BTN_RT4, HID_KEY_R }, - { BTN_RT3, HID_KEY_S }, - { BTN_RT5, HID_KEY_T }, - { BTN_RT1, HID_KEY_U }, - { BTN_RT2, HID_KEY_V }, - }, - }, - }, - .rgb_configs_count = 2, - .rgb_configs = { - RgbConfig { - .button_colors_count = 19, - .button_colors = { - { BTN_LF1, 0x0000ff }, - { BTN_LF2, 0x0000ff }, - { BTN_LF3, 0x0000ff }, - { BTN_LF4, 0x0000ff }, - { BTN_LT1, 0x0000ff }, - { BTN_LT2, 0x0000ff }, - { BTN_RF1, 0x0000ff }, - { BTN_RF2, 0x0000ff }, - { BTN_RF3, 0x0000ff }, - { BTN_RF4, 0x0000ff }, - { BTN_RF5, 0x0000ff }, - { BTN_RF6, 0x0000ff }, - { BTN_RF7, 0x0000ff }, - { BTN_RF8, 0x0000ff }, - { BTN_RT1, 0x0000ff }, - { BTN_RT2, 0x0000ff }, - { BTN_RT3, 0x0000ff }, - { BTN_RT4, 0x0000ff }, - { BTN_RT5, 0x0000ff }, - }, - }, - RgbConfig { - .button_colors_count = 12, - .button_colors = { - { BTN_LF6, 0xff0000 }, - { BTN_LF7, 0xff0000 }, - { BTN_LF8, 0xff0000 }, - { BTN_LT6, 0xff0000 }, - { BTN_RF9, 0xff0000 }, - { BTN_RF10, 0xff0000 }, - { BTN_RF11, 0xff0000 }, - { BTN_RF1, 0xff0000 }, - { BTN_RF12, 0xff0000 }, - { BTN_RF13, 0xff0000 }, - { BTN_RF14, 0xff0000 }, - { BTN_RF5, 0xff0000 }, - }, - }, - }, - .default_backend_config = 1, - .default_usb_backend_config = 1, - .rgb_brightness = 255, -}; - -const Button pixel_to_button_mappings[LED_COUNT] = { - BTN_MB1, BTN_MB1, - BTN_LF4, BTN_LF4, - BTN_LF3, BTN_LF3, - BTN_LF5, BTN_LF5, - BTN_LF2, BTN_LF2, - BTN_LF1, BTN_LF1, - BTN_LF6, BTN_LF6, - BTN_LF7, BTN_LF7, - BTN_LF8, BTN_LF8, - BTN_RF12, BTN_RF12, - BTN_RF13, BTN_RF13, - BTN_RF14, BTN_RF14, - BTN_RF5, BTN_RF5, - BTN_RF6, BTN_RF6, - BTN_RF7, BTN_RF7, - BTN_RF8, BTN_RF8, - BTN_RF4, BTN_RF4, - BTN_RF3, BTN_RF3, - BTN_RF2, BTN_RF2, - BTN_RF1, BTN_RF1, - BTN_RF11, BTN_RF11, - BTN_RF10, BTN_RF10, - BTN_RF9, BTN_RF9, - BTN_RT3, BTN_RT3, - BTN_RT4, BTN_RT4, - BTN_RT5, BTN_RT5, - BTN_RT1, BTN_RT1, - BTN_RT1, BTN_RT1, - BTN_RT2, BTN_RT2, - BTN_LT6, BTN_LT6, - BTN_LT3, BTN_LT3, - BTN_LT4, BTN_LT4, - BTN_LT5, BTN_LT5, - BTN_LT1, BTN_LT1, - BTN_LT1, BTN_LT1, - BTN_LT2, BTN_LT2, -}; - -// clang-format on - -Config glyph_default_config() { - Config config = default_config; - - // Assign layout plates and applicable backends for default gamemode configs. - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode_config = config.game_mode_configs[i]; - switch (mode_config.mode_id) { - case MODE_FGC: - mode_config.applicable_backends[0] = COMMS_BACKEND_XINPUT; - mode_config.applicable_backends[1] = COMMS_BACKEND_DINPUT; - mode_config.applicable_backends[2] = COMMS_BACKEND_NINTENDO_SWITCH; - mode_config.applicable_backends_count = 3; - break; - case MODE_MELEE: - case MODE_PROJECT_M: - case MODE_ULTIMATE: - case MODE_RIVALS_OF_AETHER: - mode_config.rgb_config = 1; - mode_config.layout_plate = LAYOUT_PLATE_PLATFORM_FIGHTER; - mode_config.applicable_backends[0] = COMMS_BACKEND_XINPUT; - mode_config.applicable_backends[1] = COMMS_BACKEND_DINPUT; - mode_config.applicable_backends[2] = COMMS_BACKEND_NINTENDO_SWITCH; - mode_config.applicable_backends[3] = COMMS_BACKEND_GAMECUBE; - mode_config.applicable_backends_count = 4; - break; - case MODE_KEYBOARD: - mode_config.applicable_backends[0] = COMMS_BACKEND_DINPUT; - mode_config.applicable_backends_count = 1; - mode_config.rgb_config = 1; - break; - default: - mode_config.layout_plate = LAYOUT_PLATE_EVERYTHING; - } - } - - return config; -} - -size_t init_secondary_backends_glyph( - CommunicationBackend **&backends, - CommunicationBackend *&primary_backend, - CommunicationBackendId backend_id, - InputState &inputs, - InputSource **input_sources, - size_t input_source_count, - Config &config, - const Pinout &pinout -) { - size_t backend_count = init_secondary_backends_default( - backends, - primary_backend, - backend_id, - inputs, - input_sources, - input_source_count, - config, - pinout - ); - - // Create new array containing all old backends but with length increased by 1 to make space for - // NeoPixel backend. - CommunicationBackend **new_backends = new CommunicationBackend *[backend_count + 1]; - for (size_t i = 0; i < backend_count; i++) { - new_backends[i] = backends[i]; - } - - // Add new backend to array and increase backend count to reflect this. - new_backends[backend_count++] = new NeoPixelBackend( - inputs, - input_sources, - input_source_count, - pixel_to_button_mappings, - config.rgb_configs, - config.rgb_configs_count, - config.rgb_brightness - ); - - // Delete the old backends array and reassign it. - delete[] backends; - backends = new_backends; - - return backend_count; -} - -#endif \ No newline at end of file diff --git a/config/glyph/src/display/GlyphConfigMenu.cpp b/config/glyph/src/display/GlyphConfigMenu.cpp deleted file mode 100644 index cf91f7bb..00000000 --- a/config/glyph/src/display/GlyphConfigMenu.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "display/GlyphConfigMenu.hpp" - -#include "core/Persistence.hpp" -#include "core/config_utils.hpp" -#include "core/mode_selection.hpp" -#include "reboot.hpp" - -GlyphConfigMenu::GlyphConfigMenu( - Config &config, - CommunicationBackend **backends, - size_t backends_count -) - : DefaultConfigMenu(config, backends, backends_count) { - /* Build gamemodes page */ - size_t gamemode_options_count = 0; - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode_config = config.game_mode_configs[i]; - MenuPage::MenuItem ¤t_option = _gamemode_options_page.items[gamemode_options_count]; - - // Only show gamemodes that are applicable to the current comms backend. - if (mode_config.applicable_backends_count > 0 && _backends_count > 0 && - _backends[0] != nullptr) { - CommunicationBackendId primary_backend_id = _backends[0]->BackendId(); - bool applicable = false; - for (size_t i = 0; i < mode_config.applicable_backends_count; i++) { - if (primary_backend_id == mode_config.applicable_backends[i]) { - applicable = true; - break; - } - } - if (!applicable) { - continue; - } - } - - if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { - strlcpy(current_option.text, mode_config.name, sizeof(current_option.text)); - } else { - strlcpy( - current_option.text, - gamemode_name(mode_config.mode_id), - sizeof(current_option.text) - ); - } - current_option.key = i; - current_option.action = &SetDefaultMode; - gamemode_options_count++; - } - _gamemode_options_page.items_count = gamemode_options_count; - - /* Add new page for dashboard option */ - // clang-format off - size_t dashboard_options_count = 2; - static MenuPage::MenuItem dashboard_options[] = { - { - .text = "Dashboard Menu", - .key = DASHBOARD_MENU_BUTTON_HINTS, - .action = &SetDashboardOption, - }, - { - .text = "Input Viewer", - .key = DASHBOARD_INPUT_VIEWER, - .action = &SetDashboardOption, - }, - }; - // clang-format on - - static MenuPage dashboard_options_page = { - .parent = _top_level_page, - .items = dashboard_options, - .items_count = sizeof(dashboard_options) / sizeof(MenuPage::MenuItem), - }; - - /* Overrides for top-level page */ - strlcpy(_top_level_page->items[2].text, "SOCD Option", sizeof(_top_level_page->items[2].text)); - _top_level_page->items[4] = { - .text = "Dashboard Option", - .page = &dashboard_options_page, - }; -} - -void GlyphConfigMenu::ReturnToDashboard(IntegratedDisplay *instance) { - instance->SetDisplayMode( - _config.default_dashboard_option == DASHBOARD_INPUT_VIEWER ? DISPLAY_MODE_VIEWER - : DISPLAY_MODE_BUTTON_HINTS - ); -} - -void GlyphConfigMenu::SetDashboardOption( - IntegratedDisplay *display_backend, - ConfigMenu *menu, - Config &config, - uint8_t dashboard_option -) { - // Restore gamemode. - GlyphConfigMenu *config_menu = (GlyphConfigMenu *)menu; - if (config_menu->_backends[0] != nullptr) { - config_menu->_backends[0]->SetGameMode(display_backend->CurrentGameMode()); - } - - config.default_dashboard_option = (DashboardOption)dashboard_option; - config_menu->ReturnToDashboard(display_backend); -} \ No newline at end of file diff --git a/config/glyph/src/display/MenuButtonHints.cpp b/config/glyph/src/display/MenuButtonHints.cpp deleted file mode 100644 index 6335f44b..00000000 --- a/config/glyph/src/display/MenuButtonHints.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "display/MenuButtonHints.hpp" - -#include "comms/IntegratedDisplay.hpp" -#include "core/config_utils.hpp" -#include "util/state_util.hpp" - -MenuButtonHints::MenuButtonHints(const CommunicationBackendId backend_id) - : _backend_id(backend_id) {} - -DisplayModeId MenuButtonHints::GetId() { - return DISPLAY_MODE_BUTTON_HINTS; -} - -void MenuButtonHints::HandleControls( - IntegratedDisplay *instance, - const DisplayControls &controls, - Button button -) { - if (button == controls.back) { - instance->SetDisplayMode(DISPLAY_MODE_CONFIG); - } -} - -void MenuButtonHints::UpdateDisplay(IntegratedDisplay *instance, Adafruit_GFX &display) { - InputState &inputs = instance->GetInputs(); - uint8_t font_width = instance->font_width; - uint8_t color = instance->default_color; - - /* Gamemode text */ - display.setCursor(0, 0); - if (instance->CurrentGameMode() != nullptr) { - const GameModeConfig &mode_config = *instance->CurrentGameMode()->GetConfig(); - if (strnlen(mode_config.name, sizeof(mode_config.name)) > 0) { - display.print(mode_config.name); - } else { - display.print(gamemode_name(mode_config.mode_id)); - } - } - - /* Backend text */ - const char *backend_text = backend_name(_backend_id); - display.setCursor(display.width() - (strlen(backend_text) * font_width), 0); - display.print(backend_name(_backend_id)); - - /* Button hints */ - uint8_t old_rotation = display.getRotation(); - display.setRotation(3); - - display.setCursor(0, 0); - - display.println("Menu\n"); - display.println("Start\n"); - display.println("Back\n"); - display.println("Home\n"); - display.println("Capt.\n"); - display.println("L3\n"); - display.println("R3\n"); - - display.setRotation(old_rotation); -} \ No newline at end of file From 05f548efcdcc30387be7f0e271d39c28f2567f47 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Wed, 12 Jun 2024 20:32:11 +0100 Subject: [PATCH 146/167] fix: don't allow keyboard modes unless DInputBackend --- src/core/mode_selection.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index a5b98822..257b9da2 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -69,7 +69,8 @@ void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config set_mode(backend, &rivals_mode); break; case MODE_KEYBOARD: - if (mode_config.keyboard_mode_config < 1 || + if (backend->BackendId() != COMMS_BACKEND_DINPUT || + mode_config.keyboard_mode_config < 1 || mode_config.keyboard_mode_config > config.keyboard_modes_count) { break; } From 65bb5e54392d90155c418c4159b31efa685b1047 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 14 Jun 2024 22:39:44 +0100 Subject: [PATCH 147/167] feat: add CommunicationBackend.GetOutputs() --- include/core/CommunicationBackend.hpp | 1 + src/core/CommunicationBackend.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/core/CommunicationBackend.hpp b/include/core/CommunicationBackend.hpp index fdcd73aa..5d661430 100644 --- a/include/core/CommunicationBackend.hpp +++ b/include/core/CommunicationBackend.hpp @@ -15,6 +15,7 @@ class CommunicationBackend { virtual ~CommunicationBackend(){}; InputState &GetInputs(); + OutputState &GetOutputs(); void ScanInputs(); void ScanInputs(InputScanSpeed input_source_filter); diff --git a/src/core/CommunicationBackend.cpp b/src/core/CommunicationBackend.cpp index c7a756d5..f38d5b5d 100644 --- a/src/core/CommunicationBackend.cpp +++ b/src/core/CommunicationBackend.cpp @@ -21,6 +21,10 @@ InputState &CommunicationBackend::GetInputs() { return _inputs; } +OutputState &CommunicationBackend::GetOutputs() { + return _outputs; +} + void CommunicationBackend::ScanInputs() { for (size_t i = 0; i < _input_source_count; i++) { _input_sources[i]->UpdateInputs(_inputs); From 602c61e67573eb47986793f69e83e44479c96e1d Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 14 Jun 2024 22:41:32 +0100 Subject: [PATCH 148/167] refactor: put OutputState analog axes in anonymous union + struct --- include/core/state.hpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/include/core/state.hpp b/include/core/state.hpp index 315199d1..8a8e7e13 100644 --- a/include/core/state.hpp +++ b/include/core/state.hpp @@ -129,12 +129,18 @@ typedef struct _OutputState { }; // Analog outputs. - uint8_t leftStickX = 128; - uint8_t leftStickY = 128; - uint8_t rightStickX = 128; - uint8_t rightStickY = 128; - uint8_t triggerRAnalog = 0; - uint8_t triggerLAnalog = 0; + union { + uint8_t analog_axes[6] = { 128, 128, 128, 128, 0, 0 }; + + struct { + uint8_t leftStickX; + uint8_t leftStickY; + uint8_t rightStickX; + uint8_t rightStickY; + uint8_t triggerLAnalog; + uint8_t triggerRAnalog; + }; + }; } OutputState; #endif \ No newline at end of file From ce0341c48a3306d00392d6ef9da58ccd3a9df5e5 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 14 Jun 2024 22:42:22 +0100 Subject: [PATCH 149/167] feat: add digital_output_name() helper --- HAL/pico/include/util/state_util.hpp | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/HAL/pico/include/util/state_util.hpp b/HAL/pico/include/util/state_util.hpp index 9f898d6f..40b8aeb9 100644 --- a/HAL/pico/include/util/state_util.hpp +++ b/HAL/pico/include/util/state_util.hpp @@ -69,4 +69,47 @@ inline uint8_t OutputState::*axis_pointer(AnalogAxis axis) { } } +constexpr const char *digital_output_name(DigitalOutput output) { + switch (output) { + case GP_A: + return "A"; + case GP_B: + return "B"; + case GP_X: + return "X"; + case GP_Y: + return "Y"; + case GP_LB: + return "L1"; + case GP_RB: + return "R1"; + case GP_LT: + return "L2"; + case GP_RT: + return "R2"; + case GP_START: + return "Start"; + case GP_SELECT: + return "Select"; + case GP_HOME: + return "Home"; + case GP_CAPTURE: + return "Capture"; + case GP_DPAD_UP: + return "D-Pad Up"; + case GP_DPAD_DOWN: + return "D-Pad Down"; + case GP_DPAD_LEFT: + return "D-Pad Left"; + case GP_DPAD_RIGHT: + return "D-Pad Right"; + case GP_LSTICK_CLICK: + return "L3"; + case GP_RSTICK_CLICK: + return "R3"; + default: + return "Unknown"; + } +} + #endif \ No newline at end of file From a836a213bd767196299d0937eb47710bbf80eb00 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Jun 2024 13:20:51 +0100 Subject: [PATCH 150/167] ci: update GitHub Actions workflows --- .github/workflows/build-device-config.yml | 8 +- .github/workflows/build.yml | 96 +++++++++++++---------- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/.github/workflows/build-device-config.yml b/.github/workflows/build-device-config.yml index aea2f77d..94afa079 100644 --- a/.github/workflows/build-device-config.yml +++ b/.github/workflows/build-device-config.yml @@ -33,9 +33,9 @@ jobs: PIO_ENV: ${{ matrix.env }} BIN_EXT: ${{ matrix.bin_ext }} strategy: - fail-fast: false - matrix: - include: ${{ fromJson(needs.metadata.outputs.meta_json).build }} + fail-fast: false + matrix: + include: ${{ fromJson(needs.metadata.outputs.meta_json).build }} steps: - name: Check out specific HayBox revision @@ -74,7 +74,7 @@ jobs: cp ".pio/build/${PIO_ENV}/firmware.${BIN_EXT}" "$ARTIFACT_PATH" - name: Publish ${{ matrix.env }} artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ env.ARTIFACT_NAME }} path: ${{ env.ARTIFACT_PATH }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf4cb592..34c64982 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,44 +9,46 @@ jobs: contents: write env: VERSION_REF: ${{ github.ref_type == 'tag' && github.ref_name || github.sha }} + PIO_ENV: ${{ matrix.env }} + BIN_EXT: ${{ matrix.bin_ext }} strategy: - fail-fast: false - matrix: - include: - - env: c53 - bin_ext: uf2 - - env: b0xx_r4 - bin_ext: uf2 - - env: glyph - bin_ext: uf2 - - env: pico - bin_ext: uf2 - - env: schism - bin_ext: uf2 - - env: arduino_uno - bin_ext: hex - - env: arduino_nano - bin_ext: hex - - env: arduino_mega - bin_ext: hex - - env: arduino_leonardo - bin_ext: hex - - env: arduino_micro - bin_ext: hex - - env: b0xx_r1 - bin_ext: hex - - env: b0xx_r2 - bin_ext: hex - - env: gccmx - bin_ext: hex - - env: gccpcb1 - bin_ext: hex - - env: gccpcb2 - bin_ext: hex - - env: lbx - bin_ext: hex - - env: smashbox - bin_ext: hex + fail-fast: false + matrix: + include: + - env: c53 + bin_ext: uf2 + - env: b0xx_r4 + bin_ext: uf2 + - env: glyph + bin_ext: uf2 + - env: pico + bin_ext: uf2 + - env: schism + bin_ext: uf2 + - env: arduino_uno + bin_ext: hex + - env: arduino_nano + bin_ext: hex + - env: arduino_mega + bin_ext: hex + - env: arduino_leonardo + bin_ext: hex + - env: arduino_micro + bin_ext: hex + - env: b0xx_r1 + bin_ext: hex + - env: b0xx_r2 + bin_ext: hex + - env: gccmx + bin_ext: hex + - env: gccpcb1 + bin_ext: hex + - env: gccpcb2 + bin_ext: hex + - env: lbx + bin_ext: hex + - env: smashbox + bin_ext: hex steps: - name: Check out source code @@ -62,20 +64,28 @@ jobs: python -m pip install --upgrade pip pip install --upgrade platformio + - name: Set artifact filename environment variable + run: | + echo "ARTIFACT_NAME=HayBox-${VERSION_REF}-${PIO_ENV}.${BIN_EXT}" >> "$GITHUB_ENV" + + - name: Set artifact path environment variable + run: | + echo "ARTIFACT_PATH=${PIO_ENV}/${ARTIFACT_NAME}" >> "$GITHUB_ENV" + - name: Build ${{ matrix.env }} env run: | - pio run -e ${{ matrix.env }} - mkdir -p ${{ matrix.env }} - cp ".pio/build/${{ matrix.env }}/firmware.${{ matrix.bin_ext }}" "${{ matrix.env }}/HayBox-${VERSION_REF}-${{ matrix.env }}.${{ matrix.bin_ext }}" + pio run -e "$PIO_ENV" + mkdir -p "$PIO_ENV" + cp ".pio/build/${PIO_ENV}/firmware.${BIN_EXT}" "$ARTIFACT_PATH" - name: Publish ${{ matrix.env }} artifacts uses: actions/upload-artifact@v4 with: - name: HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} - path: ${{ matrix.env }}/HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} + name: ${{ env.ARTIFACT_NAME }} + path: ${{ env.ARTIFACT_PATH }} - name: Upload binaries to release uses: softprops/action-gh-release@v1 if: github.ref_type == 'tag' with: - files: ${{ matrix.env }}/HayBox-${{ env.VERSION_REF }}-${{ matrix.env }}.${{ matrix.bin_ext }} + files: ${{ env.ARTIFACT_PATH }} From b38e53a64349bb2263096249813ae14f5ef1a304 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 29 Jun 2024 16:31:52 +0100 Subject: [PATCH 151/167] feat: add RoA mode config to default config --- .clang-format | 3 ++- HAL/pico/include/config_defaults.hpp | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.clang-format b/.clang-format index b65ffac5..f1a58223 100644 --- a/.clang-format +++ b/.clang-format @@ -59,4 +59,5 @@ SpacesInContainerLiterals: false TabWidth: 4 UseTab: Never --- -Language: Proto \ No newline at end of file +Language: Proto +ColumnLimit: 100 \ No newline at end of file diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index e0fcc6ed..9f74b0dd 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -7,7 +7,7 @@ // clang-format off const Config default_config = { - .game_mode_configs_count = 5, + .game_mode_configs_count = 6, .game_mode_configs = { GameModeConfig { .mode_id = MODE_MELEE, @@ -62,6 +62,19 @@ const Config default_config = { .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF1 }, }, + GameModeConfig { + .mode_id = MODE_RIVALS_OF_AETHER, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_RF1 }, + }, GameModeConfig { .mode_id = MODE_KEYBOARD, .socd_pairs_count = 2, From 211f97ccbdbc634b18d8f23eb439fc355218ad92 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sun, 29 Sep 2024 21:41:59 +0100 Subject: [PATCH 152/167] build: pin platform version --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 447587b2..2a5baa73 100644 --- a/platformio.ini +++ b/platformio.ini @@ -80,7 +80,7 @@ lib_deps = https://github.com/JonnyHaystack/ArduinoKeyboard/archive/refs/tags/1.0.5.zip [arduino_pico_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c framework = arduino board = pico extra_scripts = pre:builder_scripts/arduino_pico.py From 82a18105283bf4bcd646574ddfafea73893c7945 Mon Sep 17 00:00:00 2001 From: Grammy da goat <126632196+GrammyMoney@users.noreply.github.com> Date: Sun, 26 Jan 2025 14:23:10 -0600 Subject: [PATCH 153/167] Add Austin's Rivals 2 mode (#87) Add Austin's Rivals 2 mode --------- Co-authored-by: 901Austin <96558798+901Austin@users.noreply.github.com> --- .vscode/extensions.json | 14 +- HAL/pico/include/config_defaults.hpp | 21 ++- config/pico/config.cpp | 56 +++--- include/core/config_utils.hpp | 4 +- include/modes/Rivals2.hpp | 18 ++ platformio.ini | 2 +- src/core/mode_selection.cpp | 8 +- src/modes/Rivals2.cpp | 260 +++++++++++++++++++++++++++ 8 files changed, 341 insertions(+), 42 deletions(-) create mode 100644 include/modes/Rivals2.hpp create mode 100644 src/modes/Rivals2.cpp diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0f0d7401..e80666bf 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,7 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/HAL/pico/include/config_defaults.hpp b/HAL/pico/include/config_defaults.hpp index 9f74b0dd..96c9f971 100644 --- a/HAL/pico/include/config_defaults.hpp +++ b/HAL/pico/include/config_defaults.hpp @@ -7,9 +7,9 @@ // clang-format off const Config default_config = { - .game_mode_configs_count = 6, + .game_mode_configs_count = 7, .game_mode_configs = { - GameModeConfig { + GameModeConfig { .mode_id = MODE_MELEE, .socd_pairs_count = 4, .socd_pairs = { @@ -22,7 +22,7 @@ const Config default_config = { .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_LF4 }, }, - GameModeConfig { + GameModeConfig { .mode_id = MODE_PROJECT_M, .socd_pairs_count = 4, .socd_pairs = { @@ -75,6 +75,19 @@ const Config default_config = { .activation_binding_count = 3, .activation_binding = { BTN_LT1, BTN_MB1, BTN_RF1 }, }, + GameModeConfig { + .mode_id = MODE_RIVALS_2, + .socd_pairs_count = 4, + .socd_pairs = { + SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, + SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, + }, + .button_remapping_count = 0, + .activation_binding_count = 3, + .activation_binding = { BTN_LT1, BTN_MB1, BTN_RF5 }, + }, GameModeConfig { .mode_id = MODE_KEYBOARD, .socd_pairs_count = 2, @@ -177,4 +190,4 @@ const Config default_config = { // clang-format on -#endif \ No newline at end of file +#endif diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 68a5c754..2249f2ef 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -16,33 +16,33 @@ Config config = default_config; GpioButtonMapping button_mappings[] = { - {BTN_LF1, 2 }, - { BTN_LF2, 3 }, - { BTN_LF3, 4 }, - { BTN_LF4, 5 }, - - { BTN_LT1, 6 }, - { BTN_LT2, 7 }, - - { BTN_MB1, 0 }, - { BTN_MB2, 10}, - { BTN_MB3, 11}, - - { BTN_RT1, 14}, - { BTN_RT2, 15}, - { BTN_RT3, 13}, - { BTN_RT4, 12}, - { BTN_RT5, 16}, - - { BTN_RF1, 26}, - { BTN_RF2, 21}, - { BTN_RF3, 19}, - { BTN_RF4, 17}, - - { BTN_RF5, 27}, - { BTN_RF6, 22}, - { BTN_RF7, 20}, - { BTN_RF8, 18}, + { BTN_LF1, 2 }, + { BTN_LF2, 3 }, + { BTN_LF3, 4 }, + { BTN_LF4, 5 }, + + { BTN_LT1, 6 }, + { BTN_LT2, 7 }, + + { BTN_MB1, 0 }, + { BTN_MB2, 10 }, + { BTN_MB3, 11 }, + + { BTN_RT1, 14 }, + { BTN_RT2, 15 }, + { BTN_RT3, 13 }, + { BTN_RT4, 12 }, + { BTN_RT5, 16 }, + + { BTN_RF1, 26 }, + { BTN_RF2, 21 }, + { BTN_RF3, 19 }, + { BTN_RF4, 17 }, + + { BTN_RF5, 27 }, + { BTN_RF6, 22 }, + { BTN_RF7, 20 }, + { BTN_RF8, 18 }, }; const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); @@ -115,4 +115,4 @@ void loop1() { if (backends != nullptr) { gpio_input.UpdateInputs(backends[0]->GetInputs()); } -} +} \ No newline at end of file diff --git a/include/core/config_utils.hpp b/include/core/config_utils.hpp index 31b95581..0812c516 100644 --- a/include/core/config_utils.hpp +++ b/include/core/config_utils.hpp @@ -41,6 +41,8 @@ constexpr const char *gamemode_name(GameModeId mode_id) { return "FGC"; case MODE_RIVALS_OF_AETHER: return "Rivals"; + case MODE_RIVALS_2: + return "Rivals 2"; case MODE_KEYBOARD: return "Keyboard"; default: @@ -88,4 +90,4 @@ constexpr const char *socd_name(SocdType socd_type) { } } -#endif \ No newline at end of file +#endif diff --git a/include/modes/Rivals2.hpp b/include/modes/Rivals2.hpp new file mode 100644 index 00000000..5ccbbad3 --- /dev/null +++ b/include/modes/Rivals2.hpp @@ -0,0 +1,18 @@ +#ifndef _MODES_RIVALS_2_HPP +#define _MODES_RIVALS_2_HPP + +#include "core/ControllerMode.hpp" +#include "core/state.hpp" + +#include //this was not here, but doesn't seem to matter if I remove it from Melee20Button.hpp anyway + +class Rivals2 : public ControllerMode { + public: + Rivals2(); + + private: + void UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs); + void UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs); +}; + +#endif diff --git a/platformio.ini b/platformio.ini index 2a5baa73..0628e8e2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ custom_nanopb_options = --error-on-unmatched lib_deps = nanopb/Nanopb@^0.4.8 - https://github.com/JonnyHaystack/HayBox-proto#5b2bb5d + https://github.com/JonnyHaystack/HayBox-proto#bbd0862 [avr_base] platform = atmelavr diff --git a/src/core/mode_selection.cpp b/src/core/mode_selection.cpp index 257b9da2..81a7e1d0 100644 --- a/src/core/mode_selection.cpp +++ b/src/core/mode_selection.cpp @@ -6,6 +6,7 @@ #include "modes/FgcMode.hpp" #include "modes/Melee20Button.hpp" #include "modes/ProjectM.hpp" +#include "modes/Rivals2.hpp" #include "modes/RivalsOfAether.hpp" #include "modes/Ultimate.hpp" #include "util/state_util.hpp" @@ -17,6 +18,7 @@ ProjectM projectm_mode; Ultimate ultimate_mode; FgcMode fgc_mode; RivalsOfAether rivals_mode; +Rivals2 rivals2_mode; CustomKeyboardMode keyboard_mode; CustomControllerMode custom_mode; @@ -68,6 +70,10 @@ void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config rivals_mode.SetConfig(mode_config); set_mode(backend, &rivals_mode); break; + case MODE_RIVALS_2: + rivals2_mode.SetConfig(mode_config); + set_mode(backend, &rivals2_mode); + break; case MODE_KEYBOARD: if (backend->BackendId() != COMMS_BACKEND_DINPUT || mode_config.keyboard_mode_config < 1 || @@ -137,4 +143,4 @@ void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t m mode_configs[i].activation_binding_count ); } -} \ No newline at end of file +} diff --git a/src/modes/Rivals2.cpp b/src/modes/Rivals2.cpp new file mode 100644 index 00000000..eb8eb483 --- /dev/null +++ b/src/modes/Rivals2.cpp @@ -0,0 +1,260 @@ +#include "modes/Rivals2.hpp" + +#define ANALOG_STICK_MIN 0 +#define ANALOG_STICK_NEUTRAL 128 +#define ANALOG_STICK_MAX 255 + +bool input_persist; // for angled tilts +int timer = 0; // for angled tilts + +Rivals2::Rivals2() : ControllerMode() {} + +void Rivals2::UpdateDigitalOutputs(const InputState &inputs, OutputState &outputs) { + outputs.a = inputs.rt1; + outputs.b = inputs.rf1; + outputs.x = inputs.rf2; + outputs.y = inputs.rf6; + outputs.buttonR = inputs.rf3; + if (inputs.nunchuk_connected) { + // Lightshield with C button. + if (inputs.nunchuk_c) { + outputs.triggerLAnalog = 49; + } + outputs.triggerLDigital = inputs.nunchuk_z; + } else { + outputs.triggerLDigital = inputs.lf4; + } + outputs.triggerRDigital = inputs.rf5; + outputs.start = inputs.mb1; + outputs.select = inputs.mb3; + outputs.home = inputs.mb2; + outputs.leftStickClick = inputs.rf7; + outputs.buttonL = inputs.rf8; //changed from rightStickClick to buttonL + //only because buttonL is a default mapping in Rivals 2 (doesn't really matter) + + // Activate D-Pad layer by holding Mod X + Mod Y. + if (inputs.lt1 && inputs.lt2) { + outputs.dpadUp = inputs.rt4; + outputs.dpadDown = inputs.rt2; + outputs.dpadLeft = inputs.rt3; + outputs.dpadRight = inputs.rt5; + } +} + +void Rivals2::UpdateAnalogOutputs(const InputState &inputs, OutputState &outputs) { + // Coordinate calculations to make modifier handling simpler. + UpdateDirections( + inputs.lf3, // Left + inputs.lf1, // Right + inputs.lf2, // Down + inputs.rf4, // Up + inputs.rt3, // C-Left + inputs.rt5, // C-Right + inputs.rt2, // C-Down + inputs.rt4, // C-Up + ANALOG_STICK_MIN, + ANALOG_STICK_NEUTRAL, + ANALOG_STICK_MAX, + outputs + ); + + bool shield_button_pressed = inputs.lf4 || inputs.rf5; // if L or R are pressed + + if (directions.diagonal && !shield_button_pressed) { //added this conditional to give joystick accurate diagonals rather than (+/- 1.2, 1.2) should be (0.87~, 0.87~) + outputs.leftStickX = 128 + (directions.x * 92); // 92 (0.78 in-game), reduced below 0.8 to allow crouch tilts/crouch turn-around tilts + outputs.leftStickY = 128 + (directions.y * 96);//Y value 0.83. >0.8 allows fast fall + } + + if (directions.diagonal && shield_button_pressed) { + outputs.leftStickX = 128 + (directions.x * 92); // (0.77~, 0.77~) to prevent spot dodging when pressing diagonal on the ground + outputs.leftStickY = 128 + (directions.y * 92); + } + + // For MX Angled Tilts when input_persist is true + //(x, y), (69, 53), (~0.506, ~0.31) [coords, code_values, in-game values] + if (input_persist) { //input_persist becomes true if ModX + diagonal + A + timer++; + outputs.leftStickX = 128 + (directions.x * 69); + outputs.leftStickY = 128 + (directions.y * 53); + } + + if (timer == 150) { // 150 has a 90% success rate on pico + timer = 0; + input_persist = false; + } + + + + if (inputs.lt1) { //if ModX is held + if (directions.horizontal) { + outputs.leftStickX = 128 + (directions.x * 76); //76 gives 0.58~ in-game for a medium speed walk. will also do tilts + } + + if(directions.vertical) { + outputs.leftStickY = 128 + (directions.y * 53); // 48 (0.31~ in-game), 0.3 allows tilts and shield drop + } + + if (directions.diagonal && shield_button_pressed) { //for max-length diagonal wavedash while holding ModX + outputs.leftStickX = 128 + (directions.x * 120); + outputs.leftStickY = 128 + (directions.y * 42); + } + + if (directions.diagonal && !shield_button_pressed) { + /* 100% Magnitude UpB when holding B */ + if (inputs.rf1 && !inputs.rf3) { + // (x, y), (123, 51), (1.14~, 0.29~) [coords, code_values, in-game values] + outputs.leftStickX = 128 + (directions.x * 123); + outputs.leftStickY = 128 + (directions.y * 51); + // (x, y), (120, 61), (1.1~, 0.41~) [coords, code_values, in-game values] + if (inputs.rt2) { //C-Down + outputs.leftStickX = 128 + (directions.x * 120); + outputs.leftStickY = 128 + (directions.y * 61); + } + // (x, y), (115, 69), (1.04~, 0.51~) [coords, code_values, in-game values] + if (inputs.rt3) { //C-Left + outputs.leftStickX = 128 + (directions.x * 115); + outputs.leftStickY = 128 + (directions.y * 69); + } + // (x, y), (110, 78), (0.98~, 0.61~) [coords, code_values, in-game values] + if (inputs.rt4) { //C-Up + outputs.leftStickX = 128 + (directions.x * 110); + outputs.leftStickY = 128 + (directions.y * 78); + } + // (x, y), (103, 87), (0.9~, 0.71~) [coords, code_values, in-game values] + if (inputs.rt5) { //C-Right + outputs.leftStickX = 128 + (directions.x * 103); + outputs.leftStickY = 128 + (directions.y * 87); + } + } + /* 60% Magnitude UpB when not holding B nor Z*/ + if (!inputs.rf3 && !inputs.rf1 && !input_persist) { + // (x, y), (68, 42), (~0.49, ~0.188) [coords, code_values, in-game values] + outputs.leftStickX = 128 + (directions.x * 68); + outputs.leftStickY = 128 + (directions.y * 42); + // (x, y), (71, 47), (~0.52, ~0.24) [coords, code_values, in-game values] + if (inputs.rt2) { //C-Down + outputs.leftStickX = 128 + (directions.x * 71); + outputs.leftStickY = 128 + (directions.y * 47); + } + // (x, y), (71, 51), (~0.52, 0.29~) [coords, code_values, in-game values] + if (inputs.rt3) { //C-Left + outputs.leftStickX = 128 + (directions.x * 71); + outputs.leftStickY = 128 + (directions.y * 51); + } + // (x, y), (69, 55), (~0.51, ~0.34) [coords, code_values, in-game values] + if (inputs.rt4) { //C-Up + outputs.leftStickX = 128 + (directions.x * 69); + outputs.leftStickY = 128 + (directions.y * 55); + } + // (x, y), (64, 60), (, ~0.38) [coords, code_values, in-game values] + if (inputs.rt5) { //C-Right + outputs.leftStickX = 128 + (directions.x * 64); + outputs.leftStickY = 128 + (directions.y * 60); + } + } + /* Shortest UpB when holding Z*/ + if (inputs.rf3) { + // (x, y), (53, 68), (~0.31, ~0.188) [coords, code_values, in-game values] + outputs.leftStickX = 128 + (directions.x * 53); + outputs.leftStickY = 128 + (directions.y * 42); + } + /*ModX Angled Tilts*/ + if (inputs.rt1) { + input_persist = true; + timer = 0; + outputs.leftStickX = 128 + (directions.x * 69); + outputs.leftStickY = 128 + (directions.y * 53); + } + } + } + + + if (inputs.lt2) { // if ModY is held + if (directions.horizontal) { + outputs.leftStickX = 128 + (directions.x * 53); //53 equates to 0.318~ in-game. 0.3 is min to achieve a walk + } + + if(directions.vertical) { + outputs.leftStickY = 128 + (directions.y * 90); // 0.75~ in-game. will shield drop and tap jump; will not fast fall + } + + if (directions.diagonal && !shield_button_pressed) { + /* 100% Magnitude UpB when holding B*/ + if (inputs.rf1 && !inputs.rf3) { + // (x, y), (51, 123), (~0.29, ~1.14) [coords, code_values, in-game values] + outputs.leftStickX = 128 + (directions.x * 51); + outputs.leftStickY = 128 + (directions.y * 123); + // (x, y), (61, 120), (~0.41, ~1.1) [coords, code_values, in-game values] + if (inputs.rt2) { //C-Down + outputs.leftStickX = 128 + (directions.x * 61); + outputs.leftStickY = 128 + (directions.y * 120); + } + // (x, y), (69, 115), (~0.51, 1.04~) [coords, code_values, in-game values] + if (inputs.rt3) { //C-Left + outputs.leftStickX = 128 + (directions.x * 69); + outputs.leftStickY = 128 + (directions.y * 115); + } + // (x, y), (78, 110), (~0.61, 0.98~) [coords, code_values, in-game values] + if (inputs.rt4) { //C-Up + outputs.leftStickX = 128 + (directions.x * 78); + outputs.leftStickY = 128 + (directions.y * 110); + } + // (x, y), (87, 103), (~0.71, 0.9~) [coords, code_values, in-game values] + if (inputs.rt5) { //C-Right + outputs.leftStickX = 128 + (directions.x * 87); + outputs.leftStickY = 128 + (directions.y * 103); + } + } + /* 60% Magnitude UpB when not holding B nor Z*/ + if (!inputs.rf3 && !inputs.rf1) { + // (x, y), (42, 68), (~0.188, ~0.49) [coords, code_values, in-game values] + outputs.leftStickX = 128 + (directions.x * 42); + outputs.leftStickY = 128 + (directions.y * 68); + // (x, y), (47, 71), (~0.24, ~0.52) [coords, code_values, in-game values] + if (inputs.rt2) { //C-Down + outputs.leftStickX = 128 + (directions.x * 47); + outputs.leftStickY = 128 + (directions.y * 71); + } + // (x, y), (51, 71), (~0.29, ~0.52) [coords, code_values, in-game values] + if (inputs.rt3) { //C-Left + outputs.leftStickX = 128 + (directions.x * 51); + outputs.leftStickY = 128 + (directions.y * 71); + } + // (x, y), (55, 69), (~0.34, ~0.51) [coords, code_values, in-game values] + if (inputs.rt4) { //C-Up + outputs.leftStickX = 128 + (directions.x * 55); + outputs.leftStickY = 128 + (directions.y * 69); + } + // (x, y), (60, 64), (~0.38, ~0.) [coords, code_values, in-game values] + if (inputs.rt5) { //C-Right + outputs.leftStickX = 128 + (directions.x * 60); + outputs.leftStickY = 128 + (directions.y * 64); + } + } + /* Shortest UpB when holding Z*/ + if (inputs.rf3) { + // (x, y), (42, 53), (~0.188, ~0.31) [coords, code_values, in-game values] + outputs.leftStickX = 128 + (directions.x * 42); + outputs.leftStickY = 128 + (directions.y * 53); + } + /* For buffered turnaround up-tilt/down-tilt with ModY + Diagonal */ + if (inputs.rt1) { + outputs.leftStickX = 128 + (directions.x * 69); + outputs.leftStickY = 128 + (directions.y * 89); + } + } + } + + + // Shut off C-stick when using D-Pad layer. + if (inputs.lt1 && inputs.lt2) { + outputs.rightStickX = 128; + outputs.rightStickY = 128; + } + + // Nunchuk overrides left stick. + if (inputs.nunchuk_connected) { + outputs.leftStickX = inputs.nunchuk_x; + outputs.leftStickY = inputs.nunchuk_y; + } +} From b779b4d308e33356e16d9a8a9f416268d8db2a95 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Jan 2025 09:53:38 +0000 Subject: [PATCH 154/167] build: fix devcontainer config --- .devcontainer/devcontainer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9ac69999..f29baabe 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,12 +1,12 @@ { "name": "HayBox", - "image": "mcr.microsoft.com/devcontainers/base:ubuntu-22.04", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.11", "features": { "ghcr.io/rocker-org/devcontainer-features/apt-packages:1": { "packages": "python3-pip,python3-venv,clang-format-14" } }, - "onCreateCommand": "python3 -m pip install -U platformio && pio pkg install && pio pkg update -g -p https://github.com/maxgerhardt/platform-raspberrypi", + "onCreateCommand": "python3 -m pip install -U platformio && pio pkg install && pio pkg update -g -p https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c", "customizations": { "vscode": { "settings": { From 900b1b4948ce947b773f70cfe448b3e673caf2c0 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Mon, 27 Jan 2025 10:15:57 +0000 Subject: [PATCH 155/167] chore: remove commented out code --- include/modes/ProjectM.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/modes/ProjectM.hpp b/include/modes/ProjectM.hpp index 580fd544..0d84da8f 100644 --- a/include/modes/ProjectM.hpp +++ b/include/modes/ProjectM.hpp @@ -6,11 +6,6 @@ #include -// typedef struct { -// bool true_z_press = false; -// bool ledgedash_max_jump_traj = true; -// } ProjectMOptions; - class ProjectM : public ControllerMode { public: ProjectM(); From 7fb6b2ca9dba8a23acb5bdcbc8391737f07cefa3 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 14 Mar 2025 22:08:03 +0000 Subject: [PATCH 156/167] Update nanopb dependency --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 0628e8e2..1bf0b59f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,7 +21,7 @@ custom_nanopb_protos = custom_nanopb_options = --error-on-unmatched lib_deps = - nanopb/Nanopb@^0.4.8 + nanopb/Nanopb@^0.4.91 https://github.com/JonnyHaystack/HayBox-proto#bbd0862 [avr_base] From 393bc1d4efbfc9724deb003f1abe45b32cc85da5 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 14 Mar 2025 22:40:41 +0000 Subject: [PATCH 157/167] Get AVR builds working again --- HAL/avr/avr_nousb/src/comms/backend_init.cpp | 69 +++---- .../avr_usb/include/comms/backend_init.hpp | 105 +++++++++- HAL/avr/avr_usb/include/config_defaults.hpp | 49 ++++- HAL/avr/avr_usb/include/core/KeyboardMode.hpp | 2 +- HAL/avr/avr_usb/src/comms/DInputBackend.cpp | 2 +- HAL/avr/avr_usb/src/comms/backend_init.cpp | 169 +++++++++++++--- HAL/avr/avr_usb/src/core/KeyboardMode.cpp | 2 +- HAL/avr/avr_usb/src/core/mode_selection.cpp | 140 +++++++++++++ HAL/avr/proto/config.options | 41 ++++ HAL/avr/src/comms/N64Backend.cpp | 2 +- HAL/pico/include/comms/backend_init.hpp | 8 +- config/htangl_v1/config.cpp | 189 +++--------------- platformio.ini | 2 + 13 files changed, 533 insertions(+), 247 deletions(-) create mode 100644 HAL/avr/avr_usb/src/core/mode_selection.cpp diff --git a/HAL/avr/avr_nousb/src/comms/backend_init.cpp b/HAL/avr/avr_nousb/src/comms/backend_init.cpp index 57672542..3857f564 100644 --- a/HAL/avr/avr_nousb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_nousb/src/comms/backend_init.cpp @@ -1,3 +1,5 @@ +#include "comms/backend_init.hpp" + #include "comms/B0XXInputViewer.hpp" #include "comms/ConfiguratorBackend.hpp" #include "comms/DInputBackend.hpp" @@ -5,8 +7,8 @@ #include "comms/N64Backend.hpp" #include "comms/NintendoSwitchBackend.hpp" #include "comms/XInputBackend.hpp" -#include "comms/backend_init.hpp" #include "core/CommunicationBackend.hpp" +#include "core/config_utils.hpp" #include "core/mode_selection.hpp" #include "core/pinout.hpp" @@ -16,66 +18,53 @@ size_t initialize_backends( CommunicationBackend **&backends, - const CommunicationBackendConfig &backend_config, InputState &inputs, InputSource **input_sources, size_t input_source_count, - const Pinout &pinout, - Config &config + Config &config, + const Pinout &pinout ) { - GameModeId mode_id = backend_config.default_mode; - if (backend_config.default_mode == MODE_UNSPECIFIED) { - mode_id = MODE_MELEE; + CommunicationBackend *primary_backend; + + CommunicationBackendConfig backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { + backend_config = backend_config_from_id( + COMMS_BACKEND_GAMECUBE, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + } + // if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) {} + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { + backend_config = config.communication_backend_configs[config.default_backend_config]; } - CommunicationBackend *primary_backend; size_t backend_count; switch (backend_config.backend_id) { - case COMMS_BACKEND_DINPUT: - TUGamepad::registerDescriptor(); - TUKeyboard::registerDescriptor(); - primary_backend = new DInputBackend(inputs, input_sources, input_source_count); - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) - }; - break; - case COMMS_BACKEND_XINPUT: - primary_backend = new XInputBackend(inputs, input_sources, input_source_count); - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) - }; - break; - case COMMS_BACKEND_GAMECUBE: - primary_backend = - new GamecubeBackend(inputs, input_sources, input_source_count, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - break; case COMMS_BACKEND_N64: primary_backend = new N64Backend(inputs, input_sources, input_source_count, pinout.joybus_data); backend_count = 1; backends = new CommunicationBackend *[backend_count] { primary_backend }; break; - case COMMS_BACKEND_NINTENDO_SWITCH: - NintendoSwitchBackend::RegisterDescriptor(); - primary_backend = new NintendoSwitchBackend(inputs, input_sources, input_source_count); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - break; - case COMMS_BACKEND_UNSPECIFIED: // Fall back to configurator if invalid backend selected. - case COMMS_BACKEND_CONFIGURATOR: + case COMMS_BACKEND_GAMECUBE: default: primary_backend = - new ConfiguratorBackend(inputs, input_sources, input_source_count, config); + new GamecubeBackend(inputs, input_sources, input_source_count, pinout.joybus_data); backend_count = 1; backends = new CommunicationBackend *[backend_count] { primary_backend }; + break; } - set_mode(primary_backend, mode_id); + const GameModeConfig &mode_config = + config.game_mode_configs[backend_config.default_mode_config]; + + set_mode(primary_backend, mode_config, config.keyboard_modes, config.keyboard_modes_count); return backend_count; } \ No newline at end of file diff --git a/HAL/avr/avr_usb/include/comms/backend_init.hpp b/HAL/avr/avr_usb/include/comms/backend_init.hpp index 0d778251..7d08aad2 100644 --- a/HAL/avr/avr_usb/include/comms/backend_init.hpp +++ b/HAL/avr/avr_usb/include/comms/backend_init.hpp @@ -1,6 +1,7 @@ #ifndef _COMMS_BACKEND_INIT_HPP #define _COMMS_BACKEND_INIT_HPP +#include "comms/console_detection.hpp" #include "core/CommunicationBackend.hpp" #include "core/InputSource.hpp" #include "core/pinout.hpp" @@ -9,31 +10,115 @@ #include /** - * @brief Initialize the backends array and return the number of elements in the array + * @brief Optionally defined function that allows a device config to hook into initialize_backends() + * and use a custom method for selecting backend config before console detection + * + * @param backend_config The reference to the current backend config after checking for button holds + * and connected console + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param config Reference to the global Config struct + * @return true if the passed in backend config was altered, otherwise false + */ +typedef void (*backend_config_selector_t)( + CommunicationBackendConfig &backend_config, + const InputState &inputs, + Config &config +); + +/** + * @brief Optionally defined function that allows a device config to hook into initialize_backends() + * and use a custom method for selecting the default USB communication backend to initialize prior + * to console/USB detection + * + * @param backend_config The reference to the current backend config after checking for button holds + * and connected console + * @param config Reference to the global Config struct + * @return true if the passed in backend config was altered, otherwise false + */ +// bool usb_backend_config_custom(CommunicationBackendConfig &backend_config, const Config &config) +// __attribute__((weak)); +typedef void (*usb_backend_getter_t)( + CommunicationBackendConfig &backend_config, + const Config &config +); + +/** + * @brief Initialize primary backend based on the passed in backend id * + * @param primary_backend The reference to the primary backend pointer to initialize + * @param backend_id The id of the backend to initialize * @param backends The reference to assign to the created backends array * @param inputs Reference to the InputState struct to pass into each backend's constructor * @param input_sources Input sources array to pass into each backend's constructor * @param input_source_count Number of elements in the input_sources array * @param config Reference to global config struct * @param pinout Pinout struct used for GameCube/N64 communication backends - * @return size_t The number of backends in the array */ -size_t initialize_backends( - CommunicationBackend **&backends, +typedef void (*primary_backend_initializer_t)( + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, InputState &inputs, InputSource **input_sources, size_t input_source_count, - const Config &config, + Config &config, const Pinout &pinout ); -bool initialize_backends_custom( +/** + * @brief Initialize secondary backends and the backends array and return the number of elements in + * the array + * + * @param backends The reference to assign to the created backends array + * @param primary_backend The reference to the primary backend to insert first in the backends array + * @param backend_id The id indicating the primary backend + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct + * @param pinout Pinout struct used for GameCube/N64 communication backends + * @return The number of backends in the array + */ +typedef size_t (*secondary_backend_initializer_t)( CommunicationBackend **&backends, + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, InputSource **input_sources, - size_t input_source_count -) __attribute__((weak)); + size_t input_source_count, + Config &config, + const Pinout &pinout +); + +typedef CommunicationBackendId (*detect_console_t)(const Pinout &pinout); + +extern backend_config_selector_t get_backend_config_default; +extern usb_backend_getter_t get_usb_backend_config_default; +extern primary_backend_initializer_t init_primary_backend_default; +extern secondary_backend_initializer_t init_secondary_backends_default; -void select_backend_custom(CommunicationBackendConfig &backend_config) __attribute__((weak)); +/** + * @brief Initialize the backends array and return the number of elements in the array + * + * @param backends The reference to assign to the created backends array + * @param inputs Reference to the InputState struct to pass into each backend's constructor + * @param input_sources Input sources array to pass into each backend's constructor + * @param input_source_count Number of elements in the input_sources array + * @param config Reference to global config struct + * @param pinout Pinout struct used for GameCube/N64 communication backends + * @return size_t The number of backends in the array + */ +size_t initialize_backends( + CommunicationBackend **&backends, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout, + backend_config_selector_t get_backend_config_custom = get_backend_config_default, + usb_backend_getter_t get_usb_backend_config = get_usb_backend_config_default, + detect_console_t detect_console = &detect_console, + secondary_backend_initializer_t init_secondary_backends = init_secondary_backends_default, + primary_backend_initializer_t init_primary_backend = init_primary_backend_default +); -#endif \ No newline at end of file +#endif diff --git a/HAL/avr/avr_usb/include/config_defaults.hpp b/HAL/avr/avr_usb/include/config_defaults.hpp index 68a030b7..2c3f0c30 100644 --- a/HAL/avr/avr_usb/include/config_defaults.hpp +++ b/HAL/avr/avr_usb/include/config_defaults.hpp @@ -11,6 +11,7 @@ const Config default_config = { .game_mode_configs = new GameModeConfig[5] { GameModeConfig { .mode_id = MODE_MELEE, + .name = {}, .socd_pairs_count = 4, .socd_pairs = new SocdPair[4] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, @@ -22,9 +23,13 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, GameModeConfig { .mode_id = MODE_PROJECT_M, + .name = {}, .socd_pairs_count = 4, .socd_pairs = new SocdPair[4] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, @@ -36,9 +41,13 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, GameModeConfig { .mode_id = MODE_ULTIMATE, + .name = {}, .socd_pairs_count = 4, .socd_pairs = new SocdPair[4] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, @@ -50,9 +59,13 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, GameModeConfig { .mode_id = MODE_FGC, + .name = {}, .socd_pairs_count = 2, .socd_pairs = new SocdPair[2] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, @@ -64,9 +77,13 @@ const Config default_config = { }, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, GameModeConfig { .mode_id = MODE_KEYBOARD, + .name = {}, .socd_pairs_count = 2, .socd_pairs = new SocdPair[2] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, @@ -76,23 +93,34 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT2, BTN_MB1, BTN_LF4 }, + .custom_mode_config = 0, .keyboard_mode_config = 1, + .rgb_config = 0, }, }, - .communication_backend_configs_count = 1, - .communication_backend_configs = new CommunicationBackendConfig[1] { + .communication_backend_configs_count = 2, + .communication_backend_configs = new CommunicationBackendConfig[2] { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_DINPUT, .default_mode_config = 1, .activation_binding_count = 1, .activation_binding = new Button[1] { BTN_RF3 }, + .secondary_backends = {}, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_GAMECUBE, + .default_mode_config = 1, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RT1 }, + .secondary_backends = {}, }, }, + .custom_modes_count = 0, + .custom_modes = {}, .keyboard_modes_count = 1, .keyboard_modes = new KeyboardModeConfig[1] { KeyboardModeConfig { 0, - "Default", 22, new ButtonToKeycodeMapping[22] { { BTN_LF4, HID_KEY_A }, @@ -124,6 +152,21 @@ const Config default_config = { .rgb_configs = {}, .default_backend_config = 1, .default_usb_backend_config = 1, + .rgb_brightness = 0, + .has_melee_options = true, + .melee_options = { + .crouch_walk_os = false, + .disable_ledgedash_socd_override = false, + .has_custom_airdodge = false, + .custom_airdodge = { .x = 0, .y = 0 }, + }, + .has_project_m_options = true, + .project_m_options = { + .true_z_press = false, + .disable_ledgedash_socd_override = false, + .has_custom_airdodge = false, + .custom_airdodge = { .x = 0, .y = 0 }, + }, }; // clang-format on diff --git a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp index 42e5a23b..974ad30f 100644 --- a/HAL/avr/avr_usb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_usb/include/core/KeyboardMode.hpp @@ -9,7 +9,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(GameModeConfig &config); + KeyboardMode(); ~KeyboardMode(); void SendReport(const InputState &inputs); diff --git a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp index 72349eb4..cc1440b2 100644 --- a/HAL/avr/avr_usb/src/comms/DInputBackend.cpp +++ b/HAL/avr/avr_usb/src/comms/DInputBackend.cpp @@ -53,7 +53,7 @@ void DInputBackend::SendReport() { // D-pad Hat Switch _joystick - ->setHatSwitch(_outputs.dpadLeft, _outputs.dpadRight, _outputs.dpadDown, _outputs.dpadUp); + .setHatSwitch(_outputs.dpadLeft, _outputs.dpadRight, _outputs.dpadDown, _outputs.dpadUp); _joystick.sendState(); } diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp index 405541ac..dd748013 100644 --- a/HAL/avr/avr_usb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -4,7 +4,6 @@ #include "comms/DInputBackend.hpp" #include "comms/GamecubeBackend.hpp" #include "comms/N64Backend.hpp" -#include "comms/console_detection.hpp" #include "core/CommunicationBackend.hpp" #include "core/config_utils.hpp" #include "core/mode_selection.hpp" @@ -17,66 +16,182 @@ size_t initialize_backends( InputState &inputs, InputSource **input_sources, size_t input_source_count, - const Config &config, - const Pinout &pinout + Config &config, + const Pinout &pinout, + backend_config_selector_t get_backend_config, + usb_backend_getter_t get_usb_backend_config, + detect_console_t detect_console, + secondary_backend_initializer_t init_secondary_backends, + primary_backend_initializer_t init_primary_backend ) { + // Make sure required function pointers are not null. + if (get_backend_config == nullptr || get_usb_backend_config == nullptr || + init_primary_backend == nullptr || detect_console == nullptr) { + return 0; + } + + CommunicationBackendConfig backend_config = CommunicationBackendConfig_init_zero; + get_backend_config(backend_config, inputs, config); + CommunicationBackend *primary_backend = nullptr; - CommunicationBackendConfig backend_config = backend_config_from_buttons( - inputs, - config.communication_backend_configs, - config.communication_backend_configs_count - ); + /* If no match found for button hold, use console/USB detection to select backend instead. */ if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { - primary_backend = new DInputBackend(inputs, input_sources, input_source_count); - CommunicationBackendId detected_backend_id = detect_console(pinout); - backend_config = backend_config_from_id( - detected_backend_id, - config.communication_backend_configs, - config.communication_backend_configs_count + /* Must check default USB backend here and initialize it before console detection, so that + * we can respond correctly to device descriptor requests from host. */ + CommunicationBackendConfig usb_backend_config; + get_usb_backend_config(usb_backend_config, config); + init_primary_backend( + primary_backend, + usb_backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout ); + CommunicationBackendId detected_backend_id = COMMS_BACKEND_UNSPECIFIED; + detected_backend_id = detect_console(pinout); + if (detected_backend_id == COMMS_BACKEND_XINPUT) { + backend_config = usb_backend_config; + } else { + backend_config = backend_config_from_id( + detected_backend_id, + config.communication_backend_configs, + config.communication_backend_configs_count + ); + } } if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED && config.default_backend_config > 0) { backend_config = config.communication_backend_configs[config.default_backend_config - 1]; } - size_t backend_count; + init_primary_backend( + primary_backend, + backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); - switch (backend_config.backend_id) { + size_t backend_count = 1; + if (init_secondary_backends != nullptr) { + backend_count = init_secondary_backends( + backends, + primary_backend, + backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); + } + + if (backend_config.default_mode_config > 0) { + GameModeConfig &mode_config = + config.game_mode_configs[backend_config.default_mode_config - 1]; + for (size_t i = 0; i < backend_count; i++) { + set_mode(backends[i], mode_config, config); + } + } + + return backend_count; +} + +void init_primary_backend( + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + switch (backend_id) { case COMMS_BACKEND_GAMECUBE: delete primary_backend; primary_backend = new GamecubeBackend( inputs, input_sources, input_source_count, - inputs.rt1 ? 0 : 125, + 125, pinout.joybus_data ); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; break; case COMMS_BACKEND_N64: delete primary_backend; primary_backend = new N64Backend(inputs, input_sources, input_source_count, 60, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; break; + case COMMS_BACKEND_UNSPECIFIED: // Fall back to DInput if invalid backend selected. case COMMS_BACKEND_DINPUT: default: + if (primary_backend == nullptr) { + primary_backend = new DInputBackend(inputs, input_sources, input_source_count); + } + break; + } +} + +size_t init_secondary_backends( + CommunicationBackend **&backends, + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + size_t backend_count = 0; + + switch (backend_id) { + case COMMS_BACKEND_DINPUT: backend_count = 2; backends = new CommunicationBackend *[backend_count] { primary_backend, new B0XXInputViewer(inputs, input_sources, input_source_count) }; break; + default: + backend_count = 1; + backends = new CommunicationBackend *[backend_count] { primary_backend }; } - if (backend_config.default_mode_config > 0) { - const GameModeConfig &mode_config = - config.game_mode_configs[backend_config.default_mode_config - 1]; - set_mode(primary_backend, mode_config, config.keyboard_modes, config.keyboard_modes_count); + return backend_count; +} + +// clang-format off + +/* Default is to first check button holds for a matching comms backend config. */ +backend_config_selector_t get_backend_config_default = []( + CommunicationBackendConfig &backend_config, + const InputState &inputs, + Config &config +) { + backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); +}; + +/* Default is to get default USB backend from config. */ +usb_backend_getter_t get_usb_backend_config_default = []( + CommunicationBackendConfig &backend_config, + const Config &config +) { + if (config.default_usb_backend_config > 0 && + config.default_usb_backend_config <= config.communication_backend_configs_count) { + backend_config = + config.communication_backend_configs[config.default_usb_backend_config - 1]; } +}; - return backend_count; -} \ No newline at end of file +// clang-format on + +primary_backend_initializer_t init_primary_backend_default = &init_primary_backend; +secondary_backend_initializer_t init_secondary_backends_default = &init_secondary_backends; diff --git a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp index 5e3f5692..e7eaa625 100644 --- a/HAL/avr/avr_usb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_usb/src/core/KeyboardMode.cpp @@ -4,7 +4,7 @@ #include -KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) {} +KeyboardMode::KeyboardMode() : InputMode() {} KeyboardMode::~KeyboardMode() { _keyboard.releaseAll(); diff --git a/HAL/avr/avr_usb/src/core/mode_selection.cpp b/HAL/avr/avr_usb/src/core/mode_selection.cpp new file mode 100644 index 00000000..127212a8 --- /dev/null +++ b/HAL/avr/avr_usb/src/core/mode_selection.cpp @@ -0,0 +1,140 @@ +#include "core/mode_selection.hpp" + +#include "core/state.hpp" +#include "modes/CustomControllerMode.hpp" +#include "modes/CustomKeyboardMode.hpp" +#include "modes/FgcMode.hpp" +#include "modes/Melee20Button.hpp" +#include "modes/ProjectM.hpp" +#include "modes/RivalsOfAether.hpp" +#include "modes/Ultimate.hpp" +#include "util/state_util.hpp" + +#include + +Melee20Button melee_mode; +ProjectM projectm_mode; +Ultimate ultimate_mode; +FgcMode fgc_mode; +RivalsOfAether rivals_mode; +CustomKeyboardMode keyboard_mode; +CustomControllerMode custom_mode; + +uint64_t mode_activation_masks[10]; + +size_t current_mode_index = SIZE_MAX; + +void set_mode(CommunicationBackend *backend, ControllerMode *mode) { + // Delete keyboard mode in case one is set, so we don't end up getting both controller and + // keyboard inputs. + current_kb_mode = nullptr; + + // Set new controller mode. + backend->SetGameMode(mode); +} + +void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { + // Only DInputBackend supports keyboard modes. + if (backend->BackendId() != COMMS_BACKEND_DINPUT) { + return; + } + + // Delete and reassign current keyboard mode. + current_kb_mode = mode; + + // Unset the current controller mode so backend only gives neutral inputs. + backend->SetGameMode(mode); +} + +void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config) { + switch (mode_config.mode_id) { + case MODE_MELEE: + melee_mode.SetConfig(mode_config, config.melee_options); + set_mode(backend, &melee_mode); + break; + case MODE_PROJECT_M: + projectm_mode.SetConfig(mode_config, config.project_m_options); + set_mode(backend, &projectm_mode); + break; + case MODE_ULTIMATE: + ultimate_mode.SetConfig(mode_config); + set_mode(backend, &ultimate_mode); + break; + case MODE_FGC: + fgc_mode.SetConfig(mode_config); + set_mode(backend, &fgc_mode); + break; + case MODE_RIVALS_OF_AETHER: + rivals_mode.SetConfig(mode_config); + set_mode(backend, &rivals_mode); + break; + case MODE_KEYBOARD: + if (backend->BackendId() != COMMS_BACKEND_DINPUT || + mode_config.keyboard_mode_config < 1 || + mode_config.keyboard_mode_config > config.keyboard_modes_count) { + break; + } + keyboard_mode.SetConfig( + mode_config, + config.keyboard_modes[mode_config.keyboard_mode_config - 1] + ); + set_mode(backend, &keyboard_mode); + break; + case MODE_CUSTOM: + if (mode_config.custom_mode_config < 1 || + mode_config.custom_mode_config > config.custom_modes_count) { + break; + } + custom_mode.SetConfig( + mode_config, + config.custom_modes[mode_config.custom_mode_config - 1] + ); + set_mode(backend, &custom_mode); + break; + case MODE_UNSPECIFIED: + default: + break; + } +} + +// TODO: Maybe remove this overload in favour of looking up the gamemode outside of here using a +// config_utils function. +void set_mode(CommunicationBackend *backend, GameModeId mode_id, Config &config) { + // In this overload we only know the mode id so we need to find a mode config that matches this + // ID. + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode = config.game_mode_configs[i]; + if (mode.mode_id == mode_id) { + set_mode(backend, mode, config); + return; + } + } +} + +void select_mode(CommunicationBackend **backends, size_t backends_count, Config &config) { + // TODO: Use a counter variable to only run the contents of this function every x iterations + // rather than on every single poll. + + InputState &inputs = backends[0]->GetInputs(); + + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + if (all_buttons_held(inputs.buttons, mode_activation_masks[i]) && i != current_mode_index) { + current_mode_index = i; + for (size_t i = 0; i < backends_count; i++) { + set_mode(backends[i], mode_config, config); + } + return; + } + } +} + +void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count) { + // Build bit masks for checking for matching button holds. + for (size_t i = 0; i < mode_configs_count; i++) { + mode_activation_masks[i] = make_button_mask( + mode_configs[i].activation_binding, + mode_configs[i].activation_binding_count + ); + } +} diff --git a/HAL/avr/proto/config.options b/HAL/avr/proto/config.options index dfaf43e5..de7a0a38 100644 --- a/HAL/avr/proto/config.options +++ b/HAL/avr/proto/config.options @@ -5,6 +5,24 @@ SocdPair.button_dir1 int_size:IS_8 SocdPair.button_dir2 int_size:IS_8 SocdPair.socd_type int_size:IS_8 +AnalogTriggerMapping.button int_size:IS_8 +AnalogTriggerMapping.trigger int_size:IS_8 +AnalogTriggerMapping.value int_size:IS_8 + +AnalogModifier.buttons int_size:IS_8 +AnalogModifier.buttons max_count:3 +AnalogModifier.buttons type:FT_POINTER +AnalogModifier.axis int_size:IS_8 +AnalogModifier.combination_mode int_size:IS_8 + +ButtonComboMapping.buttons int_size:IS_8 +ButtonComboMapping.buttons max_count:3 +ButtonComboMapping.buttons type:FT_POINTER +ButtonComboMapping.digital_output int_size:IS_8 + +Coords.x int_size:IS_8 +Coords.y int_size:IS_8 + ButtonToKeycodeMapping.button int_size:IS_8 ButtonToKeycodeMapping.keycode int_size:IS_8 @@ -12,13 +30,29 @@ ButtonToColorMapping.button int_size:IS_8 GameModeConfig.mode_id int_size:IS_8 GameModeConfig.name max_length:17 +GameModeConfig.name type:FT_POINTER GameModeConfig.socd_pairs max_count:10 GameModeConfig.socd_pairs type:FT_POINTER GameModeConfig.button_remapping max_count:60 GameModeConfig.button_remapping type:FT_POINTER GameModeConfig.activation_binding max_count:4 GameModeConfig.activation_binding type:FT_POINTER +GameModeConfig.custom_mode_config int_size:IS_8 GameModeConfig.keyboard_mode_config int_size:IS_8 +GameModeConfig.rgb_config int_size:IS_8 + +CustomModeConfig.id int_size:IS_8 +CustomModeConfig.digital_button_mappings max_count:18 +CustomModeConfig.digital_button_mappings type:FT_POINTER +CustomModeConfig.stick_direction_mappings max_count:8 +CustomModeConfig.stick_direction_mappings type:FT_POINTER +CustomModeConfig.analog_trigger_mappings max_count:4 +CustomModeConfig.analog_trigger_mappings type:FT_POINTER +CustomModeConfig.button_combo_mappings max_count:5 +CustomModeConfig.button_combo_mappings type:FT_POINTER +CustomModeConfig.modifiers max_count:20 +CustomModeConfig.modifiers type:FT_POINTER +CustomModeConfig.stick_range int_size:IS_8 KeyboardModeConfig.id int_size:IS_8 KeyboardModeConfig.buttons_to_keycodes max_count:60 @@ -38,6 +72,8 @@ Config.game_mode_configs max_count:10 Config.game_mode_configs type:FT_POINTER Config.communication_backend_configs max_count:10 Config.communication_backend_configs type:FT_POINTER +Config.custom_modes max_count:5 +Config.custom_modes type:FT_POINTER Config.keyboard_modes max_count:5 Config.keyboard_modes type:FT_POINTER Config.rgb_configs max_count:10 @@ -52,6 +88,11 @@ DeviceInfo.device_name max_length:30 Command long_names:false Button long_names:false +DigitalOutput long_names:false +StickDirectionButton long_names:false +AnalogAxis long_names:false +AnalogTrigger long_names:false +ModifierCombinationMode long_names:false SocdType long_names:false GameModeId long_names:false CommunicationBackendId long_names:false diff --git a/HAL/avr/src/comms/N64Backend.cpp b/HAL/avr/src/comms/N64Backend.cpp index fbda0868..b7939a2e 100644 --- a/HAL/avr/src/comms/N64Backend.cpp +++ b/HAL/avr/src/comms/N64Backend.cpp @@ -56,7 +56,7 @@ void N64Backend::SendReport() { _data.report.yAxis = _outputs.leftStickY - 128; // Send outputs to console. - _n64->write(_data); + _n64.write(_data); delayMicroseconds(_delay); } diff --git a/HAL/pico/include/comms/backend_init.hpp b/HAL/pico/include/comms/backend_init.hpp index 783cb54e..7d08aad2 100644 --- a/HAL/pico/include/comms/backend_init.hpp +++ b/HAL/pico/include/comms/backend_init.hpp @@ -9,8 +9,6 @@ #include -// clang-format off - /** * @brief Optionally defined function that allows a device config to hook into initialize_backends() * and use a custom method for selecting backend config before console detection @@ -93,8 +91,6 @@ typedef size_t (*secondary_backend_initializer_t)( typedef CommunicationBackendId (*detect_console_t)(const Pinout &pinout); -// clang-format on - extern backend_config_selector_t get_backend_config_default; extern usb_backend_getter_t get_usb_backend_config_default; extern primary_backend_initializer_t init_primary_backend_default; @@ -109,7 +105,7 @@ extern secondary_backend_initializer_t init_secondary_backends_default; * @param input_source_count Number of elements in the input_sources array * @param config Reference to global config struct * @param pinout Pinout struct used for GameCube/N64 communication backends - * @return The number of backends in the array + * @return size_t The number of backends in the array */ size_t initialize_backends( CommunicationBackend **&backends, @@ -125,4 +121,4 @@ size_t initialize_backends( primary_backend_initializer_t init_primary_backend = init_primary_backend_default ); -#endif \ No newline at end of file +#endif diff --git a/config/htangl_v1/config.cpp b/config/htangl_v1/config.cpp index 1e7f15d2..427269e9 100644 --- a/config/htangl_v1/config.cpp +++ b/config/htangl_v1/config.cpp @@ -11,163 +11,44 @@ #include -// clang-format off - -const Config config = default_config; - -/* -const Config config = { - .default_backend = COMMS_BACKEND_DINPUT, - .game_mode_configs_count = 5, - .game_mode_configs = new GameModeConfig[5] { - GameModeConfig { - .mode_id = MODE_MELEE, - .socd_pairs_count = 4, - .socd_pairs = new SocdPair[4] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, - }, - GameModeConfig { - .mode_id = MODE_PROJECT_M, - .socd_pairs_count = 4, - .socd_pairs = new SocdPair[4] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP_NO_REAC }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP_NO_REAC }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, - }, - GameModeConfig { - .mode_id = MODE_ULTIMATE, - .socd_pairs_count = 4, - .socd_pairs = new SocdPair[4] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LF2, .button_dir2 = BTN_RF4, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT3, .button_dir2 = BTN_RT5, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_RT2, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, - }, - GameModeConfig { - .mode_id = MODE_FGC, - .socd_pairs_count = 2, - .socd_pairs = new SocdPair[2] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_NEUTRAL }, - }, - .button_remapping_count = 1, - .button_remapping = new ButtonRemap[1] { - ButtonRemap { .physical_button = BTN_RT4, .activates = BTN_LT1 }, - }, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, - }, - GameModeConfig { - .mode_id = MODE_KEYBOARD, - .socd_pairs_count = 2, - .socd_pairs = new SocdPair[2] { - SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, - SocdPair { .button_dir1 = BTN_LT1, .button_dir2 = BTN_RT4, .socd_type = SOCD_2IP }, - }, - .button_remapping_count = 0, - .button_remapping = {}, - .activation_binding_count = 3, - .activation_binding = new Button[3] { BTN_LT2, BTN_MB1, BTN_LF4 }, - }, - }, - .communication_backend_configs_count = 1, - .communication_backend_configs = new CommunicationBackendConfig[1] { - CommunicationBackendConfig { - .backend_id = COMMS_BACKEND_DINPUT, - .default_mode = MODE_MELEE, - .activation_binding_count = 1, - .activation_binding = new Button[1] { BTN_RF3 }, - }, - }, - .keyboard_modes_count = 1, - .keyboard_modes = new KeyboardModeConfig[1] { - KeyboardModeConfig { - 0, - "Default", - 22, - new ButtonToKeycodeMapping[22] { - { BTN_LF4, HID_KEY_A }, - { BTN_LF3, HID_KEY_B }, - { BTN_LF2, HID_KEY_C }, - { BTN_LF1, HID_KEY_D }, - { BTN_LT1, HID_KEY_E }, - { BTN_LT2, HID_KEY_F }, - { BTN_MB3, HID_KEY_G }, - { BTN_MB1, HID_KEY_H }, - { BTN_MB2, HID_KEY_I }, - { BTN_RF5, HID_KEY_J }, - { BTN_RF6, HID_KEY_K }, - { BTN_RF7, HID_KEY_L }, - { BTN_RF8, HID_KEY_M }, - { BTN_RF1, HID_KEY_N }, - { BTN_RF2, HID_KEY_O }, - { BTN_RF3, HID_KEY_P }, - { BTN_RF4, HID_KEY_Q }, - { BTN_RT4, HID_KEY_R }, - { BTN_RT3, HID_KEY_S }, - { BTN_RT5, HID_KEY_T }, - { BTN_RT1, HID_KEY_U }, - { BTN_RT2, HID_KEY_V }, - }, - }, - }, -}; -*/ - -// clang-format on +Config config = default_config; const GpioButtonMapping button_mappings[] = { - {BTN_LF4, 6 }, - { BTN_LF3, 4 }, - { BTN_LF2, 0 }, - { BTN_LF1, 1 }, - - { BTN_LT1, 14}, - { BTN_LT2, 16}, - - { BTN_MB3, 2 }, - { BTN_MB1, 3 }, - { BTN_MB2, 5 }, - - { BTN_RT3, A2}, - { BTN_RT4, A3}, - { BTN_RT2, 15}, - { BTN_RT1, A5}, - { BTN_RT5, A4}, - - { BTN_RF1, 10}, - { BTN_RF2, 11}, - { BTN_RF3, 13}, - { BTN_RF4, A1}, - - { BTN_RF5, 7 }, - { BTN_RF6, 9 }, - { BTN_RF7, 12}, - { BTN_RF8, A0}, + { BTN_LF4, 6 }, + { BTN_LF3, 4 }, + { BTN_LF2, 0 }, + { BTN_LF1, 1 }, + + { BTN_LT1, 14 }, + { BTN_LT2, 16 }, + + { BTN_MB3, 2 }, + { BTN_MB1, 3 }, + { BTN_MB2, 5 }, + + { BTN_RT3, A2 }, + { BTN_RT4, A3 }, + { BTN_RT2, 15 }, + { BTN_RT1, A5 }, + { BTN_RT5, A4 }, + + { BTN_RF1, 10 }, + { BTN_RF2, 11 }, + { BTN_RF3, 13 }, + { BTN_RF4, A1 }, + + { BTN_RF5, 7 }, + { BTN_RF6, 9 }, + { BTN_RF7, 12 }, + { BTN_RF8, A0 }, }; const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); const Pinout pinout = { .joybus_data = 8, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, @@ -201,13 +82,7 @@ void setup() { } void loop() { - select_mode( - backends[0], - config.game_mode_configs, - config.game_mode_configs_count, - config.keyboard_modes, - config.keyboard_modes_count - ); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/platformio.ini b/platformio.ini index 1bf0b59f..b4fbcdb9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -48,6 +48,8 @@ build_flags = build_src_filter = ${env.build_src_filter} + + - + - custom_nanopb_options = ${env.custom_nanopb_options} --options-file ../../../../HAL/avr/proto/config.options From 60e493a971b18317d68f39b68d02472da782e15c Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 14 Mar 2025 23:24:30 +0000 Subject: [PATCH 158/167] Add htangl_v1 env to CI --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 34c64982..78c3dc03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,8 @@ jobs: bin_ext: hex - env: gccpcb2 bin_ext: hex + - env: htangl_v1 + bin_ext: hex - env: lbx bin_ext: hex - env: smashbox From 60f589e0cb1ceb84f44e5a8f6daf8a3e7d915c55 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Fri, 14 Mar 2025 23:30:27 +0000 Subject: [PATCH 159/167] Add missing AVR state_util.hpp --- HAL/avr/include/util/state_util.hpp | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/HAL/avr/include/util/state_util.hpp b/HAL/avr/include/util/state_util.hpp index 1efaaa4d..65c01e0b 100644 --- a/HAL/avr/include/util/state_util.hpp +++ b/HAL/avr/include/util/state_util.hpp @@ -399,4 +399,81 @@ inline bool all_buttons_held(const uint64_t &buttons, uint64_t button_mask) { return button_mask != 0 && (buttons & button_mask) == button_mask; } +inline bool any_button_held(const uint64_t &buttons, uint64_t button_mask) { + return button_mask != 0 && (buttons & button_mask); +} + +/* OutputState utils */ + +inline void set_output(uint32_t &buttons, DigitalOutput output_index, bool pressed) { + if (output_index == GP_UNSPECIFIED) { + return; + } + DigitalOutput output_index_adjusted = (DigitalOutput)(output_index - 1); + buttons = + (buttons & ~(1UL << output_index_adjusted)) | ((uint32_t)pressed << output_index_adjusted); +} + +inline uint8_t OutputState::*axis_pointer(AnalogAxis axis) { + switch (axis) { + case AXIS_LSTICK_X: + return &OutputState::leftStickX; + case AXIS_LSTICK_Y: + return &OutputState::leftStickY; + case AXIS_RSTICK_X: + return &OutputState::rightStickX; + case AXIS_RSTICK_Y: + return &OutputState::rightStickY; + case AXIS_LTRIGGER: + return &OutputState::triggerLAnalog; + case AXIS_RTRIGGER: + return &OutputState::triggerRAnalog; + default: + return nullptr; + } +} + +constexpr const char *digital_output_name(DigitalOutput output) { + switch (output) { + case GP_A: + return "A"; + case GP_B: + return "B"; + case GP_X: + return "X"; + case GP_Y: + return "Y"; + case GP_LB: + return "L1"; + case GP_RB: + return "R1"; + case GP_LT: + return "L2"; + case GP_RT: + return "R2"; + case GP_START: + return "Start"; + case GP_SELECT: + return "Select"; + case GP_HOME: + return "Home"; + case GP_CAPTURE: + return "Capture"; + case GP_DPAD_UP: + return "D-Pad Up"; + case GP_DPAD_DOWN: + return "D-Pad Down"; + case GP_DPAD_LEFT: + return "D-Pad Left"; + case GP_DPAD_RIGHT: + return "D-Pad Right"; + case GP_LSTICK_CLICK: + return "L3"; + case GP_RSTICK_CLICK: + return "R3"; + default: + return "Unknown"; + } +} + #endif \ No newline at end of file From 9db70bda592436bde8d761f19bbd6d707dcd5bc5 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 01:00:22 +0000 Subject: [PATCH 160/167] Fix avr_nousb builds --- ...{backend_init.hpp => backend_init.hpp.bak} | 0 HAL/avr/avr_nousb/include/config_defaults.hpp | 66 +++++++- .../avr_nousb/include/core/KeyboardMode.hpp | 2 +- HAL/avr/avr_nousb/src/comms/backend_init.cpp | 142 ++++++++++++++---- .../avr_nousb/src/comms/console_detection.cpp | 4 + HAL/avr/avr_nousb/src/core/KeyboardMode.cpp | 2 +- HAL/avr/avr_usb/include/config_defaults.hpp | 13 +- HAL/avr/avr_usb/src/comms/backend_init.cpp | 2 +- HAL/avr/avr_usb/src/core/mode_selection.cpp | 140 ----------------- .../include/comms/backend_init.hpp | 0 HAL/avr/src/reboot.cpp | 2 + config/arduino/config.cpp | 127 ++++++++-------- config/arduino/env.ini | 8 +- 13 files changed, 252 insertions(+), 256 deletions(-) rename HAL/avr/avr_nousb/include/comms/{backend_init.hpp => backend_init.hpp.bak} (100%) delete mode 100644 HAL/avr/avr_usb/src/core/mode_selection.cpp rename HAL/avr/{avr_usb => }/include/comms/backend_init.hpp (100%) diff --git a/HAL/avr/avr_nousb/include/comms/backend_init.hpp b/HAL/avr/avr_nousb/include/comms/backend_init.hpp.bak similarity index 100% rename from HAL/avr/avr_nousb/include/comms/backend_init.hpp rename to HAL/avr/avr_nousb/include/comms/backend_init.hpp.bak diff --git a/HAL/avr/avr_nousb/include/config_defaults.hpp b/HAL/avr/avr_nousb/include/config_defaults.hpp index 8668191f..0b4a47ef 100644 --- a/HAL/avr/avr_nousb/include/config_defaults.hpp +++ b/HAL/avr/avr_nousb/include/config_defaults.hpp @@ -2,16 +2,15 @@ #define _CONFIG_DEFAULTS_HPP #include -#include // clang-format off const Config default_config = { - .default_backend = COMMS_BACKEND_DINPUT, .game_mode_configs_count = 4, .game_mode_configs = new GameModeConfig[4] { GameModeConfig { .mode_id = MODE_MELEE, + .name = {}, .socd_pairs_count = 4, .socd_pairs = new SocdPair[4] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, @@ -23,9 +22,13 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF4 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, GameModeConfig { .mode_id = MODE_PROJECT_M, + .name = {}, .socd_pairs_count = 4, .socd_pairs = new SocdPair[4] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP_NO_REAC }, @@ -37,9 +40,13 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF3 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, GameModeConfig { .mode_id = MODE_ULTIMATE, + .name = {}, .socd_pairs_count = 4, .socd_pairs = new SocdPair[4] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_2IP }, @@ -51,9 +58,13 @@ const Config default_config = { .button_remapping = {}, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF2 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, GameModeConfig { .mode_id = MODE_FGC, + .name = {}, .socd_pairs_count = 2, .socd_pairs = new SocdPair[2] { SocdPair { .button_dir1 = BTN_LF3, .button_dir2 = BTN_LF1, .socd_type = SOCD_NEUTRAL }, @@ -65,21 +76,60 @@ const Config default_config = { }, .activation_binding_count = 3, .activation_binding = new Button[3] { BTN_LT1, BTN_MB1, BTN_LF1 }, + .custom_mode_config = 0, + .keyboard_mode_config = 0, + .rgb_config = 0, }, }, - .communication_backend_configs_count = 1, - .communication_backend_configs = new CommunicationBackendConfig[1] { + .communication_backend_configs_count = 3, + .communication_backend_configs = new CommunicationBackendConfig[3] { + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_DINPUT, + .default_mode_config = 1, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RF3 }, + .secondary_backends = {}, + }, CommunicationBackendConfig { .backend_id = COMMS_BACKEND_GAMECUBE, - .default_mode = MODE_MELEE, - .activation_binding_count = 0, - .activation_binding = {}, + .default_mode_config = 1, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RT1 }, + .secondary_backends = {}, + }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_N64, + .default_mode_config = 1, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RT3 }, + .secondary_backends = {}, }, }, + .custom_modes_count = 0, + .custom_modes = {}, .keyboard_modes_count = 0, .keyboard_modes = {}, + .rgb_configs_count = 0, + .rgb_configs = {}, + .default_backend_config = 1, + .default_usb_backend_config = 1, + .rgb_brightness = 0, + .has_melee_options = true, + .melee_options = { + .crouch_walk_os = false, + .disable_ledgedash_socd_override = false, + .has_custom_airdodge = false, + .custom_airdodge = { .x = 0, .y = 0 }, + }, + .has_project_m_options = true, + .project_m_options = { + .true_z_press = false, + .disable_ledgedash_socd_override = false, + .has_custom_airdodge = false, + .custom_airdodge = { .x = 0, .y = 0 }, + }, }; // clang-format on -#endif \ No newline at end of file +#endif diff --git a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp index 738027cc..8d816c8f 100644 --- a/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp +++ b/HAL/avr/avr_nousb/include/core/KeyboardMode.hpp @@ -8,7 +8,7 @@ class KeyboardMode : public InputMode { public: - KeyboardMode(GameModeConfig &config); + KeyboardMode(); ~KeyboardMode(); void SendReport(const InputState &inputs); diff --git a/HAL/avr/avr_nousb/src/comms/backend_init.cpp b/HAL/avr/avr_nousb/src/comms/backend_init.cpp index 3857f564..d908690c 100644 --- a/HAL/avr/avr_nousb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_nousb/src/comms/backend_init.cpp @@ -1,19 +1,12 @@ #include "comms/backend_init.hpp" -#include "comms/B0XXInputViewer.hpp" -#include "comms/ConfiguratorBackend.hpp" -#include "comms/DInputBackend.hpp" #include "comms/GamecubeBackend.hpp" #include "comms/N64Backend.hpp" -#include "comms/NintendoSwitchBackend.hpp" -#include "comms/XInputBackend.hpp" #include "core/CommunicationBackend.hpp" #include "core/config_utils.hpp" #include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include -#include #include size_t initialize_backends( @@ -22,15 +15,29 @@ size_t initialize_backends( InputSource **input_sources, size_t input_source_count, Config &config, - const Pinout &pinout + const Pinout &pinout, + backend_config_selector_t get_backend_config, + usb_backend_getter_t get_usb_backend_config, + detect_console_t detect_console, + secondary_backend_initializer_t init_secondary_backends, + primary_backend_initializer_t init_primary_backend ) { - CommunicationBackend *primary_backend; + // Make sure required function pointers are not null. + if (get_backend_config == nullptr || init_primary_backend == nullptr || + detect_console == nullptr) { + return 0; + } - CommunicationBackendConfig backend_config = backend_config_from_buttons( - inputs, - config.communication_backend_configs, - config.communication_backend_configs_count - ); + CommunicationBackendConfig backend_config = CommunicationBackendConfig_init_zero; + get_backend_config(backend_config, inputs, config); + + /* If no match found for button hold, use default backend config. */ + if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED && + config.default_backend_config > 0) { + backend_config = config.communication_backend_configs[config.default_backend_config - 1]; + } + + /* If no default backend config use GameCube backend. */ if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { backend_config = backend_config_from_id( COMMS_BACKEND_GAMECUBE, @@ -38,33 +45,104 @@ size_t initialize_backends( config.communication_backend_configs_count ); } - // if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) {} - if (backend_config.backend_id == COMMS_BACKEND_UNSPECIFIED) { - backend_config = config.communication_backend_configs[config.default_backend_config]; + + CommunicationBackend *primary_backend = nullptr; + + init_primary_backend( + primary_backend, + backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); + + size_t backend_count = 1; + if (init_secondary_backends != nullptr) { + backend_count = init_secondary_backends( + backends, + primary_backend, + backend_config.backend_id, + inputs, + input_sources, + input_source_count, + config, + pinout + ); } - size_t backend_count; + if (backend_config.default_mode_config > 0) { + GameModeConfig &mode_config = + config.game_mode_configs[backend_config.default_mode_config - 1]; + for (size_t i = 0; i < backend_count; i++) { + set_mode(backends[i], mode_config, config); + } + } - switch (backend_config.backend_id) { + return backend_count; +} + +void init_primary_backend( + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + switch (backend_id) { case COMMS_BACKEND_N64: + delete primary_backend; primary_backend = - new N64Backend(inputs, input_sources, input_source_count, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; + new N64Backend(inputs, input_sources, input_source_count, 60, pinout.joybus_data); break; case COMMS_BACKEND_GAMECUBE: + case COMMS_BACKEND_UNSPECIFIED: // Fall back to GameCube if invalid backend selected. default: - primary_backend = - new GamecubeBackend(inputs, input_sources, input_source_count, pinout.joybus_data); - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - break; + delete primary_backend; + primary_backend = new GamecubeBackend( + inputs, + input_sources, + input_source_count, + inputs.rt1 ? 1000 : 125, + pinout.joybus_data + ); } +} - const GameModeConfig &mode_config = - config.game_mode_configs[backend_config.default_mode_config]; +size_t init_secondary_backends( + CommunicationBackend **&backends, + CommunicationBackend *&primary_backend, + CommunicationBackendId backend_id, + InputState &inputs, + InputSource **input_sources, + size_t input_source_count, + Config &config, + const Pinout &pinout +) { + return 0; +} - set_mode(primary_backend, mode_config, config.keyboard_modes, config.keyboard_modes_count); +// clang-format off - return backend_count; -} \ No newline at end of file +/* Default is to first check button holds for a matching comms backend config. */ +backend_config_selector_t get_backend_config_default = []( + CommunicationBackendConfig &backend_config, + const InputState &inputs, + Config &config +) { + backend_config = backend_config_from_buttons( + inputs, + config.communication_backend_configs, + config.communication_backend_configs_count + ); +}; + +usb_backend_getter_t get_usb_backend_config_default = nullptr; + +// clang-format on + +primary_backend_initializer_t init_primary_backend_default = &init_primary_backend; +secondary_backend_initializer_t init_secondary_backends_default = nullptr; diff --git a/HAL/avr/avr_nousb/src/comms/console_detection.cpp b/HAL/avr/avr_nousb/src/comms/console_detection.cpp index a679e359..86c51b06 100644 --- a/HAL/avr/avr_nousb/src/comms/console_detection.cpp +++ b/HAL/avr/avr_nousb/src/comms/console_detection.cpp @@ -1,5 +1,9 @@ #include "comms/console_detection.hpp" +#include "core/pinout.hpp" + +#include + CommunicationBackendId detect_console(const Pinout &pinout) { return COMMS_BACKEND_GAMECUBE; } diff --git a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp index 66cc370a..1c96e6e3 100644 --- a/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp +++ b/HAL/avr/avr_nousb/src/core/KeyboardMode.cpp @@ -2,7 +2,7 @@ #include "core/InputMode.hpp" -KeyboardMode::KeyboardMode(GameModeConfig &config) : InputMode(config) {} +KeyboardMode::KeyboardMode() : InputMode() {} KeyboardMode::~KeyboardMode() {} diff --git a/HAL/avr/avr_usb/include/config_defaults.hpp b/HAL/avr/avr_usb/include/config_defaults.hpp index 2c3f0c30..aedbf71f 100644 --- a/HAL/avr/avr_usb/include/config_defaults.hpp +++ b/HAL/avr/avr_usb/include/config_defaults.hpp @@ -98,8 +98,8 @@ const Config default_config = { .rgb_config = 0, }, }, - .communication_backend_configs_count = 2, - .communication_backend_configs = new CommunicationBackendConfig[2] { + .communication_backend_configs_count = 3, + .communication_backend_configs = new CommunicationBackendConfig[3] { CommunicationBackendConfig { .backend_id = COMMS_BACKEND_DINPUT, .default_mode_config = 1, @@ -114,6 +114,13 @@ const Config default_config = { .activation_binding = new Button[1] { BTN_RT1 }, .secondary_backends = {}, }, + CommunicationBackendConfig { + .backend_id = COMMS_BACKEND_N64, + .default_mode_config = 1, + .activation_binding_count = 1, + .activation_binding = new Button[1] { BTN_RT3 }, + .secondary_backends = {}, + }, }, .custom_modes_count = 0, .custom_modes = {}, @@ -171,4 +178,4 @@ const Config default_config = { // clang-format on -#endif \ No newline at end of file +#endif diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp index dd748013..2ffb89a2 100644 --- a/HAL/avr/avr_usb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -118,7 +118,7 @@ void init_primary_backend( inputs, input_sources, input_source_count, - 125, + inputs.rt1 ? 1000 : 125, pinout.joybus_data ); break; diff --git a/HAL/avr/avr_usb/src/core/mode_selection.cpp b/HAL/avr/avr_usb/src/core/mode_selection.cpp deleted file mode 100644 index 127212a8..00000000 --- a/HAL/avr/avr_usb/src/core/mode_selection.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "core/mode_selection.hpp" - -#include "core/state.hpp" -#include "modes/CustomControllerMode.hpp" -#include "modes/CustomKeyboardMode.hpp" -#include "modes/FgcMode.hpp" -#include "modes/Melee20Button.hpp" -#include "modes/ProjectM.hpp" -#include "modes/RivalsOfAether.hpp" -#include "modes/Ultimate.hpp" -#include "util/state_util.hpp" - -#include - -Melee20Button melee_mode; -ProjectM projectm_mode; -Ultimate ultimate_mode; -FgcMode fgc_mode; -RivalsOfAether rivals_mode; -CustomKeyboardMode keyboard_mode; -CustomControllerMode custom_mode; - -uint64_t mode_activation_masks[10]; - -size_t current_mode_index = SIZE_MAX; - -void set_mode(CommunicationBackend *backend, ControllerMode *mode) { - // Delete keyboard mode in case one is set, so we don't end up getting both controller and - // keyboard inputs. - current_kb_mode = nullptr; - - // Set new controller mode. - backend->SetGameMode(mode); -} - -void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { - // Only DInputBackend supports keyboard modes. - if (backend->BackendId() != COMMS_BACKEND_DINPUT) { - return; - } - - // Delete and reassign current keyboard mode. - current_kb_mode = mode; - - // Unset the current controller mode so backend only gives neutral inputs. - backend->SetGameMode(mode); -} - -void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config) { - switch (mode_config.mode_id) { - case MODE_MELEE: - melee_mode.SetConfig(mode_config, config.melee_options); - set_mode(backend, &melee_mode); - break; - case MODE_PROJECT_M: - projectm_mode.SetConfig(mode_config, config.project_m_options); - set_mode(backend, &projectm_mode); - break; - case MODE_ULTIMATE: - ultimate_mode.SetConfig(mode_config); - set_mode(backend, &ultimate_mode); - break; - case MODE_FGC: - fgc_mode.SetConfig(mode_config); - set_mode(backend, &fgc_mode); - break; - case MODE_RIVALS_OF_AETHER: - rivals_mode.SetConfig(mode_config); - set_mode(backend, &rivals_mode); - break; - case MODE_KEYBOARD: - if (backend->BackendId() != COMMS_BACKEND_DINPUT || - mode_config.keyboard_mode_config < 1 || - mode_config.keyboard_mode_config > config.keyboard_modes_count) { - break; - } - keyboard_mode.SetConfig( - mode_config, - config.keyboard_modes[mode_config.keyboard_mode_config - 1] - ); - set_mode(backend, &keyboard_mode); - break; - case MODE_CUSTOM: - if (mode_config.custom_mode_config < 1 || - mode_config.custom_mode_config > config.custom_modes_count) { - break; - } - custom_mode.SetConfig( - mode_config, - config.custom_modes[mode_config.custom_mode_config - 1] - ); - set_mode(backend, &custom_mode); - break; - case MODE_UNSPECIFIED: - default: - break; - } -} - -// TODO: Maybe remove this overload in favour of looking up the gamemode outside of here using a -// config_utils function. -void set_mode(CommunicationBackend *backend, GameModeId mode_id, Config &config) { - // In this overload we only know the mode id so we need to find a mode config that matches this - // ID. - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode = config.game_mode_configs[i]; - if (mode.mode_id == mode_id) { - set_mode(backend, mode, config); - return; - } - } -} - -void select_mode(CommunicationBackend **backends, size_t backends_count, Config &config) { - // TODO: Use a counter variable to only run the contents of this function every x iterations - // rather than on every single poll. - - InputState &inputs = backends[0]->GetInputs(); - - for (size_t i = 0; i < config.game_mode_configs_count; i++) { - GameModeConfig &mode_config = config.game_mode_configs[i]; - if (all_buttons_held(inputs.buttons, mode_activation_masks[i]) && i != current_mode_index) { - current_mode_index = i; - for (size_t i = 0; i < backends_count; i++) { - set_mode(backends[i], mode_config, config); - } - return; - } - } -} - -void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count) { - // Build bit masks for checking for matching button holds. - for (size_t i = 0; i < mode_configs_count; i++) { - mode_activation_masks[i] = make_button_mask( - mode_configs[i].activation_binding, - mode_configs[i].activation_binding_count - ); - } -} diff --git a/HAL/avr/avr_usb/include/comms/backend_init.hpp b/HAL/avr/include/comms/backend_init.hpp similarity index 100% rename from HAL/avr/avr_usb/include/comms/backend_init.hpp rename to HAL/avr/include/comms/backend_init.hpp diff --git a/HAL/avr/src/reboot.cpp b/HAL/avr/src/reboot.cpp index 3c4f98ea..110d4bd3 100644 --- a/HAL/avr/src/reboot.cpp +++ b/HAL/avr/src/reboot.cpp @@ -12,8 +12,10 @@ void reboot_firmware() { } void reboot_bootloader() { +#ifdef MAGIC_KEY_POS uint16_t *magic_key_pos = (uint16_t *)MAGIC_KEY_POS; *magic_key_pos = MAGIC_KEY; +#endif wdt_enable(WDTO_15MS); while (true) { delay(1); diff --git a/config/arduino/config.cpp b/config/arduino/config.cpp index 033456d6..fecb270e 100644 --- a/config/arduino/config.cpp +++ b/config/arduino/config.cpp @@ -1,100 +1,95 @@ -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" #include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" -#include "input/NunchukInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +#include + +Config config = default_config; // Customise this to match your controller's pinout. -GpioButtonMapping button_mappings[] = { - {&InputState::l, 15}, - { &InputState::left, 16}, - { &InputState::down, 14}, - { &InputState::right, 1 }, - - { &InputState::mod_x, 12}, - { &InputState::mod_y, 0 }, - - { &InputState::select, 2 }, - { &InputState::start, 4 }, - { &InputState::home, 3 }, - - { &InputState::c_left, 8 }, - { &InputState::c_up, 10}, - { &InputState::c_down, 6 }, - { &InputState::a, 9 }, - { &InputState::c_right, 5 }, - - { &InputState::b, A2}, - { &InputState::x, A1}, - { &InputState::z, A0}, - { &InputState::up, 13}, - - { &InputState::r, 7 }, - { &InputState::y, A5}, - { &InputState::lightshield, A4}, - { &InputState::midshield, A3}, +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 15 }, + { BTN_LF3, 16 }, + { BTN_LF2, 14 }, + { BTN_LF1, 1 }, + + { BTN_LT1, 12 }, + { BTN_LT2, 0 }, + + { BTN_MB3, 2 }, + { BTN_MB1, 4 }, + { BTN_MB2, 3 }, + + { BTN_RT3, 8 }, + { BTN_RT4, 10 }, + { BTN_RT2, 6 }, + { BTN_RT1, 9 }, + { BTN_RT5, 5 }, + + { BTN_RF1, A2 }, + { BTN_RF2, A1 }, + { BTN_RF3, A0 }, + { BTN_RF4, 13 }, + + { BTN_RF5, 7 }, + { BTN_RF6, A5 }, + { BTN_RF7, A4 }, + { BTN_RF8, A3 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -Pinout pinout = { - .joybus_data = 13, +const Pinout pinout = { + .joybus_data = 8, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { - // Create Nunchuk input source - must be done before GPIO input source otherwise it would - // disable the pullups on the i2c pins. - NunchukInput *nunchuk = new NunchukInput(); + static InputState inputs; // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input, nunchuk }; + static InputSource *input_sources[] = { &gpio_input }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - CommunicationBackend *primary_backend = nullptr; - if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); } + + if (current_kb_mode != nullptr) { + current_kb_mode->SendReport(backends[0]->GetInputs()); + } } diff --git a/config/arduino/env.ini b/config/arduino/env.ini index 630377b1..3913bcc1 100644 --- a/config/arduino/env.ini +++ b/config/arduino/env.ini @@ -1,20 +1,20 @@ [env:arduino_uno] extends = avr_nousb board = uno -build_src_filter = +build_src_filter = ${avr_nousb.build_src_filter} + [env:arduino_nano] extends = avr_nousb board = nanoatmega328 -build_src_filter = +build_src_filter = ${avr_nousb.build_src_filter} + [env:arduino_mega] extends = avr_nousb board = megaatmega2560 -build_src_filter = +build_src_filter = ${avr_nousb.build_src_filter} - + \ No newline at end of file + + From ed38be35e6ee20c18bf96f820442abd42910057e Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 01:01:17 +0000 Subject: [PATCH 161/167] build: Remove glyph from CI --- .github/workflows/build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78c3dc03..d62fdece 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,8 +19,6 @@ jobs: bin_ext: uf2 - env: b0xx_r4 bin_ext: uf2 - - env: glyph - bin_ext: uf2 - env: pico bin_ext: uf2 - env: schism From 23a584731499cb7ae38dafb1428f9c1902c5e9ae Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 01:02:10 +0000 Subject: [PATCH 162/167] Add missing file --- HAL/avr/src/core/mode_selection.cpp | 140 ++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 HAL/avr/src/core/mode_selection.cpp diff --git a/HAL/avr/src/core/mode_selection.cpp b/HAL/avr/src/core/mode_selection.cpp new file mode 100644 index 00000000..127212a8 --- /dev/null +++ b/HAL/avr/src/core/mode_selection.cpp @@ -0,0 +1,140 @@ +#include "core/mode_selection.hpp" + +#include "core/state.hpp" +#include "modes/CustomControllerMode.hpp" +#include "modes/CustomKeyboardMode.hpp" +#include "modes/FgcMode.hpp" +#include "modes/Melee20Button.hpp" +#include "modes/ProjectM.hpp" +#include "modes/RivalsOfAether.hpp" +#include "modes/Ultimate.hpp" +#include "util/state_util.hpp" + +#include + +Melee20Button melee_mode; +ProjectM projectm_mode; +Ultimate ultimate_mode; +FgcMode fgc_mode; +RivalsOfAether rivals_mode; +CustomKeyboardMode keyboard_mode; +CustomControllerMode custom_mode; + +uint64_t mode_activation_masks[10]; + +size_t current_mode_index = SIZE_MAX; + +void set_mode(CommunicationBackend *backend, ControllerMode *mode) { + // Delete keyboard mode in case one is set, so we don't end up getting both controller and + // keyboard inputs. + current_kb_mode = nullptr; + + // Set new controller mode. + backend->SetGameMode(mode); +} + +void set_mode(CommunicationBackend *backend, KeyboardMode *mode) { + // Only DInputBackend supports keyboard modes. + if (backend->BackendId() != COMMS_BACKEND_DINPUT) { + return; + } + + // Delete and reassign current keyboard mode. + current_kb_mode = mode; + + // Unset the current controller mode so backend only gives neutral inputs. + backend->SetGameMode(mode); +} + +void set_mode(CommunicationBackend *backend, GameModeConfig &mode_config, Config &config) { + switch (mode_config.mode_id) { + case MODE_MELEE: + melee_mode.SetConfig(mode_config, config.melee_options); + set_mode(backend, &melee_mode); + break; + case MODE_PROJECT_M: + projectm_mode.SetConfig(mode_config, config.project_m_options); + set_mode(backend, &projectm_mode); + break; + case MODE_ULTIMATE: + ultimate_mode.SetConfig(mode_config); + set_mode(backend, &ultimate_mode); + break; + case MODE_FGC: + fgc_mode.SetConfig(mode_config); + set_mode(backend, &fgc_mode); + break; + case MODE_RIVALS_OF_AETHER: + rivals_mode.SetConfig(mode_config); + set_mode(backend, &rivals_mode); + break; + case MODE_KEYBOARD: + if (backend->BackendId() != COMMS_BACKEND_DINPUT || + mode_config.keyboard_mode_config < 1 || + mode_config.keyboard_mode_config > config.keyboard_modes_count) { + break; + } + keyboard_mode.SetConfig( + mode_config, + config.keyboard_modes[mode_config.keyboard_mode_config - 1] + ); + set_mode(backend, &keyboard_mode); + break; + case MODE_CUSTOM: + if (mode_config.custom_mode_config < 1 || + mode_config.custom_mode_config > config.custom_modes_count) { + break; + } + custom_mode.SetConfig( + mode_config, + config.custom_modes[mode_config.custom_mode_config - 1] + ); + set_mode(backend, &custom_mode); + break; + case MODE_UNSPECIFIED: + default: + break; + } +} + +// TODO: Maybe remove this overload in favour of looking up the gamemode outside of here using a +// config_utils function. +void set_mode(CommunicationBackend *backend, GameModeId mode_id, Config &config) { + // In this overload we only know the mode id so we need to find a mode config that matches this + // ID. + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode = config.game_mode_configs[i]; + if (mode.mode_id == mode_id) { + set_mode(backend, mode, config); + return; + } + } +} + +void select_mode(CommunicationBackend **backends, size_t backends_count, Config &config) { + // TODO: Use a counter variable to only run the contents of this function every x iterations + // rather than on every single poll. + + InputState &inputs = backends[0]->GetInputs(); + + for (size_t i = 0; i < config.game_mode_configs_count; i++) { + GameModeConfig &mode_config = config.game_mode_configs[i]; + if (all_buttons_held(inputs.buttons, mode_activation_masks[i]) && i != current_mode_index) { + current_mode_index = i; + for (size_t i = 0; i < backends_count; i++) { + set_mode(backends[i], mode_config, config); + } + return; + } + } +} + +void setup_mode_activation_bindings(const GameModeConfig *mode_configs, size_t mode_configs_count) { + // Build bit masks for checking for matching button holds. + for (size_t i = 0; i < mode_configs_count; i++) { + mode_activation_masks[i] = make_button_mask( + mode_configs[i].activation_binding, + mode_configs[i].activation_binding_count + ); + } +} From 3c11591ff528d979b92dca79a0ea51353e7f0fcd Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 01:10:10 +0000 Subject: [PATCH 163/167] build: Fix leonardo and micro env builds --- config/arduino/env.ini | 14 ++++ config/arduino_nativeusb/config.cpp | 121 ---------------------------- config/arduino_nativeusb/env.ini | 13 --- 3 files changed, 14 insertions(+), 134 deletions(-) delete mode 100644 config/arduino_nativeusb/config.cpp delete mode 100644 config/arduino_nativeusb/env.ini diff --git a/config/arduino/env.ini b/config/arduino/env.ini index 3913bcc1..ef851b7b 100644 --- a/config/arduino/env.ini +++ b/config/arduino/env.ini @@ -18,3 +18,17 @@ board = megaatmega2560 build_src_filter = ${avr_nousb.build_src_filter} + + +[env:arduino_leonardo] +extends = avr_usb +board = leonardo +build_src_filter = + ${avr_usb.build_src_filter} + + + +[env:arduino_micro] +extends = avr_usb +board = micro +build_src_filter = + ${avr_usb.build_src_filter} + + diff --git a/config/arduino_nativeusb/config.cpp b/config/arduino_nativeusb/config.cpp deleted file mode 100644 index b615000f..00000000 --- a/config/arduino_nativeusb/config.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" -#include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" -#include "core/KeyboardMode.hpp" -#include "core/pinout.hpp" -#include "core/socd.hpp" -#include "core/state.hpp" -#include "input/GpioButtonInput.hpp" -#include "input/NunchukInput.hpp" -#include "modes/Melee20Button.hpp" -#include "stdlib.hpp" - -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; - -// Customise this to match your controller's pinout. -GpioButtonMapping button_mappings[] = { - {&InputState::l, 15}, - { &InputState::left, 16}, - { &InputState::down, 14}, - { &InputState::right, 1 }, - - { &InputState::mod_x, 12}, - { &InputState::mod_y, 0 }, - - { &InputState::select, 2 }, - { &InputState::start, 4 }, - { &InputState::home, 3 }, - - { &InputState::c_left, 8 }, - { &InputState::c_up, 10}, - { &InputState::c_down, 6 }, - { &InputState::a, 9 }, - { &InputState::c_right, 5 }, - - { &InputState::b, A2}, - { &InputState::x, A1}, - { &InputState::z, A0}, - { &InputState::up, 13}, - - { &InputState::r, 7 }, - { &InputState::y, A5}, - { &InputState::lightshield, A4}, - { &InputState::midshield, A3}, -}; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); - -Pinout pinout = { - .joybus_data = 17, - .mux = -1, - .nunchuk_detect = -1, - .nunchuk_sda = -1, - .nunchuk_scl = -1, -}; - -void setup() { - // Create Nunchuk input source - must be done before GPIO input source otherwise it would - // disable the pullups on the i2c pins. - NunchukInput *nunchuk = new NunchukInput(); - - // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); - - InputState button_holds; - gpio_input->UpdateInputs(button_holds); - - // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input, nunchuk }; - size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - - CommunicationBackend *primary_backend = new DInputBackend(input_sources, input_source_count); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - - /* Select communication backend. */ - if (usb_connected) { - // Default to DInput mode if USB is connected. - // Input viewer only used when connected to PC i.e. when using DInput mode. - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - delete primary_backend; - if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - // If not DInput then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } - - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); -} - -void loop() { - select_mode(backends[0]); - - for (size_t i = 0; i < backend_count; i++) { - backends[i]->SendReport(); - } - - if (current_kb_mode != nullptr) { - current_kb_mode->SendReport(backends[0]->GetInputs()); - } -} diff --git a/config/arduino_nativeusb/env.ini b/config/arduino_nativeusb/env.ini deleted file mode 100644 index 08688de6..00000000 --- a/config/arduino_nativeusb/env.ini +++ /dev/null @@ -1,13 +0,0 @@ -[env:arduino_leonardo] -extends = avr_usb -board = leonardo -build_src_filter = - ${avr_usb.build_src_filter} - + - -[env:arduino_micro] -extends = avr_usb -board = micro -build_src_filter = - ${avr_usb.build_src_filter} - + \ No newline at end of file From bb276981ec8e818c3370b2bea06d9345a633dfc2 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 11:27:50 +0000 Subject: [PATCH 164/167] Update AVR device configs --- HAL/avr/avr_nousb/src/comms/backend_init.cpp | 2 +- HAL/avr/avr_usb/src/comms/backend_init.cpp | 2 +- config/arduino/config.cpp | 1 + config/b0xx_r1/config.cpp | 125 +++++------- config/b0xx_r2/config.cpp | 139 ++++++-------- config/gccmx/config.cpp | 2 +- config/gccpcb1/config.cpp | 136 ++++++------- config/gccpcb2/config.cpp | 151 +++++++-------- config/htangl_v1/config.cpp | 1 + config/lbx/config.cpp | 190 +++++++++---------- config/smashbox/config.cpp | 121 ++++++------ 11 files changed, 379 insertions(+), 491 deletions(-) diff --git a/HAL/avr/avr_nousb/src/comms/backend_init.cpp b/HAL/avr/avr_nousb/src/comms/backend_init.cpp index d908690c..0871884f 100644 --- a/HAL/avr/avr_nousb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_nousb/src/comms/backend_init.cpp @@ -106,7 +106,7 @@ void init_primary_backend( inputs, input_sources, input_source_count, - inputs.rt1 ? 1000 : 125, + inputs.rt1 ? 0 : 125, pinout.joybus_data ); } diff --git a/HAL/avr/avr_usb/src/comms/backend_init.cpp b/HAL/avr/avr_usb/src/comms/backend_init.cpp index 2ffb89a2..63d28814 100644 --- a/HAL/avr/avr_usb/src/comms/backend_init.cpp +++ b/HAL/avr/avr_usb/src/comms/backend_init.cpp @@ -118,7 +118,7 @@ void init_primary_backend( inputs, input_sources, input_source_count, - inputs.rt1 ? 1000 : 125, + inputs.rt1 ? 0 : 125, pinout.joybus_data ); break; diff --git a/config/arduino/config.cpp b/config/arduino/config.cpp index fecb270e..4041caed 100644 --- a/config/arduino/config.cpp +++ b/config/arduino/config.cpp @@ -67,6 +67,7 @@ void setup() { static GpioButtonInput gpio_input(button_mappings, button_count); gpio_input.UpdateInputs(inputs); + // Check bootloader button hold as early as possible for safety. if (inputs.mb1) { Serial.begin(115200); reboot_bootloader(); diff --git a/config/b0xx_r1/config.cpp b/config/b0xx_r1/config.cpp index 22a50744..1ab72221 100644 --- a/config/b0xx_r1/config.cpp +++ b/config/b0xx_r1/config.cpp @@ -1,113 +1,90 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" +#include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" #include "input/NunchukInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +#include -GpioButtonMapping button_mappings[] = { - {&InputState::l, 7 }, - { &InputState::left, 15}, - { &InputState::down, 16}, - { &InputState::right, 14}, +Config config = default_config; - { &InputState::mod_x, 6 }, - { &InputState::mod_y, 8 }, +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 7 }, + { BTN_LF3, 15 }, + { BTN_LF2, 16 }, + { BTN_LF1, 14 }, - { &InputState::start, 12}, + { BTN_LT1, 6 }, + { BTN_LT2, 8 }, - { &InputState::c_left, A1}, - { &InputState::c_up, A2}, - { &InputState::c_down, 5 }, - { &InputState::a, 13}, - { &InputState::c_right, A0}, + { BTN_MB1, 12 }, - { &InputState::b, 4 }, - { &InputState::x, A5}, - { &InputState::z, A4}, - { &InputState::up, A3}, + { BTN_RT3, A1 }, + { BTN_RT4, A2 }, + { BTN_RT2, 5 }, + { BTN_RT1, 13 }, + { BTN_RT5, A0 }, - { &InputState::r, 0 }, - { &InputState::y, 1 }, + { BTN_RF1, 4 }, + { BTN_RF2, A5 }, + { BTN_RF3, A4 }, + { BTN_RF4, A3 }, + + { BTN_RF5, 0 }, + { BTN_RF6, 1 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -Pinout pinout = { +const Pinout pinout = { .joybus_data = 17, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { + static InputState inputs; + // Create Nunchuk input source - must be done before GPIO input source otherwise it would // disable the pullups on the i2c pins. - NunchukInput *nunchuk = new NunchukInput(); + static NunchukInput nunchuk; // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + // Check bootloader button hold as early as possible for safety. + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input, nunchuk }; + static InputSource *input_sources[] = { &gpio_input, &nunchuk }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - CommunicationBackend *primary_backend = new DInputBackend(input_sources, input_source_count); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - - /* Select communication backend. */ - if (usb_connected) { - // Default to DInput mode if USB is connected. - // Input viewer only used when connected to PC i.e. when using DInput mode. - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - delete primary_backend; - if (button_holds.c_left) { - // Hold C-Left on plugin for N64. - primary_backend = - new N64Backend(input_sources, input_source_count, 60, pinout.joybus_data); - } else if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - // If not DInput then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/b0xx_r2/config.cpp b/config/b0xx_r2/config.cpp index 1843a01b..d287384d 100644 --- a/config/b0xx_r2/config.cpp +++ b/config/b0xx_r2/config.cpp @@ -1,122 +1,99 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" +#include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" #include "input/NunchukInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +#include -GpioButtonMapping button_mappings[] = { - {&InputState::l, 9 }, - { &InputState::left, 15}, - { &InputState::down, 16}, - { &InputState::right, 14}, +Config config = default_config; - { &InputState::mod_x, 8 }, - { &InputState::mod_y, 6 }, +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 9 }, + { BTN_LF3, 15 }, + { BTN_LF2, 16 }, + { BTN_LF1, 14 }, - { &InputState::start, 12}, + { BTN_LT1, 8 }, + { BTN_LT2, 6 }, - { &InputState::c_left, A1}, - { &InputState::c_up, A2}, - { &InputState::c_down, 5 }, - { &InputState::a, 13}, - { &InputState::c_right, A0}, + { BTN_MB1, 12 }, - { &InputState::b, 4 }, - { &InputState::x, A5}, - { &InputState::z, A4}, - { &InputState::up, A3}, + { BTN_RT3, A1 }, + { BTN_RT4, A2 }, + { BTN_RT2, 5 }, + { BTN_RT1, 13 }, + { BTN_RT5, A0 }, - { &InputState::r, 0 }, - { &InputState::y, 1 }, - { &InputState::lightshield, 10}, - { &InputState::midshield, 11}, + { BTN_RF1, 4 }, + { BTN_RF2, A5 }, + { BTN_RF3, A4 }, + { BTN_RF4, A3 }, + + { BTN_RF5, 0 }, + { BTN_RF6, 1 }, + { BTN_RF7, 10 }, + { BTN_RF8, 11 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -Pinout pinout = { +const Pinout pinout = { .joybus_data = 17, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = 7, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { + static InputState inputs; + // Create Nunchuk input source - must be done before GPIO input source otherwise it would // disable the pullups on the i2c pins. - NunchukInput *nunchuk = new NunchukInput(); + static NunchukInput nunchuk; // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - InputState button_holds; - gpio_input->UpdateInputs(button_holds); - - // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input, nunchuk }; - size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + // Check bootloader button hold as early as possible for safety. + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } - // Hold B on plugin for Brook board mode. + // Hold RF1 (B) on plugin for Brook board mode. pinMode(pinout.mux, OUTPUT); - if (button_holds.b) + if (inputs.rf1) digitalWrite(pinout.mux, LOW); else digitalWrite(pinout.mux, HIGH); - CommunicationBackend *primary_backend = new DInputBackend(input_sources, input_source_count); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - - /* Select communication backend. */ - if (usb_connected) { - // Default to DInput mode if USB is connected. - // Input viewer only used when connected to PC i.e. when using DInput mode. - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - delete primary_backend; - if (button_holds.c_left) { - // Hold C-Left on plugin for N64. - primary_backend = - new N64Backend(input_sources, input_source_count, 60, pinout.joybus_data); - } else if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - // If not DInput then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + // Create array of input sources to be used. + static InputSource *input_sources[] = { &gpio_input, &nunchuk }; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/gccmx/config.cpp b/config/gccmx/config.cpp index 604331cb..de24dbd1 100644 --- a/config/gccmx/config.cpp +++ b/config/gccmx/config.cpp @@ -4,7 +4,7 @@ #include "comms/N64Backend.hpp" #include "config/mode_selection.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" +#include "core/KeyboardMode.hpp" #include "core/pinout.hpp" #include "core/socd.hpp" #include "core/state.hpp" diff --git a/config/gccpcb1/config.cpp b/config/gccpcb1/config.cpp index 072deeaf..ec00fb10 100644 --- a/config/gccpcb1/config.cpp +++ b/config/gccpcb1/config.cpp @@ -1,109 +1,87 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" +#include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +#include + +Config config = default_config; + +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 16 }, + { BTN_LF3, 1 }, + { BTN_LF2, 0 }, + { BTN_LF1, 4 }, + + { BTN_LT1, 5 }, + { BTN_LT2, 6 }, + + { BTN_MB1, 7 }, + + { BTN_RT3, 9 }, + { BTN_RT4, 8 }, + { BTN_RT2, 12 }, + { BTN_RT1, 15 }, + { BTN_RT5, 14 }, -GpioButtonMapping button_mappings[] = { - {&InputState::l, 16}, - { &InputState::left, 1 }, - { &InputState::down, 0 }, - { &InputState::right, 4 }, - { &InputState::mod_x, 5 }, - { &InputState::mod_y, 6 }, - - { &InputState::start, 7 }, - - { &InputState::c_left, 9 }, - { &InputState::c_up, 8 }, - { &InputState::c_down, 12}, - { &InputState::a, 15}, - { &InputState::c_right, 14}, - - { &InputState::b, A2}, - { &InputState::x, A1}, - { &InputState::z, A0}, - { &InputState::up, 13}, - - { &InputState::r, A4}, - { &InputState::y, A3}, - { &InputState::lightshield, 11}, - { &InputState::midshield, 10}, + { BTN_RF1, A2 }, + { BTN_RF2, A1 }, + { BTN_RF3, A0 }, + { BTN_RF4, 13 }, + + { BTN_RF5, A4 }, + { BTN_RF6, A3 }, + { BTN_RF7, 11 }, + { BTN_RF8, 10 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -Pinout pinout = { +const Pinout pinout = { .joybus_data = A5, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { + static InputState inputs; + // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + // Check bootloader button hold as early as possible for safety. + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input }; + static InputSource *input_sources[] = { &gpio_input }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - CommunicationBackend *primary_backend = new DInputBackend(input_sources, input_source_count); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - - /* Select communication backend. */ - if (usb_connected) { - // Default to DInput mode if USB is connected. - // Input viewer only used when connected to PC i.e. when using DInput mode. - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - delete primary_backend; - if (button_holds.c_left) { - // Hold C-Left on plugin for N64. - primary_backend = - new N64Backend(input_sources, input_source_count, 60, pinout.joybus_data); - } else if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - // If not DInput then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/gccpcb2/config.cpp b/config/gccpcb2/config.cpp index 9366e92f..9e5f9118 100644 --- a/config/gccpcb2/config.cpp +++ b/config/gccpcb2/config.cpp @@ -1,119 +1,96 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" +#include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +#include + +Config config = default_config; + +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 2 }, + { BTN_LF3, 10 }, + { BTN_LF2, 13 }, + { BTN_LF1, 5 }, + + { BTN_LT1, 7 }, + { BTN_LT2, 3 }, -GpioButtonMapping button_mappings[] = { - {&InputState::l, 2 }, - { &InputState::left, 10}, - { &InputState::down, 13}, - { &InputState::right, 5 }, - - { &InputState::mod_x, 7 }, - { &InputState::mod_y, 3 }, - - { &InputState::select, 9 }, - { &InputState::start, 6 }, - { &InputState::home, 8 }, - - { &InputState::c_left, A1}, - { &InputState::c_up, A3}, - { &InputState::c_down, A0}, - { &InputState::a, A2}, - { &InputState::c_right, A4}, - - { &InputState::b, A5}, - { &InputState::x, 14}, - { &InputState::z, 16}, - { &InputState::up, 15}, - - { &InputState::r, 12}, - { &InputState::y, 4 }, - { &InputState::lightshield, 1 }, - { &InputState::midshield, 0 }, + { BTN_MB3, 9 }, + { BTN_MB1, 6 }, + { BTN_MB2, 8 }, + + { BTN_RT3, A1 }, + { BTN_RT4, A3 }, + { BTN_RT2, A0 }, + { BTN_RT1, A2 }, + { BTN_RT5, A4 }, + + { BTN_RF1, A5 }, + { BTN_RF2, 14 }, + { BTN_RF3, 16 }, + { BTN_RF4, 15 }, + + { BTN_RF5, 12 }, + { BTN_RF6, 4 }, + { BTN_RF7, 1 }, + { BTN_RF8, 0 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -Pinout pinout = { +const Pinout pinout = { .joybus_data = 17, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = 11, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { - // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static InputState inputs; - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + // Create GPIO input source and use it to read button states for checking button holds. + GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input }; - size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + // Check bootloader button hold as early as possible for safety. + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } - // Hold B on plugin for Brook board mode. + // Hold RF1 (B) on plugin for Brook board mode. pinMode(pinout.mux, OUTPUT); - if (button_holds.b) + if (inputs.rf1) digitalWrite(pinout.mux, HIGH); else digitalWrite(pinout.mux, LOW); - CommunicationBackend *primary_backend = new DInputBackend(input_sources, input_source_count); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - - /* Select communication backend. */ - if (usb_connected) { - // Default to DInput mode if USB is connected. - // Input viewer only used when connected to PC i.e. when using DInput mode. - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - delete primary_backend; - if (button_holds.c_left) { - // Hold C-Left on plugin for N64. - primary_backend = - new N64Backend(input_sources, input_source_count, 60, pinout.joybus_data); - } else if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - // If not DInput then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + // Create array of input sources to be used. + static InputSource *input_sources[] = { &gpio_input }; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/htangl_v1/config.cpp b/config/htangl_v1/config.cpp index 427269e9..927eeaeb 100644 --- a/config/htangl_v1/config.cpp +++ b/config/htangl_v1/config.cpp @@ -66,6 +66,7 @@ void setup() { static GpioButtonInput gpio_input(button_mappings, button_count); gpio_input.UpdateInputs(inputs); + // Check bootloader button hold as early as possible for safety. if (inputs.mb1) { Serial.begin(115200); reboot_bootloader(); diff --git a/config/lbx/config.cpp b/config/lbx/config.cpp index a9c379a0..70b5eb6f 100644 --- a/config/lbx/config.cpp +++ b/config/lbx/config.cpp @@ -1,97 +1,106 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" +#include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -const int brook_up_pin = 17; -const int brook_l_pin = 30; +#include -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; -bool brook_mode = false; +Config config = default_config; + +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 11 }, + { BTN_LF3, 15 }, + { BTN_LF2, 16 }, + { BTN_LF1, 14 }, -GpioButtonMapping button_mappings[] = { - {&InputState::l, 11}, - { &InputState::left, 15}, - { &InputState::down, 16}, - { &InputState::right, 14}, - - { &InputState::mod_x, 3 }, - { &InputState::mod_y, 0 }, - { &InputState::nunchuk_c, 2 }, // Dpad Toggle button - - { &InputState::start, A5}, - - { &InputState::c_left, 4 }, - { &InputState::c_up, 8 }, - { &InputState::c_down, 1 }, - { &InputState::a, 12}, - { &InputState::c_right, 6 }, - - { &InputState::b, 13}, - { &InputState::x, 5 }, - { &InputState::z, 10}, - { &InputState::up, 9 }, - - { &InputState::r, A0}, - { &InputState::y, A1}, - { &InputState::lightshield, A2}, - { &InputState::midshield, A3}, + { BTN_LT1, 3 }, + { BTN_LT2, 0 }, + // { &InputState::nunchuk_c, 2 }, // Dpad Toggle button + + { BTN_MB1, A5 }, + + { BTN_RT3, 4 }, + { BTN_RT4, 8 }, + { BTN_RT2, 1 }, + { BTN_RT1, 12 }, + { BTN_RT5, 6 }, + + { BTN_RF1, 13 }, + { BTN_RF2, 5 }, + { BTN_RF3, 10 }, + { BTN_RF4, 9 }, + + { BTN_RF5, A0 }, + { BTN_RF6, A1 }, + { BTN_RF7, A2 }, + { BTN_RF8, A3 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); - -GpioButtonMapping brook_button_mappings[] = { - // These are the only buttons which aren't also bound on brook board directly. - // And so the only buttons which can be bound to dpad_up and l3 on brook - // WARNING: Bind as few of these as you need, since it increases latency - {&InputState::l, 11}, - - { &InputState::mod_x, 3 }, - { &InputState::mod_y, 0 }, - { &InputState::nunchuk_c, 2 }, - - { &InputState::c_left, 4 }, - { &InputState::c_up, 8 }, - { &InputState::c_down, 1 }, - { &InputState::a, 12}, - { &InputState::c_right, 6 }, +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); + +const GpioButtonMapping brook_button_mappings[] = { + // These are the only buttons which aren't also bound on brook board directly. + // And so the only buttons which can be bound to dpad_up and l3 on brook + // WARNING: Bind as few of these as you need, since it increases latency + { BTN_LF4, 11 }, + + { BTN_LT1, 3 }, + { BTN_LT2, 0 }, + // { &InputState::nunchuk_c, 2 }, + + { BTN_RT3, 4 }, + { BTN_RT4, 8 }, + { BTN_RT2, 1 }, + { BTN_RT1, 12 }, + { BTN_RT5, 6 }, }; Pinout pinout = { .joybus_data = 7, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = A4, + .nunchuk_detect = -1, + .nunchuk_sda = -1, + .nunchuk_scl = -1, }; +const int brook_up_pin = 17; +const int brook_l_pin = 30; + +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; +bool brook_mode = false; + void setup() { - // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static InputState inputs; - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + // Create GPIO input source and use it to read button states for checking button holds. + GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input }; - size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + // Check bootloader button hold as early as possible for safety. + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } - // Hold B on plugin for Brook board mode. + // Hold RF1 (B) on plugin for Brook board mode. pinMode(pinout.mux, OUTPUT); - if (button_holds.b) { + if (inputs.rf1) { digitalWrite(pinout.mux, HIGH); brook_mode = true; return; // Remaining code is no-op if brook is enabled. // Brook Firmware takes control, so we can't control layout/gamemode/backend in this branch - // IN Addition, you can force the following brook modes by holding the corresponding button + // In addition, you can force the following brook modes by holding the corresponding button // on connecting. If none are held, brook will auto-detect. 1P/X = PS3 2P/Y = PS4 3P/RB = // XID-PC 4P/LB = Nintendo Switch These listed buttons correspond to the mapping in brook // mode (so can't be remapped) So in the case of the default layout for lbx these correspond @@ -100,43 +109,14 @@ void setup() { digitalWrite(pinout.mux, LOW); brook_mode = false; - CommunicationBackend *primary_backend = new DInputBackend(input_sources, input_source_count); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - - /* Select communication backend. */ - if (usb_connected) { - // Default to DInput mode if USB is connected. - // Input viewer only used when connected to PC i.e. when using DInput mode. - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - delete primary_backend; - if (button_holds.c_left) { - // Hold C-Left on plugin for N64. - primary_backend = - new N64Backend(input_sources, input_source_count, 60, pinout.joybus_data); - } else if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - // If not DInput then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + // Create array of input sources to be used. + static InputSource *input_sources[] = { &gpio_input }; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { @@ -152,7 +132,7 @@ void loop() { return; } - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/smashbox/config.cpp b/config/smashbox/config.cpp index ea54a6f4..17803feb 100644 --- a/config/smashbox/config.cpp +++ b/config/smashbox/config.cpp @@ -1,97 +1,94 @@ -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" -#include "core/InputMode.hpp" #include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" #include "input/NunchukInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +#include + +Config config = default_config; + +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 47 }, + { BTN_LF3, 24 }, + { BTN_LF2, 23 }, + { BTN_LF1, 25 }, + + { BTN_LT1, 28 }, + { BTN_LT2, 29 }, + { BTN_LT3, 30 }, + { BTN_LT4, 31 }, + + { BTN_MB1, 50 }, + + { BTN_RT3, 36 }, + { BTN_RT4, 34 }, + { BTN_RT2, 46 }, + { BTN_RT1, 35 }, + { BTN_RT5, 37 }, + + { BTN_RF1, 44 }, + { BTN_RF2, 42 }, + { BTN_RF3, 7 }, + { BTN_RF4, 45 }, -GpioButtonMapping button_mappings[] = { - {&InputState::l, 47}, - { &InputState::left, 24}, - { &InputState::down, 23}, - { &InputState::right, 25}, - - { &InputState::mod_x, 28}, - { &InputState::mod_y, 29}, - { &InputState::select, 30}, - { &InputState::home, 31}, - - { &InputState::start, 50}, - - { &InputState::c_left, 36}, - { &InputState::c_up, 34}, - { &InputState::c_down, 46}, - { &InputState::a, 35}, - { &InputState::c_right, 37}, - - { &InputState::b, 44}, - { &InputState::x, 42}, - { &InputState::z, 7 }, - { &InputState::up, 45}, - - { &InputState::r, 41}, - { &InputState::y, 43}, - { &InputState::lightshield, 40}, - { &InputState::midshield, 12}, + { BTN_RF5, 41 }, + { BTN_RF6, 43 }, + { BTN_RF7, 40 }, + { BTN_RF8, 12 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -Pinout pinout = { +const Pinout pinout = { .joybus_data = 52, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { + static InputState inputs; + // Create Nunchuk input source - must be done before GPIO input source otherwise it would // disable the pullups on the i2c pins. - NunchukInput *nunchuk = new NunchukInput(); + static NunchukInput nunchuk; // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + // Check bootloader button hold as early as possible for safety. + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input, nunchuk }; + static InputSource *input_sources[] = { &gpio_input, &nunchuk }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - CommunicationBackend *primary_backend = nullptr; - if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); From 58727241c955e1175153fabf58a1477e9258bbb5 Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 11:28:28 +0000 Subject: [PATCH 165/167] build: increase RP2040 clock rate to 200MHz --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index b4fbcdb9..93e77235 100644 --- a/platformio.ini +++ b/platformio.ini @@ -90,7 +90,7 @@ debug_tool = cmsis-dap ; upload_protocol = cmsis-dap monitor_speed = 115200 board_build.core = earlephilhower -board_build.f_cpu = 130000000L +board_build.f_cpu = 200000000L board_build.filesystem_size = 0.5m build_unflags = -Os build_flags = From 82704b1509d03d9378562c692cc06386f29acb8c Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 11:55:27 +0000 Subject: [PATCH 166/167] Fix gccmx and c53 builds --- config/b0xx_r4/config.cpp | 5 +- config/c53/config.cpp | 56 ++++++++------- config/gccmx/config.cpp | 148 ++++++++++++++++---------------------- config/pico/config.cpp | 5 +- include/core/pinout.hpp | 6 +- 5 files changed, 105 insertions(+), 115 deletions(-) diff --git a/config/b0xx_r4/config.cpp b/config/b0xx_r4/config.cpp index 6fa7df61..b3042533 100644 --- a/config/b0xx_r4/config.cpp +++ b/config/b0xx_r4/config.cpp @@ -46,6 +46,9 @@ const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); const Pinout pinout = { .joybus_data = 2, + .nes_data = -1, + .nes_clock = -1, + .nes_latch = -1, .mux = -1, .nunchuk_detect = 3, .nunchuk_sda = 4, @@ -62,7 +65,7 @@ KeyboardMode *current_kb_mode = nullptr; void setup() { static InputState inputs; - // Create GPIO input source and use it to read button states for checking button holds. + // Read button states for checking button holds. gpio_input.UpdateInputs(inputs); // Check bootsel button hold as early as possible for safety. diff --git a/config/c53/config.cpp b/config/c53/config.cpp index a1989668..fed8becd 100644 --- a/config/c53/config.cpp +++ b/config/c53/config.cpp @@ -10,11 +10,9 @@ #include "reboot.hpp" #include "stdlib.hpp" -Config config = default_config; +#include -CommunicationBackend **backends; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +Config config = default_config; const size_t num_rows = 5; const size_t num_cols = 13; @@ -29,22 +27,29 @@ const Button matrix[num_rows][num_cols] = { { NA, NA, BTN_LT1, BTN_LT2, NA, BTN_LT6, BTN_RT7, BTN_RT6, NA, BTN_RT2, BTN_RT1, NA, NA }, }; // clang-format on -DiodeDirection diode_direction = DiodeDirection::COL2ROW; +const DiodeDirection diode_direction = DiodeDirection::COL2ROW; const Pinout pinout = { .joybus_data = 22, + .nes_data = -1, + .nes_clock = -1, + .nes_latch = -1, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +SwitchMatrixInput matrix_input(row_pins, col_pins, matrix, diode_direction); + +CommunicationBackend **backends; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { static InputState inputs; - // Create switch matrix input source and use it to read button states for checking button holds. - static SwitchMatrixInput - matrix_input(row_pins, col_pins, matrix, diode_direction); + // Read button states for checking button holds. matrix_input.UpdateInputs(inputs); // Bootsel button hold as early as possible for safety. @@ -58,30 +63,17 @@ void setup() { gpio_put(PICO_DEFAULT_LED_PIN, 1); // Attempt to load config, or write default config to flash if failed to load config. - Persistence *persistence = new Persistence(); - if (!persistence->LoadConfig(config)) { - persistence->SaveConfig(config); + if (!persistence.LoadConfig(config)) { + persistence.SaveConfig(config); } - delete persistence; - - // Create array of input sources to be used. - static InputSource *input_sources[] = { &matrix_input }; - size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); - backend_count = - initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); + backend_count = initialize_backends(backends, inputs, nullptr, 0, config, pinout); setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode( - backends[0], - config.game_mode_configs, - config.game_mode_configs_count, - config.keyboard_modes, - config.keyboard_modes_count - ); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); @@ -91,3 +83,17 @@ void loop() { current_kb_mode->SendReport(backends[0]->GetInputs()); } } + +/* Button inputs are read from the second core */ + +void setup1() { + while (backends == nullptr) { + tight_loop_contents(); + } +} + +void loop1() { + if (backends != nullptr) { + matrix_input.UpdateInputs(backends[0]->GetInputs()); + } +} \ No newline at end of file diff --git a/config/gccmx/config.cpp b/config/gccmx/config.cpp index de24dbd1..62cf2bfa 100644 --- a/config/gccmx/config.cpp +++ b/config/gccmx/config.cpp @@ -1,118 +1,96 @@ -#include "comms/B0XXInputViewer.hpp" -#include "comms/DInputBackend.hpp" -#include "comms/GamecubeBackend.hpp" -#include "comms/N64Backend.hpp" -#include "config/mode_selection.hpp" +#include "comms/backend_init.hpp" +#include "config_defaults.hpp" #include "core/CommunicationBackend.hpp" #include "core/KeyboardMode.hpp" +#include "core/mode_selection.hpp" #include "core/pinout.hpp" -#include "core/socd.hpp" #include "core/state.hpp" #include "input/GpioButtonInput.hpp" -#include "modes/Melee20Button.hpp" +#include "reboot.hpp" #include "stdlib.hpp" -CommunicationBackend **backends = nullptr; -size_t backend_count; -KeyboardMode *current_kb_mode = nullptr; +#include + +Config config = default_config; + +const GpioButtonMapping button_mappings[] = { + { BTN_LF4, 15 }, + { BTN_LF3, 16 }, + { BTN_LF2, 14 }, + { BTN_LF1, 3 }, + + { BTN_LT1, 2 }, + { BTN_LT2, 0 }, -GpioButtonMapping button_mappings[] = { - {&InputState::l, 15}, - { &InputState::left, 16}, - { &InputState::down, 14}, - { &InputState::right, 3 }, - { &InputState::mod_x, 2 }, - { &InputState::mod_y, 0 }, - - { &InputState::select, 1 }, - { &InputState::start, 4 }, - { &InputState::home, 12}, - - { &InputState::c_left, 8 }, - { &InputState::c_up, 10}, - { &InputState::c_down, 6 }, - { &InputState::a, 9 }, - { &InputState::c_right, 5 }, - - { &InputState::b, A2}, - { &InputState::x, A1}, - { &InputState::z, A0}, - { &InputState::up, 13}, - - { &InputState::r, 7 }, - { &InputState::y, A5}, - { &InputState::lightshield, A4}, - { &InputState::midshield, A3}, + { BTN_MB3, 1 }, + { BTN_MB1, 4 }, + { BTN_MB2, 12 }, + + { BTN_RT3, 8 }, + { BTN_RT4, 10 }, + { BTN_RT2, 6 }, + { BTN_RT1, 9 }, + { BTN_RT5, 5 }, + + { BTN_RF1, A2 }, + { BTN_RF2, A1 }, + { BTN_RF3, A0 }, + { BTN_RF4, 13 }, + + { BTN_RF5, 7 }, + { BTN_RF6, A5 }, + { BTN_RF7, A4 }, + { BTN_RF8, A3 }, }; -size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); +const size_t button_count = sizeof(button_mappings) / sizeof(GpioButtonMapping); -Pinout pinout = { +const Pinout pinout = { .joybus_data = 17, + .nes_data = 0, + .nes_clock = 0, + .nes_latch = 0, .mux = 11, .nunchuk_detect = -1, .nunchuk_sda = -1, .nunchuk_scl = -1, }; +CommunicationBackend **backends = nullptr; +size_t backend_count; +KeyboardMode *current_kb_mode = nullptr; + void setup() { - // Create GPIO input source and use it to read button states for checking button holds. - GpioButtonInput *gpio_input = new GpioButtonInput(button_mappings, button_count); + static InputState inputs; - InputState button_holds; - gpio_input->UpdateInputs(button_holds); + // Create GPIO input source and use it to read button states for checking button holds. + GpioButtonInput gpio_input(button_mappings, button_count); + gpio_input.UpdateInputs(inputs); - // Create array of input sources to be used. - static InputSource *input_sources[] = { gpio_input }; - size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + // Check bootloader button hold as early as possible for safety. + if (inputs.mb1) { + Serial.begin(115200); + reboot_bootloader(); + } - // Hold B on plugin for Brook board mode. + // Hold RF1 (B) on plugin for Brook board mode. pinMode(pinout.mux, OUTPUT); - if (button_holds.b) + if (inputs.rf1) digitalWrite(pinout.mux, HIGH); else digitalWrite(pinout.mux, LOW); - CommunicationBackend *primary_backend = new DInputBackend(input_sources, input_source_count); - delay(500); - bool usb_connected = UDADDR & _BV(ADDEN); - - /* Select communication backend. */ - if (usb_connected) { - // Default to DInput mode if USB is connected. - // Input viewer only used when connected to PC i.e. when using DInput mode. - backend_count = 2; - backends = new CommunicationBackend *[backend_count] { - primary_backend, new B0XXInputViewer(input_sources, input_source_count) - }; - } else { - delete primary_backend; - if (button_holds.c_left) { - // Hold C-Left on plugin for N64. - primary_backend = - new N64Backend(input_sources, input_source_count, 60, pinout.joybus_data); - } else if (button_holds.a) { - // Hold A on plugin for GameCube adapter. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 0, pinout.joybus_data); - } else { - // Default to GameCube/Wii. - primary_backend = - new GamecubeBackend(input_sources, input_source_count, 125, pinout.joybus_data); - } - - // If not DInput then only using 1 backend (no input viewer). - backend_count = 1; - backends = new CommunicationBackend *[backend_count] { primary_backend }; - } + // Create array of input sources to be used. + static InputSource *input_sources[] = { &gpio_input }; + size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); + + backend_count = + initialize_backends(backends, inputs, input_sources, input_source_count, config, pinout); - // Default to Melee mode. - primary_backend->SetGameMode( - new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false }) - ); + setup_mode_activation_bindings(config.game_mode_configs, config.game_mode_configs_count); } void loop() { - select_mode(backends[0]); + select_mode(backends, backend_count, config); for (size_t i = 0; i < backend_count; i++) { backends[i]->SendReport(); diff --git a/config/pico/config.cpp b/config/pico/config.cpp index 2249f2ef..cdb0dc6d 100644 --- a/config/pico/config.cpp +++ b/config/pico/config.cpp @@ -50,6 +50,9 @@ DebouncedGpioButtonInput gpio_input(button_mappings); const Pinout pinout = { .joybus_data = 28, + .nes_data = -1, + .nes_clock = -1, + .nes_latch = -1, .mux = -1, .nunchuk_detect = -1, .nunchuk_sda = -1, @@ -115,4 +118,4 @@ void loop1() { if (backends != nullptr) { gpio_input.UpdateInputs(backends[0]->GetInputs()); } -} \ No newline at end of file +} diff --git a/include/core/pinout.hpp b/include/core/pinout.hpp index 79426892..7ba44310 100644 --- a/include/core/pinout.hpp +++ b/include/core/pinout.hpp @@ -5,9 +5,9 @@ typedef struct { uint8_t joybus_data; - uint8_t nes_data; - uint8_t nes_clock; - uint8_t nes_latch; + int nes_data; + int nes_clock; + int nes_latch; int mux; int nunchuk_detect; int nunchuk_sda; From bc357ad3ab7dfde890ab7578631d876e523dfebe Mon Sep 17 00:00:00 2001 From: Jonathan Haylett Date: Sat, 15 Mar 2025 13:00:09 +0000 Subject: [PATCH 167/167] Disable AVR Nunchuk functionality to fix build --- config/b0xx_r1/config.cpp | 7 +++++-- config/b0xx_r2/config.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/config/b0xx_r1/config.cpp b/config/b0xx_r1/config.cpp index 1ab72221..5829bb5b 100644 --- a/config/b0xx_r1/config.cpp +++ b/config/b0xx_r1/config.cpp @@ -61,7 +61,7 @@ void setup() { // Create Nunchuk input source - must be done before GPIO input source otherwise it would // disable the pullups on the i2c pins. - static NunchukInput nunchuk; + // static NunchukInput nunchuk; // Create GPIO input source and use it to read button states for checking button holds. static GpioButtonInput gpio_input(button_mappings, button_count); @@ -74,7 +74,10 @@ void setup() { } // Create array of input sources to be used. - static InputSource *input_sources[] = { &gpio_input, &nunchuk }; + static InputSource *input_sources[] = { + &gpio_input, + // &nunchuk, + }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); backend_count = diff --git a/config/b0xx_r2/config.cpp b/config/b0xx_r2/config.cpp index d287384d..e2c7e4e2 100644 --- a/config/b0xx_r2/config.cpp +++ b/config/b0xx_r2/config.cpp @@ -63,7 +63,7 @@ void setup() { // Create Nunchuk input source - must be done before GPIO input source otherwise it would // disable the pullups on the i2c pins. - static NunchukInput nunchuk; + // static NunchukInput nunchuk; // Create GPIO input source and use it to read button states for checking button holds. static GpioButtonInput gpio_input(button_mappings, button_count); @@ -83,7 +83,10 @@ void setup() { digitalWrite(pinout.mux, HIGH); // Create array of input sources to be used. - static InputSource *input_sources[] = { &gpio_input, &nunchuk }; + static InputSource *input_sources[] = { + &gpio_input, + // &nunchuk, + }; size_t input_source_count = sizeof(input_sources) / sizeof(InputSource *); backend_count =