diff --git a/.gitignore b/.gitignore index 70bc105..38023be 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,3 @@ debug hid-nintendo.c __pycache__ !.vscode/* -.omo/* -.slim/* -pytest-*/* -build-*/* -.ignore diff --git a/ADAPTER_PARITY_PLAN.md b/ADAPTER_PARITY_PLAN.md index 5bcc361..18e4f06 100644 --- a/ADAPTER_PARITY_PLAN.md +++ b/ADAPTER_PARITY_PLAN.md @@ -427,7 +427,7 @@ with the current identity. #### 4A — Output-driver boundary and production XInput -- replace `SWITCH_PICO_ADAPTER_FEASIBILITY` branches in `src/firmware/main.cpp` with +- replace `SWITCH_PICO_ADAPTER_FEASIBILITY` branches in `switch-pico.cpp` with one fixed static driver interface: descriptors, init/reset, input, task, readiness/capabilities, and host output - keep the Phase 3 profile/runtime transform exactly once before serialization diff --git a/CMakeLists.txt b/CMakeLists.txt index a7e7c57..61e4f38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,29 +56,26 @@ pico_sdk_init() # Configure BLUEPAD32 input backend if selected if(SWITCH_PICO_INPUT_BACKEND STREQUAL "BLUEPAD32") + # Ensure Python3 is available and execute patch preparation find_package(Python3 REQUIRED COMPONENTS Interpreter) - + set(BLUEPAD32_PREP_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/tools/prepare_bluepad32.py) - set(BLUEPAD32_SOURCE ${CMAKE_CURRENT_LIST_DIR}/external/bluepad32) - set(BLUEPAD32_PATCH ${CMAKE_CURRENT_LIST_DIR}/patches/bluepad32-sdl3-imu.patch) - set(BLUEPAD32_ROOT ${CMAKE_CURRENT_BINARY_DIR}/_deps/bluepad32-src) execute_process( COMMAND ${Python3_EXECUTABLE} ${BLUEPAD32_PREP_SCRIPT} - --bluepad32 ${BLUEPAD32_SOURCE} - --patch ${BLUEPAD32_PATCH} - --output ${BLUEPAD32_ROOT} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} RESULT_VARIABLE BLUEPAD32_PREP_RESULT OUTPUT_VARIABLE BLUEPAD32_PREP_OUTPUT ERROR_VARIABLE BLUEPAD32_PREP_ERROR ) - + if(NOT BLUEPAD32_PREP_RESULT EQUAL 0) message(FATAL_ERROR - "Failed to prepare isolated Bluepad32 source. " + "Failed to prepare Bluepad32: Patch application or validation failed. " "Details: ${BLUEPAD32_PREP_ERROR}") endif() - + + # Configure Bluepad32 include paths and subdirectory + set(BLUEPAD32_ROOT ${CMAKE_CURRENT_LIST_DIR}/external/bluepad32) set(BTSTACK_ROOT ${PICO_SDK_PATH}/lib/btstack) include_directories( ${CMAKE_CURRENT_LIST_DIR}/bluepad32_config @@ -92,37 +89,36 @@ if(SWITCH_PICO_INPUT_BACKEND STREQUAL "BLUEPAD32") ) endif() -# Firmware sources live under one include root and are grouped by responsibility. -set(SWITCH_PICO_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/src/firmware) +# Add executable. Default name is the project name, version 0.1 add_executable(switch-pico - ${SWITCH_PICO_SOURCE_DIR}/main.cpp - ${SWITCH_PICO_SOURCE_DIR}/usb/usb_output_driver.cpp - ${SWITCH_PICO_SOURCE_DIR}/usb/switch/switch_pro_driver.cpp - ${SWITCH_PICO_SOURCE_DIR}/usb/switch/switch_haptics.cpp + switch-pico.cpp + switch_pro_driver.cpp + usb_output_driver.cpp + switch_haptics.cpp ) if(SWITCH_PICO_INPUT_BACKEND STREQUAL "BLUEPAD32") target_sources(switch-pico PRIVATE - ${SWITCH_PICO_SOURCE_DIR}/adapter/adapter_host_probe.cpp - ${SWITCH_PICO_SOURCE_DIR}/adapter/adapter_mode_controller.cpp - ${SWITCH_PICO_SOURCE_DIR}/configuration/adapter_configuration.cpp - ${SWITCH_PICO_SOURCE_DIR}/configuration/configuration_service.cpp - ${SWITCH_PICO_SOURCE_DIR}/configuration/configuration_storage.cpp - ${SWITCH_PICO_SOURCE_DIR}/configuration/configuration_transaction.cpp - ${SWITCH_PICO_SOURCE_DIR}/core/controller_identity.cpp - ${SWITCH_PICO_SOURCE_DIR}/input/bluepad32_input_backend.cpp - ${SWITCH_PICO_SOURCE_DIR}/platform/pico/bootsel_pairing_button.cpp - ${SWITCH_PICO_SOURCE_DIR}/platform/pico/pico_configuration_storage.cpp - ${SWITCH_PICO_SOURCE_DIR}/platform/pico/pico_profile_storage.cpp - ${SWITCH_PICO_SOURCE_DIR}/profile/controller_profile.cpp - ${SWITCH_PICO_SOURCE_DIR}/profile/controller_profile_runtime.cpp - ${SWITCH_PICO_SOURCE_DIR}/profile/controller_profile_transform.cpp - ${SWITCH_PICO_SOURCE_DIR}/profile/controller_synthetic_input.cpp - ${SWITCH_PICO_SOURCE_DIR}/profile/profile_service.cpp - ${SWITCH_PICO_SOURCE_DIR}/profile/profile_storage.cpp - ${SWITCH_PICO_SOURCE_DIR}/usb/generic_hid/generic_hid_driver.cpp - ${SWITCH_PICO_SOURCE_DIR}/usb/usb_configuration_management.cpp - ${SWITCH_PICO_SOURCE_DIR}/usb/xinput/xinput_driver.cpp + bluepad32_input_backend.cpp + adapter_host_probe.cpp + adapter_mode_controller.cpp + controller_identity.cpp + controller_profile.cpp + controller_profile_transform.cpp + controller_synthetic_input.cpp + controller_profile_runtime.cpp + profile_storage.cpp + profile_service.cpp + pico_profile_storage.cpp + bootsel_pairing_button.cpp + adapter_configuration.cpp + configuration_storage.cpp + configuration_transaction.cpp + configuration_service.cpp + pico_configuration_storage.cpp + usb_configuration_management.cpp + xinput_driver.cpp + generic_hid_driver.cpp ) target_compile_definitions(switch-pico PRIVATE SWITCH_PICO_BLUEPAD32=1 @@ -170,11 +166,9 @@ if (SWITCH_PICO_LOG) target_compile_definitions(switch-pico PRIVATE SWITCH_PICO_LOG=1) endif() -# Internal includes are rooted at src/firmware. TinyUSB discovers tusb_config.h -# through the Pico platform directory. +# Add the standard include files to the build target_include_directories(switch-pico PRIVATE - ${SWITCH_PICO_SOURCE_DIR} - ${SWITCH_PICO_SOURCE_DIR}/platform/pico + ${CMAKE_CURRENT_LIST_DIR} ) pico_add_extra_outputs(switch-pico) diff --git a/README.md b/README.md index 9cf6348..6215526 100644 --- a/README.md +++ b/README.md @@ -3,31 +3,11 @@ Raspberry Pi Pico firmware that emulates one or more Switch Pro controllers over USB. Input can come from the SDL3-to-UART computer bridge or, on Pico 2 W, directly from Bluetooth controllers through Bluepad32. ## What you get -- **Firmware** (`src/firmware/`): acts as a Switch Pro controller (one on standard Pico, four on Pico 2 W AIO), accepting either UART bridge reports or the optional Pico 2 W Bluepad32 backend. +- **Firmware** (`switch-pico.cpp` + `switch_pro_driver.*`): acts as a Switch Pro controller (one on standard Pico, four on Pico 2 W AIO), accepting either UART bridge reports or the optional Pico 2 W Bluepad32 backend. - **Python bridge** (`switch_pico_bridge.controller_uart_bridge` / CLI `controller-uart-bridge`): reads SDL3 controllers on the host, sends reports over UART, and applies rumble locally. Hot‑plug friendly and cross‑platform (macOS/Windows/Linux). -- **Color configuration** (`src/firmware/platform/pico/controller_color_config.h`): compile-time RGB colors for emulated controller grips and supported Bluetooth controller LEDs. +- **Color configuration** (`controller_color_config.h`): compile-time RGB colors for emulated controller grips and supported Bluetooth controller LEDs. - **Pico 2 W AIO firmware** (`firmware/switch-pico-aio.uf2`): hosts four concurrent Bluetooth controllers and sends their controls, calibrated motion, rumble, and slot identity through four separate Switch Pro USB interfaces without a computer. -## Source layout - -Firmware code has one include root, `src/firmware`, with responsibility-based -modules: - -| Path | Responsibility | -|---|---| -| `src/firmware/main.cpp` | Firmware entry point and backend orchestration | -| `src/firmware/adapter/` | USB mode selection, host probing, and managed reboot | -| `src/firmware/configuration/` | Persistent adapter configuration and transactions | -| `src/firmware/core/` | Shared controller identity, color, and input-state types | -| `src/firmware/input/` | Bluepad32 controller input backend and hotkeys | -| `src/firmware/platform/pico/` | Pico flash/BOOTSEL integrations and compile-time board configuration | -| `src/firmware/profile/` | Controller profiles, transforms, storage, and runtime | -| `src/firmware/usb/` | USB output boundary, management protocol, and per-protocol drivers | - -Internal includes are rooted at `src/firmware`, for example -`#include "profile/controller_profile.h"`. Host-side Python remains in -`src/switch_pico_bridge/`; native firmware tests remain in `tests/`. - ## Quick start 1. Flash the Pico with `firmware/switch-pico.uf2` (or build your own) using BOOTSEL drag-and-drop (see “Manual UF2 flashing” below). 2. Wire Pico UART1 to a USB↔UART adapter (GPIO4 TX, GPIO5 RX, GND) and plug that adapter into your host PC. @@ -64,7 +44,7 @@ This uses an isolated `build-aio/` CMake cache and publishes: The default `python3 build.py` command and `firmware/switch-pico.*` artifacts remain the UART/Pico build. The AIO build requires `PICO_BOARD=pico2_w`; it is not interchangeable with the original non-wireless Pico firmware. -Both `build.py --aio` and direct AIO CMake configuration copy the pinned Bluepad32 source into the active build directory and apply `patches/bluepad32-sdl3-imu.patch` there before compiling. The patch makes supported motion controllers use SDL3-equivalent axes and fixed-point units before conversion to Nintendo samples. The `external/bluepad32` submodule remains pristine; patch or source-revision drift fails configuration. +Both `build.py --aio` and direct AIO CMake configuration apply `patches/bluepad32-sdl3-imu.patch` idempotently before compiling Bluepad32. The patch makes supported motion controllers use SDL3-equivalent axes and fixed-point units before conversion to Nintendo samples. It intentionally leaves the dependency worktree dirty; the committed submodule revision remains Bluepad32 4.2.0. ### Pairing up to four controllers @@ -182,7 +162,7 @@ Each AIO slot has one color shared by its emulated Switch Pro grips and its phys 3. Yellow `#F6C945` 4. Green `#2ECC71` -When a controller becomes ready, RGB-capable devices such as DualSense and DualShock 4 receive a darker, more saturated RGB value derived automatically from the slot's Switch grip color. Controllers without an RGB light use player indicator 1, 2, 3, or 4 when Bluepad32 exposes player-LED control. Devices without either capability are left unchanged. Edit only the four grip colors in `src/firmware/platform/pico/controller_color_config.h`; rebuilding automatically recalibrates their lightbar colors. +When a controller becomes ready, RGB-capable devices such as DualSense and DualShock 4 receive a darker, more saturated RGB value derived automatically from the slot's Switch grip color. Controllers without an RGB light use player indicator 1, 2, 3, or 4 when Bluepad32 exposes player-LED control. Devices without either capability are left unchanged. Edit only the four grip colors in `controller_color_config.h`; rebuilding automatically recalibrates their lightbar colors. ### Controller capabilities @@ -372,7 +352,7 @@ python3 build.py --grip-color FF00AA ``` Both options update all four slot definitions in -`src/firmware/platform/pico/controller_color_config.h` before building. With no color option, the +`controller_color_config.h` before building. With no color option, the per-slot blue/red/yellow/green palette is left unchanged. Run `python3 build.py --help` to see the available command-line options. @@ -567,7 +547,7 @@ Keep `SwitchImuMode` as a three-state value. Never acknowledge mode 2 and then e #### Mode-2 implementation -`src/firmware/usb/switch/switch_pro_driver.cpp` implements this in `integrate_motion_sample()` and `fill_quaternion_imu_report_data()`: +`switch_pro_driver.cpp` implements this in `integrate_motion_sample()` and `fill_quaternion_imu_report_data()`: 1. Reset quaternion state to `(0, 0, 0, 1)` when transitioning into mode 2. 2. Integrate each report's three gyro samples at 5 ms per sample. The Nintendo quaternion axes use sensor `Y, X, Z`, not `X, Y, Z`. diff --git a/src/firmware/configuration/adapter_configuration.cpp b/adapter_configuration.cpp similarity index 98% rename from src/firmware/configuration/adapter_configuration.cpp rename to adapter_configuration.cpp index c8d3623..f0aa7c2 100644 --- a/src/firmware/configuration/adapter_configuration.cpp +++ b/adapter_configuration.cpp @@ -1,4 +1,4 @@ -#include "configuration/adapter_configuration.h" +#include "adapter_configuration.h" namespace { diff --git a/src/firmware/configuration/adapter_configuration.h b/adapter_configuration.h similarity index 97% rename from src/firmware/configuration/adapter_configuration.h rename to adapter_configuration.h index dd49212..9026731 100644 --- a/src/firmware/configuration/adapter_configuration.h +++ b/adapter_configuration.h @@ -3,7 +3,7 @@ #include #include -#include "adapter/adapter_usb_mode.h" +#include "adapter_usb_mode.h" constexpr uint16_t ADAPTER_CONFIGURATION_LEGACY_SCHEMA_VERSION = 1; constexpr uint16_t ADAPTER_CONFIGURATION_SCHEMA_VERSION = 2; diff --git a/src/firmware/adapter/adapter_host_probe.cpp b/adapter_host_probe.cpp similarity index 96% rename from src/firmware/adapter/adapter_host_probe.cpp rename to adapter_host_probe.cpp index e4ecf0a..9f5c09d 100644 --- a/src/firmware/adapter/adapter_host_probe.cpp +++ b/adapter_host_probe.cpp @@ -1,4 +1,5 @@ -#include "adapter/adapter_host_probe.h" +#include "adapter_host_probe.h" + #include #ifdef SWITCH_PICO_LOG #include @@ -7,12 +8,12 @@ #define PROBE_LOG(...) ((void)0) #endif -#include "adapter/adapter_host_probe_state.h" -#include "profile/controller_profile_runtime.h" +#include "adapter_host_probe_state.h" +#include "controller_profile_runtime.h" #include "hardware/structs/watchdog.h" #include "hardware/watchdog.h" #include "pico/time.h" -#include "usb/xinput/xinput_descriptors.h" +#include "xinput_descriptors.h" namespace { diff --git a/src/firmware/adapter/adapter_host_probe.h b/adapter_host_probe.h similarity index 92% rename from src/firmware/adapter/adapter_host_probe.h rename to adapter_host_probe.h index 1a08d15..8ea8ed2 100644 --- a/src/firmware/adapter/adapter_host_probe.h +++ b/adapter_host_probe.h @@ -2,7 +2,7 @@ #include -#include "adapter/adapter_usb_mode.h" +#include "adapter_usb_mode.h" #include "tusb.h" // Consume watchdog scratch and freeze the active mode. Call exactly once diff --git a/src/firmware/adapter/adapter_host_probe_state.h b/adapter_host_probe_state.h similarity index 100% rename from src/firmware/adapter/adapter_host_probe_state.h rename to adapter_host_probe_state.h diff --git a/src/firmware/adapter/adapter_mode_controller.cpp b/adapter_mode_controller.cpp similarity index 97% rename from src/firmware/adapter/adapter_mode_controller.cpp rename to adapter_mode_controller.cpp index df93387..2c5c6c6 100644 --- a/src/firmware/adapter/adapter_mode_controller.cpp +++ b/adapter_mode_controller.cpp @@ -1,15 +1,16 @@ -#include "adapter/adapter_mode_controller.h" -#include "adapter/adapter_reboot.h" -#include "configuration/adapter_configuration.h" -#include "adapter/adapter_host_probe.h" -#include "input/bluepad32_input_backend.h" -#include "configuration/configuration_service.h" -#include "profile/controller_profile.h" -#include "profile/controller_profile_runtime.h" +#include "adapter_mode_controller.h" +#include "adapter_reboot.h" + +#include "adapter_configuration.h" +#include "adapter_host_probe.h" +#include "bluepad32_input_backend.h" +#include "configuration_service.h" +#include "controller_profile.h" +#include "controller_profile_runtime.h" #include "hardware/watchdog.h" #include "pico/bootrom.h" #include "tusb.h" -#include "usb/usb_output_driver.h" +#include "usb_output_driver.h" namespace { diff --git a/src/firmware/adapter/adapter_mode_controller.h b/adapter_mode_controller.h similarity index 95% rename from src/firmware/adapter/adapter_mode_controller.h rename to adapter_mode_controller.h index 3677156..1908572 100644 --- a/src/firmware/adapter/adapter_mode_controller.h +++ b/adapter_mode_controller.h @@ -2,8 +2,8 @@ #include -#include "adapter/adapter_usb_mode.h" -#include "core/controller_state.h" +#include "adapter_usb_mode.h" +#include "controller_state.h" constexpr uint8_t ADAPTER_MODE_CONTROLLER_SLOT_COUNT = 4; constexpr uint32_t ADAPTER_MODE_CHORD_HOLD_MS = 3000; diff --git a/src/firmware/adapter/adapter_reboot.h b/adapter_reboot.h similarity index 100% rename from src/firmware/adapter/adapter_reboot.h rename to adapter_reboot.h diff --git a/src/firmware/adapter/adapter_usb_mode.h b/adapter_usb_mode.h similarity index 100% rename from src/firmware/adapter/adapter_usb_mode.h rename to adapter_usb_mode.h diff --git a/src/firmware/input/bluepad32_input_backend.cpp b/bluepad32_input_backend.cpp similarity index 99% rename from src/firmware/input/bluepad32_input_backend.cpp rename to bluepad32_input_backend.cpp index 44a42d2..bfd521e 100644 --- a/src/firmware/input/bluepad32_input_backend.cpp +++ b/bluepad32_input_backend.cpp @@ -1,7 +1,8 @@ -#include "input/bluepad32_input_backend.h" -#include "input/controller_hotkey_config.h" -#include "configuration/configuration_service.h" -#include "profile/profile_service.h" +#include "bluepad32_input_backend.h" +#include "controller_hotkey_config.h" +#include "configuration_service.h" +#include "profile_service.h" + #include #include #include @@ -14,7 +15,7 @@ #include #include #ifdef SWITCH_PICO_USB_OUTPUT_MODES -#include "adapter/adapter_usb_mode.h" +#include "adapter_usb_mode.h" #endif namespace { diff --git a/src/firmware/input/bluepad32_input_backend.h b/bluepad32_input_backend.h similarity index 95% rename from src/firmware/input/bluepad32_input_backend.h rename to bluepad32_input_backend.h index 64f4b83..220ec9d 100644 --- a/src/firmware/input/bluepad32_input_backend.h +++ b/bluepad32_input_backend.h @@ -2,11 +2,11 @@ #include -#include "core/controller_color.h" -#include "core/controller_identity.h" -#include "profile/controller_profile.h" -#include "core/controller_state.h" -#include "usb/switch/switch_haptics.h" +#include "controller_color.h" +#include "controller_identity.h" +#include "controller_profile.h" +#include "controller_state.h" +#include "switch_haptics.h" constexpr uint8_t BLUEPAD32_INPUT_BACKEND_SLOT_COUNT = 4; constexpr uint8_t BLUEPAD32_PAIRING_RECORD_CAPACITY = 16; diff --git a/src/firmware/platform/pico/bootsel_pairing_button.cpp b/bootsel_pairing_button.cpp similarity index 98% rename from src/firmware/platform/pico/bootsel_pairing_button.cpp rename to bootsel_pairing_button.cpp index a358c12..fc50a46 100644 --- a/src/firmware/platform/pico/bootsel_pairing_button.cpp +++ b/bootsel_pairing_button.cpp @@ -1,4 +1,5 @@ -#include "platform/pico/bootsel_pairing_button.h" +#include "bootsel_pairing_button.h" + #include "hardware/gpio.h" #include "hardware/structs/ioqspi.h" #include "hardware/structs/sio.h" diff --git a/src/firmware/platform/pico/bootsel_pairing_button.h b/bootsel_pairing_button.h similarity index 100% rename from src/firmware/platform/pico/bootsel_pairing_button.h rename to bootsel_pairing_button.h diff --git a/build.py b/build.py index eda4f08..e1360f1 100644 --- a/build.py +++ b/build.py @@ -10,8 +10,7 @@ import sys from pathlib import Path SCRIPT_DIR = Path(__file__).resolve().parent -FIRMWARE_SOURCE_DIR = SCRIPT_DIR / "src" / "firmware" -CONFIG_FILE = FIRMWARE_SOURCE_DIR / "platform" / "pico" / "controller_color_config.h" +CONFIG_FILE = SCRIPT_DIR / "controller_color_config.h" BUILD_DIR = SCRIPT_DIR / "build" AIO_BUILD_DIR = SCRIPT_DIR / "build-aio" FEASIBILITY_BUILD_DIR = SCRIPT_DIR / "build-feasibility" @@ -266,7 +265,7 @@ def parse_args(): parser = argparse.ArgumentParser( description="Build and flash the project, optionally setting grip colors.", formatter_class=argparse.RawDescriptionHelpFormatter, - epilog=f"Default behavior leaves {CONFIG_FILE.relative_to(SCRIPT_DIR)} unchanged.", + epilog="Default behavior leaves controller_color_config.h unchanged.", ) mode_group = parser.add_mutually_exclusive_group() mode_group.add_argument( @@ -366,6 +365,7 @@ def build( firmware_uf2_path, ): if aio or adapter_feasibility: + run_cmd([sys.executable, str(SCRIPT_DIR / "tools" / "prepare_bluepad32.py")]) definitions = [ "-DSWITCH_PICO_LOG=OFF", "-DPICO_BOARD=pico2_w", diff --git a/src/firmware/configuration/configuration_service.cpp b/configuration_service.cpp similarity index 99% rename from src/firmware/configuration/configuration_service.cpp rename to configuration_service.cpp index 6a0b239..b450ad7 100644 --- a/src/firmware/configuration/configuration_service.cpp +++ b/configuration_service.cpp @@ -1,8 +1,9 @@ -#include "configuration/configuration_service.h" +#include "configuration_service.h" + #include #include "pico/critical_section.h" -#include "platform/pico/pico_configuration_storage.h" +#include "pico_configuration_storage.h" namespace { diff --git a/src/firmware/configuration/configuration_service.h b/configuration_service.h similarity index 96% rename from src/firmware/configuration/configuration_service.h rename to configuration_service.h index 6b2ca67..ab453be 100644 --- a/src/firmware/configuration/configuration_service.h +++ b/configuration_service.h @@ -3,8 +3,8 @@ #include #include -#include "configuration/adapter_configuration.h" -#include "configuration/configuration_transaction.h" +#include "adapter_configuration.h" +#include "configuration_transaction.h" constexpr uint32_t CONFIGURATION_SERVICE_INTERNAL_TRANSACTION_ID_MASK = 0x80000000u; diff --git a/src/firmware/configuration/configuration_storage.cpp b/configuration_storage.cpp similarity index 99% rename from src/firmware/configuration/configuration_storage.cpp rename to configuration_storage.cpp index 85ab605..80b3269 100644 --- a/src/firmware/configuration/configuration_storage.cpp +++ b/configuration_storage.cpp @@ -1,4 +1,5 @@ -#include "configuration/configuration_storage.h" +#include "configuration_storage.h" + #include namespace { diff --git a/src/firmware/configuration/configuration_storage.h b/configuration_storage.h similarity index 100% rename from src/firmware/configuration/configuration_storage.h rename to configuration_storage.h diff --git a/src/firmware/configuration/configuration_transaction.cpp b/configuration_transaction.cpp similarity index 97% rename from src/firmware/configuration/configuration_transaction.cpp rename to configuration_transaction.cpp index c477202..5e2c1bd 100644 --- a/src/firmware/configuration/configuration_transaction.cpp +++ b/configuration_transaction.cpp @@ -1,7 +1,9 @@ -#include "configuration/configuration_transaction.h" +#include "configuration_transaction.h" + #include -#include "configuration/adapter_configuration.h" +#include "adapter_configuration.h" + ConfigurationTransactionStatus ConfigurationTransaction::begin( uint32_t transaction_id, uint16_t schema_version, size_t payload_size, uint32_t payload_crc) { diff --git a/src/firmware/configuration/configuration_transaction.h b/configuration_transaction.h similarity index 97% rename from src/firmware/configuration/configuration_transaction.h rename to configuration_transaction.h index 1439e41..0045c69 100644 --- a/src/firmware/configuration/configuration_transaction.h +++ b/configuration_transaction.h @@ -3,7 +3,7 @@ #include #include -#include "configuration/configuration_storage.h" +#include "configuration_storage.h" enum class ConfigurationTransactionStatus : uint8_t { kIdle = 0, diff --git a/src/firmware/core/controller_color.h b/controller_color.h similarity index 100% rename from src/firmware/core/controller_color.h rename to controller_color.h diff --git a/src/firmware/platform/pico/controller_color_config.h b/controller_color_config.h similarity index 100% rename from src/firmware/platform/pico/controller_color_config.h rename to controller_color_config.h diff --git a/src/firmware/input/controller_hotkey_config.h b/controller_hotkey_config.h similarity index 100% rename from src/firmware/input/controller_hotkey_config.h rename to controller_hotkey_config.h diff --git a/src/firmware/core/controller_identity.cpp b/controller_identity.cpp similarity index 98% rename from src/firmware/core/controller_identity.cpp rename to controller_identity.cpp index eb8de61..bfe32b3 100644 --- a/src/firmware/core/controller_identity.cpp +++ b/controller_identity.cpp @@ -1,4 +1,5 @@ -#include "core/controller_identity.h" +#include "controller_identity.h" + #include namespace { diff --git a/src/firmware/core/controller_identity.h b/controller_identity.h similarity index 100% rename from src/firmware/core/controller_identity.h rename to controller_identity.h diff --git a/src/firmware/profile/controller_profile.cpp b/controller_profile.cpp similarity index 99% rename from src/firmware/profile/controller_profile.cpp rename to controller_profile.cpp index 304ba84..7209944 100644 --- a/src/firmware/profile/controller_profile.cpp +++ b/controller_profile.cpp @@ -1,4 +1,5 @@ -#include "profile/controller_profile.h" +#include "controller_profile.h" + #include namespace { diff --git a/src/firmware/profile/controller_profile.h b/controller_profile.h similarity index 99% rename from src/firmware/profile/controller_profile.h rename to controller_profile.h index 84ffea4..d7e7618 100644 --- a/src/firmware/profile/controller_profile.h +++ b/controller_profile.h @@ -3,7 +3,7 @@ #include #include -#include "core/controller_identity.h" +#include "controller_identity.h" constexpr uint16_t CONTROLLER_PROFILE_LEGACY_SCHEMA_VERSION = 1; constexpr uint16_t CONTROLLER_PROFILE_SCHEMA_VERSION = 2; diff --git a/src/firmware/profile/controller_profile_runtime.cpp b/controller_profile_runtime.cpp similarity index 98% rename from src/firmware/profile/controller_profile_runtime.cpp rename to controller_profile_runtime.cpp index c02f97f..ddf6478 100644 --- a/src/firmware/profile/controller_profile_runtime.cpp +++ b/controller_profile_runtime.cpp @@ -1,8 +1,9 @@ -#include "profile/controller_profile_runtime.h" -#include "configuration/configuration_service.h" -#include "core/controller_identity.h" -#include "profile/controller_synthetic_input.h" -#include "profile/profile_service.h" +#include "controller_profile_runtime.h" + +#include "configuration_service.h" +#include "controller_identity.h" +#include "controller_synthetic_input.h" +#include "profile_service.h" namespace { diff --git a/src/firmware/profile/controller_profile_runtime.h b/controller_profile_runtime.h similarity index 95% rename from src/firmware/profile/controller_profile_runtime.h rename to controller_profile_runtime.h index 96783f9..be8d1f1 100644 --- a/src/firmware/profile/controller_profile_runtime.h +++ b/controller_profile_runtime.h @@ -2,10 +2,10 @@ #include -#include "adapter/adapter_usb_mode.h" +#include "adapter_usb_mode.h" -#include "input/bluepad32_input_backend.h" -#include "profile/controller_profile_transform.h" +#include "bluepad32_input_backend.h" +#include "controller_profile_transform.h" constexpr uint8_t CONTROLLER_PROFILE_RUNTIME_SLOT_COUNT = 4; constexpr uint16_t CONTROLLER_PROFILE_DEFAULT_SWITCHING_CHORD = diff --git a/src/firmware/profile/controller_profile_transform.cpp b/controller_profile_transform.cpp similarity index 99% rename from src/firmware/profile/controller_profile_transform.cpp rename to controller_profile_transform.cpp index 883aa07..9039035 100644 --- a/src/firmware/profile/controller_profile_transform.cpp +++ b/controller_profile_transform.cpp @@ -1,4 +1,5 @@ -#include "profile/controller_profile_transform.h" +#include "controller_profile_transform.h" + #include namespace { diff --git a/src/firmware/profile/controller_profile_transform.h b/controller_profile_transform.h similarity index 91% rename from src/firmware/profile/controller_profile_transform.h rename to controller_profile_transform.h index 7b4a0d8..54c4904 100644 --- a/src/firmware/profile/controller_profile_transform.h +++ b/controller_profile_transform.h @@ -2,9 +2,9 @@ #include -#include "profile/controller_profile.h" -#include "core/controller_state.h" -#include "usb/switch/switch_haptics.h" +#include "controller_profile.h" +#include "controller_state.h" +#include "switch_haptics.h" struct ControllerProfileTransformResult { ControllerState state{}; diff --git a/src/firmware/core/controller_state.h b/controller_state.h similarity index 100% rename from src/firmware/core/controller_state.h rename to controller_state.h diff --git a/src/firmware/profile/controller_synthetic_input.cpp b/controller_synthetic_input.cpp similarity index 99% rename from src/firmware/profile/controller_synthetic_input.cpp rename to controller_synthetic_input.cpp index 1a57ba6..d777aff 100644 --- a/src/firmware/profile/controller_synthetic_input.cpp +++ b/controller_synthetic_input.cpp @@ -1,4 +1,4 @@ -#include "profile/controller_synthetic_input.h" +#include "controller_synthetic_input.h" namespace { diff --git a/src/firmware/profile/controller_synthetic_input.h b/controller_synthetic_input.h similarity index 95% rename from src/firmware/profile/controller_synthetic_input.h rename to controller_synthetic_input.h index 36c0bf9..507065c 100644 --- a/src/firmware/profile/controller_synthetic_input.h +++ b/controller_synthetic_input.h @@ -2,7 +2,7 @@ #include -#include "profile/controller_profile_transform.h" +#include "controller_profile_transform.h" struct ControllerSyntheticBindingState { bool active = false; diff --git a/src/firmware/usb/generic_hid/generic_hid_descriptors.h b/generic_hid_descriptors.h similarity index 99% rename from src/firmware/usb/generic_hid/generic_hid_descriptors.h rename to generic_hid_descriptors.h index 00791fe..ef74467 100644 --- a/src/firmware/usb/generic_hid/generic_hid_descriptors.h +++ b/generic_hid_descriptors.h @@ -3,7 +3,7 @@ #include #include -#include "core/controller_state.h" +#include "controller_state.h" #ifndef SWITCH_PICO_HID_INSTANCE_COUNT #define SWITCH_PICO_HID_INSTANCE_COUNT 1 diff --git a/src/firmware/usb/generic_hid/generic_hid_driver.cpp b/generic_hid_driver.cpp similarity index 96% rename from src/firmware/usb/generic_hid/generic_hid_driver.cpp rename to generic_hid_driver.cpp index eb697b5..6b733a6 100644 --- a/src/firmware/usb/generic_hid/generic_hid_driver.cpp +++ b/generic_hid_driver.cpp @@ -1,7 +1,8 @@ -#include "usb/generic_hid/generic_hid_driver.h" +#include "generic_hid_driver.h" + #include -#include "usb/generic_hid/generic_hid_descriptors.h" +#include "generic_hid_descriptors.h" namespace { diff --git a/src/firmware/usb/generic_hid/generic_hid_driver.h b/generic_hid_driver.h similarity index 95% rename from src/firmware/usb/generic_hid/generic_hid_driver.h rename to generic_hid_driver.h index dcc9ff8..1c9d6e5 100644 --- a/src/firmware/usb/generic_hid/generic_hid_driver.h +++ b/generic_hid_driver.h @@ -2,9 +2,8 @@ #include -#include "core/controller_state.h" +#include "controller_state.h" #include "tusb.h" - namespace GenericHid { enum class ReportDescriptorVariant : uint8_t { diff --git a/src/firmware/platform/pico/pico_configuration_storage.cpp b/pico_configuration_storage.cpp similarity index 98% rename from src/firmware/platform/pico/pico_configuration_storage.cpp rename to pico_configuration_storage.cpp index 1a7de87..a63a5b6 100644 --- a/src/firmware/platform/pico/pico_configuration_storage.cpp +++ b/pico_configuration_storage.cpp @@ -1,4 +1,5 @@ -#include "platform/pico/pico_configuration_storage.h" +#include "pico_configuration_storage.h" + #include #include "hardware/flash.h" diff --git a/src/firmware/platform/pico/pico_configuration_storage.h b/pico_configuration_storage.h similarity index 59% rename from src/firmware/platform/pico/pico_configuration_storage.h rename to pico_configuration_storage.h index b1cfcda..abe9f82 100644 --- a/src/firmware/platform/pico/pico_configuration_storage.h +++ b/pico_configuration_storage.h @@ -1,5 +1,5 @@ #pragma once -#include "configuration/configuration_storage.h" +#include "configuration_storage.h" ConfigurationStorageIo pico_configuration_storage_io(); diff --git a/src/firmware/platform/pico/pico_profile_storage.cpp b/pico_profile_storage.cpp similarity index 98% rename from src/firmware/platform/pico/pico_profile_storage.cpp rename to pico_profile_storage.cpp index 196052e..5b44551 100644 --- a/src/firmware/platform/pico/pico_profile_storage.cpp +++ b/pico_profile_storage.cpp @@ -1,7 +1,8 @@ -#include "platform/pico/pico_profile_storage.h" +#include "pico_profile_storage.h" + #include -#include "configuration/configuration_storage.h" +#include "configuration_storage.h" #include "hardware/flash.h" #include "pico/btstack_flash_bank.h" #include "pico/flash.h" diff --git a/src/firmware/platform/pico/pico_profile_storage.h b/pico_profile_storage.h similarity index 61% rename from src/firmware/platform/pico/pico_profile_storage.h rename to pico_profile_storage.h index 94d3be9..3fd8b42 100644 --- a/src/firmware/platform/pico/pico_profile_storage.h +++ b/pico_profile_storage.h @@ -1,5 +1,5 @@ #pragma once -#include "profile/profile_storage.h" +#include "profile_storage.h" ProfileStorageIo pico_profile_storage_io(); diff --git a/src/firmware/profile/profile_service.cpp b/profile_service.cpp similarity index 99% rename from src/firmware/profile/profile_service.cpp rename to profile_service.cpp index 4a29b2d..b880900 100644 --- a/src/firmware/profile/profile_service.cpp +++ b/profile_service.cpp @@ -1,9 +1,10 @@ -#include "profile/profile_service.h" +#include "profile_service.h" + #include #include "pico/critical_section.h" -#include "platform/pico/pico_profile_storage.h" -#include "profile/profile_storage.h" +#include "pico_profile_storage.h" +#include "profile_storage.h" namespace { diff --git a/src/firmware/profile/profile_service.h b/profile_service.h similarity index 97% rename from src/firmware/profile/profile_service.h rename to profile_service.h index 704308d..c922795 100644 --- a/src/firmware/profile/profile_service.h +++ b/profile_service.h @@ -3,8 +3,8 @@ #include #include -#include "configuration/configuration_transaction.h" -#include "profile/controller_profile.h" +#include "configuration_transaction.h" +#include "controller_profile.h" constexpr uint8_t PROFILE_SERVICE_LIST_CAPACITY = CONTROLLER_PROFILE_STABLE_IDENTITY_CAPACITY + 1; diff --git a/src/firmware/profile/profile_storage.cpp b/profile_storage.cpp similarity index 99% rename from src/firmware/profile/profile_storage.cpp rename to profile_storage.cpp index 068fd77..75a7250 100644 --- a/src/firmware/profile/profile_storage.cpp +++ b/profile_storage.cpp @@ -1,4 +1,5 @@ -#include "profile/profile_storage.h" +#include "profile_storage.h" + #include namespace { diff --git a/src/firmware/profile/profile_storage.h b/profile_storage.h similarity index 98% rename from src/firmware/profile/profile_storage.h rename to profile_storage.h index b793e6b..7e2d0bc 100644 --- a/src/firmware/profile/profile_storage.h +++ b/profile_storage.h @@ -3,7 +3,7 @@ #include #include -#include "profile/controller_profile.h" +#include "controller_profile.h" constexpr uint8_t PROFILE_STORAGE_BANK_COUNT = 2; constexpr size_t PROFILE_STORAGE_SECTOR_SIZE = 4096; diff --git a/src/firmware/main.cpp b/switch-pico.cpp similarity index 97% rename from src/firmware/main.cpp rename to switch-pico.cpp index bd3a2af..3dd0fc9 100644 --- a/src/firmware/main.cpp +++ b/switch-pico.cpp @@ -2,15 +2,15 @@ #include "bsp/board.h" #include "pico/stdlib.h" #include "tusb.h" -#include "usb/switch/switch_pro_driver.h" -#include "usb/usb_output_driver.h" +#include "switch_pro_driver.h" +#include "usb_output_driver.h" #ifndef SWITCH_PICO_BLUEPAD32 #include "hardware/uart.h" #else -#include "adapter/adapter_mode_controller.h" -#include "input/bluepad32_input_backend.h" -#include "platform/pico/bootsel_pairing_button.h" -#include "profile/controller_profile_runtime.h" +#include "adapter_mode_controller.h" +#include "bluepad32_input_backend.h" +#include "bootsel_pairing_button.h" +#include "controller_profile_runtime.h" #endif #ifdef SWITCH_PICO_LOG diff --git a/src/firmware/usb/switch/switch_haptics.cpp b/switch_haptics.cpp similarity index 99% rename from src/firmware/usb/switch/switch_haptics.cpp rename to switch_haptics.cpp index e9ac083..8bade37 100644 --- a/src/firmware/usb/switch/switch_haptics.cpp +++ b/switch_haptics.cpp @@ -1,4 +1,5 @@ -#include "usb/switch/switch_haptics.h" +#include "switch_haptics.h" + #include #include diff --git a/src/firmware/usb/switch/switch_haptics.h b/switch_haptics.h similarity index 100% rename from src/firmware/usb/switch/switch_haptics.h rename to switch_haptics.h diff --git a/src/firmware/usb/switch/switch_pro_descriptors.h b/switch_pro_descriptors.h similarity index 100% rename from src/firmware/usb/switch/switch_pro_descriptors.h rename to switch_pro_descriptors.h diff --git a/src/firmware/usb/switch/switch_pro_driver.cpp b/switch_pro_driver.cpp similarity index 99% rename from src/firmware/usb/switch/switch_pro_driver.cpp rename to switch_pro_driver.cpp index c9fb250..590e92d 100644 --- a/src/firmware/usb/switch/switch_pro_driver.cpp +++ b/switch_pro_driver.cpp @@ -1,4 +1,4 @@ -#include "usb/switch/switch_pro_driver.h" +#include "switch_pro_driver.h" #include #include @@ -81,8 +81,8 @@ static SwitchProContext* context_for(uint8_t instance) { } // Optional compile-time color palette shared with Bluetooth controller LEDs. -#if __has_include("platform/pico/controller_color_config.h") -#include "platform/pico/controller_color_config.h" +#if __has_include("controller_color_config.h") +#include "controller_color_config.h" #endif #ifndef SWITCH_COLOR_BODY_R #define SWITCH_COLOR_BODY_R 0x1B diff --git a/src/firmware/usb/switch/switch_pro_driver.h b/switch_pro_driver.h similarity index 94% rename from src/firmware/usb/switch/switch_pro_driver.h rename to switch_pro_driver.h index a6525d5..3c3561a 100644 --- a/src/firmware/usb/switch/switch_pro_driver.h +++ b/switch_pro_driver.h @@ -8,11 +8,11 @@ #include #include -#include "core/controller_color.h" -#include "core/controller_state.h" -#include "usb/switch/switch_haptics.h" +#include "controller_color.h" +#include "controller_state.h" +#include "switch_haptics.h" #include "tusb.h" -#include "usb/switch/switch_pro_descriptors.h" +#include "switch_pro_descriptors.h" // Preserve the pre-neutral-state 35%-of-1023 digital trigger boundary. constexpr uint32_t SWITCH_PRO_LEGACY_TRIGGER_RANGE_MAXIMUM = 1023; constexpr uint32_t SWITCH_PRO_LEGACY_TRIGGER_PRESS_THRESHOLD = 358; diff --git a/tests/adapter_host_probe_test.cpp b/tests/adapter_host_probe_test.cpp index e8b79b1..971251f 100644 --- a/tests/adapter_host_probe_test.cpp +++ b/tests/adapter_host_probe_test.cpp @@ -1,4 +1,5 @@ -#include "adapter/adapter_host_probe.h" +#include "adapter_host_probe.h" + #include #include #include @@ -6,7 +7,7 @@ #include "hardware/structs/watchdog.h" #include "pico/time.h" -#include "usb/xinput/xinput_descriptors.h" +#include "xinput_descriptors.h" namespace { diff --git a/tests/adapter_mode_controller_test.cpp b/tests/adapter_mode_controller_test.cpp index 931adc5..99bd61b 100644 --- a/tests/adapter_mode_controller_test.cpp +++ b/tests/adapter_mode_controller_test.cpp @@ -1,15 +1,16 @@ -#include "adapter/adapter_mode_controller.h" +#include "adapter_mode_controller.h" + #include #include #include #include #include -#include "configuration/adapter_configuration.h" -#include "adapter/adapter_reboot.h" -#include "input/bluepad32_input_backend.h" -#include "configuration/configuration_service.h" -#include "profile/controller_profile.h" +#include "adapter_configuration.h" +#include "adapter_reboot.h" +#include "bluepad32_input_backend.h" +#include "configuration_service.h" +#include "controller_profile.h" namespace { diff --git a/tests/bluepad32_backend_lifecycle_test.cpp b/tests/bluepad32_backend_lifecycle_test.cpp index 2933d48..7d8b174 100644 --- a/tests/bluepad32_backend_lifecycle_test.cpp +++ b/tests/bluepad32_backend_lifecycle_test.cpp @@ -4,7 +4,7 @@ #include #include -#include "platform/pico/controller_color_config.h" +#include "../controller_color_config.h" namespace { @@ -442,9 +442,8 @@ uint32_t btstack_run_loop_get_time_ms() { } -#include "core/controller_identity.cpp" -#include "input/bluepad32_input_backend.cpp" - +#include "../controller_identity.cpp" +#include "../bluepad32_input_backend.cpp" namespace { void require_clear_completion_pending() { if (expected_pending_clear_token != 0) { diff --git a/tests/bootsel_pairing_button_test.cpp b/tests/bootsel_pairing_button_test.cpp index 60cd7d3..1e6ab19 100644 --- a/tests/bootsel_pairing_button_test.cpp +++ b/tests/bootsel_pairing_button_test.cpp @@ -1,4 +1,5 @@ -#include "platform/pico/bootsel_pairing_button.h" +#include "bootsel_pairing_button.h" + #include #include #include diff --git a/tests/configuration_service_test.cpp b/tests/configuration_service_test.cpp index 55db59d..557bf55 100644 --- a/tests/configuration_service_test.cpp +++ b/tests/configuration_service_test.cpp @@ -1,7 +1,8 @@ -#include "configuration/adapter_configuration.h" -#include "configuration/configuration_service.h" -#include "configuration/configuration_storage.h" -#include "platform/pico/pico_configuration_storage.h" +#include "adapter_configuration.h" +#include "configuration_service.h" +#include "configuration_storage.h" +#include "pico_configuration_storage.h" + #include #include #include diff --git a/tests/configuration_storage_test.cpp b/tests/configuration_storage_test.cpp index 3c0052d..97c6d45 100644 --- a/tests/configuration_storage_test.cpp +++ b/tests/configuration_storage_test.cpp @@ -1,6 +1,7 @@ -#include "configuration/adapter_configuration.h" -#include "configuration/configuration_storage.h" -#include "configuration/configuration_transaction.h" +#include "adapter_configuration.h" +#include "configuration_storage.h" +#include "configuration_transaction.h" + #include #include #include diff --git a/tests/controller_profile_legacy_fixtures.h b/tests/controller_profile_legacy_fixtures.h index 98ccfde..eb29b40 100644 --- a/tests/controller_profile_legacy_fixtures.h +++ b/tests/controller_profile_legacy_fixtures.h @@ -2,7 +2,7 @@ #include -#include "profile/controller_profile.h" +#include "controller_profile.h" constexpr uint8_t kLegacyDefaultProfile[CONTROLLER_PROFILE_ENCODED_SIZE] = { 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, diff --git a/tests/controller_profile_runtime_test.cpp b/tests/controller_profile_runtime_test.cpp index a166a24..a79f8de 100644 --- a/tests/controller_profile_runtime_test.cpp +++ b/tests/controller_profile_runtime_test.cpp @@ -1,7 +1,9 @@ -#include "profile/controller_profile_runtime.h" -#include "core/controller_identity.h" -#include "profile/controller_profile.h" -#include "profile/profile_service.h" +#include "controller_profile_runtime.h" + +#include "controller_identity.h" +#include "controller_profile.h" +#include "profile_service.h" + #include #include #include diff --git a/tests/controller_profile_test.cpp b/tests/controller_profile_test.cpp index b9de8ed..91d1bac 100644 --- a/tests/controller_profile_test.cpp +++ b/tests/controller_profile_test.cpp @@ -1,6 +1,6 @@ -#include "core/controller_identity.h" -#include "profile/controller_profile.h" -#include "controller_profile_legacy_fixtures.h" +#include "controller_identity.h" +#include "controller_profile.h" +#include "tests/controller_profile_legacy_fixtures.h" #include #include diff --git a/tests/controller_profile_transform_test.cpp b/tests/controller_profile_transform_test.cpp index bd68722..e398638 100644 --- a/tests/controller_profile_transform_test.cpp +++ b/tests/controller_profile_transform_test.cpp @@ -1,6 +1,7 @@ -#include "core/controller_identity.h" -#include "profile/controller_profile.h" -#include "profile/controller_profile_transform.h" +#include "controller_identity.h" +#include "controller_profile.h" +#include "controller_profile_transform.h" + #include #include #include diff --git a/tests/controller_synthetic_input_test.cpp b/tests/controller_synthetic_input_test.cpp index b2af3e6..7af5e26 100644 --- a/tests/controller_synthetic_input_test.cpp +++ b/tests/controller_synthetic_input_test.cpp @@ -1,4 +1,5 @@ -#include "profile/controller_synthetic_input.h" +#include "controller_synthetic_input.h" + #include #include #include diff --git a/tests/generic_hid_descriptors_test.cpp b/tests/generic_hid_descriptors_test.cpp index 8f08c88..a69e280 100644 --- a/tests/generic_hid_descriptors_test.cpp +++ b/tests/generic_hid_descriptors_test.cpp @@ -1,4 +1,5 @@ -#include "usb/generic_hid/generic_hid_descriptors.h" +#include "generic_hid_descriptors.h" + #include #include #include diff --git a/tests/generic_hid_driver_test.cpp b/tests/generic_hid_driver_test.cpp index 9a795ae..f84d191 100644 --- a/tests/generic_hid_driver_test.cpp +++ b/tests/generic_hid_driver_test.cpp @@ -1,5 +1,7 @@ -#include "usb/generic_hid/generic_hid_driver.h" -#include "usb/generic_hid/generic_hid_descriptors.h" +#include "generic_hid_driver.h" + +#include "generic_hid_descriptors.h" + #include #include #include diff --git a/tests/profile_service_test.cpp b/tests/profile_service_test.cpp index 13b5f9d..7296fd6 100644 --- a/tests/profile_service_test.cpp +++ b/tests/profile_service_test.cpp @@ -1,8 +1,9 @@ -#include "core/controller_identity.h" -#include "profile/controller_profile.h" -#include "platform/pico/pico_profile_storage.h" -#include "profile/profile_service.h" -#include "profile/profile_storage.h" +#include "controller_identity.h" +#include "controller_profile.h" +#include "pico_profile_storage.h" +#include "profile_service.h" +#include "profile_storage.h" + #include #include #include diff --git a/tests/profile_storage_test.cpp b/tests/profile_storage_test.cpp index e0fdc9d..f0d2ef0 100644 --- a/tests/profile_storage_test.cpp +++ b/tests/profile_storage_test.cpp @@ -1,7 +1,7 @@ -#include "core/controller_identity.h" -#include "profile/controller_profile.h" -#include "profile/profile_storage.h" -#include "controller_profile_legacy_fixtures.h" +#include "controller_identity.h" +#include "controller_profile.h" +#include "profile_storage.h" +#include "tests/controller_profile_legacy_fixtures.h" #include #include diff --git a/tests/switch_haptics_test.cpp b/tests/switch_haptics_test.cpp index 6db7ec4..bec8a15 100644 --- a/tests/switch_haptics_test.cpp +++ b/tests/switch_haptics_test.cpp @@ -1,4 +1,5 @@ -#include "usb/switch/switch_haptics.h" +#include "switch_haptics.h" + #include #include #include diff --git a/tests/switch_pro_descriptors_test.cpp b/tests/switch_pro_descriptors_test.cpp index ef0c4ee..edcf392 100644 --- a/tests/switch_pro_descriptors_test.cpp +++ b/tests/switch_pro_descriptors_test.cpp @@ -1,5 +1,6 @@ -#include "usb/switch/switch_pro_descriptors.h" -#include "platform/pico/tusb_config.h" +#include "switch_pro_descriptors.h" +#include "tusb_config.h" + #include #include #include diff --git a/tests/switch_pro_driver_context_test.cpp b/tests/switch_pro_driver_context_test.cpp index ecee2d1..fb595ed 100644 --- a/tests/switch_pro_driver_context_test.cpp +++ b/tests/switch_pro_driver_context_test.cpp @@ -1,6 +1,6 @@ -#include "usb/switch/switch_pro_driver.h" -#include "usb/usb_output_driver.h" -#include "platform/pico/controller_color_config.h" +#include "switch_pro_driver.h" +#include "usb_output_driver.h" +#include "controller_color_config.h" #include "tusb.h" #include "pico/time.h" diff --git a/tests/test_adapter_host_probe_native.py b/tests/test_adapter_host_probe_native.py index 638e9fb..24d31e2 100644 --- a/tests/test_adapter_host_probe_native.py +++ b/tests/test_adapter_host_probe_native.py @@ -20,8 +20,8 @@ def test_adapter_host_probe_native(tmp_path: Path) -> None: "-pedantic", "-DSWITCH_PICO_HID_INSTANCE_COUNT=4", f"-I{root / 'tests' / 'mode_native_stubs'}", - f"-I{root / 'src' / 'firmware'}", - str(root / "src" / "firmware" / "adapter" / "adapter_host_probe.cpp"), + f"-I{root}", + str(root / "adapter_host_probe.cpp"), str(root / "tests" / "adapter_host_probe_test.cpp"), "-o", str(executable), diff --git a/tests/test_adapter_mode_controller_native.py b/tests/test_adapter_mode_controller_native.py index c42a4c7..29ea44a 100644 --- a/tests/test_adapter_mode_controller_native.py +++ b/tests/test_adapter_mode_controller_native.py @@ -20,8 +20,8 @@ def test_adapter_mode_controller_native(tmp_path: Path) -> None: "-pedantic", "-DSWITCH_PICO_HID_INSTANCE_COUNT=4", f"-I{root / 'tests' / 'mode_native_stubs'}", - f"-I{root / 'src' / 'firmware'}", - str(root / "src" / "firmware" / "adapter" / "adapter_mode_controller.cpp"), + f"-I{root}", + str(root / "adapter_mode_controller.cpp"), str(root / "tests" / "adapter_mode_controller_test.cpp"), "-o", str(executable), diff --git a/tests/test_bluepad32_backend_lifecycle_native.py b/tests/test_bluepad32_backend_lifecycle_native.py index 0bfea37..489702c 100644 --- a/tests/test_bluepad32_backend_lifecycle_native.py +++ b/tests/test_bluepad32_backend_lifecycle_native.py @@ -27,7 +27,7 @@ def test_bluepad32_backend_lifecycle_native(tmp_path: Path) -> None: command.extend( [ f"-I{root / 'tests' / 'bluepad32_native_stubs'}", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "bluepad32_backend_lifecycle_test.cpp"), "-o", str(executable), diff --git a/tests/test_bootsel_pairing_button_native.py b/tests/test_bootsel_pairing_button_native.py index 315eded..b05f1b7 100644 --- a/tests/test_bootsel_pairing_button_native.py +++ b/tests/test_bootsel_pairing_button_native.py @@ -22,8 +22,8 @@ def test_bootsel_pairing_button_native(tmp_path: Path) -> None: "-pedantic", f"-DPICO_RP2350={rp2350}", f"-I{root / 'tests' / 'bootsel_native_stubs'}", - f"-I{root / 'src' / 'firmware'}", - str(root / "src" / "firmware" / "platform" / "pico" / "bootsel_pairing_button.cpp"), + f"-I{root}", + str(root / "bootsel_pairing_button.cpp"), str(root / "tests" / "bootsel_pairing_button_test.cpp"), "-o", str(executable), diff --git a/tests/test_configuration_service_native.py b/tests/test_configuration_service_native.py index 914c75a..7707392 100644 --- a/tests/test_configuration_service_native.py +++ b/tests/test_configuration_service_native.py @@ -18,12 +18,12 @@ def test_configuration_service_native(tmp_path: Path) -> None: "-Werror", "-pedantic", f"-I{root / 'tests' / 'bluepad32_native_stubs'}", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "configuration_service_test.cpp"), - str(root / "src" / "firmware" / "configuration" / "adapter_configuration.cpp"), - str(root / "src" / "firmware" / "configuration" / "configuration_service.cpp"), - str(root / "src" / "firmware" / "configuration" / "configuration_storage.cpp"), - str(root / "src" / "firmware" / "configuration" / "configuration_transaction.cpp"), + str(root / "adapter_configuration.cpp"), + str(root / "configuration_service.cpp"), + str(root / "configuration_storage.cpp"), + str(root / "configuration_transaction.cpp"), "-o", str(executable), ], diff --git a/tests/test_configuration_storage_native.py b/tests/test_configuration_storage_native.py index b979171..0f0839a 100644 --- a/tests/test_configuration_storage_native.py +++ b/tests/test_configuration_storage_native.py @@ -17,11 +17,11 @@ def test_configuration_storage_native(tmp_path: Path) -> None: "-Wextra", "-Werror", "-pedantic", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "configuration_storage_test.cpp"), - str(root / "src" / "firmware" / "configuration" / "adapter_configuration.cpp"), - str(root / "src" / "firmware" / "configuration" / "configuration_storage.cpp"), - str(root / "src" / "firmware" / "configuration" / "configuration_transaction.cpp"), + str(root / "adapter_configuration.cpp"), + str(root / "configuration_storage.cpp"), + str(root / "configuration_transaction.cpp"), "-o", str(executable), ], diff --git a/tests/test_controller_profile_native.py b/tests/test_controller_profile_native.py index aad656e..3cf5575 100644 --- a/tests/test_controller_profile_native.py +++ b/tests/test_controller_profile_native.py @@ -17,10 +17,10 @@ def test_controller_profile_native(tmp_path: Path) -> None: "-Wextra", "-Werror", "-pedantic", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "controller_profile_test.cpp"), - str(root / "src" / "firmware" / "core" / "controller_identity.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), "-o", str(executable), ], diff --git a/tests/test_controller_profile_runtime_native.py b/tests/test_controller_profile_runtime_native.py index ee81c4d..0fa353d 100644 --- a/tests/test_controller_profile_runtime_native.py +++ b/tests/test_controller_profile_runtime_native.py @@ -17,13 +17,13 @@ def test_controller_profile_runtime_native(tmp_path: Path) -> None: "-Wextra", "-Werror", "-pedantic", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "controller_profile_runtime_test.cpp"), - str(root / "src" / "firmware" / "core" / "controller_identity.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile_transform.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_synthetic_input.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile_runtime.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "controller_profile_transform.cpp"), + str(root / "controller_synthetic_input.cpp"), + str(root / "controller_profile_runtime.cpp"), "-o", str(executable), ], diff --git a/tests/test_controller_profile_transform_native.py b/tests/test_controller_profile_transform_native.py index b8eb399..474cdb6 100644 --- a/tests/test_controller_profile_transform_native.py +++ b/tests/test_controller_profile_transform_native.py @@ -17,11 +17,11 @@ def test_controller_profile_transform_native(tmp_path: Path) -> None: "-Wextra", "-Werror", "-pedantic", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "controller_profile_transform_test.cpp"), - str(root / "src" / "firmware" / "core" / "controller_identity.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile_transform.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "controller_profile_transform.cpp"), "-o", str(executable), ], diff --git a/tests/test_controller_synthetic_input_native.py b/tests/test_controller_synthetic_input_native.py index 8f75956..aa347a8 100644 --- a/tests/test_controller_synthetic_input_native.py +++ b/tests/test_controller_synthetic_input_native.py @@ -17,12 +17,12 @@ def test_controller_synthetic_input_native(tmp_path: Path) -> None: "-Wextra", "-Werror", "-pedantic", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "controller_synthetic_input_test.cpp"), - str(root / "src" / "firmware" / "core" / "controller_identity.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile_transform.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_synthetic_input.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "controller_profile_transform.cpp"), + str(root / "controller_synthetic_input.cpp"), "-o", str(executable), ], diff --git a/tests/test_generic_hid_native.py b/tests/test_generic_hid_native.py index bd47b7a..7c3e500 100644 --- a/tests/test_generic_hid_native.py +++ b/tests/test_generic_hid_native.py @@ -32,7 +32,7 @@ def compile_cpp( command.append(f"-I{root / 'tests' / 'native_stubs'}") command.extend( [ - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", *[str(source) for source in sources], "-o", str(output), @@ -98,7 +98,7 @@ def test_generic_hid_driver_contexts(tmp_path: Path) -> None: host_compiler(), executable, [ - root / "src" / "firmware" / "usb" / "generic_hid" / "generic_hid_driver.cpp", + root / "generic_hid_driver.cpp", root / "tests" / "generic_hid_driver_test.cpp", ], ["SWITCH_PICO_HID_INSTANCE_COUNT=4"], diff --git a/tests/test_prepare_bluepad32.py b/tests/test_prepare_bluepad32.py index fe17f76..3e4673f 100644 --- a/tests/test_prepare_bluepad32.py +++ b/tests/test_prepare_bluepad32.py @@ -1,194 +1,339 @@ -from __future__ import annotations +""" +Tests for prepare_bluepad32.py patch preparation tool. + +Tests cover: +- Fresh patch application +- Idempotence (second invocation succeeds without changing content) +- Missing paths validation +- Diverged/ambiguous repository states +""" -import shutil import subprocess -import sys -from pathlib import Path - +import tempfile import pytest +from pathlib import Path +from unittest.mock import patch as mock_patch +import sys sys.path.insert(0, str(Path(__file__).parent.parent / "tools")) -from prepare_bluepad32 import ( # noqa: E402 +from prepare_bluepad32 import ( PatchError, - check_paths, - main, - prepare_bluepad32, resolve_paths, + check_paths, + is_patch_applied, + apply_patch, + prepare_bluepad32, ) -def run_git(repository: Path, *args: str) -> subprocess.CompletedProcess[str]: - return subprocess.run( - ["git", "-C", str(repository), *args], +@pytest.fixture +def temp_repo_structure(): + """Create a temporary directory structure with git repositories.""" + with tempfile.TemporaryDirectory() as tmpdir: + root = Path(tmpdir) + + # Create bluepad32 repo + bp_dir = root / "external" / "bluepad32" + bp_dir.mkdir(parents=True) + subprocess.run(["git", "init"], cwd=bp_dir, check=True, capture_output=True) + subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=bp_dir, check=True, capture_output=True) + subprocess.run(["git", "config", "user.name", "Test User"], cwd=bp_dir, check=True, capture_output=True) + + # Create a file to patch + test_file = bp_dir / "test.txt" + test_file.write_text("line 1\n") + subprocess.run(["git", "add", "test.txt"], cwd=bp_dir, check=True, capture_output=True) + subprocess.run(["git", "commit", "-m", "initial"], cwd=bp_dir, check=True, capture_output=True) + + # Create patches dir + patches_dir = root / "patches" + patches_dir.mkdir() + + yield root, bp_dir, patches_dir + + +def create_simple_patch(repo_path: Path, patch_path: Path, file_to_patch: str = "test.txt") -> str: + """ + Create a simple patch file that modifies a file in the repository. + + Returns the patch content as a string. + """ + # Create the modification + test_file = repo_path / file_to_patch + original_content = test_file.read_text() + modified_content = original_content + "line 2\n" + + # Generate patch using git diff + test_file.write_text(modified_content) + result = subprocess.run( + ["git", "diff", file_to_patch], + cwd=repo_path, capture_output=True, text=True, check=True, ) + patch_content = result.stdout + + # Reset the file to original state + test_file.write_text(original_content) + + # Write patch to file + patch_path.write_text(patch_content) + return patch_content -@pytest.fixture -def bluepad32_fixture(tmp_path: Path) -> tuple[Path, Path, Path, Path]: - source = tmp_path / "external" / "bluepad32" - source.mkdir(parents=True) - run_git(source, "init") - run_git(source, "config", "user.email", "test@example.com") - run_git(source, "config", "user.name", "Test User") - (source / "test.txt").write_text("line 1\n", encoding="utf-8") - run_git(source, "add", "test.txt") - run_git(source, "commit", "-m", "initial") - - patches = tmp_path / "patches" - patches.mkdir() - patch = patches / "bluepad32-sdl3-imu.patch" - original = (source / "test.txt").read_text(encoding="utf-8") - (source / "test.txt").write_text(f"{original}line 2\n", encoding="utf-8") - patch.write_text(run_git(source, "diff", "--", "test.txt").stdout, encoding="utf-8") - run_git(source, "restore", "test.txt") - - output = tmp_path / "build-aio" / "_deps" / "bluepad32-src" - return tmp_path, source, patch, output +def test_resolve_paths_with_defaults(): + """Test that resolve_paths returns expected default paths.""" + with tempfile.TemporaryDirectory() as tmpdir: + bp_path, patch_path = resolve_paths(Path(tmpdir)) + assert bp_path == Path(tmpdir) / "external" / "bluepad32" + assert patch_path == Path(tmpdir) / "patches" / "bluepad32-sdl3-imu.patch" -def source_status(source: Path) -> str: - return run_git(source, "status", "--porcelain", "--untracked-files=all").stdout +def test_resolve_paths_no_root(): + """Test resolve_paths with no root uses current directory.""" + bp_path, patch_path = resolve_paths() + assert bp_path.is_absolute() + assert patch_path.is_absolute() -def test_resolve_paths_uses_project_build_tree(tmp_path: Path) -> None: - source, patch, output = resolve_paths(tmp_path) - - assert source == tmp_path / "external" / "bluepad32" - assert patch == tmp_path / "patches" / "bluepad32-sdl3-imu.patch" - assert output == tmp_path / "build" / "_deps" / "bluepad32-src" - - -def test_check_paths_rejects_missing_source( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, output = bluepad32_fixture - shutil.rmtree(source) - +def test_check_paths_missing_bluepad32(temp_repo_structure): + """Test that check_paths fails if bluepad32 dir is missing.""" + root, bp_dir, patches_dir = temp_repo_structure + + # Remove bluepad32 + import shutil + shutil.rmtree(bp_dir) + + patch_file = patches_dir / "test.patch" + patch_file.write_text("dummy") + with pytest.raises(PatchError, match="bluepad32 directory does not exist"): - check_paths(source, patch, output) + check_paths(bp_dir, patch_file) -def test_check_paths_rejects_missing_patch( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, output = bluepad32_fixture - patch.unlink() - +def test_check_paths_missing_patch(temp_repo_structure): + """Test that check_paths fails if patch file is missing.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "nonexistent.patch" + with pytest.raises(PatchError, match="patch file does not exist"): - check_paths(source, patch, output) + check_paths(bp_dir, patch_file) -def test_check_paths_rejects_non_repository( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, output = bluepad32_fixture - shutil.rmtree(source / ".git") - +def test_check_paths_bluepad32_not_git_repo(temp_repo_structure): + """Test that check_paths fails if bluepad32 is not a git repo.""" + root, bp_dir, patches_dir = temp_repo_structure + + # Remove .git to make it not a git repo + import shutil + shutil.rmtree(bp_dir / ".git") + + patch_file = patches_dir / "test.patch" + patch_file.write_text("dummy") + with pytest.raises(PatchError, match="not a git repository"): - check_paths(source, patch, output) + check_paths(bp_dir, patch_file) -def test_check_paths_rejects_output_inside_source( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, _ = bluepad32_fixture - - with pytest.raises(PatchError, match="outside the Bluepad32 source tree"): - check_paths(source, patch, source / "patched") +def test_fresh_patch_application(temp_repo_structure): + """Test applying a fresh patch to a clean repository.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "test.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + # Verify test.txt before patch + test_file = bp_dir / "test.txt" + original = test_file.read_text() + assert "line 2" not in original + + # Apply patch + apply_patch(bp_dir, patch_file) + + # Verify test.txt after patch + patched = test_file.read_text() + assert "line 2" in patched -def test_prepare_patches_copy_and_preserves_pristine_source( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, output = bluepad32_fixture - - result = prepare_bluepad32(source, patch, output) - - assert result == output - assert (source / "test.txt").read_text(encoding="utf-8") == "line 1\n" - assert (output / "test.txt").read_text(encoding="utf-8") == "line 1\nline 2\n" - assert not (output / ".git").exists() - assert source_status(source) == "" +def test_idempotent_patch_application(temp_repo_structure): + """Test that applying the same patch twice succeeds (idempotence).""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "test.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + # First application + apply_patch(bp_dir, patch_file) + test_file = bp_dir / "test.txt" + after_first = test_file.read_text() + + # Second application should succeed without changing content + apply_patch(bp_dir, patch_file) + after_second = test_file.read_text() + + assert after_first == after_second -def test_prepare_replaces_existing_output_idempotently( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, output = bluepad32_fixture - prepare_bluepad32(source, patch, output) - (output / "stale.txt").write_text("stale", encoding="utf-8") - - prepare_bluepad32(source, patch, output) - - assert not (output / "stale.txt").exists() - assert (output / "test.txt").read_text(encoding="utf-8") == "line 1\nline 2\n" - assert source_status(source) == "" +def test_is_patch_applied_not_applied(temp_repo_structure): + """Test is_patch_applied returns False for unapplied patch.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "test.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + # Patch not applied yet + assert is_patch_applied(bp_dir, patch_file) is False -def test_prepare_rejects_dirty_source_without_replacing_output( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, output = bluepad32_fixture - output.mkdir(parents=True) - sentinel = output / "sentinel.txt" - sentinel.write_text("keep", encoding="utf-8") - (source / "test.txt").write_text("local edit\n", encoding="utf-8") - - with pytest.raises(PatchError, match="must be pristine"): - prepare_bluepad32(source, patch, output) - - assert sentinel.read_text(encoding="utf-8") == "keep" +def test_is_patch_applied_already_applied(temp_repo_structure): + """Test is_patch_applied returns True for already applied patch.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "test.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + # Apply patch first + apply_patch(bp_dir, patch_file) + + # Now check should detect it's applied + assert is_patch_applied(bp_dir, patch_file) is True -def test_prepare_rejects_diverged_source_revision( - bluepad32_fixture: tuple[Path, Path, Path, Path], -) -> None: - _, source, patch, output = bluepad32_fixture - (source / "test.txt").write_text("different base\n", encoding="utf-8") - run_git(source, "add", "test.txt") - run_git(source, "commit", "-m", "diverge") - +def test_diverged_repository_state(temp_repo_structure): + """Test that diverged repository (patch doesn't apply cleanly) is rejected.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "test.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + # Diverge the repository by modifying the file such that the patch conflicts + test_file = bp_dir / "test.txt" + test_file.write_text("completely different line 1\n") + subprocess.run(["git", "add", "test.txt"], cwd=bp_dir, check=True, capture_output=True) + subprocess.run(["git", "commit", "-m", "divergence"], cwd=bp_dir, check=True, capture_output=True) + + # Try to apply patch - should fail because file content doesn't match with pytest.raises(PatchError, match="Patch validation failed"): - prepare_bluepad32(source, patch, output) - - assert not output.exists() + apply_patch(bp_dir, patch_file) -def test_prepare_uses_default_paths( - bluepad32_fixture: tuple[Path, Path, Path, Path], monkeypatch: pytest.MonkeyPatch -) -> None: - root, source, _, _ = bluepad32_fixture - monkeypatch.chdir(root) - - output = prepare_bluepad32() - - assert output == root / "build" / "_deps" / "bluepad32-src" - assert (output / "test.txt").read_text(encoding="utf-8") == "line 1\nline 2\n" - assert source_status(source) == "" +def test_missing_bluepad32_path(temp_repo_structure): + """Test prepare_bluepad32 fails gracefully with missing bluepad32.""" + root, bp_dir, patches_dir = temp_repo_structure + + import shutil + shutil.rmtree(bp_dir) + + patch_file = patches_dir / "test.patch" + patch_file.write_text("dummy") + + with pytest.raises(PatchError, match="bluepad32 directory does not exist"): + prepare_bluepad32(bp_dir, patch_file) -def test_cli_accepts_explicit_output( - bluepad32_fixture: tuple[Path, Path, Path, Path], monkeypatch: pytest.MonkeyPatch -) -> None: - _, source, patch, output = bluepad32_fixture - monkeypatch.setattr( - sys, - "argv", - [ - "prepare_bluepad32.py", - "--bluepad32", - str(source), - "--patch", - str(patch), - "--output", - str(output), - ], - ) +def test_missing_patch_file(temp_repo_structure): + """Test prepare_bluepad32 fails gracefully with missing patch file.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "nonexistent.patch" + + with pytest.raises(PatchError, match="patch file does not exist"): + prepare_bluepad32(bp_dir, patch_file) - assert main() == 0 - assert (output / "test.txt").read_text(encoding="utf-8") == "line 1\nline 2\n" - assert source_status(source) == "" + +def test_prepare_bluepad32_full_workflow(temp_repo_structure): + """Test complete prepare_bluepad32 workflow: apply then idempotent re-apply.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "test.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + test_file = bp_dir / "test.txt" + original = test_file.read_text() + + # First prepare (should apply patch) + prepare_bluepad32(bp_dir, patch_file) + after_first = test_file.read_text() + assert after_first != original + assert "line 2" in after_first + + # Second prepare (should be idempotent) + prepare_bluepad32(bp_dir, patch_file) + after_second = test_file.read_text() + assert after_first == after_second + + +def test_prepare_bluepad32_with_defaults(temp_repo_structure): + """Test prepare_bluepad32 uses correct defaults when paths not provided.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "bluepad32-sdl3-imu.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + # Change to root directory and call with defaults + import os + original_cwd = os.getcwd() + try: + os.chdir(root) + prepare_bluepad32() # Use defaults + finally: + os.chdir(original_cwd) + + # Verify patch was applied + test_file = bp_dir / "test.txt" + assert "line 2" in test_file.read_text() + + +def test_patch_application_with_conflicting_content(temp_repo_structure): + """Test that patch with conflicting content is rejected.""" + root, bp_dir, patches_dir = temp_repo_structure + + # Create a patch that adds a specific change + patch_content = """--- a/test.txt ++++ b/test.txt +@@ -1 +1,3 @@ + line 1 ++line 2 ++line 3 +""" + + patch_file = patches_dir / "conflict.patch" + patch_file.write_text(patch_content) + + # Modify the file to have different content that won't match the patch context + test_file = bp_dir / "test.txt" + test_file.write_text("modified line 1\n") + subprocess.run(["git", "add", "test.txt"], cwd=bp_dir, check=True, capture_output=True) + subprocess.run(["git", "commit", "-m", "modify"], cwd=bp_dir, check=True, capture_output=True) + + # Try to apply patch - should fail due to context mismatch + with pytest.raises(PatchError): + apply_patch(bp_dir, patch_file) + + +def test_cli_with_explicit_paths(temp_repo_structure): + """Test CLI argument parsing with explicit paths.""" + root, bp_dir, patches_dir = temp_repo_structure + + patch_file = patches_dir / "test.patch" + create_simple_patch(bp_dir, patch_file, "test.txt") + + # Simulate CLI call + sys.argv = [ + "prepare_bluepad32.py", + "--bluepad32", str(bp_dir), + "--patch", str(patch_file), + ] + + from prepare_bluepad32 import main + + # Should not raise + try: + main() + except SystemExit as e: + # main() calls sys.exit on success, which we need to catch + if e.code != 0: + raise diff --git a/tests/test_profile_service_native.py b/tests/test_profile_service_native.py index 5bcb524..20fd48b 100644 --- a/tests/test_profile_service_native.py +++ b/tests/test_profile_service_native.py @@ -18,12 +18,12 @@ def test_profile_service_native(tmp_path: Path) -> None: "-Werror", "-pedantic", f"-I{root / 'tests' / 'bluepad32_native_stubs'}", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "profile_service_test.cpp"), - str(root / "src" / "firmware" / "core" / "controller_identity.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile.cpp"), - str(root / "src" / "firmware" / "profile" / "profile_storage.cpp"), - str(root / "src" / "firmware" / "profile" / "profile_service.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "profile_storage.cpp"), + str(root / "profile_service.cpp"), "-o", str(executable), ], diff --git a/tests/test_profile_storage_native.py b/tests/test_profile_storage_native.py index 134b90d..80e204f 100644 --- a/tests/test_profile_storage_native.py +++ b/tests/test_profile_storage_native.py @@ -17,11 +17,11 @@ def test_profile_storage_native(tmp_path: Path) -> None: "-Wextra", "-Werror", "-pedantic", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "profile_storage_test.cpp"), - str(root / "src" / "firmware" / "core" / "controller_identity.cpp"), - str(root / "src" / "firmware" / "profile" / "controller_profile.cpp"), - str(root / "src" / "firmware" / "profile" / "profile_storage.cpp"), + str(root / "controller_identity.cpp"), + str(root / "controller_profile.cpp"), + str(root / "profile_storage.cpp"), "-o", str(executable), ], diff --git a/tests/test_switch_haptics_native.py b/tests/test_switch_haptics_native.py index a8e0263..a56e27f 100644 --- a/tests/test_switch_haptics_native.py +++ b/tests/test_switch_haptics_native.py @@ -19,8 +19,8 @@ def test_switch_haptics_native(tmp_path: Path) -> None: "-Wextra", "-Werror", "-pedantic", - f"-I{root / 'src' / 'firmware'}", - str(root / "src" / "firmware" / "usb" / "switch" / "switch_haptics.cpp"), + f"-I{root}", + str(root / "switch_haptics.cpp"), str(root / "tests" / "switch_haptics_test.cpp"), "-o", str(executable), diff --git a/tests/test_switch_pro_descriptors_native.py b/tests/test_switch_pro_descriptors_native.py index 57fa816..a586843 100644 --- a/tests/test_switch_pro_descriptors_native.py +++ b/tests/test_switch_pro_descriptors_native.py @@ -25,7 +25,7 @@ def compile_descriptor_test( command.append(f"-DSWITCH_PICO_HID_INSTANCE_COUNT={configured_count}") command.extend( [ - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "switch_pro_descriptors_test.cpp"), "-o", str(output), diff --git a/tests/test_switch_pro_driver_context_native.py b/tests/test_switch_pro_driver_context_native.py index 9010f8b..d3c2963 100644 --- a/tests/test_switch_pro_driver_context_native.py +++ b/tests/test_switch_pro_driver_context_native.py @@ -21,10 +21,10 @@ def test_switch_pro_driver_four_contexts_native(tmp_path: Path) -> None: "-pedantic", "-DSWITCH_PICO_HID_INSTANCE_COUNT=4", f"-I{root / 'tests' / 'native_stubs'}", - f"-I{root / 'src' / 'firmware'}", - str(root / "src" / "firmware" / "usb" / "switch" / "switch_pro_driver.cpp"), - str(root / "src" / "firmware" / "usb" / "usb_output_driver.cpp"), - str(root / "src" / "firmware" / "usb" / "switch" / "switch_haptics.cpp"), + f"-I{root}", + str(root / "switch_pro_driver.cpp"), + str(root / "usb_output_driver.cpp"), + str(root / "switch_haptics.cpp"), str(root / "tests" / "switch_pro_driver_context_test.cpp"), "-o", str(executable), diff --git a/tests/test_usb_configuration_management_native.py b/tests/test_usb_configuration_management_native.py index 5d279f0..7eb2d6b 100644 --- a/tests/test_usb_configuration_management_native.py +++ b/tests/test_usb_configuration_management_native.py @@ -19,7 +19,7 @@ def test_usb_configuration_management_native(tmp_path: Path) -> None: "-Werror", "-pedantic", f"-I{root / 'tests' / 'usb_management_native_stubs'}", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "usb_configuration_management_test.cpp"), "-o", str(executable), diff --git a/tests/test_usb_output_driver_native.py b/tests/test_usb_output_driver_native.py index cfe956a..b6f4ff8 100644 --- a/tests/test_usb_output_driver_native.py +++ b/tests/test_usb_output_driver_native.py @@ -36,13 +36,13 @@ def test_usb_output_driver_contracts(tmp_path: Path) -> None: "-DSWITCH_PICO_USB_OUTPUT_MODES=1", *backend_definitions, f"-I{root / 'tests' / 'native_stubs'}", - f"-I{root / 'src' / 'firmware'}", + f"-I{root}", str(root / "tests" / "usb_output_driver_test.cpp"), - str(root / "src" / "firmware" / "usb" / "switch" / "switch_pro_driver.cpp"), - str(root / "src" / "firmware" / "usb" / "usb_output_driver.cpp"), - str(root / "src" / "firmware" / "usb" / "generic_hid" / "generic_hid_driver.cpp"), - str(root / "src" / "firmware" / "usb" / "xinput" / "xinput_driver.cpp"), - str(root / "src" / "firmware" / "usb" / "switch" / "switch_haptics.cpp"), + str(root / "switch_pro_driver.cpp"), + str(root / "usb_output_driver.cpp"), + str(root / "generic_hid_driver.cpp"), + str(root / "xinput_driver.cpp"), + str(root / "switch_haptics.cpp"), "-o", str(executable), ], diff --git a/tests/usb_configuration_management_test.cpp b/tests/usb_configuration_management_test.cpp index 2ea86f9..9a6601a 100644 --- a/tests/usb_configuration_management_test.cpp +++ b/tests/usb_configuration_management_test.cpp @@ -1,11 +1,12 @@ -#include "usb/usb_configuration_management.h" +#include "usb_configuration_management.h" + #include #include #include #include #include -#include "usb/usb_output_driver.h" +#include "usb_output_driver.h" namespace { @@ -787,10 +788,10 @@ bool tud_control_status(uint8_t, const tusb_control_request_t*) { return true; } -#include "configuration/adapter_configuration.cpp" -#include "core/controller_identity.cpp" -#include "profile/controller_profile.cpp" -#include "usb/usb_configuration_management.cpp" +#include "../adapter_configuration.cpp" +#include "../controller_identity.cpp" +#include "../controller_profile.cpp" +#include "../usb_configuration_management.cpp" int main() { current_configuration.state = ConfigurationServiceState::kReady; diff --git a/tests/usb_output_driver_test.cpp b/tests/usb_output_driver_test.cpp index edf1f2d..7ffdb78 100644 --- a/tests/usb_output_driver_test.cpp +++ b/tests/usb_output_driver_test.cpp @@ -4,17 +4,17 @@ #include #include -#include "adapter/adapter_host_probe_state.h" -#include "usb/generic_hid/generic_hid_descriptors.h" -#include "usb/generic_hid/generic_hid_driver.h" -#include "usb/xinput/xinput_descriptors.h" -#include "usb/xinput/xinput_protocol.h" +#include "adapter_host_probe_state.h" +#include "generic_hid_descriptors.h" +#include "generic_hid_driver.h" +#include "xinput_descriptors.h" +#include "xinput_protocol.h" #include "device/usbd_pvt.h" #include "pico/time.h" -#include "usb/switch/switch_pro_driver.h" +#include "switch_pro_driver.h" #include "tusb.h" -#include "usb/usb_output_driver.h" -#include "usb/xinput/xinput_driver.h" +#include "usb_output_driver.h" +#include "xinput_driver.h" namespace { diff --git a/tools/prepare_bluepad32.py b/tools/prepare_bluepad32.py index 67a634e..981d40f 100755 --- a/tools/prepare_bluepad32.py +++ b/tools/prepare_bluepad32.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 -"""Create a patched build-local copy of the pinned Bluepad32 source.""" +"""Apply the project Bluepad32 patch exactly once.""" from __future__ import annotations import argparse -import shutil import subprocess import sys from pathlib import Path @@ -13,125 +12,69 @@ class PatchError(RuntimeError): pass -def resolve_paths(repo_root: Path | None = None) -> tuple[Path, Path, Path]: +def resolve_paths(repo_root: Path | None = None) -> tuple[Path, Path]: root = Path.cwd() if repo_root is None else Path(repo_root) return ( root / "external" / "bluepad32", root / "patches" / "bluepad32-sdl3-imu.patch", - root / "build" / "_deps" / "bluepad32-src", ) -def _run(command: list[str], *, cwd: Path | None = None) -> subprocess.CompletedProcess[str]: +def check_paths(bluepad32_path: Path, patch_path: Path) -> None: + if not bluepad32_path.is_dir(): + raise PatchError(f"bluepad32 directory does not exist: {bluepad32_path}") + if not (bluepad32_path / ".git").exists(): + raise PatchError(f"Bluepad32 is not a git repository: {bluepad32_path}") + if not patch_path.is_file(): + raise PatchError(f"patch file does not exist: {patch_path}") + + +def git_apply(bluepad32_path: Path, patch_path: Path, *args: str) -> subprocess.CompletedProcess[str]: return subprocess.run( - command, - cwd=cwd, + ["git", "-C", str(bluepad32_path), "apply", *args, str(patch_path)], capture_output=True, text=True, check=False, ) -def check_paths(source_path: Path, patch_path: Path, output_path: Path) -> None: - if not source_path.is_dir(): - raise PatchError(f"bluepad32 directory does not exist: {source_path}") - if not patch_path.is_file(): - raise PatchError(f"patch file does not exist: {patch_path}") - - repository_check = _run( - ["git", "-C", str(source_path), "rev-parse", "--is-inside-work-tree"] - ) - if repository_check.returncode != 0: - raise PatchError(f"Bluepad32 is not a git repository: {source_path}") - - source = source_path.resolve() - output = output_path.resolve() - if output == source or source in output.parents: - raise PatchError("patched output must be outside the Bluepad32 source tree") +def is_patch_applied(bluepad32_path: Path, patch_path: Path) -> bool: + return git_apply(bluepad32_path, patch_path, "--reverse", "--check").returncode == 0 -def validate_pristine_source(source_path: Path, patch_path: Path) -> None: - status = _run( - [ - "git", - "-C", - str(source_path), - "status", - "--porcelain", - "--untracked-files=all", - ] - ) - if status.returncode != 0: - detail = status.stderr.strip() or "git status failed" - raise PatchError(f"Could not inspect Bluepad32 source: {detail}") - if status.stdout.strip(): - raise PatchError( - "Bluepad32 source must be pristine; patches are applied only to the build-local copy" - ) +def apply_patch(bluepad32_path: Path, patch_path: Path) -> None: + if is_patch_applied(bluepad32_path, patch_path): + return - check = _run( - ["git", "-C", str(source_path), "apply", "--check", str(patch_path)] - ) + check = git_apply(bluepad32_path, patch_path, "--check") if check.returncode != 0: detail = check.stderr.strip() or "patch does not apply" - raise PatchError(f"Patch validation failed (source revision may have diverged):\n{detail}") + raise PatchError(f"Patch validation failed (repository may be diverged):\n{detail}") - -def _copy_and_patch(source_path: Path, patch_path: Path, output_path: Path) -> None: - output_path.parent.mkdir(parents=True, exist_ok=True) - staging_path = output_path.with_name(f".{output_path.name}.tmp") - - if staging_path.exists(): - shutil.rmtree(staging_path) - - try: - shutil.copytree( - source_path, - staging_path, - symlinks=True, - ignore=shutil.ignore_patterns(".git"), - ) - result = _run( - ["git", "apply", "--no-index", str(patch_path.resolve())], - cwd=staging_path, - ) - if result.returncode != 0: - detail = result.stderr.strip() or "git apply failed" - raise PatchError(f"Could not patch build-local Bluepad32 copy: {detail}") - - if output_path.exists(): - shutil.rmtree(output_path) - staging_path.replace(output_path) - except Exception: - if staging_path.exists(): - shutil.rmtree(staging_path) - raise + result = git_apply(bluepad32_path, patch_path) + if result.returncode != 0: + detail = result.stderr.strip() or "git apply failed" + raise PatchError(f"Could not patch Bluepad32: {detail}") def prepare_bluepad32( - source_path: Path | None = None, + bluepad32_path: Path | None = None, patch_path: Path | None = None, - output_path: Path | None = None, -) -> Path: - default_source, default_patch, default_output = resolve_paths() - source = Path(source_path or default_source) +) -> None: + default_bluepad32, default_patch = resolve_paths() + dependency = Path(bluepad32_path or default_bluepad32) patch = Path(patch_path or default_patch) - output = Path(output_path or default_output) - - check_paths(source, patch, output) - validate_pristine_source(source, patch) - _copy_and_patch(source, patch, output) - return output + check_paths(dependency, patch) + apply_patch(dependency, patch) def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--bluepad32", type=Path) parser.add_argument("--patch", type=Path) - parser.add_argument("--output", type=Path) args = parser.parse_args() try: - prepare_bluepad32(args.bluepad32, args.patch, args.output) + prepare_bluepad32(args.bluepad32, args.patch) except PatchError as exc: print(f"error: {exc}", file=sys.stderr) return 1 diff --git a/src/firmware/platform/pico/tusb_config.h b/tusb_config.h similarity index 100% rename from src/firmware/platform/pico/tusb_config.h rename to tusb_config.h diff --git a/src/firmware/usb/usb_configuration_management.cpp b/usb_configuration_management.cpp similarity index 99% rename from src/firmware/usb/usb_configuration_management.cpp rename to usb_configuration_management.cpp index a4e7628..40c5d72 100644 --- a/src/firmware/usb/usb_configuration_management.cpp +++ b/usb_configuration_management.cpp @@ -1,12 +1,13 @@ -#include "usb/usb_configuration_management.h" +#include "usb_configuration_management.h" + #include -#include "configuration/adapter_configuration.h" -#include "adapter/adapter_host_probe.h" -#include "adapter/adapter_reboot.h" -#include "adapter/adapter_usb_mode.h" +#include "adapter_configuration.h" +#include "adapter_host_probe.h" +#include "adapter_reboot.h" +#include "adapter_usb_mode.h" #include "tusb.h" -#include "usb/usb_output_driver.h" +#include "usb_output_driver.h" namespace UsbConfigurationManagement { namespace { diff --git a/src/firmware/usb/usb_configuration_management.h b/usb_configuration_management.h similarity index 95% rename from src/firmware/usb/usb_configuration_management.h rename to usb_configuration_management.h index 0477795..2671ed4 100644 --- a/src/firmware/usb/usb_configuration_management.h +++ b/usb_configuration_management.h @@ -5,9 +5,9 @@ #include "tusb.h" -#include "input/bluepad32_input_backend.h" -#include "configuration/configuration_service.h" -#include "profile/profile_service.h" +#include "bluepad32_input_backend.h" +#include "configuration_service.h" +#include "profile_service.h" namespace UsbConfigurationManagement { diff --git a/src/firmware/usb/usb_output_driver.cpp b/usb_output_driver.cpp similarity index 96% rename from src/firmware/usb/usb_output_driver.cpp rename to usb_output_driver.cpp index ab77939..ec51f2f 100644 --- a/src/firmware/usb/usb_output_driver.cpp +++ b/usb_output_driver.cpp @@ -1,23 +1,23 @@ -#include "usb/usb_output_driver.h" +#include "usb_output_driver.h" #include #include #include "device/usbd_pvt.h" -#include "usb/switch/switch_pro_driver.h" -#include "usb/switch/switch_pro_descriptors.h" +#include "switch_pro_driver.h" +#include "switch_pro_descriptors.h" #include "tusb.h" #ifdef SWITCH_PICO_BLUEPAD32 -#include "usb/usb_configuration_management.h" +#include "usb_configuration_management.h" #endif #ifdef SWITCH_PICO_USB_OUTPUT_MODES -#include "adapter/adapter_host_probe.h" -#include "usb/generic_hid/generic_hid_descriptors.h" -#include "usb/generic_hid/generic_hid_driver.h" -#include "usb/xinput/xinput_descriptors.h" -#include "usb/xinput/xinput_driver.h" +#include "adapter_host_probe.h" +#include "generic_hid_descriptors.h" +#include "generic_hid_driver.h" +#include "xinput_descriptors.h" +#include "xinput_driver.h" #endif #ifdef SWITCH_PICO_LOG diff --git a/src/firmware/usb/usb_output_driver.h b/usb_output_driver.h similarity index 92% rename from src/firmware/usb/usb_output_driver.h rename to usb_output_driver.h index ae0bd4b..ec2bad4 100644 --- a/src/firmware/usb/usb_output_driver.h +++ b/usb_output_driver.h @@ -2,9 +2,9 @@ #include -#include "adapter/adapter_usb_mode.h" -#include "core/controller_state.h" -#include "usb/switch/switch_haptics.h" +#include "adapter_usb_mode.h" +#include "controller_state.h" +#include "switch_haptics.h" // Mode capability bits published in USB management info. Input is present in // every current mode; rumble/motion describe host-visible USB capabilities. diff --git a/src/firmware/usb/xinput/xinput_descriptors.h b/xinput_descriptors.h similarity index 100% rename from src/firmware/usb/xinput/xinput_descriptors.h rename to xinput_descriptors.h diff --git a/src/firmware/usb/xinput/xinput_driver.cpp b/xinput_driver.cpp similarity index 98% rename from src/firmware/usb/xinput/xinput_driver.cpp rename to xinput_driver.cpp index 6a3a5bd..8844ad4 100644 --- a/src/firmware/usb/xinput/xinput_driver.cpp +++ b/xinput_driver.cpp @@ -1,11 +1,12 @@ -#include "usb/xinput/xinput_driver.h" +#include "xinput_driver.h" + #include #include #include "device/usbd_pvt.h" #include "tusb.h" -#include "usb/xinput/xinput_descriptors.h" -#include "usb/xinput/xinput_protocol.h" +#include "xinput_descriptors.h" +#include "xinput_protocol.h" namespace { diff --git a/src/firmware/usb/xinput/xinput_driver.h b/xinput_driver.h similarity index 84% rename from src/firmware/usb/xinput/xinput_driver.h rename to xinput_driver.h index e4fe683..a6158fb 100644 --- a/src/firmware/usb/xinput/xinput_driver.h +++ b/xinput_driver.h @@ -2,9 +2,9 @@ #include -#include "core/controller_state.h" +#include "controller_state.h" #include "device/usbd_pvt.h" -#include "usb/switch/switch_haptics.h" +#include "switch_haptics.h" void xinput_init(uint8_t instance); void xinput_set_rumble_callback(uint8_t instance, diff --git a/src/firmware/usb/xinput/xinput_protocol.h b/xinput_protocol.h similarity index 97% rename from src/firmware/usb/xinput/xinput_protocol.h rename to xinput_protocol.h index 48cfa9c..ca49c54 100644 --- a/src/firmware/usb/xinput/xinput_protocol.h +++ b/xinput_protocol.h @@ -2,8 +2,8 @@ #include -#include "core/controller_state.h" -#include "usb/switch/switch_haptics.h" +#include "controller_state.h" +#include "switch_haptics.h" namespace XInput {