Support Bluepad32 gamepads as native Joy-Con pair sources
This commit is contained in:
parent
ab70536fdf
commit
a17ca603aa
33 changed files with 2529 additions and 851 deletions
|
|
@ -13,8 +13,8 @@
|
|||
#include <inttypes.h>
|
||||
extern "C" int probe_debug_printf(const char* format, ...);
|
||||
#endif
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#include "dualsense_input.h"
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
#include "native_gamepad_input.h"
|
||||
#endif
|
||||
#if SWITCH2_BRIDGE_WII_INPUT
|
||||
#include <math.h>
|
||||
|
|
@ -26,9 +26,9 @@ extern "C" int probe_debug_printf(const char* format, ...);
|
|||
|
||||
#if !SWITCH_PICO_SWITCH2_USB_BRIDGE || !SWITCH_PICO_BLUEPAD32
|
||||
#error "The controller bridge requires Bluepad32"
|
||||
#elif SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if !SWITCH_PICO_ENABLE_CLASSIC
|
||||
#error "The DualSense bridge requires Classic Bluetooth"
|
||||
#elif SWITCH2_BRIDGE_FULL_INPUT
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT && !SWITCH_PICO_ENABLE_CLASSIC
|
||||
#error "The DualSense source requires Classic Bluetooth"
|
||||
#endif
|
||||
#elif !SWITCH_PICO_ENABLE_BLE || !SWITCH_PICO_SWITCH2_MOUSE_CAPTURE || \
|
||||
!SWITCH_PICO_SWITCH2_MOUSE_CAPTURE_NATIVE
|
||||
|
|
@ -36,7 +36,7 @@ extern "C" int probe_debug_printf(const char* format, ...);
|
|||
#endif
|
||||
|
||||
namespace {
|
||||
#if !SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if !SWITCH2_BRIDGE_FULL_INPUT
|
||||
constexpr uint8_t kSourceAddress[] = {SWITCH2_BRIDGE_SOURCE_ADDRESS_BYTES};
|
||||
static_assert(sizeof(kSourceAddress) == 6, "Select one physical Bluetooth address");
|
||||
#if SWITCH2_PROBE_COMPOSITE || SWITCH2_PROBE_HUB
|
||||
|
|
@ -56,7 +56,7 @@ bool g_start_attempted;
|
|||
bool g_flash_ready;
|
||||
#if SWITCH2_BRIDGE_WII_INPUT
|
||||
probe_controller_input g_input;
|
||||
#elif !SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#elif !SWITCH2_BRIDGE_FULL_INPUT
|
||||
probe_controller_input g_inputs[PROBE_CONTROLLER_COUNT];
|
||||
uint32_t g_received_times[PROBE_CONTROLLER_COUNT];
|
||||
#endif
|
||||
|
|
@ -382,9 +382,9 @@ extern "C" void probe_controller_input_clock_init(void) {
|
|||
|
||||
extern "C" void probe_controller_input_init(void) {
|
||||
if (g_initialized) return;
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
bluepad32_input_backend_init();
|
||||
probe_dualsense_input_init();
|
||||
probe_native_gamepad_input_init();
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
bluepad32_input_backend_init();
|
||||
bluepad32_input_backend_select_wii_source(kSourceAddress);
|
||||
|
|
@ -484,17 +484,17 @@ extern "C" void probe_controller_input_set_native_features(uint8_t features) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
extern "C" void probe_controller_input_set_full_stick_calibration(
|
||||
uint8_t instance, const uint8_t calibration[9]) {
|
||||
probe_dualsense_input_set_stick_calibration(instance, calibration);
|
||||
probe_native_gamepad_input_set_stick_calibration(instance, calibration);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void probe_controller_input_set_native_stream(uint8_t instance, bool enabled) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT) return;
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
probe_dualsense_input_set_native_stream(instance, enabled && g_flash_ready);
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
probe_native_gamepad_input_set_native_stream(instance, enabled && g_flash_ready);
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
enabled = enabled && g_flash_ready;
|
||||
if (g_native_stream != enabled || !enabled) discard_wii_output();
|
||||
|
|
@ -508,8 +508,8 @@ extern "C" void probe_controller_input_set_native_stream(uint8_t instance, bool
|
|||
extern "C" uint32_t probe_controller_input_peek_native_report(
|
||||
uint8_t instance, uint32_t now_ms, uint8_t report[63]) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT || !g_flash_ready) return 0;
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
return probe_dualsense_input_peek_native_report(instance, now_ms, report);
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
return probe_native_gamepad_input_peek_native_report(instance, now_ms, report);
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
(void)now_ms;
|
||||
return prepare_wii_report(report);
|
||||
|
|
@ -520,8 +520,8 @@ extern "C" uint32_t probe_controller_input_peek_native_report(
|
|||
|
||||
extern "C" bool probe_controller_input_commit_native_report(uint8_t instance, uint32_t serial) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT || !g_flash_ready) return false;
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
return probe_dualsense_input_commit_native_report(instance, serial);
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
return probe_native_gamepad_input_commit_native_report(instance, serial);
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
if (!g_native_stream || !serial || serial != g_pending_serial ||
|
||||
g_pending_generation != g_wii_generation || !g_wii_active) return false;
|
||||
|
|
@ -543,8 +543,8 @@ extern "C" bool probe_controller_input_play_sample(uint8_t instance, uint8_t sam
|
|||
if (token != nullptr) *token = 0;
|
||||
return false;
|
||||
}
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
return bluepad32_input_backend_dualsense_sample_request(instance, sample_id, token);
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
return bluepad32_input_backend_native_sample_request(instance, sample_id, token);
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
return bluepad32_input_backend_wii_sample_request(sample_id, token);
|
||||
#else
|
||||
|
|
@ -555,9 +555,9 @@ extern "C" bool probe_controller_input_play_sample(uint8_t instance, uint8_t sam
|
|||
|
||||
extern "C" int probe_controller_input_sample_result(uint8_t instance, uint64_t token, uint32_t now_ms) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT || !g_flash_ready) return -1;
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
(void)now_ms;
|
||||
return bluepad32_input_backend_dualsense_sample_result(instance, token);
|
||||
return bluepad32_input_backend_native_sample_result(instance, token);
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
(void)now_ms;
|
||||
return bluepad32_input_backend_wii_sample_result(token);
|
||||
|
|
@ -568,8 +568,8 @@ extern "C" int probe_controller_input_sample_result(uint8_t instance, uint64_t t
|
|||
|
||||
extern "C" void probe_controller_input_cancel_sample(uint8_t instance) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT) return;
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
bluepad32_input_backend_dualsense_sample_cancel(instance);
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
bluepad32_input_backend_native_sample_cancel(instance);
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
bluepad32_input_backend_wii_sample_cancel();
|
||||
#else
|
||||
|
|
@ -584,8 +584,8 @@ extern "C" void probe_controller_input_poll(uint8_t instance, uint32_t now_ms,
|
|||
*out = {};
|
||||
return;
|
||||
}
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
probe_dualsense_input_poll(instance, now_ms, out);
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
probe_native_gamepad_input_poll(instance, now_ms, out);
|
||||
return;
|
||||
#elif SWITCH2_BRIDGE_WII_INPUT
|
||||
poll_wii_source(now_ms);
|
||||
|
|
@ -618,7 +618,7 @@ extern "C" void probe_controller_input_poll(uint8_t instance, uint32_t now_ms,
|
|||
g_input.mouse_surface = 0;
|
||||
}
|
||||
#endif
|
||||
#if !SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if !SWITCH2_BRIDGE_FULL_INPUT
|
||||
*out = g_input;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ void probe_controller_input_set_stick_calibration(const uint8_t calibration[9]);
|
|||
// Native feature changes are output barriers, not Bluetooth/IMU resets.
|
||||
void probe_controller_input_set_native_features(uint8_t features);
|
||||
#endif
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
// Supply each child's advertised, validated nine-byte stick record. Native
|
||||
// output stays unavailable until that child's calibration has been supplied.
|
||||
void probe_controller_input_set_full_stick_calibration(uint8_t instance, const uint8_t calibration[9]);
|
||||
|
|
@ -55,7 +55,7 @@ void probe_controller_input_set_full_stick_calibration(uint8_t instance, const u
|
|||
// Core0 native07/08 output. Disable discards queued/prepared data; repeated
|
||||
// enable preserves it. Joy-Con mode relays its bounded FIFO; right-only Wii
|
||||
// mode synthesizes fresh calibrated sensors and the selected IR pointer.
|
||||
// DualSense mode splits one full controller into independent R/L output streams;
|
||||
// Full-controller mode splits one supported gamepad into independent R/L output streams;
|
||||
// controls remain live while motion is unavailable. Only Wii estimates stationary bias.
|
||||
// No pairing changes.
|
||||
void probe_controller_input_set_native_stream(uint8_t instance, bool enabled);
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "controller_input.h"
|
||||
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
// Core 0 only. One coherent profile/motion evaluation feeds both native children.
|
||||
void probe_dualsense_input_init();
|
||||
void probe_dualsense_input_set_stick_calibration(uint8_t instance, const uint8_t calibration[9]);
|
||||
void probe_dualsense_input_set_native_stream(uint8_t instance, bool enabled);
|
||||
void probe_dualsense_input_poll(uint8_t instance, uint32_t now_ms, probe_controller_input* out);
|
||||
uint32_t probe_dualsense_input_peek_native_report(uint8_t instance, uint32_t now_ms, uint8_t report[63]);
|
||||
bool probe_dualsense_input_commit_native_report(uint8_t instance, uint32_t token);
|
||||
#endif
|
||||
|
|
@ -319,7 +319,7 @@ static void reset_controller_protocol(uint8_t instance) {
|
|||
#if SWITCH2_BRIDGE_WII_INPUT
|
||||
probe_controller_input_set_stick_calibration(stick_calibration);
|
||||
probe_controller_input_set_native_features(0);
|
||||
#elif SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#elif SWITCH2_BRIDGE_FULL_INPUT
|
||||
probe_controller_input_set_full_stick_calibration(instance, stick_calibration);
|
||||
#endif
|
||||
protocol->read_memory = read_memory;
|
||||
|
|
@ -487,8 +487,8 @@ static void protocol_task(probe_usb_controller* controller, uint32_t now) {
|
|||
#if SWITCH2_BRIDGE_WII_INPUT
|
||||
probe_debug_printf("[PROBE] Wii cue dispatched itf=%u token=%" PRIu64 "\n",
|
||||
instance, reply->deferred_token);
|
||||
#elif SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
probe_debug_printf("[PROBE] DualSense cue dispatched itf=%u token=%" PRIu64 "\n",
|
||||
#elif SWITCH2_BRIDGE_FULL_INPUT
|
||||
probe_debug_printf("[PROBE] Native gamepad cue dispatched itf=%u token=%" PRIu64 "\n",
|
||||
instance, reply->deferred_token);
|
||||
#else
|
||||
probe_debug_printf("[PROBE] Source sample ACK itf=%u token=%" PRIu64 "\n",
|
||||
|
|
@ -528,7 +528,7 @@ static void protocol_task(probe_usb_controller* controller, uint32_t now) {
|
|||
native_serial = probe_controller_input_peek_native_report(instance, now, input);
|
||||
if (!native_serial) return;
|
||||
length = sizeof(input);
|
||||
#if SWITCH2_BRIDGE_WII_INPUT || SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if SWITCH2_BRIDGE_WII_INPUT || SWITCH2_BRIDGE_FULL_INPUT
|
||||
input[8] = (uint8_t)(0x30 | ((protocol->enabled_features & 0x20) ? 8 : 0));
|
||||
#endif
|
||||
probe_protocol_gate_native_report(protocol, input);
|
||||
|
|
@ -792,6 +792,8 @@ int main(void) {
|
|||
probe_controller_input_init();
|
||||
#if SWITCH2_BRIDGE_WII_INPUT
|
||||
probe_debug_printf("[PROBE] UART0 GP0=TX, 115200 8N1; selected Wii IR/MotionPlus source enabled\n");
|
||||
#elif SWITCH2_BRIDGE_FULL_INPUT
|
||||
probe_debug_printf("[PROBE] UART0 GP0=TX, 115200 8N1; one supported gamepad feeds the native R/L pair\n");
|
||||
#else
|
||||
probe_debug_printf("[PROBE] UART0 GP0=TX, 115200 8N1; %u selected Joy-Con Bluetooth source(s)\n",
|
||||
PROBE_CONTROLLER_COUNT);
|
||||
|
|
@ -819,6 +821,10 @@ int main(void) {
|
|||
#if SWITCH2_BRIDGE_WII_INPUT
|
||||
probe_debug_printf("[PROBE] Wii IR drives native mouse movement; buttons retain profile mapping; keep Wii still for MotionPlus calibration\n");
|
||||
probe_debug_printf("[PROBE] Hold BOOTSEL2s for pairing; Wii cue feedback uses bounded ERM patterns, not HD audio waveforms\n");
|
||||
#elif SWITCH2_BRIDGE_FULL_INPUT
|
||||
probe_debug_printf("[PROBE] Full gamepad controls on R/L; IMU mask=%u; only Wii requires settling\n",
|
||||
(unsigned)SWITCH2_BRIDGE_IMU_TARGET_MASK);
|
||||
probe_debug_printf("[PROBE] Hold BOOTSEL 2s for Bluetooth pairing (never clears pairings); cues use source capabilities\n");
|
||||
#else
|
||||
probe_debug_printf("[PROBE] Live Joy-Con buttons/stick/native mouse; hold BOOTSEL 2s for Bluetooth pairing (never clears pairings)\n");
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "dualsense_input.h"
|
||||
#include "native_gamepad_input.h"
|
||||
|
||||
#if SWITCH2_BRIDGE_DUALSENSE_INPUT
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
#include "profile/controller_profile_runtime.h"
|
||||
|
||||
#if !SWITCH2_PROBE_HUB || SWITCH2_BRIDGE_WII_INPUT
|
||||
#error "One DualSense requires the native R/L USB hub source mode"
|
||||
#error "A full gamepad source requires the native R/L USB hub"
|
||||
#endif
|
||||
static_assert(PROBE_CONTROLLER_COUNT == 2);
|
||||
extern "C" int probe_debug_printf(const char* format, ...);
|
||||
|
|
@ -40,15 +40,17 @@ struct Child {
|
|||
uint32_t pending_token = 0;
|
||||
uint32_t pending_us = 0;
|
||||
uint32_t pending_ticks = 0;
|
||||
uint32_t pending_motion_sequence = 0;
|
||||
uint32_t pending_accel_sequence = 0;
|
||||
uint32_t pending_gyro_sequence = 0;
|
||||
bool pending_motion = false;
|
||||
uint8_t pending_report[63]{};
|
||||
bool have_committed_motion = false;
|
||||
uint32_t committed_motion_sequence = 0;
|
||||
uint32_t committed_accel_sequence = 0;
|
||||
uint32_t committed_gyro_sequence = 0;
|
||||
uint32_t committed_ticks = 0;
|
||||
};
|
||||
Child g_children[PROBE_CONTROLLER_COUNT];
|
||||
Bluepad32DualSenseBridgeSnapshot g_source;
|
||||
Bluepad32NativeGamepadSnapshot g_source;
|
||||
ControllerProfileTransformResult g_mapped;
|
||||
ProbeNativeMotion g_motion;
|
||||
bool g_active;
|
||||
|
|
@ -78,8 +80,10 @@ void discard_output(Child& child) {
|
|||
child.have_committed_motion = false;
|
||||
}
|
||||
|
||||
bool sensors_fresh(uint32_t now_us) {
|
||||
return g_source.motion_valid && now_us - g_source.motion_received_us < kSensorDeadlineUs;
|
||||
bool sensors_fresh(const Bluepad32NativeGamepadSnapshot& source, uint32_t now_us) {
|
||||
return source.accel_valid && source.gyro_valid &&
|
||||
now_us - source.accel_received_us < kSensorDeadlineUs &&
|
||||
now_us - source.gyro_received_us < kSensorDeadlineUs;
|
||||
}
|
||||
|
||||
void unpack_stick_pair(const uint8_t* bytes, uint16_t pair[2]) {
|
||||
|
|
@ -147,7 +151,7 @@ void lose_source(uint32_t now_ms) {
|
|||
g_motion.reset();
|
||||
for (uint8_t i = 0; i < PROBE_CONTROLLER_COUNT; ++i) {
|
||||
discard_output(g_children[i]);
|
||||
bluepad32_input_backend_dualsense_sample_cancel(i);
|
||||
bluepad32_input_backend_native_sample_cancel(i);
|
||||
}
|
||||
g_sensor_status = -1;
|
||||
}
|
||||
|
|
@ -156,8 +160,8 @@ void lose_source(uint32_t now_ms) {
|
|||
}
|
||||
|
||||
void refresh(uint32_t now_ms) {
|
||||
Bluepad32DualSenseBridgeSnapshot source;
|
||||
bluepad32_input_backend_dualsense_snapshot(&source);
|
||||
Bluepad32NativeGamepadSnapshot source;
|
||||
bluepad32_input_backend_native_snapshot(&source);
|
||||
// Snapshot first: source receipt timestamps must not be ahead of this clock.
|
||||
const uint32_t now_us = time_us_32();
|
||||
advance_clock(now_us);
|
||||
|
|
@ -174,13 +178,15 @@ void refresh(uint32_t now_ms) {
|
|||
// motion evaluation. A real publication in the same millisecond still wins.
|
||||
if (!changed_connection && g_evaluated && g_evaluated_ms == now_ms &&
|
||||
source.state_generation == g_source.state_generation && source.received_us == g_source.received_us &&
|
||||
source.motion_sequence == g_source.motion_sequence &&
|
||||
source.motion_received_us == g_source.motion_received_us && source.motion_valid == g_source.motion_valid) return;
|
||||
source.accel_sequence == g_source.accel_sequence && source.gyro_sequence == g_source.gyro_sequence &&
|
||||
source.accel_received_us == g_source.accel_received_us && source.gyro_received_us == g_source.gyro_received_us &&
|
||||
source.accel_valid == g_source.accel_valid && source.gyro_valid == g_source.gyro_valid &&
|
||||
source.requires_stationary_bias == g_source.requires_stationary_bias) return;
|
||||
if (changed_connection) {
|
||||
lose_source(now_ms);
|
||||
g_motion.reset();
|
||||
for (Child& child : g_children) discard_output(child);
|
||||
probe_debug_printf("[PROBE] DualSense source active in slot %u; using validated factory IMU calibration\n", source.slot);
|
||||
probe_debug_printf("[PROBE] Native gamepad source active in slot %u\n", source.slot);
|
||||
}
|
||||
g_source = source;
|
||||
g_active = true;
|
||||
|
|
@ -194,9 +200,12 @@ void refresh(uint32_t now_ms) {
|
|||
feedback.active_profile_number, feedback.policy);
|
||||
}
|
||||
ProbeNativeMotionSample sample{};
|
||||
sample.accel_valid = sample.gyro_valid = source.motion_valid;
|
||||
sample.accel_sequence = sample.gyro_sequence = source.motion_sequence;
|
||||
sample.accel_us = sample.gyro_us = source.motion_received_us;
|
||||
sample.accel_valid = source.accel_valid;
|
||||
sample.gyro_valid = source.gyro_valid;
|
||||
sample.accel_sequence = source.accel_sequence;
|
||||
sample.gyro_sequence = source.gyro_sequence;
|
||||
sample.accel_us = source.accel_received_us;
|
||||
sample.gyro_us = source.gyro_received_us;
|
||||
// SDL -> upright native body [X,-Z,Y], the same physical transform used by
|
||||
// the Wii adapter before its mouse-mount rotation. Both halves represent
|
||||
// one rigid, full controller: no solo-Joy-Con or mouse mounting rotation.
|
||||
|
|
@ -206,12 +215,15 @@ void refresh(uint32_t now_ms) {
|
|||
sample.gyro_dps[0] = static_cast<float>(source.gyro_q10[0]) / 1024.0f;
|
||||
sample.gyro_dps[1] = -static_cast<float>(source.gyro_q10[2]) / 1024.0f;
|
||||
sample.gyro_dps[2] = static_cast<float>(source.gyro_q10[1]) / 1024.0f;
|
||||
g_motion.update(now_us, source.controller.connection_generation, sample);
|
||||
const int status = !sensors_fresh(now_us) ? 0 : g_motion.ready() ? 2 : 1;
|
||||
g_motion.update(now_us, source.controller.connection_generation, sample,
|
||||
source.requires_stationary_bias ? ProbeNativeMotionBias::kEstimateStationary :
|
||||
ProbeNativeMotionBias::kAlreadyCalibrated);
|
||||
const int status = !sensors_fresh(g_source, now_us) ? 0 : g_motion.ready() ? 2 : 1;
|
||||
if (status != g_sensor_status) {
|
||||
g_sensor_status = status;
|
||||
probe_debug_printf("[PROBE] DualSense native IMU %s\n", status == 2 ? "ready" :
|
||||
status == 1 ? "waiting for a usable acceleration sample" : "waiting for fresh complete sensors");
|
||||
probe_debug_printf("[PROBE] Native gamepad IMU %s\n", status == 2 ? "ready" :
|
||||
status == 1 ? (source.requires_stationary_bias ? "Wii calibrating: keep still" :
|
||||
"waiting for a usable acceleration sample") : "waiting for supported fresh sensors");
|
||||
}
|
||||
for (uint8_t i = 0; i < PROBE_CONTROLLER_COUNT; ++i) {
|
||||
// Latest-only: a blocked endpoint never queues obsolete controls/IMU.
|
||||
|
|
@ -221,15 +233,15 @@ void refresh(uint32_t now_ms) {
|
|||
}
|
||||
} // namespace
|
||||
|
||||
void probe_dualsense_input_init() {
|
||||
void probe_native_gamepad_input_init() {
|
||||
#if SWITCH2_BRIDGE_SOURCE_AUTO
|
||||
bluepad32_input_backend_select_dualsense_source(nullptr);
|
||||
bluepad32_input_backend_select_native_source(nullptr);
|
||||
#else
|
||||
bluepad32_input_backend_select_dualsense_source(kSourceAddress);
|
||||
bluepad32_input_backend_select_native_source(kSourceAddress);
|
||||
#endif
|
||||
}
|
||||
|
||||
void probe_dualsense_input_set_stick_calibration(uint8_t instance, const uint8_t calibration[9]) {
|
||||
void probe_native_gamepad_input_set_stick_calibration(uint8_t instance, const uint8_t calibration[9]) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT) return;
|
||||
Child& child = g_children[instance];
|
||||
child.calibrated = false;
|
||||
|
|
@ -248,30 +260,31 @@ void probe_dualsense_input_set_stick_calibration(uint8_t instance, const uint8_t
|
|||
pack_controls(instance);
|
||||
}
|
||||
|
||||
void probe_dualsense_input_set_native_stream(uint8_t instance, bool enabled) {
|
||||
void probe_native_gamepad_input_set_native_stream(uint8_t instance, bool enabled) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT) return;
|
||||
Child& child = g_children[instance];
|
||||
if (child.enabled != enabled || !enabled) discard_output(child);
|
||||
child.enabled = enabled;
|
||||
if (!enabled) bluepad32_input_backend_dualsense_sample_cancel(instance);
|
||||
if (!enabled) bluepad32_input_backend_native_sample_cancel(instance);
|
||||
}
|
||||
|
||||
void probe_dualsense_input_poll(uint8_t instance, uint32_t now_ms, probe_controller_input* out) {
|
||||
void probe_native_gamepad_input_poll(uint8_t instance, uint32_t now_ms, probe_controller_input* out) {
|
||||
if (!out) return;
|
||||
if (instance >= PROBE_CONTROLLER_COUNT) { *out = {}; return; }
|
||||
refresh(now_ms);
|
||||
*out = g_children[instance].input;
|
||||
}
|
||||
|
||||
uint32_t probe_dualsense_input_peek_native_report(uint8_t instance, uint32_t now_ms, uint8_t report[63]) {
|
||||
uint32_t probe_native_gamepad_input_peek_native_report(uint8_t instance, uint32_t now_ms, uint8_t report[63]) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT || !report) return 0;
|
||||
refresh(now_ms);
|
||||
Child& child = g_children[instance];
|
||||
if (!child.enabled || !child.input.active) return 0;
|
||||
const uint32_t now_us = time_us_32();
|
||||
const bool motion_ready = (SWITCH2_BRIDGE_IMU_TARGET_MASK & (1u << instance)) != 0 &&
|
||||
g_motion.ready() && sensors_fresh(now_us) &&
|
||||
(!child.have_committed_motion || child.committed_motion_sequence != g_source.motion_sequence);
|
||||
g_motion.ready() && sensors_fresh(g_source, now_us) &&
|
||||
(!child.have_committed_motion || child.committed_accel_sequence != g_source.accel_sequence ||
|
||||
child.committed_gyro_sequence != g_source.gyro_sequence);
|
||||
if (child.pending_token && (now_us - child.pending_us >= kOutputDeadlineUs ||
|
||||
child.pending_motion != motion_ready)) child.pending_token = 0;
|
||||
if (!child.pending_token) {
|
||||
|
|
@ -293,7 +306,8 @@ uint32_t probe_dualsense_input_peek_native_report(uint8_t instance, uint32_t now
|
|||
g_motion.quaternion(), g_motion.acceleration(), static_cast<uint16_t>(child.pending_ticks & 0xfff),
|
||||
wire_elapsed, 0, child.pending_report + probe_model_imu_data_offset(instance));
|
||||
if (child.pending_motion) child.pending_report[probe_model_imu_length_offset(instance)] = 30;
|
||||
child.pending_motion_sequence = g_source.motion_sequence;
|
||||
child.pending_accel_sequence = g_source.accel_sequence;
|
||||
child.pending_gyro_sequence = g_source.gyro_sequence;
|
||||
child.pending_us = now_us;
|
||||
child.pending_token = ++g_report_token;
|
||||
}
|
||||
|
|
@ -301,27 +315,28 @@ uint32_t probe_dualsense_input_peek_native_report(uint8_t instance, uint32_t now
|
|||
return child.pending_token;
|
||||
}
|
||||
|
||||
bool probe_dualsense_input_commit_native_report(uint8_t instance, uint32_t token) {
|
||||
bool probe_native_gamepad_input_commit_native_report(uint8_t instance, uint32_t token) {
|
||||
if (instance >= PROBE_CONTROLLER_COUNT || !token) return false;
|
||||
Child& child = g_children[instance];
|
||||
// Check the live source even when the caller did not poll after a disconnect.
|
||||
Bluepad32DualSenseBridgeSnapshot source;
|
||||
bluepad32_input_backend_dualsense_snapshot(&source);
|
||||
Bluepad32NativeGamepadSnapshot source;
|
||||
bluepad32_input_backend_native_snapshot(&source);
|
||||
const uint32_t now_us = time_us_32();
|
||||
if (!child.enabled || !g_active || child.pending_token != token ||
|
||||
!source.controller.active || source.slot != g_source.slot ||
|
||||
source.controller.connection_generation != g_source.controller.connection_generation ||
|
||||
source.state_generation != g_source.state_generation ||
|
||||
source.motion_sequence != g_source.motion_sequence ||
|
||||
source.motion_received_us != g_source.motion_received_us ||
|
||||
source.motion_valid != g_source.motion_valid ||
|
||||
source.accel_sequence != g_source.accel_sequence || source.gyro_sequence != g_source.gyro_sequence ||
|
||||
source.accel_received_us != g_source.accel_received_us || source.gyro_received_us != g_source.gyro_received_us ||
|
||||
source.accel_valid != g_source.accel_valid || source.gyro_valid != g_source.gyro_valid ||
|
||||
source.requires_stationary_bias != g_source.requires_stationary_bias ||
|
||||
now_us - source.received_us >= kInputDeadlineUs || now_us - child.pending_us >= kOutputDeadlineUs ||
|
||||
(child.pending_motion && (!source.motion_valid ||
|
||||
now_us - g_source.motion_received_us >= kSensorDeadlineUs))) return false;
|
||||
(child.pending_motion && !sensors_fresh(source, now_us))) return false;
|
||||
child.pending_token = 0;
|
||||
if (child.pending_motion) {
|
||||
child.have_committed_motion = true;
|
||||
child.committed_motion_sequence = child.pending_motion_sequence;
|
||||
child.committed_accel_sequence = child.pending_accel_sequence;
|
||||
child.committed_gyro_sequence = child.pending_gyro_sequence;
|
||||
child.committed_ticks = child.pending_ticks;
|
||||
}
|
||||
++child.counter;
|
||||
13
tools/switch2_usb_probe/native_gamepad_input.h
Normal file
13
tools/switch2_usb_probe/native_gamepad_input.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "controller_input.h"
|
||||
|
||||
#if SWITCH2_BRIDGE_FULL_INPUT
|
||||
// Core 0 only. One coherent profile/motion evaluation feeds both native children.
|
||||
void probe_native_gamepad_input_init();
|
||||
void probe_native_gamepad_input_set_stick_calibration(uint8_t instance, const uint8_t calibration[9]);
|
||||
void probe_native_gamepad_input_set_native_stream(uint8_t instance, bool enabled);
|
||||
void probe_native_gamepad_input_poll(uint8_t instance, uint32_t now_ms, probe_controller_input* out);
|
||||
uint32_t probe_native_gamepad_input_peek_native_report(uint8_t instance, uint32_t now_ms, uint8_t report[63]);
|
||||
bool probe_native_gamepad_input_commit_native_report(uint8_t instance, uint32_t token);
|
||||
#endif
|
||||
|
|
@ -25,8 +25,8 @@ else()
|
|||
endif()
|
||||
if(SWITCH2_PROBE_COMPOSITE OR SWITCH2_PROBE_HUB)
|
||||
if(NOT SWITCH_PICO_SWITCH2_USB_BRIDGE OR SWITCH2_BRIDGE_WII_INPUT
|
||||
OR (NOT SWITCH2_BRIDGE_INPUT STREQUAL "JOYCON2" AND NOT SWITCH2_BRIDGE_DUALSENSE_INPUT))
|
||||
message(FATAL_ERROR "Native R/L output requires JOYCON2 input, or DUALSENSE with HUB")
|
||||
OR (NOT SWITCH2_BRIDGE_INPUT STREQUAL "JOYCON2" AND NOT SWITCH2_BRIDGE_FULL_INPUT))
|
||||
message(FATAL_ERROR "Native R/L output requires JOYCON2 input or a full-controller HUB source")
|
||||
endif()
|
||||
set(probe_composite 0)
|
||||
if(SWITCH2_PROBE_COMPOSITE)
|
||||
|
|
@ -54,10 +54,10 @@ set(SWITCH2_BRIDGE_SECOND_SOURCE_ADDRESS "" CACHE STRING
|
|||
set(SWITCH2_BRIDGE_SOURCE_AUTO OFF)
|
||||
if(SWITCH_PICO_SWITCH2_USB_BRIDGE OR SWITCH2_PROBE_COMPOSITE)
|
||||
set(probe_source_fields SWITCH2_BRIDGE_SOURCE_ADDRESS)
|
||||
if(SWITCH2_BRIDGE_DUALSENSE_INPUT AND SWITCH2_BRIDGE_SOURCE_ADDRESS STREQUAL "")
|
||||
if(SWITCH2_BRIDGE_FULL_INPUT AND SWITCH2_BRIDGE_SOURCE_ADDRESS STREQUAL "")
|
||||
set(SWITCH2_BRIDGE_SOURCE_AUTO ON)
|
||||
set(probe_source_fields "")
|
||||
elseif((SWITCH2_PROBE_COMPOSITE OR SWITCH2_PROBE_HUB) AND NOT SWITCH2_BRIDGE_DUALSENSE_INPUT)
|
||||
elseif((SWITCH2_PROBE_COMPOSITE OR SWITCH2_PROBE_HUB) AND NOT SWITCH2_BRIDGE_FULL_INPUT)
|
||||
list(APPEND probe_source_fields SWITCH2_BRIDGE_SECOND_SOURCE_ADDRESS)
|
||||
endif()
|
||||
set(probe_source_addresses "")
|
||||
|
|
@ -367,11 +367,11 @@ function(switch2_usb_probe_configure target)
|
|||
else()
|
||||
pico_set_program_name(${target} "Switch 2 USB initialization capture")
|
||||
endif()
|
||||
if(SWITCH2_PROBE_HUB AND SWITCH2_BRIDGE_DUALSENSE_INPUT)
|
||||
if(SWITCH2_PROBE_HUB AND SWITCH2_BRIDGE_FULL_INPUT)
|
||||
if(SWITCH2_PROBE_TRACE_NATIVE_INPUT)
|
||||
pico_set_program_version(${target} "0.69-native-hub-imu-trace")
|
||||
pico_set_program_version(${target} "0.70-native-gamepad-trace")
|
||||
else()
|
||||
pico_set_program_version(${target} "0.69-native-hub-imu")
|
||||
pico_set_program_version(${target} "0.70-native-gamepad")
|
||||
endif()
|
||||
elseif(SWITCH2_PROBE_HUB)
|
||||
pico_set_program_version(${target} "0.67-native-hub-latency")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue