From d765b487f1e8a7fce90da630842716a22ebd2247 Mon Sep 17 00:00:00 2001 From: Gin <> Date: Mon, 5 Oct 2026 23:10:21 -0700 Subject: [PATCH] PybindSwitchProController: document the interface Document what the class does and how its methods behave today: queued commands, controller type, units, and the meaning of the delay/hold/release timings. No code changes. --- .gitignore | 1 + .../Integrations/PybindSwitchController.h | 103 +++++++++++++++++- 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1b8b69d245..053e1db970 100644 --- a/.gitignore +++ b/.gitignore @@ -71,6 +71,7 @@ __pycache__ vcpkg/ CLAUDE.md +.claude/ build_*/ .cache/* diff --git a/SerialPrograms/Source/Integrations/PybindSwitchController.h b/SerialPrograms/Source/Integrations/PybindSwitchController.h index d8a33bc38a..0e6ea3abed 100644 --- a/SerialPrograms/Source/Integrations/PybindSwitchController.h +++ b/SerialPrograms/Source/Integrations/PybindSwitchController.h @@ -15,28 +15,129 @@ namespace NintendoSwitch{ +// Models a Nintendo Switch wired controller connected via serial port. This class is used +// as an interface for Python API and AI agent use. +// +// Commands are queued: every `push_*()` call returns as soon as the command is +// scheduled on the device, not when it finishes. Call `wait_for_all_requests()` to +// block until everything queued so far has actually been executed. This mirrors how +// `pbf_*()` functions work inside the main program. +// +// The wired controller type (Switch 1/2, Pro vs. 3rd-party controller) is +// whatever the device firmware is currently set to. Use the main GUI program once to +// choose it; the device remembers the setting. +// TODO: we should make this PybindSwitchProController interface able to switch +// controller type in future. +// +// Button bitfields use `NintendoSwitch::Button` values, and d-pad positions use +// `NintendoSwitch::DpadPosition` values (0 = up, clockwise to 7 = up-left, 8 = none). +// Joystick coordinates are in [-1.0, 1.0] with +x = right and +y = up. class PybindSwitchProController{ PybindSwitchProController(const PybindSwitchProController&) = delete; void operator=(const PybindSwitchProController&) = delete; public: + // Open a connection to the PABotBase2 device on serial port `port_name`. + // `port_name` may be a full path ("/dev/cu.usbserial-0001") or a bare device name + // "cu.usbserial-0001" or "COM3". + // The connection is established asynchronously; After the constructor, call + // `wait_for_ready()` next to wait until it is ready. + // Log lines go to the command-line logger with tag "Pybind", which also prints + // them to stdout. PybindSwitchProController(const std::string& port_name); ~PybindSwitchProController(); + // Block until the device handshake finishes and a Switch controller has been + // created, or `timeout_millis` passes. + // Returns true if the controller is ready to receive commands. bool wait_for_ready(uint64_t timeout_millis); bool is_ready() const; + + // The connection status text shown in the GUI (formatted as HTML), e.g. + // device name and firmware version, or the error message if the connection failed. std::string current_status() const; + // Block until every command queued so far has been executed by the device. + // Returns immediately if the controller is not ready. void wait_for_all_requests(); - // All times are in milliseconds. +public: + // Commands. If the controller is not ready, these log an error and do nothing. + // They block only if the device's command queue is full. + // + // `delay` is how long to wait before the next command may start, `hold` how long + // the input is held, and `release` how long it must stay released before the same + // button can be used again. `delay = hold + release` runs commands back to back + // like `pbf_press_button()`; `delay < hold` overlaps them, e.g. to hold a button + // while moving a stick. + + // Send a wait command to the controller. Nothing is pressed during the wait time. + // duration: wait duration, milliseconds. + // If the controller is not ready, these log an error and do nothing. + // The function will block only if the device's command queue is full. void wait(uint64_t duration); + + // Send a button press command to the controller. It will press all buttons in + // `bitfield` simultaneously. D-pad buttons are excluded and should be called via + // `push_dpad()`. + // delay: how long to wait before the next command may start. + // hold: how long the button press is held, milliseconds. + // release: how long the buttons stay released before the same button can be used again, + // milliseconds. + // bitfield: values from `NintendoSwitch::Button`. + // + // `delay = hold + release` runs commands back to back like `pbf_press_button()`; + // `delay < hold` overlaps commands, e.g. to hold a button while moving a stick. + // If the controller is not ready, these log an error and do nothing. + // The function will block only if the device's command queue is full. void push_button(uint64_t delay, uint64_t hold, uint64_t release, uint32_t bitfield); + // Send a D-pad press command to the controller. It will press one or two D-pad buttons to + // indicate a direction to the game. + // delay: how long to wait before the next command may start. + // hold: how long the button press is held, milliseconds. + // release: how long the buttons stay released before the same button can be used again, + // milliseconds. + // position: `NintendoSwitch::DpadPosition` values (0 = up, clockwise to 7 = up-left, 8 = none). + // + // `delay = hold + release` runs commands back to back like `pbf_press_button()`; + // `delay < hold` overlaps commands, e.g. to hold a button while moving a stick. + // If the controller is not ready, these log an error and do nothing. + // The function will block only if the device's command queue is full. void push_dpad(uint64_t delay, uint64_t hold, uint64_t release, uint8_t position); + // Send a left joystick push command to the controller. + // delay: how long to wait before the next command may start. + // hold: how long the joystick is pushed, milliseconds. + // release: how long the joystick stay released before the same the joystick can be used again, + // milliseconds. + // x, y: in [-1.0, 1.0] with +x = right and +y = up. + // + // `delay = hold + release` runs commands back to back like `pbf_press_button()`; + // `delay < hold` overlaps commands, e.g. to hold a button while moving a stick. + // If the controller is not ready, these log an error and do nothing. + // The function will block only if the device's command queue is full. void push_left_joystick(uint64_t delay, uint64_t hold, uint64_t release, double x, double y); + // Send a right joystick push command to the controller. + // delay: how long to wait before the next command may start. + // hold: how long the joystick is pushed, milliseconds. + // release: how long the joystick stay released before the same the joystick can be used again, + // milliseconds. + // x, y: in [-1.0, 1.0] with +x = right and +y = up. + // + // `delay = hold + release` runs commands back to back like `pbf_press_button()`; + // `delay < hold` overlaps commands, e.g. to hold a button while moving a stick. + // If the controller is not ready, these log an error and do nothing. + // The function will block only if the device's command queue is full. void push_right_joystick(uint64_t delay, uint64_t hold, uint64_t release, double x, double y); + // Set the entire controller state at once and hold it for `duration`. + // Everything not specified is released. This is the most direct way to hold + // arbitrary combinations, e.g. running (B + left stick) while turning the camera. + // duration: how long to hold the buttons/joysticks, milliseconds. + // button_bitfield: one or more non-D-pad buttons, values from `NintendoSwitch::Button`. + // dpad_position: `NintendoSwitch::DpadPosition` values (0 = up, clockwise to 7 = up-left, 8 = none). + // left_x, left_y: in [-1.0, 1.0] with +x = right and +y = up. + // right_x, right_y: in [-1.0, 1.0] with +x = right and +y = up. void controller_state( uint64_t duration, uint32_t button_bitfield,