swbt-python 0.5.0__tar.gz → 0.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swbt_python-0.5.0 → swbt_python-0.5.1}/PKG-INFO +5 -6
- {swbt_python-0.5.0 → swbt_python-0.5.1}/README.md +4 -5
- {swbt_python-0.5.0 → swbt_python-0.5.1}/pyproject.toml +1 -1
- swbt_python-0.5.1/spec/complete/unit_068/DIRECT_PRE_CLOSE_INPUT_REFLECTION.md +143 -0
- swbt_python-0.5.1/spec/complete/unit_069/CONTROLLER_HANDSHAKE_READINESS.md +370 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/hardware-test-log.md +58 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/api.md +6 -1
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/lifecycle.md +29 -9
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/protocol.md +9 -2
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/testing.md +11 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/connection.py +15 -5
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/core.py +11 -11
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/output.py +28 -1
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/runtime.py +206 -37
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/profiles/base.py +1 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/profiles/joycon.py +3 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/session.py +26 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/subcommand.py +36 -5
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/report_loop.py +13 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/fake.py +10 -1
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_pairing_profile.py +414 -3
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/integration/test_examples.py +4 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/integration/test_switch_gamepad_fake_transport.py +494 -68
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/fixtures/source_audit/switch_protocol_values.toml +30 -1
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_protocol_session.py +64 -1
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_public_api_boundary.py +24 -2
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_source_audit_fixtures.py +2 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_subcommand_responder.py +23 -1
- {swbt_python-0.5.0 → swbt_python-0.5.1}/AGENTS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/LICENSE +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/examples/hardware_bringup.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/examples/pairing_probe.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/examples/tap_a.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_001/M0_PROTOCOL_CORE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_002/M1_SWITCH_GAMEPAD_FAKE_TRANSPORT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_003/M2_BUMBLE_HID_TRANSPORT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_004/M3_PAIRING_L2CAP.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_005/M4_SUBCOMMAND_RESPONDER_HARDWARE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_006/M5_INPUT_OPERATION_API.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_007/M6_RECONNECT_KEYSTORE_DIAGNOSTICS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_008/M7_PACKAGING_EXAMPLES_CLI.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_009/PORTING_SOURCE_AUDIT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_010/DIAGNOSTICS_TRACE_SCHEMA.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_011/HARDWARE_TEST_LOG_MATRIX.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_012/INITIAL_RELEASE_GATE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_013/POST_M5_INPUT_SEMANTIC_CHARACTERIZATION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_014/DEVICE_CLOSE_GRACEFUL_DISCONNECT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_015/CONTEXT_MANAGER_RESOURCE_SCOPE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_016/JSON_KEY_STORE_CURRENT_PREVIOUS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_017/SWITCH_GAMEPAD_API_HARDENING.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_018/KEY_STORE_TRANSPORT_BOUNDARY.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_019/TRANSPORT_RECONNECT_CONTRACT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_020/STRUCTURAL_REFACTOR_BOUNDARIES.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_021/SWITCH_GAMEPAD_INPUT_API_CONTRACT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_022/PUBLIC_API_USAGE_HARDWARE_DOCS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_023/MKDOCS_DOCUMENTATION_SITE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_024/STICK_INPUT_SHORTHAND_API.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_025/IMU_INPUT_SHORTHAND_API.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_026/LINUX_MACOS_ADAPTER_EXPERIMENTAL.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_027/ADAPTER_DISCOVERY_API.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_028/CONTROLLER_PROFILE_CUSTOMIZATION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_029/CONTROLLER_PROFILE_INJECTION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_030/JOYCON_PROFILE_IDENTITY_SPI.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_031/JOYCON_INPUT_REPORT_MAPPING.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_032/PROFILE_AWARE_SUBCOMMAND_STATE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_033/PROFILE_AWARE_BUMBLE_SDP.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_034/JOYCON_CONVENIENCE_API_DOCS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_035/JOYCON_DEVICE_INFO_ADDRESS_WIRING.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_036/JOYCON_SDP_IDENTITY_POLICY.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_037/JOYCON_DEFAULT_CONTROLLER_COLORS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_038/REARCHITECTURE_DECISION_BOUNDARY_TESTS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_039/CONTROLLER_RUNTIME_EXTRACTION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_040/PUBLIC_CONTROLLER_API_MODEL.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_041/CONTROLLER_CONFIG_PROFILE_OWNERSHIP.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_042/INTERNAL_TRANSPORT_FACTORY.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_043/PROTOCOL_PROFILE_MODULE_SPLIT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_044/REARCHITECTURE_DOCS_RELEASE_MATRIX.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_045/INTERNAL_API_BOUNDARY_CLEANUP.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_046/HARDWARE_PROFILE_TEST_SCENARIOS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_047/VIRTUAL_GYRO_CALIBRATION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_048/VIRTUAL_ACCELEROMETER_CALIBRATION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_049/IMU_SESSION_AND_ENCODING_REDESIGN.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_050/DIRECT_REPORTING_TYPES.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_051/CSR_BD_ADDR_REWRITE_EXPERIMENT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_052/EXP_LOCAL_ADDRESS_PROFILE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_053/EXP_LOCAL_ADDRESS_PROFILE_JOYCON.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_054/EXP_LOCAL_ADDRESS_PROFILE_DIRECT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_055/REMOVE_NATIVE_KEY_STORE_API.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_058/MULTI_ADDRESS_RECONNECT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_059/EXPERIMENTAL_DIRECT_SEND_TIMING_PROBE.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_060/HCI_ACL_COMPLETION_CORRELATION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_061/EXPERIMENTAL_CLASSIC_LINK_POLICY_AB.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_062/PERIODIC_ACL_DRAIN_CHARACTERIZATION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_063/PERIODIC_NO_DRAIN_CHARACTERIZATION.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_064/BUMBLE_ENQUEUE_COMPLETION_CONTRACT.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_065/PERIODIC_DEADLINE_SCHEDULER.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_066/PAIRING_PROFILE_DEFAULT_ADDRESS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/complete/unit_067/DEFAULT_BATTERY_STATUS.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/dev-journal.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/README.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/architecture.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/naming.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/risks.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/roadmap.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/initial/transport-bumble.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/rearchitecture/01-design-change-overview.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/rearchitecture/02-as-is-to-be.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/rearchitecture/03-public-api-config-profile.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/rearchitecture/04-runtime-profile-transport-details.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/rearchitecture/05-milestones-implementation.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/rearchitecture/README.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/rearchitecture/mkdocs-nav-snippet.yml +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/wip/unit_056/PAIRING_PROFILE_NAMING.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/spec/wip/unit_057/PAIRING_PROFILE_CONTROLLER_KIND.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/__init__.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/_testing/__init__.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/_testing/gamepad.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/adapter_discovery.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/diagnostics.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/errors.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/__init__.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/_config.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/constants.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/interface.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/gamepad/transport_factory.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/imu.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/input.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/probe.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/__init__.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/buttons.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/descriptors.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/imu_report.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/input_report.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/output_report.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/profiles/__init__.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/profiles/pro_controller.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/rumble.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/protocol/spi.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/py.typed +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/state_store.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/__init__.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_adapter_identity.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_bumble_acl.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_bumble_hidp.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_bumble_key_store.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_bumble_lifecycle.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_bumble_sdp.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_bumble_usb_devices.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_csr_bd_addr.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_csr_bd_addr_harness.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/_pairing_profile.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/base.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/src/swbt/transport/bumble.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/conftest.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/README.md +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_battery_status.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_bumble_transport.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_close_disconnect.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_context_manager_resource_scope.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_controller_colors.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_multi_address_reconnect.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/hardware/test_pairing_l2cap.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/integration/test_pairing_profile.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_adapter_discovery.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_adapter_identity.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_bumble_acl.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_bumble_hidp.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_bumble_lifecycle.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_bumble_sdp.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_bumble_transport.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_ci_workflow.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_csr_bd_addr_experiment.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_csr_bd_addr_harness.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_diagnostics.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_gamepad_connection_workflow.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_gamepad_output_dispatcher.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_gamepad_transport_factory.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_imu_report.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_input_report.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_input_state.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_output_report.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_package_import.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_package_metadata.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_pairing_profile.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_pairing_profile_runtime.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_probe_cli.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_protocol_boundary.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_protocol_profile.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_publish_workflow.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_report_loop.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_rumble_state.py +0 -0
- {swbt_python-0.5.0 → swbt_python-0.5.1}/tests/unit/test_virtual_spi_flash.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swbt-python
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Python library for presenting an NX-compatible virtual Bluetooth HID input device.
|
|
5
5
|
Keywords: bluetooth,bluetooth-hid,controller,gamepad,hid,nx
|
|
6
6
|
Author: niart120
|
|
@@ -55,7 +55,7 @@ uv sync --dev
|
|
|
55
55
|
- [API リファレンス](https://niart120.github.io/swbt-python/api/)
|
|
56
56
|
- [利用例](https://niart120.github.io/swbt-python/usage/)
|
|
57
57
|
- [実機準備手順](https://niart120.github.io/swbt-python/hardware/)
|
|
58
|
-
- [
|
|
58
|
+
- [AI エージェント向け要約](https://niart120.github.io/swbt-python/agent-brief/)
|
|
59
59
|
|
|
60
60
|
同じ内容は `docs/` 配下でも確認できます。
|
|
61
61
|
|
|
@@ -96,7 +96,6 @@ async def main() -> None:
|
|
|
96
96
|
profile_path="switch-left-joycon-profile.json",
|
|
97
97
|
) as left:
|
|
98
98
|
await left.connect(timeout=30.0, allow_pairing=True)
|
|
99
|
-
await left.tap(Button.SR, Button.SL)
|
|
100
99
|
await left.tap(Button.L)
|
|
101
100
|
await left.lstick(Stick.left())
|
|
102
101
|
await left.neutral()
|
|
@@ -105,7 +104,7 @@ async def main() -> None:
|
|
|
105
104
|
asyncio.run(main())
|
|
106
105
|
```
|
|
107
106
|
|
|
108
|
-
「持ちかた/順番を変える」画面で Joy-Con
|
|
107
|
+
「持ちかた/順番を変える」画面で Joy-Con としてペアリングする場合も、接続後に登録用の SR+SL 入力を追加送信する必要はありません。ライブラリは Joy-Con 用の初期化応答を返し、0 以外のプレイヤーライトが設定されるまで `connect()` を完了しません。Joy-Con L/R の `Button.SL` と `Button.SR` は、接続後に利用者が送る通常のボタン入力として引き続き利用できます。
|
|
109
108
|
|
|
110
109
|
Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetooth アドレスの選択方法とペアリングキーをまとめる `profile_path` を使います。新規プロファイルは各具象クラスの `create_profile()` で作成し、コントローラー形状と対象機器ごとに保存先を分けてください。v0.4.0 の `key_store_path` で使用していた JSON 形式のペアリング情報との互換経路はありません。Joy-Con L で右スティックや A/B/X/Y、Joy-Con R で左スティックや十字キーを入力すると `UnsupportedInputError` が送出されます。`JoyConPair` は未実装です。
|
|
111
110
|
|
|
@@ -117,9 +116,9 @@ Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetoo
|
|
|
117
116
|
|
|
118
117
|
### 確認済み構成
|
|
119
118
|
|
|
120
|
-
2026-07-
|
|
119
|
+
2026-07-24 時点では、Windows 11 / CSR8510 A10 / WinUSB / `usb:0` で、Pro Controller、Joy-Con L、Joy-Con R の初回ペアリング、保存済みプロファイルを使う再接続、初期化完了後のオブジェクト返却を確認済みです。Joy-Con L/R は、登録用の SR+SL 入力を追加送信せずに初期化を完了しました。
|
|
121
120
|
|
|
122
|
-
同じ Windows 構成で、Joy-Con L/R
|
|
121
|
+
同じ Windows 構成で、Pro Controller の主要なボタン / スティック入力、ニュートラル復帰と、Joy-Con L/R の対応ボタン / スティック入力も確認しています。確認済み範囲と未確認範囲の詳細は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)にあります。
|
|
123
122
|
|
|
124
123
|
macOS 15.7.7 / CSR8510 A10 では、Pro Controller のペアリング、保存済みペアリング情報を使う再接続、ボタン入力、ニュートラル復帰を記録しています。
|
|
125
124
|
|
|
@@ -29,7 +29,7 @@ uv sync --dev
|
|
|
29
29
|
- [API リファレンス](https://niart120.github.io/swbt-python/api/)
|
|
30
30
|
- [利用例](https://niart120.github.io/swbt-python/usage/)
|
|
31
31
|
- [実機準備手順](https://niart120.github.io/swbt-python/hardware/)
|
|
32
|
-
- [
|
|
32
|
+
- [AI エージェント向け要約](https://niart120.github.io/swbt-python/agent-brief/)
|
|
33
33
|
|
|
34
34
|
同じ内容は `docs/` 配下でも確認できます。
|
|
35
35
|
|
|
@@ -70,7 +70,6 @@ async def main() -> None:
|
|
|
70
70
|
profile_path="switch-left-joycon-profile.json",
|
|
71
71
|
) as left:
|
|
72
72
|
await left.connect(timeout=30.0, allow_pairing=True)
|
|
73
|
-
await left.tap(Button.SR, Button.SL)
|
|
74
73
|
await left.tap(Button.L)
|
|
75
74
|
await left.lstick(Stick.left())
|
|
76
75
|
await left.neutral()
|
|
@@ -79,7 +78,7 @@ async def main() -> None:
|
|
|
79
78
|
asyncio.run(main())
|
|
80
79
|
```
|
|
81
80
|
|
|
82
|
-
「持ちかた/順番を変える」画面で Joy-Con
|
|
81
|
+
「持ちかた/順番を変える」画面で Joy-Con としてペアリングする場合も、接続後に登録用の SR+SL 入力を追加送信する必要はありません。ライブラリは Joy-Con 用の初期化応答を返し、0 以外のプレイヤーライトが設定されるまで `connect()` を完了しません。Joy-Con L/R の `Button.SL` と `Button.SR` は、接続後に利用者が送る通常のボタン入力として引き続き利用できます。
|
|
83
82
|
|
|
84
83
|
Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetooth アドレスの選択方法とペアリングキーをまとめる `profile_path` を使います。新規プロファイルは各具象クラスの `create_profile()` で作成し、コントローラー形状と対象機器ごとに保存先を分けてください。v0.4.0 の `key_store_path` で使用していた JSON 形式のペアリング情報との互換経路はありません。Joy-Con L で右スティックや A/B/X/Y、Joy-Con R で左スティックや十字キーを入力すると `UnsupportedInputError` が送出されます。`JoyConPair` は未実装です。
|
|
85
84
|
|
|
@@ -91,9 +90,9 @@ Pro Controller、周期送信型 Joy-Con、直接送信型はすべて、Bluetoo
|
|
|
91
90
|
|
|
92
91
|
### 確認済み構成
|
|
93
92
|
|
|
94
|
-
2026-07-
|
|
93
|
+
2026-07-24 時点では、Windows 11 / CSR8510 A10 / WinUSB / `usb:0` で、Pro Controller、Joy-Con L、Joy-Con R の初回ペアリング、保存済みプロファイルを使う再接続、初期化完了後のオブジェクト返却を確認済みです。Joy-Con L/R は、登録用の SR+SL 入力を追加送信せずに初期化を完了しました。
|
|
95
94
|
|
|
96
|
-
同じ Windows 構成で、Joy-Con L/R
|
|
95
|
+
同じ Windows 構成で、Pro Controller の主要なボタン / スティック入力、ニュートラル復帰と、Joy-Con L/R の対応ボタン / スティック入力も確認しています。確認済み範囲と未確認範囲の詳細は[実機準備手順](https://niart120.github.io/swbt-python/hardware/)にあります。
|
|
97
96
|
|
|
98
97
|
macOS 15.7.7 / CSR8510 A10 では、Pro Controller のペアリング、保存済みペアリング情報を使う再接続、ボタン入力、ニュートラル復帰を記録しています。
|
|
99
98
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Direct close 前入力反映観測 仕様書
|
|
2
|
+
|
|
3
|
+
## 1. 概要
|
|
4
|
+
|
|
5
|
+
### 1.1 目的
|
|
6
|
+
|
|
7
|
+
Direct controller の実機テストで、入力送信後に `close()` へ進む前の観測窓を設ける。通常送信中は入力が Switch へ届かず、切断前の ACL queue drain で初めて送られる退行を、従来の local state assertion だけで成功扱いしない。
|
|
8
|
+
|
|
9
|
+
### 1.2 起点 / source
|
|
10
|
+
|
|
11
|
+
| source | 内容 | path |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| external review / user request | Direct pairing 実機テストは `send()` 後に local state だけを確認して直ちに `close()` するため、close 前の Switch 入力反映を確認できない | `tests/hardware/test_pairing_profile.py` |
|
|
14
|
+
| current transport contract | Direct の成功と `report_tx` は Bumble enqueue 受理を表し、Switch 反映を表さない。切断時は pending ACL queue を drain する | `spec/complete/unit_064/BUMBLE_ENQUEUE_COMPLETION_CONTRACT.md` |
|
|
15
|
+
|
|
16
|
+
### 1.3 use case
|
|
17
|
+
|
|
18
|
+
| actor / boundary | 入力または状態 | 期待する観測結果 | 制約 |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| hardware test operator | Switch の入力確認画面を開き、Direct controller の sentinel button を送信する | `close()` 開始前の観測窓で対象 button が表示される | 画面反映は pytest だけでは判定せず、利用者確認を hardware log に記録する |
|
|
21
|
+
| transport regression | 通常 send の queue が close まで進行しない | pytest の trace 順序は通っても、close 前の Switch 画面確認が失敗する | close 時 drain による遅延送信を成功根拠にしない |
|
|
22
|
+
|
|
23
|
+
## 2. 対象範囲
|
|
24
|
+
|
|
25
|
+
- Direct Pro Controller / Joy-Con L / Joy-Con R の fresh pairing 実機テスト。
|
|
26
|
+
- 実機 gate は Direct Pro / Button A の代表ケースを先に実行する。
|
|
27
|
+
- Direct input の enqueue 後、neutral と `close()` の前に設ける手動観測窓。
|
|
28
|
+
- operator の準備条件、期待 button、観測窓完了、close 開始、cleanup を trace に記録する。
|
|
29
|
+
- pytest pass と Switch UI の目視結果を別の証拠として扱う。
|
|
30
|
+
|
|
31
|
+
## 3. 対象外
|
|
32
|
+
|
|
33
|
+
- `send()` を controller completion や Switch 反映まで待つ API への変更。
|
|
34
|
+
- Bumble `DataPacketQueue` の内部計測や production diagnostics の追加。
|
|
35
|
+
- CI での実機入力反映検証。
|
|
36
|
+
- report bytes、button bit、controller profile の変更。
|
|
37
|
+
- active reconnect の入力反映。今回の起点は fresh pairing test の acceptance gap であり、reconnect は別検証とする。
|
|
38
|
+
|
|
39
|
+
## 4. 関連 docs
|
|
40
|
+
|
|
41
|
+
- `spec/initial/api.md`
|
|
42
|
+
- `spec/initial/lifecycle.md`
|
|
43
|
+
- `spec/initial/testing.md`
|
|
44
|
+
- `spec/complete/unit_050/DIRECT_REPORTING_TYPES.md`
|
|
45
|
+
- `spec/complete/unit_054/EXP_LOCAL_ADDRESS_PROFILE_DIRECT.md`
|
|
46
|
+
- `spec/complete/unit_064/BUMBLE_ENQUEUE_COMPLETION_CONTRACT.md`
|
|
47
|
+
- `tests/hardware/README.md`
|
|
48
|
+
|
|
49
|
+
## 5. 根拠監査
|
|
50
|
+
|
|
51
|
+
| 項目 | 要否 | 状態 | 根拠 / 理由 |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| Switch HID / report bytes | not applicable | not applicable | 既存の sentinel `InputState` と report builder を変更しない |
|
|
54
|
+
| Bumble / transport | required | done | unit_064 の enqueue 受理と disconnect 前 drain 契約を利用する。新しい transport 仮定は追加しない |
|
|
55
|
+
| OS / driver / adapter | required | done | Windows 11、専用 `usb:0`、CSR8510 A10、WinUSB、Bumble 0.0.230、Python 3.13.5 で代表ケースを実行し、`spec/hardware-test-log.md` に記録した |
|
|
56
|
+
|
|
57
|
+
## 6. 振る舞い仕様
|
|
58
|
+
|
|
59
|
+
| 振る舞い | 入力・状態 | 期待結果 | 備考 |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| operator preparation | Direct fresh pairing を開始する | Switch の controller search / change grip order 画面、controller、button、観測秒数を trace と stderr に出す | 画面準備なしの run は input reflection の根拠にしない |
|
|
62
|
+
| pre-close observation | `send(sentinel_state)` が正常終了する | local state と direct `report_tx` を確認し、neutral / close を呼ばず観測窓を維持する | `report_tx` 自体は enqueue 受理だけを表す |
|
|
63
|
+
| cleanup ordering | 観測窓が完了する | 観測窓完了後に初めて `close(neutral=True)` を開始する | button pressed を残さない |
|
|
64
|
+
| evidence classification | pytest が pass する | enqueue、trace 順序、profile、cleanup の成功として扱う | Switch UI は利用者確認が記録された場合だけ observed-pass |
|
|
65
|
+
|
|
66
|
+
## 7. TDD Test List
|
|
67
|
+
|
|
68
|
+
| status | item | type | layer | hardware | notes |
|
|
69
|
+
|---|---|---|---|---|---|
|
|
70
|
+
| green | fresh pairing の Direct input は close 前の観測窓を完了してから neutral close する | regression | hardware | yes | Pro / Button A の代表ケースが `1 passed in 33.27s`。Joy-Con L / R は collection のみ |
|
|
71
|
+
| green | trace は direct enqueue、観測窓完了、close 開始、transport close の順序を保持する | regression | hardware | yes | direct `0x30` index 23、観測窓完了 71、close 開始 72、transport close 103、cleanup 104 |
|
|
72
|
+
| green | Switch UI に対象 button が close 前に表示される | characterization | hardware | yes | 利用者が観測窓中の画面反応とコントローラー認識を目視確認した |
|
|
73
|
+
|
|
74
|
+
## 8. 文書検証計画
|
|
75
|
+
|
|
76
|
+
公開文書は変更しない。作業仕様、hardware test docstring、`tests/hardware/README.md` を照合し、pytest pass と人間の目視結果を混同していないことをレビューする。
|
|
77
|
+
|
|
78
|
+
## 9. 設計メモ
|
|
79
|
+
|
|
80
|
+
### Test Desiderata Review
|
|
81
|
+
|
|
82
|
+
| test | value | trade-off | decision |
|
|
83
|
+
|---|---|---|---|
|
|
84
|
+
| fake transport Direct send | isolated、deterministic、fast、precise | Switch-facing queue progression を表さない | 既存 integration test を維持する |
|
|
85
|
+
| Direct pre-close hardware observation | representative。close drain に隠れる退行を観測できる | 手動、低速、adapter と Switch 状態に依存する | CI 外の承認制 hardware test として追加する |
|
|
86
|
+
| Bumble private queue assertion | queue 内部には precise | Bumble 内部構造へ密結合し、Switch 反映を証明しない | 追加しない |
|
|
87
|
+
|
|
88
|
+
### Gaps
|
|
89
|
+
|
|
90
|
+
- 自動化された Switch UI assertion はない。利用者確認と hardware log が必要。
|
|
91
|
+
- 観測窓は queue completion の時刻を測定しない。close 前に入力反映を確認するための時間境界である。
|
|
92
|
+
|
|
93
|
+
## 10. 対象ファイル
|
|
94
|
+
|
|
95
|
+
| path | change | 内容 |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `tests/hardware/test_pairing_profile.py` | modify | Direct fresh pairing に operator checkpoint と close 前観測窓を追加 |
|
|
98
|
+
| `spec/complete/unit_068/DIRECT_PRE_CLOSE_INPUT_REFLECTION.md` | new | 対象範囲、検証境界、実機条件を記録 |
|
|
99
|
+
| `spec/hardware-test-log.md` | modify | 実機 rerun、cleanup、利用者確認を記録 |
|
|
100
|
+
|
|
101
|
+
## 11. 検証
|
|
102
|
+
|
|
103
|
+
| command | result | notes |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `uv sync --dev` | pass | 53 packages resolved |
|
|
106
|
+
| `uv run ruff format --check .` | pass | 100 files already formatted |
|
|
107
|
+
| `uv run ruff check .` | pass | All checks passed |
|
|
108
|
+
| `uv run ty check --no-progress` | pass | All checks passed |
|
|
109
|
+
| `uv run pytest tests/unit` | pass | 468 passed |
|
|
110
|
+
| `uv run pytest tests/integration` | pass | 137 passed |
|
|
111
|
+
| `uv run pytest tests/hardware/test_pairing_profile.py --collect-only -q` | pass | adapter を開かず14件を収集。Direct fresh / reconnect は各3 controller |
|
|
112
|
+
| `uv run pytest tests/hardware/test_pairing_profile.py -q` | skipped | adapter option を指定せず14件すべて skip。実機経路は未実行 |
|
|
113
|
+
| `uv sync --dev --group docs` | pass | docs dependencies を同期 |
|
|
114
|
+
| `uv run mkdocs build --strict` | pass | strict build 成功 |
|
|
115
|
+
| read-only adapter identity preflight / postflight | pass | HCI / CSR はともに `0E:08:71:C0:B4:5C`、postflight は `adapter_closed` |
|
|
116
|
+
| Direct Pro fresh pairing / Button A | pass | `1 passed in 33.27s`。30秒の close 前観測窓と trace 順序 assertion が成功 |
|
|
117
|
+
| Switch UI 目視 | observed-pass | 利用者が close 前に画面反応とコントローラー認識を確認 |
|
|
118
|
+
| 先行 reconnect 2件 | failed before send | HCI authentication failure reason 5。Button A 送信と観測窓より前の失敗であり、input reflection の判定には使用しない |
|
|
119
|
+
|
|
120
|
+
## 12. 実機実行条件
|
|
121
|
+
|
|
122
|
+
| 項目 | 内容 |
|
|
123
|
+
|---|---|
|
|
124
|
+
| 実機要否 | required for input reflection completion |
|
|
125
|
+
| 承認範囲 | 専用 adapter open、profile identity preparation、Direct HID fresh pairing、sentinel button 1件、close 前観測窓、neutral close |
|
|
126
|
+
| adapter | dedicated `usb:0`、CSR8510 A10、VID:PID `0A12:0001`、WinUSB |
|
|
127
|
+
| 実行遮断 | 環境変数による遮断は採用しない。明示承認、対象 adapter、command、cleanup plan で管理する |
|
|
128
|
+
| log / artifact | `build/hardware/unit_068/direct-pro-fresh-pre-close-20260724-115129/` と利用者目視結果を `spec/hardware-test-log.md` に記録 |
|
|
129
|
+
| cleanup | `close(neutral=True)`、disconnect、transport close、adapter release を実行。postflight で identity 一致と `adapter_closed` を確認 |
|
|
130
|
+
|
|
131
|
+
## 13. 先送り事項
|
|
132
|
+
|
|
133
|
+
- Joy-Con L / Joy-Con R の同一観測は未実行。今回の完了 gate は仕様どおり Direct Pro / Button A の代表ケースとし、両 variant は必要になった時点で同じ parameterized test を実行する。
|
|
134
|
+
|
|
135
|
+
## 14. チェックリスト
|
|
136
|
+
|
|
137
|
+
- [x] 対象範囲と対象外を確認した
|
|
138
|
+
- [x] TDD Test List または文書検証計画を更新した
|
|
139
|
+
- [x] 必要な根拠監査を記録した
|
|
140
|
+
- [x] 実機実行条件を記録した
|
|
141
|
+
- [x] close 前観測窓を実装した
|
|
142
|
+
- [x] 非実機 gate の結果を記録した
|
|
143
|
+
- [x] 実機 rerun と利用者確認を記録した
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# CONTROLLER_HANDSHAKE_READINESS 仕様書
|
|
2
|
+
|
|
3
|
+
## 1. 概要
|
|
4
|
+
|
|
5
|
+
### 1.1 目的
|
|
6
|
+
|
|
7
|
+
`ProController`、`JoyConL`、`JoyConR` の接続成功を、HID control / interrupt
|
|
8
|
+
channel が開いた時点ではなく、Switch の初期 subcommand に応答し、通常入力を
|
|
9
|
+
受け付けられる protocol ready へ到達した時点として定義する。
|
|
10
|
+
|
|
11
|
+
`create_profile()` は protocol ready に到達してからコントローラーオブジェクトを返す。
|
|
12
|
+
`pair()`、`reconnect()`、`connect()` と対応する `try_*` API も同じ完了境界を使う。
|
|
13
|
+
Periodic / Direct の送信方式はこの境界を共有する。
|
|
14
|
+
|
|
15
|
+
### 1.2 起点 / source
|
|
16
|
+
|
|
17
|
+
| source | 内容 | path |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| user request | subcommand sequence 完了後に利用者へ object を返し、Pro Controller / Joy-Con L / Joy-Con R を併せて設計する | conversation |
|
|
20
|
+
| current lifecycle | `pair()` は HID control / interrupt channel 接続だけで戻る | `src/swbt/gamepad/runtime.py` |
|
|
21
|
+
| current public API | concrete controller の `create_profile()` は `pair()` 後に object を返す | `spec/initial/api.md`、`src/swbt/gamepad/core.py` |
|
|
22
|
+
| Pro Controller 実機観測 | 初期化終盤で `0x30 00`、`0x48`、`0x21`、`0x30 01` を受信し、最後の応答後に入力反映を確認した | `spec/hardware-test-log.md`、unit_067 / unit_068 hardware artifact |
|
|
23
|
+
| Joy-Con 実機観測 | 初期 subcommand 応答後の SR+SL hold で Joy-Con L/R の登録を確認した | `spec/hardware-test-log.md`、`spec/complete/unit_046/HARDWARE_PROFILE_TEST_SCENARIOS.md` |
|
|
24
|
+
| upstream precedent | joycontrol は controller profile ごとの `0x04` trigger elapsed 値を返し、player lights 設定後を入力受付可能として待つ | joycontrol pinned source |
|
|
25
|
+
|
|
26
|
+
### 1.3 use case
|
|
27
|
+
|
|
28
|
+
| actor / boundary | 入力または状態 | 期待する観測結果 | 制約 |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| profile 作成利用者 | `await ProController.create_profile(...)` | Switch が通常入力を受理できる状態になってから object が返る | L2CAP 接続だけでは返さない |
|
|
31
|
+
| Joy-Con 利用者 | `JoyConL` / `JoyConR` の初回 pairing | profile に合った登録用 trigger elapsed reply を返し、player assignment 完了後に object が返る | 利用者 object を先に返して SR+SL を要求しない |
|
|
32
|
+
| 既存 profile 利用者 | `connect()` / `reconnect()` | bonded reconnect 後の初期 subcommand sequence と player assignment を待って成功する | pairing fallback の選択規則は変えない |
|
|
33
|
+
| Direct 利用者 | Direct Pro / Joy-Con の `create_profile()` / `connect()` | `0x03 30` 後だけ内部の requested report mode を動かし、同じ ready 条件へ到達する | ready 前の利用者入力は送らず、ready 後は自動 `0x30` を継続しない |
|
|
34
|
+
| diagnostics 利用者 | 接続が初期化途中で停止する | link 接続、観測済み subcommand、report mode、player lights、失敗原因を区別できる | 固定 subcommand 集合を成功条件にしない |
|
|
35
|
+
|
|
36
|
+
## 2. 対象範囲
|
|
37
|
+
|
|
38
|
+
- `ProController`、`JoyConL`、`JoyConR` と対応する Direct controller の接続完了条件。
|
|
39
|
+
- transport link 接続と protocol ready の内部 event 分離。
|
|
40
|
+
- `SwitchHidSessionState` による report mode と player lights の接続単位の状態管理。
|
|
41
|
+
- `0x04` trigger buttons elapsed reply の profile 対応。
|
|
42
|
+
- `0x30` player lights reply 送信後の ready 判定。
|
|
43
|
+
- `pair()`、`reconnect()`、`connect()`、`try_reconnect()`、`try_connect()`、
|
|
44
|
+
`create_profile()` の完了、timeout、失敗 semantics。
|
|
45
|
+
- ready 前の Periodic / Direct 入力送信境界。
|
|
46
|
+
- fake transport による全 profile / reporting type の検証。
|
|
47
|
+
- Pro Controller / Joy-Con L / Joy-Con R の明示承認付き実機 gate。
|
|
48
|
+
- diagnostics と初期設計文書の更新。
|
|
49
|
+
|
|
50
|
+
## 3. 対象外
|
|
51
|
+
|
|
52
|
+
- firmware、Switch model、adapter、OS をまたいだ subcommand 順序の固定保証。
|
|
53
|
+
- `{0x02, 0x08, 0x10, 0x03, 0x04, 0x40, 0x48, 0x21, 0x30}` の
|
|
54
|
+
全件受信を公開 API の契約にすること。
|
|
55
|
+
- Joy-Con Pair API と左右 Joy-Con の同時登録。
|
|
56
|
+
- amiibo、NFC、IR camera の意味実装。
|
|
57
|
+
- ready 後の Switch UI 画面遷移完了を自動判定すること。
|
|
58
|
+
- 初回実装での SR+SL input report 自動送信。profile 対応した `0x04` reply だけで
|
|
59
|
+
Joy-Con の player assignment が進まない場合は、実機結果を記録して設計を再開する。
|
|
60
|
+
- Nintendo 非公開仕様を公式保証として扱うこと。
|
|
61
|
+
|
|
62
|
+
## 4. 関連 docs
|
|
63
|
+
|
|
64
|
+
- `spec/initial/api.md`
|
|
65
|
+
- `spec/initial/lifecycle.md`
|
|
66
|
+
- `spec/initial/protocol.md`
|
|
67
|
+
- `spec/initial/testing.md`
|
|
68
|
+
- `spec/initial/risks.md`
|
|
69
|
+
- `spec/complete/unit_005/M4_SUBCOMMAND_RESPONDER_HARDWARE.md`
|
|
70
|
+
- `spec/complete/unit_006/M5_INPUT_OPERATION_API.md`
|
|
71
|
+
- `spec/complete/unit_032/PROFILE_AWARE_SUBCOMMAND_STATE.md`
|
|
72
|
+
- `spec/complete/unit_046/HARDWARE_PROFILE_TEST_SCENARIOS.md`
|
|
73
|
+
- `spec/hardware-test-log.md`
|
|
74
|
+
- `tests/unit/fixtures/source_audit/switch_protocol_values.toml`
|
|
75
|
+
|
|
76
|
+
## 5. 根拠監査
|
|
77
|
+
|
|
78
|
+
### 5.1 監査結果
|
|
79
|
+
|
|
80
|
+
| 項目 | 値 | 根拠分類 | source | status |
|
|
81
|
+
|---|---|---|---|---|
|
|
82
|
+
| `0x03` | input report mode。`0x30` は standard full mode | source fact | [dekuNukem protocol notes](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/d2ece786a81b5b72a7ddc2742ce97a2afa7a637f/bluetooth_hid_subcommands_notes.md)、`subcommand_report_mode_session_state` fixture | stable |
|
|
83
|
+
| `0x04` payload layout | L、R、ZL、ZR、SL、SR、HOME の順に 7 個の UInt16LE。単位は 10 ms | source fact | dekuNukem protocol notes | stable |
|
|
84
|
+
| Pro Controller の登録用 `0x04` 値 | L / R を各 300 tick、残りを 0 | implementation fact | joycontrol `protocol.py`、`swbt-daemon/swbt/switch/switch_subcommand_dispatcher.c`、現行 swbt-python | established precedent |
|
|
85
|
+
| Joy-Con L/R の登録用 `0x04` 値 | SL / SR を各 300 tick、残りを 0 | implementation fact | [joycontrol protocol.py](https://github.com/mart1nro/joycontrol/blob/3adf0b2878b2a9677644a88eda351e122f432095/joycontrol/protocol.py)、unit_069 hardware trace | tested condition only |
|
|
86
|
+
| 変更前 swbt-python の `0x04` | 全 profile に Pro Controller 用 L / R 値を返していた | implementation fact | unit_069着手前の`src/swbt/protocol/subcommand.py`、red test | profile対応実装で解消 |
|
|
87
|
+
| `0x08` | Switch は接続ごとに `0x08 00` を送る | source fact | dekuNukem protocol notes | stable observation from reverse engineering |
|
|
88
|
+
| `0x30` payload | 下位 4 bit は点灯、上位 4 bit は点滅する player light の bitfield | source fact | dekuNukem protocol notes | stable |
|
|
89
|
+
| player lights 後の入力受付 | joycontrol は `0x30` reply 送信後に event を立て、`ControllerState.connect()` はその event を待つ | implementation fact | joycontrol `protocol.py` / [controller_state.py](https://github.com/mart1nro/joycontrol/blob/3adf0b2878b2a9677644a88eda351e122f432095/joycontrol/controller_state.py) | strong precedent |
|
|
90
|
+
| 現行 Switch 2 の Pro sequence | 終盤に `0x30 00`、`0x48`、`0x21`、`0x30 01`。最後の `0x30` reply 後に入力反映を確認 | hardware observation | `spec/hardware-test-log.md`、unit_067 / unit_068 trace と debug log | tested condition only |
|
|
91
|
+
| handshake 起動 report | joycontrol は接続後に empty input report を最大10回・1秒間隔で送り、最初の output report を待つ。NxBT も接続直後に empty input report を送り reply を促す | implementation fact | joycontrol `server.py` commit `3adf0b2`、NxBT `controller/server.py` | upstream precedent |
|
|
92
|
+
| swbt-python 起動 report | link 後に outgoing report がない3 runはsubcommand 0件でtimeout。neutral `0x30` を送ったrunは最初の `0x02` からreadyまで進行 | hardware observation | `spec/hardware-test-log.md` unit_069 | Pro / tested environment only |
|
|
93
|
+
| 起動 report 再送停止 | 最初の有効な subcommand をparseした時点で停止し、`0x03 30` replyまではrequest/replyで進める | inference / implementation policy | upstream precedent と unit_069 Pro reconnect trace | tested condition only |
|
|
94
|
+
| Joy-Con L 登録 | 初期 sequence の応答後に SR+SL `000030` を hold して登録成功 | hardware observation | `spec/hardware-test-log.md` 2026-07-06 / 2026-07-07 | tested condition only |
|
|
95
|
+
| Joy-Con R 登録 | 初期 sequence の応答後に SR+SL `300000` を hold して登録成功。`0x22` を追加観測 | hardware observation | `spec/hardware-test-log.md` 2026-07-07 | tested condition only |
|
|
96
|
+
| 全 profile 共通の固定 required set | firmware と profile を問わず 9 種類すべてが必須 | unverified hypothesis | stable source なし | completion gate にしない |
|
|
97
|
+
| player lights ACK | `0x30 SET_PLAYER_LIGHTS` は swbt-python / joycontrol / swbt-daemon とも simple ACK `0x80`。`0x31 GET_PLAYER_LIGHTS` は player lights 1 byte を伴う ACK `0xb0` | implementation fact | local implementations、joycontrol | `0x30` と `0x31` を分離して source-audit fixture を訂正。現行 swbt-python は `0x31` 未実装 |
|
|
98
|
+
|
|
99
|
+
### 5.2 未解決事項
|
|
100
|
+
|
|
101
|
+
- Joy-Con L/R は今回のSwitch / adapter環境で、profile対応した`0x04` replyだけにより
|
|
102
|
+
追加のSR+SL input reportなしでnonzero player lightsへ到達した。別firmwareやadapterへ
|
|
103
|
+
一般化できる根拠はない。
|
|
104
|
+
- `0x30 SET_PLAYER_LIGHTS` の ACK は `0x80` で実装間差分はない。`0xb0` は
|
|
105
|
+
`0x31 GET_PLAYER_LIGHTS` の ACK であり、現行swbt-pythonは`0x31`を実装していない。
|
|
106
|
+
- Nintendo 公式の公開 protocol 仕様は確認できていない。source fact は公開された
|
|
107
|
+
reverse engineering notes の記述範囲を表す。
|
|
108
|
+
|
|
109
|
+
## 6. 振る舞い仕様
|
|
110
|
+
|
|
111
|
+
| 振る舞い | 入力・状態 | 期待結果 | 備考 |
|
|
112
|
+
|---|---|---|---|
|
|
113
|
+
| link 接続 | HID control / interrupt channel が利用可能 | runtime は `initializing` になり、subcommand reply 経路を開始する | public 接続 API はまだ戻らない |
|
|
114
|
+
| handshake bootstrap | link 接続後、Switch の subcommand が未観測 | neutral `0x30` を直ちに1件送り、未受信中だけ1秒間隔で再送する | Periodic / Direct 共通。通常 ReportLoop ではない |
|
|
115
|
+
| bootstrap stop | 最初の有効な subcommand を parse | 起動 report の再送を停止し、当該 subcommand へ reply する | ready まで pump を継続しない |
|
|
116
|
+
| requested report mode | supported `0x03 30` reply が transport に受理済み | neutral `0x30` を開始して残りの初期化を進める | bootstrap とは別。ready 前の利用者 state は送らない |
|
|
117
|
+
| intermediate player lights | reply 送信済みの `0x30 00` | player lights を session に記録するが ready にしない | current Switch 2 で観測済み |
|
|
118
|
+
| report mode | reply 送信済みの `0x03 30` | `report_mode_supported=True` を session に記録する | unsupported mode は ready にしない |
|
|
119
|
+
| protocol ready | 同じ session で supported report mode と nonzero player lights が揃い、対応 reply が transport に受理された | runtime を `connected` にし、待機中の接続 API を完了する | subcommand の順序は固定しない |
|
|
120
|
+
| duplicate player lights | ready 後に同じ `0x30` を再受信 | 通常 reply は返すが ready event は再発火しない | diagnostics は通常受信として残す |
|
|
121
|
+
| malformed player lights | `0x30` payload が空 | `ProtocolError` として接続初期化を失敗させる | 既存の無条件 simple ACK から変更 |
|
|
122
|
+
| Pro `0x04` | trigger elapsed request | L / R = 300 tick の reply を返す | 既存値を維持 |
|
|
123
|
+
| Joy-Con `0x04` | trigger elapsed request | SL / SR = 300 tick の reply を返す | L/R と Direct/Periodic で同じ profile policy |
|
|
124
|
+
| factory return | `create_profile()` が link 接続済み、protocol 初期化中 | object を返さず待機する | ready 後だけ caller が lifetime を所有 |
|
|
125
|
+
| success-required API | `pair()` / `reconnect()` / `connect()` | protocol ready 後だけ正常終了する | `"connected"` の意味を強化 |
|
|
126
|
+
| result API | `try_reconnect()` / `try_connect()` | protocol ready 後だけ `status="connected"` | handshake timeout は `"timeout"`、protocol failure は `"failed"` |
|
|
127
|
+
| timeout | advertising / transport connect から ready までに指定時間を超える | 1 個の deadline で失敗し、観測済み subcommand と session state を diagnostics に残して cleanup する | link と handshake で timeout を二重消費しない |
|
|
128
|
+
| early disconnect | link 接続後、ready 前に disconnect | 接続成功にせず失敗として待機 API を起こす | 半初期化 object を返さない |
|
|
129
|
+
| Periodic の ready 前入力 | 利用者が接続前に `press()` / `apply()` で state を準備済み | local state は保持するが、initializing 中の periodic / subcommand reply は neutral wire state を使う | ready 後の次回 report から利用者 state を使う |
|
|
130
|
+
| Direct の ready 前入力 | 接続 API と並行して利用者入力を試す | `ClosedError` を維持し、入力を送らない | internal link 接続を public connected とみなさない |
|
|
131
|
+
| session reset | disconnect 後の新しい接続 | report mode、player lights、ready event、観測済み subcommand を初期化する | 前回 session の ready を再利用しない |
|
|
132
|
+
|
|
133
|
+
## 7. TDD Test List
|
|
134
|
+
|
|
135
|
+
| status | item | type | layer | hardware | notes |
|
|
136
|
+
|---|---|---|---|---|---|
|
|
137
|
+
| green | `0x04` reply は Pro Controller で L / R = 300 tick を返す | regression | unit | no | 現行 byte を保持。profile 対応実装後も pass |
|
|
138
|
+
| green | `0x04` reply は Joy-Con L/R で SL / SR = 300 tick を返す | new | unit | no | profile parameterized。全 profile 共通 L/R 値による red 後に green |
|
|
139
|
+
| green | `0x30 00` は session に記録されるが protocol ready にならない | new | unit | no | simple ACK から session state へ移し、zero で ready にならないことを確認 |
|
|
140
|
+
| green | supported `0x03 30` と nonzero `0x30` が同じ session で揃うと ready predicate が成立する | new | unit | no | 到着順と点灯 / 点滅 bit を入れ替え、constant-false red 後に green |
|
|
141
|
+
| green | `0x30` reply の transport 受理前には ready event が発火しない | regression | integration | no | Direct fake send を event で停止し、受理後だけ pair 完了 |
|
|
142
|
+
| green | `0x30` reply の送信失敗は ready にせず接続失敗へ伝播する | edge | integration | no | session state を送信前へ戻し、pair failure と cleanup を確認 |
|
|
143
|
+
| green | HID channel 接続だけでは `pair()` が完了せず、state は `initializing` になる | regression | integration | no | link 接続直後に完了する red 後、link / ready event を分離 |
|
|
144
|
+
| green | known set の一部を省略または重複しても ready predicate が揃えば `pair()` が完了する | edge | integration | no | `0x03` / `0x30` だけで完了し、`0x30` 重複でも再発火しない |
|
|
145
|
+
| green | Pro / Joy-Con L / Joy-Con R の `create_profile()` は protocol ready 後だけ object を返す | new | integration | no | 全 concrete class の `pair()` 境界と factory の委譲・失敗 cleanup を確認 |
|
|
146
|
+
| green | Periodic / Direct の全 concrete controller が同じ ready 境界を使う | new | integration | no | 6 concrete class parameterized |
|
|
147
|
+
| green | Periodic の接続前 state は initializing 中に wire へ出ず、ready 後に反映される | edge | integration | no | subcommand reply prefix は neutral |
|
|
148
|
+
| green | Periodic / Direct は起動 report を送り、最初の subcommand 後に再送を停止する | regression | integration | no | 起動 report 不在の red 後、両 reporting type と1秒再送を green |
|
|
149
|
+
| green | supported `0x03 30` reply 後は neutral reporting を開始し、ready 後は Periodic だけ継続する | regression | integration | no | reply-only 実機runは追加SPI後に停止。実装後Pro reconnectがpass。Direct停止はfakeでgreen |
|
|
150
|
+
| green | Direct Pro は実機ready後に自動`0x30`を継続しない | characterization | hardware | yes | neutral-only active reconnectでready前periodicあり、ready後1秒間はautomatic periodic 0件 |
|
|
151
|
+
| green | Direct の input operation は link 接続後でも ready 前は失敗し、ready 後は送信できる | edge | integration | no | `ClosedError` 後、ready で送信成功 |
|
|
152
|
+
| green | timeout は link と handshake を含む 1 個の budget で評価される | new | unit / integration | no | advertising と reconnect+ready を外側の1 deadlineで囲み、timeout diagnostics に session state を記録 |
|
|
153
|
+
| green | ready 前 disconnect / unsupported subcommand は待機 API を直ちに failure で起こす | edge | integration | no | disconnect と reply failure を timeout 前に通知。unsupported は既存 protocol failure 経路を共有 |
|
|
154
|
+
| green | reconnect session は前回の report mode / player lights / ready を再利用しない | regression | integration | no | reopen 時の session reset に player lights / ready を追加 |
|
|
155
|
+
| green | `protocol_ready` は reply event より後に 1 回だけ記録される | new | integration | no | observed subcommands、profile kind、route と event 順を確認 |
|
|
156
|
+
| green | Pro Controller の fresh pairing / reconnect が nonzero player lights reply 後に戻る | characterization | hardware | yes | ready trace assertion付きでreconnect `1 passed in 4.98s`、fresh pairing `1 passed in 5.39s` |
|
|
157
|
+
| green | Joy-Con L の profile 対応 `0x04` だけで fresh pairing が完了するか確認する | characterization | hardware | yes | 追加SR+SLなしでfresh `1 passed in 5.15s`、nonzero player lights後にready |
|
|
158
|
+
| green | Joy-Con R の profile 対応 `0x04` だけで fresh pairing が完了するか確認する | characterization | hardware | yes | 追加SR+SLなしでfresh `1 passed in 5.52s`。optional `0x22`へreply後、`0x30 08`でready |
|
|
159
|
+
| green | Joy-Con L/R の active reconnect が追加の登録 input なしで ready へ戻る | characterization | hardware | yes | Joy-Con L `1 passed in 5.94s`、Joy-Con R `1 passed in 6.46s` |
|
|
160
|
+
|
|
161
|
+
## 8. 文書検証計画
|
|
162
|
+
|
|
163
|
+
| document | audience / task | source of truth | mechanical check | review result | unresolved |
|
|
164
|
+
|---|---|---|---|---|---|
|
|
165
|
+
| `spec/initial/api.md` | object を受け取った時点の利用可能条件 | 本仕様 §6 / §9 | `uv run mkdocs build --strict` | pass | ready後returnとDirect内部loopの範囲を反映 |
|
|
166
|
+
| `spec/initial/lifecycle.md` | link connected と protocol ready の状態遷移 | 本仕様 §9.1 | `uv run mkdocs build --strict` | pass | bootstrap、requested report mode、ready後の方式差を反映 |
|
|
167
|
+
| `spec/initial/protocol.md` | player lights session state と profile 対応 `0x04` | 本仕様 §5 / §9.2 / §9.3 | `uv run mkdocs build --strict` | pass | ACK差分は監査済み。固定ready条件には不使用 |
|
|
168
|
+
| `spec/initial/testing.md` | fake / hardware の分担 | 本仕様 §7 / §12 | `uv run mkdocs build --strict` | pass | fakeと全profile実機gateを照合 |
|
|
169
|
+
|
|
170
|
+
## 9. 設計メモ
|
|
171
|
+
|
|
172
|
+
### 9.1 lifecycle state
|
|
173
|
+
|
|
174
|
+
| public `connection_state` | 内部条件 | 接続 API |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| `opened` | transport resource 準備済み | 待機前 |
|
|
177
|
+
| `advertising` / `reconnecting` | link 確立待ち | 待機中 |
|
|
178
|
+
| `initializing` | HID control / interrupt channel 利用可能、protocol ready 未到達 | 待機中 |
|
|
179
|
+
| `connected` | protocol ready 到達 | 正常終了可能 |
|
|
180
|
+
| `failed` | protocol error、reply failure、ready 前 disconnect | 失敗終了 |
|
|
181
|
+
|
|
182
|
+
transport の connected callback 用 event と public 接続成功用 event を分ける。
|
|
183
|
+
report sender と subcommand responder は link connected から利用できるが、利用者入力の
|
|
184
|
+
connected guard は protocol ready event を見る。
|
|
185
|
+
|
|
186
|
+
### 9.2 ready predicate
|
|
187
|
+
|
|
188
|
+
同じ `SwitchHidSession` 内で次を満たすことを protocol ready とする。
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
report_mode_supported is true
|
|
192
|
+
and player_lights is not None
|
|
193
|
+
and player_lights != 0x00
|
|
194
|
+
and predicate を成立させた subcommand reply が transport に受理済み
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
player lights は点灯 bit と点滅 bit のどちらも assignment として扱うため、下位 nibble
|
|
198
|
+
だけではなく 1 byte 全体の nonzero を見る。`0x30 00` は current Switch 2 で初期化途中に
|
|
199
|
+
観測されているため完了に使わない。
|
|
200
|
+
|
|
201
|
+
`0x03` と `0x30` の到着順は契約にしない。各 reply 送信成功後に session predicate を
|
|
202
|
+
再評価し、初めて成立した 1 回だけ ready event を発火する。
|
|
203
|
+
|
|
204
|
+
### 9.3 profile 対応 trigger elapsed
|
|
205
|
+
|
|
206
|
+
`0x04` は reply payload の field layout と、pairing 用に合成する button 選択を分ける。
|
|
207
|
+
button 選択は `ControllerProfile` が持ち、encoder が 14 byte へ変換する。
|
|
208
|
+
|
|
209
|
+
| profile | 300 tick を設定する field | reply data |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| Pro Controller | L、R | `2c012c0100000000000000000000` |
|
|
212
|
+
| Joy-Con L | SL、SR | `00000000000000002c012c010000` |
|
|
213
|
+
| Joy-Con R | SL、SR | `00000000000000002c012c010000` |
|
|
214
|
+
|
|
215
|
+
300 tick は 10 ms 単位で 3000 ms を表す。
|
|
216
|
+
|
|
217
|
+
profile 対応 `0x04` により Switch が player assignment を進める設計を先に検証する。
|
|
218
|
+
初期実装では Periodic / Direct の違いをまたぐ一時的な SR+SL report pump を追加しない。
|
|
219
|
+
|
|
220
|
+
### 9.4 subcommand の扱い
|
|
221
|
+
|
|
222
|
+
| subcommand | ready との関係 |
|
|
223
|
+
|---|---|
|
|
224
|
+
| `0x03` | supported report mode は ready predicate の一部 |
|
|
225
|
+
| `0x30` | nonzero player lights は ready predicate の一部 |
|
|
226
|
+
| `0x04` | profile ごとの player assignment 進行に使うが、受信そのものを固定 gate にしない |
|
|
227
|
+
| `0x02` / `0x08` / `0x10` | 現行初期 sequence で必要な互換応答。受信集合を完了条件にしない |
|
|
228
|
+
| `0x21` / `0x22` / `0x40` / `0x48` | profile / firmware に応じて応答する。受信有無を完了条件にしない |
|
|
229
|
+
|
|
230
|
+
全観測 subcommand に reply があることは diagnostics / hardware test の整合確認に使う。
|
|
231
|
+
「何種類見えたか」と「利用者入力を受け付けられるか」を同じ条件にしない。
|
|
232
|
+
|
|
233
|
+
### 9.5 public API と timeout
|
|
234
|
+
|
|
235
|
+
- `create_profile()` は内部 object を作成後、`pair()` が protocol ready へ到達してから返す。
|
|
236
|
+
- `pair()` / `reconnect()` / `connect()` の正常終了は protocol ready を意味する。
|
|
237
|
+
- `try_*` の `"connected"` も同じ意味にする。
|
|
238
|
+
- timeout は 1 回の接続操作に 1 個の deadline を作り、transport connect、HID channel、
|
|
239
|
+
subcommand handshake で残り時間を共有する。
|
|
240
|
+
- timeout または failure では half-ready 接続を cleanup し、object を factory caller に返さない。
|
|
241
|
+
- 明示 constructor で object を先に所有している場合も、接続 API が戻る前の
|
|
242
|
+
`status().connection_state` は `initializing` とする。
|
|
243
|
+
|
|
244
|
+
### 9.6 ready 前の input state
|
|
245
|
+
|
|
246
|
+
Periodic API は接続前の state 準備を許しているため、local state の更新自体は維持する。
|
|
247
|
+
link 接続直後の起動 report と initializing 中の `0x21` reply prefix は neutral state を
|
|
248
|
+
使う。最初の有効な subcommand を parse した時点で起動 report の再送を止める。
|
|
249
|
+
supported `0x03 30` reply 後に ReportLoop を開始するが、ready 前は neutral state だけを
|
|
250
|
+
送る。ready 後に Periodic の wire state を local state store へ切り替える。
|
|
251
|
+
|
|
252
|
+
Direct は ready 前の利用者 input operation を拒否する。subcommand reply は Direct でも
|
|
253
|
+
内部 report sender から送る。起動 report は同じ sender を使うが、通常 ReportLoop は
|
|
254
|
+
`0x03 30` reply 後にだけ開始する。ready 到達後は task を終了し、利用者操作のない
|
|
255
|
+
`0x30` を送らない。
|
|
256
|
+
|
|
257
|
+
### 9.7 diagnostics
|
|
258
|
+
|
|
259
|
+
少なくとも次を構造化 event として記録する。
|
|
260
|
+
|
|
261
|
+
- `protocol_initialization_started`: route、profile kind。
|
|
262
|
+
- `subcommand_session_state`: report mode、player lights、ready predicate。
|
|
263
|
+
- `protocol_ready`: route、profile kind、report mode、player lights、観測済み subcommand。
|
|
264
|
+
- `protocol_initialization_failed`: stage、error type、観測済み subcommand、session state。
|
|
265
|
+
- `connection_timeout`: `stage="protocol_initialization"` と残りの session state。
|
|
266
|
+
|
|
267
|
+
`subcommand_reply_tx` の後に `protocol_ready` を記録し、trace から送信完了順を確認できるようにする。
|
|
268
|
+
|
|
269
|
+
### 9.8 cancellation / reset
|
|
270
|
+
|
|
271
|
+
- 接続 API の task cancellation は ready waiter と内部 deadline を解除し、既存 cleanup 規則へ渡す。
|
|
272
|
+
- disconnect、close、次回 open のいずれでも ready event と session state を初期化する。
|
|
273
|
+
- 前回 session の nonzero player lights を reconnect の成功に流用しない。
|
|
274
|
+
- ready と disconnect が競合した場合、reply 送信完了より先に disconnect が確定していれば
|
|
275
|
+
成功を返さない。
|
|
276
|
+
|
|
277
|
+
## 10. 対象ファイル
|
|
278
|
+
|
|
279
|
+
| path | change | 内容 |
|
|
280
|
+
|---|---|---|
|
|
281
|
+
| `src/swbt/protocol/session.py` | modify | player lights と ready predicate を connection-scoped state に追加 |
|
|
282
|
+
| `src/swbt/protocol/subcommand.py` | modify | `0x30` payload state、profile 対応 `0x04` reply |
|
|
283
|
+
| `src/swbt/protocol/profiles/base.py` | modify | pairing trigger button policy |
|
|
284
|
+
| `src/swbt/protocol/profiles/pro_controller.py` | modify | L / R policy |
|
|
285
|
+
| `src/swbt/protocol/profiles/joycon.py` | modify | SL / SR policy |
|
|
286
|
+
| `src/swbt/gamepad/output.py` | modify | reply 送信成功後の ready notification |
|
|
287
|
+
| `src/swbt/gamepad/runtime.py` | modify | link / ready event、起動 report、deadline、input gate、diagnostics |
|
|
288
|
+
| `src/swbt/gamepad/connection.py` | modify | reconnect / connect result を protocol ready に接続 |
|
|
289
|
+
| `tests/unit/test_subcommand_responder.py` | modify | profile 対応 `0x04`、`0x30` validation |
|
|
290
|
+
| `tests/unit/test_protocol_session.py` | new | ready predicate と reset |
|
|
291
|
+
| `tests/integration/test_switch_gamepad_fake_transport.py` | modify | 全 profile / reporting type の lifecycle |
|
|
292
|
+
| `tests/unit/fixtures/source_audit/switch_protocol_values.toml` | modify | trigger elapsed policy と player lights SET / GET ACK の監査結果 |
|
|
293
|
+
| `tests/hardware/test_pairing_profile.py` | modify | profile ごとの ready trace / UI gate |
|
|
294
|
+
| `spec/initial/api.md` | modify | object return / connected semantics |
|
|
295
|
+
| `spec/initial/lifecycle.md` | modify | initializing / ready state |
|
|
296
|
+
| `spec/initial/protocol.md` | modify | player lights session state、profile 対応 `0x04` |
|
|
297
|
+
| `spec/initial/testing.md` | modify | fake / hardware gate |
|
|
298
|
+
| `spec/hardware-test-log.md` | modify | 明示承認後の実機結果だけ追記 |
|
|
299
|
+
|
|
300
|
+
## 11. 検証
|
|
301
|
+
|
|
302
|
+
| command | result | notes |
|
|
303
|
+
|---|---|---|
|
|
304
|
+
| `git diff --check` | pass | tracked 差分に whitespace error なし。新規仕様書は末尾空白を別途検査 |
|
|
305
|
+
| `uv run mkdocs build --strict` | pass | 設計文書とリンクの機械検証 |
|
|
306
|
+
| `uv run pytest tests/unit/test_subcommand_responder.py::test_trigger_buttons_elapsed_subcommand_builds_pairing_reply tests/unit/test_subcommand_responder.py::test_joycon_trigger_buttons_elapsed_reports_sr_sl_pairing_hold -q` | pass | `3 passed`。Joy-Con は red `2 failed` を確認後に profile 対応して green |
|
|
307
|
+
| `uv run pytest tests/unit/test_protocol_session.py::test_zero_player_lights_is_recorded_without_protocol_readiness tests/unit/test_subcommand_responder.py::test_simple_ack_subcommands_build_0x21_reply -q` | pass | `6 passed`。player lights field 不在の red 後に `0x30 00` state を実装 |
|
|
308
|
+
| `uv run pytest tests/unit/test_protocol_session.py -q` | pass | `3 passed`。ready predicate の red `2 failed` 後に report mode + nonzero player lights 条件で green |
|
|
309
|
+
| `uv run pytest tests/integration/test_switch_gamepad_fake_transport.py::test_pair_starts_advertising_and_waits_for_fake_connection -q` | pass | `1 passed`。link 接続だけで pair task が完了する red 後に `initializing` / ready event を分離 |
|
|
310
|
+
| `uv run pytest tests/integration/test_switch_gamepad_fake_transport.py::test_pair_waits_until_ready_subcommand_reply_is_transport_accepted -q` | pass | `1 passed`。fake transport に delayed send がない red 後、受理待ちを追加して ready event 順を確認 |
|
|
311
|
+
| `uv run ruff format --check .` | pass | `100 files already formatted` |
|
|
312
|
+
| `uv run ruff check .` | pass | `All checks passed!` |
|
|
313
|
+
| `uv run ty check --no-progress` | pass | `All checks passed!` |
|
|
314
|
+
| `uv run pytest tests/unit -q` | pass | `474 passed` |
|
|
315
|
+
| `uv run pytest tests/integration -q` | pass | final gate `154 passed` |
|
|
316
|
+
| `uv run mkdocs build --strict` | pass | 公開 docs と初期設計のリンク・site build |
|
|
317
|
+
| `uv run pytest tests/integration/test_switch_gamepad_fake_transport.py::test_periodic_bootstrap_stops_after_first_subcommand_then_starts_when_ready tests/integration/test_switch_gamepad_fake_transport.py::test_handshake_bootstrap_retries_until_first_subcommand tests/integration/test_switch_gamepad_fake_transport.py::test_direct_bootstrap_stops_after_first_subcommand_and_remains_nonperiodic -q` | pass | 起動 report 不在の `2 failed` を確認後、`3 passed`。最初の subcommand 後の停止、再送、ready 後の方式差を確認 |
|
|
318
|
+
| same targeted tests after report-mode-driven change | pass | `0x03 30` 後の `0x30` 不在で `2 failed` を確認後、`3 passed`。ready 前neutral、Periodic継続、Direct停止を確認 |
|
|
319
|
+
| `uv run pytest tests/unit/test_report_loop.py -q` | pass | `8 passed` |
|
|
320
|
+
| `uv run pytest tests/integration/test_switch_gamepad_fake_transport.py -q` | pass | `139 passed` |
|
|
321
|
+
| Pro Controller active reconnect hardware gate | pass | `1 passed in 3.60s`。`0x30 00` は ready にせず、`0x03 30` と最後の `0x30 01` reply 後に `protocol_ready`、続いて接続 API が完了 |
|
|
322
|
+
| Pro Controller report-mode-driven reconnect | pass | `1 passed in 4.44s`。bootstrap 2件を最初の `0x02` で停止し、`0x03 30` 後だけperiodic開始、`0x30 01` reply後にready |
|
|
323
|
+
| Pro Controller reconnect with ready trace assertions | pass | `1 passed in 4.98s`。bootstrap停止、全受信subcommandへのreply、`0x03 30`、nonzero player lights、reply直後のreadyを自動検査 |
|
|
324
|
+
| Pro Controller fresh pairing with ready trace assertions | pass | `1 passed in 5.39s`。key store update、bootstrap停止、`0x03 30`、`0x30 00`待機継続、`0x30 01` reply直後のready、cleanupを確認 |
|
|
325
|
+
| Direct Pro ready-stop hardware gate | pass | `1 passed in 5.44s`。ready前periodic 2件、ready後1秒間automatic periodic 0件。終了時neutralとtransport closeを確認 |
|
|
326
|
+
| Joy-Con L adapter-default fresh pairing | pass | `1 passed in 5.15s`。追加SR+SLなしで`0x04` reply後に`0x30 01`へ進みready |
|
|
327
|
+
| Joy-Con L adapter-default active reconnect | pass | `1 passed in 5.94s`。profile bytes不変、pairing fallbackなし、session ready再構築とcleanupを確認 |
|
|
328
|
+
| Joy-Con R adapter-default fresh pairing | pass | `1 passed in 5.52s`。追加SR+SLなし。optional `0x22` reply後、`0x30 08`でready |
|
|
329
|
+
| Joy-Con R adapter-default active reconnect | pass | `1 passed in 6.46s`。profile bytes不変、pairing fallbackなし、session ready再構築とcleanupを確認 |
|
|
330
|
+
| final `uv run pytest tests/unit -q` | pass | `474 passed` |
|
|
331
|
+
| Pro Controller / Joy-Con L / Joy-Con R hardware gate | pass | 各profileのfresh pairing / active reconnectがpass。Direct Pro ready後停止もpass |
|
|
332
|
+
|
|
333
|
+
## 12. 実機実行条件
|
|
334
|
+
|
|
335
|
+
| 項目 | 内容 |
|
|
336
|
+
|---|---|
|
|
337
|
+
| 実機要否 | required for completion |
|
|
338
|
+
| 承認範囲 | 対象 profile ごとに adapter open、pairing または active reconnect、HID advertising、subcommand handling、neutral report、UI 観測、close を列挙する |
|
|
339
|
+
| adapter | 実行直前に確認した専用 adapter。過去観測は `usb:0` / CSR8510 A10 / WinUSB |
|
|
340
|
+
| 対象機器 | Switch model / firmware、controller search または change grip/order 画面を記録する |
|
|
341
|
+
| 実行遮断 | 環境変数による遮断は採用しない。明示承認、adapter、command、Switch-facing 範囲、cleanup plan で管理する |
|
|
342
|
+
| log / artifact | profile、route、`0x04` reply data、`0x03` mode、すべての `0x30` payload、reply 完了順、`protocol_ready`、UI 観測を保存する |
|
|
343
|
+
| cleanup | neutral、disconnect request、transport close、adapter release。timeout / failure でも同じ cleanup を確認する |
|
|
344
|
+
|
|
345
|
+
実機 gate は Pro Controller、Joy-Con L、Joy-Con R を別 run とする。Joy-Con run では
|
|
346
|
+
利用者または test から SR+SL input report を送らず、profile 対応 `0x04` reply の効果を
|
|
347
|
+
分離する。自動登録が進まない場合は timeout を pass にせず、観測結果を本仕様へ戻す。
|
|
348
|
+
|
|
349
|
+
## 13. 先送り事項
|
|
350
|
+
|
|
351
|
+
- Joy-Con の profile 対応 `0x04` だけで登録できない場合の内部 SR+SL report pump。
|
|
352
|
+
Periodic / Direct 共通の bounded handshake sender として別 Intent Delta を作る。
|
|
353
|
+
- ready 後の player lights 更新を公開 API で通知する機能。
|
|
354
|
+
- controller order slot や UI 画面を公開 object として表現する機能。
|
|
355
|
+
- firmware ごとの alternative ready marker。nonzero player lights が得られない実機観測が
|
|
356
|
+
出た場合だけ、hardware evidence とともに追加する。
|
|
357
|
+
|
|
358
|
+
## 14. チェックリスト
|
|
359
|
+
|
|
360
|
+
- [x] 対象範囲と対象外を確認した
|
|
361
|
+
- [x] Pro Controller / Joy-Con L / Joy-Con R と Periodic / Direct の境界を設計した
|
|
362
|
+
- [x] TDD Test List を作成した
|
|
363
|
+
- [x] 必要な根拠監査を記録した
|
|
364
|
+
- [x] 固定 subcommand 集合を public completion gate から除外した
|
|
365
|
+
- [x] Joy-Con の profile 対応 trigger elapsed policy を記録した
|
|
366
|
+
- [x] 実機実行条件を記録した
|
|
367
|
+
- [x] `0x30` / `0x31` の ACK を再監査し、SET / GET の混同を訂正した
|
|
368
|
+
- [x] 実装と local gate を完了した
|
|
369
|
+
- [x] Pro Controller / Joy-Con L / Joy-Con R の実機 gate を完了した
|
|
370
|
+
- [x] 初期設計文書へ完了後の contract を反映した
|