switch-pico/tests/test_haptics_experiment_native.py
Joey Yakimowich-Payne 80b788099b feat(native-usb): add 32-frame HD gameplay rumble and USB flight diagnostics
Preserve native frequency/amplitude timelines for DualSense PCM output,
remove the unsupported 64-frame path, and retain compatibility rumble for
other controllers. Use the validated 300 MHz sampling phase and restrict
non-bondable Classic discovery autoconnect to previously paired peers.

Buffer native-hub UART stdout and release USB IRQs around port-reset
callbacks. Add observer liveness and pre-SETUP root-response observations
without changing recovery behavior. Cover transport and haptics boundaries.

Record the user-accepted 0.108 trial: controls remained responsive and
rumble felt fine. Instrumentation changes timing; the disconnect root
cause and long-term reliability remain unqualified.

Validation: 624 tests, 11 affected firmware/probe builds, and on-device
concurrent USB and HD-auto-start checks. Private captures, generated
images, and unrelated working-tree files are intentionally excluded.
2026-09-19 17:03:46 -06:00

51 lines
2 KiB
Python

import shutil
import subprocess
import zlib
from pathlib import Path
import pytest
@pytest.mark.parametrize("ram", [0, 1], ids=["flash", "sram"])
def test_haptics_experiment_native(tmp_path: Path, ram: int) -> None:
root = Path(__file__).resolve().parents[1]
compiler = shutil.which("c++") or shutil.which("g++")
assert compiler is not None, "a host C++ compiler is required"
executable = tmp_path / "haptics_experiment_test"
corpus = tmp_path / "native_reports.bin"
subprocess.run(
[
compiler,
"-std=c++17",
"-O2",
"-Wall",
"-Wextra",
"-Werror",
"-pedantic",
"-DSWITCH_PICO_HAPTICS_EXPERIMENT=1",
f"-DSWITCH_PICO_HAPTICS_EXPERIMENT_RAM={ram}",
"-DSWITCH_PICO_HD_PACKET_FRAMES=32",
"-DSWITCH_PICO_CYW43_PACKET_READ=1",
"-DSWITCH_PICO_HCI_CREDIT_BATCH=1",
"-DSWITCH_PICO_SYS_CLOCK_MHZ=300",
f"-I{root / 'tests' / 'haptics_experiment_native_stubs'}",
f"-I{root / 'src' / 'firmware'}",
str(root / "tests" / "haptics_experiment_test.cpp"),
str(root / "src" / "firmware" / "input" / "haptics_experiment.cpp"),
str(root / "src" / "firmware" / "input" / "native_output_scheduler.cpp"),
str(root / "src" / "firmware" / "input" / "switch_hd_rumble_synth.cpp"),
str(root / "src" / "firmware" / "usb" / "switch" / "switch_haptics.cpp"),
"-o",
str(executable),
],
check=True,
cwd=root,
)
subprocess.run([str(executable), str(corpus)], check=True, cwd=root)
reports = corpus.read_bytes()
assert len(reports) == (18432 // 32) * 143
# Independent standard-library CRC across real module-generated packets:
# A2 is covered once, CRC itself excluded, and stored little-endian.
for offset in range(0, len(reports), 143):
report = reports[offset : offset + 143]
assert int.from_bytes(report[-4:], "little") == zlib.crc32(report[:-4])