From 22cfe62c4167d777233b62a0b1e51e8d7519963e Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 14 Dec 2025 14:04:28 -0700 Subject: [PATCH 1/4] Add gyro branch ref --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3bed2e..bb69056 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Raspberry Pi Pico firmware that emulates a Switch Pro controller over USB and a 5. Connect the Pico to the Switch (dock USB-A or USB-C OTG); the Switch should see it as a wired Pro Controller. ## Planned features -- IMU support for motion controls (gyro/accelerometer passthrough for controllers that support it to the Switch). +- IMU support for motion controls (gyro/accelerometer passthrough for controllers that support it to the Switch) (WIP branch on `gyrov3`). ## Limitations - No motion controls/IMU passthrough yet (planned). From e41a1746ba3f1744785bd56cf9848f81c51e0e73 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 14 Dec 2025 14:08:03 -0700 Subject: [PATCH 2/4] Add references --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index bb69056..e64a169 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,12 @@ with SwitchUARTClient("/dev/cu.usbserial-0001") as client: ### Linux tips - You may need udev permissions for `/dev/ttyUSB*`/`/dev/ttyACM*` (add user to `dialout`/`uucp` or use `udev` rules). +## References +- GP2040-CE (controller firmware ecosystem): https://github.com/OpenStickCommunity/GP2040-CE +- nxbt (Switch controller research/tools): https://github.com/Brikwerk/nxbt +- Nintendo Switch Reverse Engineering notes: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering +- `hid-nintendo` driver reference: https://github.com/DanielOgorchock/linux/blob/ogorchock/drivers/hid/hid-nintendo.c + ## Troubleshooting - **No input on Switch**: verify UART wiring (Pico GPIO4/5), baud matches both sides, Pico flashed with current firmware, and `Pro Controller Wired Communication` is enabled on the Switch. - **Constant buzzing rumble**: the bridge filters small rumble payloads; ensure baud isn’t dropping bytes. Try lowering rumble scale in `switch_pico_bridge.controller_uart_bridge` if needed. From b04a6d29ca861dba1cd813d612259dc0e21aae97 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sun, 14 Dec 2025 14:47:49 -0700 Subject: [PATCH 3/4] Add license --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..54aabb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Joey Yakimowich-Payne + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file From ae65251cb467f8a8daf46c20c7f51ed5a748c885 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sat, 10 Jan 2026 23:19:13 -0700 Subject: [PATCH 4/4] Fix controllers --- .../controller_uart_bridge.py | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/switch_pico_bridge/controller_uart_bridge.py b/src/switch_pico_bridge/controller_uart_bridge.py index e223ed0..4f13857 100644 --- a/src/switch_pico_bridge/controller_uart_bridge.py +++ b/src/switch_pico_bridge/controller_uart_bridge.py @@ -214,6 +214,7 @@ class ControllerContext: last_rumble_energy: float = 0.0 rumble_active: bool = False axis_offsets: Dict[int, int] = field(default_factory=dict) + swap_abxy: bool = False def capture_stick_offsets(controller: sdl2.SDL_GameController) -> Dict[int, int]: @@ -395,12 +396,9 @@ def toggle_abxy_for_context(ctx: ControllerContext, config: BridgeConfig, consol if config.swap_abxy_global: console.print("[yellow]Global --swap-abxy is enabled; disable it to use per-controller toggles.[/yellow]") return - swapped = ctx.stable_id in config.swap_abxy_ids + swapped = ctx.swap_abxy action = "standard" if swapped else "swapped" - if swapped: - config.swap_abxy_ids.discard(ctx.stable_id) - else: - config.swap_abxy_ids.add(ctx.stable_id) + ctx.swap_abxy = not swapped console.print( f"[cyan]Controller {ctx.controller_index} ({controller_display_name(ctx)}, inst {ctx.instance_id}) now using {action} ABXY layout.[/cyan]" ) @@ -425,7 +423,7 @@ def prompt_swap_abxy_controller( table.add_column("GUID") table.add_column("Layout", justify="center") for idx, ctx in enumerate(controllers): - swapped = config.swap_abxy_global or (ctx.stable_id in config.swap_abxy_ids) + swapped = config.swap_abxy_global or ctx.swap_abxy state = "Swapped" if swapped else "Standard" if config.swap_abxy_global: state += " (global)" @@ -988,8 +986,7 @@ def open_initial_contexts( console.print(f"[red]Failed to open controller {index}: {exc}[/red]") continue stable_id = guid - if index in config.swap_abxy_indices: - config.swap_abxy_ids.add(stable_id) + should_swap = index in config.swap_abxy_indices or stable_id in config.swap_abxy_ids uart = open_uart_or_warn(port, args.baud, console) if port else None if uart: uarts.append(uart) @@ -1007,6 +1004,7 @@ def open_initial_contexts( stable_id=stable_id, port=port, uart=uart, + swap_abxy=should_swap, ) if config.zero_sticks: zero_context_sticks(ctx, console) @@ -1058,7 +1056,7 @@ def handle_button_event( return current_button_map = ( config.button_map_swapped - if (config.swap_abxy_global or ctx.stable_id in config.swap_abxy_ids) + if (config.swap_abxy_global or ctx.swap_abxy) else config.button_map_default ) button = event.cbutton.button @@ -1103,9 +1101,8 @@ def handle_device_added( console.print(f"[red]Hotplug open failed for controller {idx}: {exc}[/red]") return stable_id = guid - # Promote any index-based swap flags to stable IDs on first sight. - if idx in config.swap_abxy_indices: - config.swap_abxy_ids.add(stable_id) + # Determine if this controller should have swapped ABXY based on index or GUID + should_swap = idx in config.swap_abxy_indices or stable_id in config.swap_abxy_ids uart = open_uart_or_warn(port, args.baud, console) if port else None if uart: uarts.append(uart) @@ -1123,6 +1120,7 @@ def handle_device_added( stable_id=stable_id, port=port, uart=uart, + swap_abxy=should_swap, ) if config.zero_sticks: zero_context_sticks(ctx, console) @@ -1163,7 +1161,7 @@ def service_contexts( for ctx in list(contexts.values()): current_button_map = ( config.button_map_swapped - if (config.swap_abxy_global or ctx.stable_id in config.swap_abxy_ids) + if (config.swap_abxy_global or ctx.swap_abxy) else config.button_map_default ) poll_controller_buttons(ctx, current_button_map)