swbt-python 0.5.3__tar.gz → 0.5.4__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.3 → swbt_python-0.5.4}/PKG-INFO +1 -1
- {swbt_python-0.5.3 → swbt_python-0.5.4}/pyproject.toml +1 -1
- swbt_python-0.5.4/spec/complete/unit_086/NORMAL_INPUT_READINESS.md +297 -0
- swbt_python-0.5.4/spec/dev-journal.md +17 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/hardware-test-log.md +136 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/api.md +12 -3
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/architecture.md +4 -4
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/lifecycle.md +13 -9
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/protocol.md +1 -1
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/testing.md +8 -4
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/interface.py +18 -14
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/runtime.py +93 -23
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/report_loop.py +11 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/gamepad_factory.py +21 -1
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_reply_holdoff.py +74 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/integration/test_examples.py +3 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/integration/test_switch_gamepad_fake_transport.py +374 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_report_loop.py +78 -0
- swbt_python-0.5.3/spec/dev-journal.md +0 -3
- {swbt_python-0.5.3 → swbt_python-0.5.4}/AGENTS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/LICENSE +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/README.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/examples/hardware_bringup.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/examples/pairing_probe.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/examples/tap_a.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_001/M0_PROTOCOL_CORE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_002/M1_SWITCH_GAMEPAD_FAKE_TRANSPORT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_003/M2_BUMBLE_HID_TRANSPORT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_004/M3_PAIRING_L2CAP.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_005/M4_SUBCOMMAND_RESPONDER_HARDWARE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_006/M5_INPUT_OPERATION_API.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_007/M6_RECONNECT_KEYSTORE_DIAGNOSTICS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_008/M7_PACKAGING_EXAMPLES_CLI.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_009/PORTING_SOURCE_AUDIT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_010/DIAGNOSTICS_TRACE_SCHEMA.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_011/HARDWARE_TEST_LOG_MATRIX.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_012/INITIAL_RELEASE_GATE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_013/POST_M5_INPUT_SEMANTIC_CHARACTERIZATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_014/DEVICE_CLOSE_GRACEFUL_DISCONNECT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_015/CONTEXT_MANAGER_RESOURCE_SCOPE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_016/JSON_KEY_STORE_CURRENT_PREVIOUS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_017/SWITCH_GAMEPAD_API_HARDENING.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_018/KEY_STORE_TRANSPORT_BOUNDARY.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_019/TRANSPORT_RECONNECT_CONTRACT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_020/STRUCTURAL_REFACTOR_BOUNDARIES.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_021/SWITCH_GAMEPAD_INPUT_API_CONTRACT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_022/PUBLIC_API_USAGE_HARDWARE_DOCS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_023/MKDOCS_DOCUMENTATION_SITE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_024/STICK_INPUT_SHORTHAND_API.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_025/IMU_INPUT_SHORTHAND_API.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_026/LINUX_MACOS_ADAPTER_EXPERIMENTAL.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_027/ADAPTER_DISCOVERY_API.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_028/CONTROLLER_PROFILE_CUSTOMIZATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_029/CONTROLLER_PROFILE_INJECTION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_030/JOYCON_PROFILE_IDENTITY_SPI.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_031/JOYCON_INPUT_REPORT_MAPPING.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_032/PROFILE_AWARE_SUBCOMMAND_STATE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_033/PROFILE_AWARE_BUMBLE_SDP.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_034/JOYCON_CONVENIENCE_API_DOCS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_035/JOYCON_DEVICE_INFO_ADDRESS_WIRING.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_036/JOYCON_SDP_IDENTITY_POLICY.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_037/JOYCON_DEFAULT_CONTROLLER_COLORS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_038/REARCHITECTURE_DECISION_BOUNDARY_TESTS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_039/CONTROLLER_RUNTIME_EXTRACTION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_040/PUBLIC_CONTROLLER_API_MODEL.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_041/CONTROLLER_CONFIG_PROFILE_OWNERSHIP.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_042/INTERNAL_TRANSPORT_FACTORY.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_043/PROTOCOL_PROFILE_MODULE_SPLIT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_044/REARCHITECTURE_DOCS_RELEASE_MATRIX.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_045/INTERNAL_API_BOUNDARY_CLEANUP.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_046/HARDWARE_PROFILE_TEST_SCENARIOS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_047/VIRTUAL_GYRO_CALIBRATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_048/VIRTUAL_ACCELEROMETER_CALIBRATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_049/IMU_SESSION_AND_ENCODING_REDESIGN.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_050/DIRECT_REPORTING_TYPES.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_051/CSR_BD_ADDR_REWRITE_EXPERIMENT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_052/EXP_LOCAL_ADDRESS_PROFILE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_053/EXP_LOCAL_ADDRESS_PROFILE_JOYCON.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_054/EXP_LOCAL_ADDRESS_PROFILE_DIRECT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_055/REMOVE_NATIVE_KEY_STORE_API.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_056/PAIRING_PROFILE_NAMING.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_057/PAIRING_PROFILE_CONTROLLER_KIND.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_058/MULTI_ADDRESS_RECONNECT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_059/EXPERIMENTAL_DIRECT_SEND_TIMING_PROBE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_060/HCI_ACL_COMPLETION_CORRELATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_061/EXPERIMENTAL_CLASSIC_LINK_POLICY_AB.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_062/PERIODIC_ACL_DRAIN_CHARACTERIZATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_063/PERIODIC_NO_DRAIN_CHARACTERIZATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_064/BUMBLE_ENQUEUE_COMPLETION_CONTRACT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_065/PERIODIC_DEADLINE_SCHEDULER.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_066/PAIRING_PROFILE_DEFAULT_ADDRESS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_067/DEFAULT_BATTERY_STATUS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_068/DIRECT_PRE_CLOSE_INPUT_REFLECTION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_069/CONTROLLER_HANDSHAKE_READINESS.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_070/DIAGNOSTICS_AND_UNUSED_PATHS_CLEANUP.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_071/CONTROLLER_CONSTRUCTION_PATH.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_072/CONNECTION_RUNTIME_INTEGRATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_073/TEST_CONTRACT_BOUNDARY_CLEANUP.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_074/PUBLIC_GAMEPAD_IMPLEMENTATION_OWNERSHIP.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_075/CONCRETE_CONTROLLER_MODULE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_076/HARDWARE_HAPPY_CASE_VALIDATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_077/RUNTIME_INPUT_UPDATE_DISPATCH.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_078/TEST_RUNTIME_FIXTURES.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_079/PAIRING_PROFILE_KEY_STORE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_080/TRANSPORT_PROTOCOL_CONTRACT.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_081/PROTOCOL_HANDSHAKE.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_082/REPLY_HOLDOFF_VALIDATION.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/complete/unit_083/PROFILE_SCHEMA_V2_CURRENT_KEY_ONLY.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/README.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/naming.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/risks.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/roadmap.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/initial/transport-bumble.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/rearchitecture/01-design-change-overview.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/rearchitecture/02-as-is-to-be.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/rearchitecture/03-public-api-config-profile.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/rearchitecture/04-runtime-profile-transport-details.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/rearchitecture/05-milestones-implementation.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/rearchitecture/README.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/rearchitecture/mkdocs-nav-snippet.yml +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/spec/wip/unit_084/BUMBLE_0_0_233.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/adapter_discovery.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/diagnostics.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/errors.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/_config.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/connection.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/constants.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/controllers.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/output.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/protocol_handshake.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/gamepad/transport_factory.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/imu.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/input.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/probe.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/buttons.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/descriptors.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/imu_report.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/input_report.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/output_report.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/profiles/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/profiles/base.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/profiles/joycon.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/profiles/pro_controller.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/rumble.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/session.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/spi.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/protocol/subcommand.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/py.typed +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/state_store.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_adapter_identity.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_bumble_acl.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_bumble_hidp.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_bumble_key_store.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_bumble_lifecycle.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_bumble_sdp.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_bumble_usb_devices.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_csr_bd_addr.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_csr_bd_addr_harness.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/_pairing_profile.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/base.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/bumble.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/src/swbt/transport/fake.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/conftest.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/README.md +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_battery_status.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_bumble_transport.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_close_disconnect.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_context_manager_resource_scope.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_controller_colors.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_multi_address_reconnect.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_pairing_l2cap.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/hardware/test_pairing_profile.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/integration/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/integration/test_pairing_profile.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/__init__.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/fixtures/source_audit/switch_protocol_values.toml +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_adapter_discovery.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_adapter_identity.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_bumble_acl.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_bumble_hidp.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_bumble_lifecycle.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_bumble_sdp.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_bumble_transport.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_ci_workflow.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_csr_bd_addr_experiment.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_csr_bd_addr_harness.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_diagnostics.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_gamepad_config.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_gamepad_connection_workflow.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_gamepad_output_dispatcher.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_gamepad_transport_factory.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_imu_report.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_input_report.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_input_state.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_output_report.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_package_import.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_package_metadata.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_pairing_profile.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_pairing_profile_runtime.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_probe_cli.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_protocol_boundary.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_protocol_handshake.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_protocol_profile.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_protocol_session.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_public_api_boundary.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_publish_workflow.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_rumble_state.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_source_audit_fixtures.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_subcommand_responder.py +0 -0
- {swbt_python-0.5.3 → swbt_python-0.5.4}/tests/unit/test_virtual_spi_flash.py +0 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# 通常入力 readiness 仕様書
|
|
2
|
+
|
|
3
|
+
## 1. 概要
|
|
4
|
+
|
|
5
|
+
### 1.1 目的
|
|
6
|
+
|
|
7
|
+
GitHub Issue #149 に従い、`pair()` / `reconnect()` などの接続 API が正常終了した時点で、
|
|
8
|
+
controller の通常入力経路が接続初期化中の automatic input holdoff によって抑止されない
|
|
9
|
+
契約を定義する。
|
|
10
|
+
|
|
11
|
+
Periodic / Direct は同じ公開契約を共有する。ただし、通常入力の送信主体は異なる。
|
|
12
|
+
Periodic は library の `ReportLoop`、Direct は呼び出し側の明示 input operation が送信を
|
|
13
|
+
所有する。このため、共通の完了条件を特定の periodic report の送信有無では定義しない。
|
|
14
|
+
|
|
15
|
+
### 1.2 起点 / source
|
|
16
|
+
|
|
17
|
+
| source | 内容 | path |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| GitHub Issue | Pair / active reconnect 完了直後の 50 ms press / release が、300 ms holdoff 中に local state 上で上書きされ、wire へ出ない | https://github.com/niart120/swbt-python/issues/149 |
|
|
20
|
+
| user decision | 「短時間入力を一度も欠落させない」キュー型契約には強めず、接続初期化由来の抑止だけを除く | conversation |
|
|
21
|
+
| current implementation | `ReportSender` は全 `0x21` reply 受理後に automatic input を 300 ms 抑止し、明示 input は抑止しない | `src/swbt/report_loop.py` |
|
|
22
|
+
| pre-change lifecycle | protocol ready で接続 waiter を起こした後、Periodic の `ReportLoop` を開始していた | 変更前の `src/swbt/gamepad/runtime.py` |
|
|
23
|
+
| prior validation | 300 ms は fake / hardware 比較後に維持され、ready 後の新規 subcommand は未観測 | `spec/complete/unit_082/REPLY_HOLDOFF_VALIDATION.md` |
|
|
24
|
+
| prior readiness contract | Periodic / Direct は supported report mode と nonzero player lights による protocol ready を共有する | `spec/complete/unit_069/CONTROLLER_HANDSHAKE_READINESS.md` |
|
|
25
|
+
|
|
26
|
+
### 1.3 use case
|
|
27
|
+
|
|
28
|
+
| actor / boundary | 入力または状態 | 期待する観測結果 | 制約 |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| Periodic controller 利用者 | `await pair()` / `await reconnect()` の直後に `apply()` し、既定 8 ms 周期より長い 50 ms 後に neutral へ戻す | 接続初期化で設定された holdoff に全送信機会を奪われず、通常 cadence の `0x30` に入力が現れる | 1周期未満の全 state 遷移配送は保証しない |
|
|
31
|
+
| Direct controller 利用者 | 接続 API 完了直後に `send()` または意味的入力操作を呼ぶ | protocol ready 後の明示 input が従来どおり transport へ送られる | Direct に automatic report や待機用 neutral probe を追加しない |
|
|
32
|
+
| diagnostics 利用者 | protocol ready から通常入力 readiness までを trace する | protocol handshake 完了と public 接続 API の完了境界を区別できる | report counter のポーリングを利用者へ要求しない |
|
|
33
|
+
| timeout / cancellation 利用者 | Periodic が protocol ready 後の holdoff 終了を待っている間に timeout、cancel、disconnect が起きる | 接続成功を返さず、既存の cleanup と失敗 semantics を維持する | 接続 timeout budget を新たに加算しない |
|
|
34
|
+
|
|
35
|
+
## 2. 対象範囲
|
|
36
|
+
|
|
37
|
+
- `pair()`、`reconnect()`、`connect()` と対応する `try_*` API の正常終了条件。
|
|
38
|
+
- これらへ委譲する `create_profile()` の object return 条件。
|
|
39
|
+
- protocol ready と通常入力 readiness の内部境界。
|
|
40
|
+
- Periodic の automatic input holdoff と接続完了の同期。
|
|
41
|
+
- Direct の明示 input 経路が同じ公開契約を満たすことの回帰確認。
|
|
42
|
+
- timeout、cancellation、disconnect、close、session reset。
|
|
43
|
+
- diagnostics、公開 API docstring、利用者向け docs、初期設計文書の整合。
|
|
44
|
+
- fake transport による Pair / active reconnect と全 controller profile の検証。
|
|
45
|
+
- Pro Controller の代表的な実機確認。
|
|
46
|
+
|
|
47
|
+
## 3. 対象外
|
|
48
|
+
|
|
49
|
+
- `apply()` の各 state 遷移をキューに保存し、必ず1回以上配送する機能。
|
|
50
|
+
- report period より短い press / release を含む全 transient input の配送保証。
|
|
51
|
+
- Periodic の latest-state coalescing semantics の変更。
|
|
52
|
+
- Direct に automatic `0x30`、待機用 neutral probe、`ReportLoop` を追加すること。
|
|
53
|
+
- 300 ms holdoff の値、開始条件、ready 後 subcommand への適用範囲の変更。
|
|
54
|
+
- steady-state report cadence、deadline scheduler、Bluetooth transport の変更。
|
|
55
|
+
- HID report ID、byte layout、timer、IMU encoding の変更。
|
|
56
|
+
- Joy-Con 実機確認。共通 runtime / sender 以外へ変更が及ぶ場合は実機要否を再評価する。
|
|
57
|
+
|
|
58
|
+
## 4. 関連 docs
|
|
59
|
+
|
|
60
|
+
- `spec/initial/api.md`
|
|
61
|
+
- `spec/initial/architecture.md`
|
|
62
|
+
- `spec/initial/lifecycle.md`
|
|
63
|
+
- `spec/initial/protocol.md`
|
|
64
|
+
- `spec/initial/testing.md`
|
|
65
|
+
- `spec/initial/risks.md`
|
|
66
|
+
- `spec/complete/unit_069/CONTROLLER_HANDSHAKE_READINESS.md`
|
|
67
|
+
- `spec/complete/unit_081/PROTOCOL_HANDSHAKE.md`
|
|
68
|
+
- `spec/complete/unit_082/REPLY_HOLDOFF_VALIDATION.md`
|
|
69
|
+
- `spec/hardware-test-log.md`
|
|
70
|
+
|
|
71
|
+
## 5. 根拠監査
|
|
72
|
+
|
|
73
|
+
| 項目 | 要否 | 状態 | 根拠 / 理由 |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| 300 ms automatic input holdoff | required | done | unit_082 で implementation fact と実機比較を記録済み。値と適用範囲は変更しない |
|
|
76
|
+
| Switch HID / report bytes | not applicable | not applicable | `0x21` / `0x30` の ID、layout、payload を変更しない |
|
|
77
|
+
| Bumble / transport | not applicable | not applicable | transport の受理契約と実装を変更しない |
|
|
78
|
+
| OS / driver / adapter | required | done | no-open列挙とPnP driver情報で、Windows 11、`usb:0`、CSR8510 A10 `0A12:0001`、WinUSB / libwdiを実行直前に確認 |
|
|
79
|
+
|
|
80
|
+
### 5.1 事実
|
|
81
|
+
|
|
82
|
+
- `send_subcommand_reply()` は transport の受理後に holdoff deadline を更新する。
|
|
83
|
+
- `send_automatic_input()` は同じ sender lock 内で deadline を検査し、期限前は送信しない。
|
|
84
|
+
- Direct の `send_input()` は automatic input ではなく、holdoff を検査しない。
|
|
85
|
+
- protocol ready を成立させる最後の reply 自身が holdoff deadline を更新する。
|
|
86
|
+
- 変更前の runtime は接続 waiter を起こしてから Periodic の `ReportLoop` を開始していた。
|
|
87
|
+
|
|
88
|
+
### 5.2 推論
|
|
89
|
+
|
|
90
|
+
- public 接続 API の完了条件を「最初の periodic `0x30` 送信」にすると、automatic report を
|
|
91
|
+
持たない Direct では成立しない。
|
|
92
|
+
- 共通契約は report の有無ではなく、「その reporting mode の通常入力経路が接続初期化由来の
|
|
93
|
+
抑止を受けない状態」として定義できる。
|
|
94
|
+
- Periodic では protocol ready 時点の holdoff deadline だけを snapshot して待つと、待機中に
|
|
95
|
+
受理した追加 reply が deadline を延長する競合を見落とす。readiness 公開前に受理された
|
|
96
|
+
最新 reply の deadline を反映する必要がある。
|
|
97
|
+
|
|
98
|
+
### 5.3 未検証
|
|
99
|
+
|
|
100
|
+
- protocol ready 後に Switch が新しい subcommand を送る条件と頻度は未確認である。
|
|
101
|
+
- 接続完了後に届いた新しい reply が automatic input を再び一時抑止する挙動は、本仕様で変更しない。
|
|
102
|
+
- active reconnect、Joy-Con、別adapter、別OS、別firmwareでの修正後50 ms inputは未検証である。
|
|
103
|
+
|
|
104
|
+
## 6. 振る舞い仕様
|
|
105
|
+
|
|
106
|
+
| 振る舞い | 入力・状態 | 期待結果 | 備考 |
|
|
107
|
+
|---|---|---|---|
|
|
108
|
+
| protocol ready | supported report mode と nonzero player lights が揃い、成立させた reply が transport に受理される | protocol handshake を停止・回収し、通常入力 readiness の評価へ進む | protocol ready 自体の predicate は変更しない |
|
|
109
|
+
| Periodic readiness 待機 | protocol ready だが最新 reply の automatic input holdoff 中 | public 接続成功を返さず、connection state は接続処理中のままとする | 外部の固定 sleep や report counter polling は不要 |
|
|
110
|
+
| Periodic readiness 成立 | readiness 公開前に受理された最新 reply の holdoff deadline に到達する | `ReportLoop` を開始してから接続成功を公開する | probe report の成功を条件にしない |
|
|
111
|
+
| Periodic 最初の通常 cadence | 接続 API 完了後に local state が更新される | 次の通常 cadence から latest state を送信対象にできる | 各 state の配送保証ではない |
|
|
112
|
+
| Direct readiness 成立 | protocol ready に到達する | 明示 input 経路が holdoff 対象外であるため、同じ接続成功契約を直ちに満たす | automatic deadline の経過を待たない |
|
|
113
|
+
| Direct 無送信 | Direct の接続 API が完了する | 待機確認のための `0x30` を自動送信しない | lifecycle 全体で ReportLoop を持たない |
|
|
114
|
+
| 追加 reply | Periodic が readiness 待機中に新しい reply を transport が受理する | 待機 deadline を最新値へ延長し、古い deadline では成功を公開しない | holdoff 更新と readiness 公開を競合させない |
|
|
115
|
+
| readiness 公開後の reply | 接続 API 完了後に新しい reply を受理する | 既存方針どおり automatic input holdoff を適用できる | 永続的な「無抑止」は保証しない |
|
|
116
|
+
| timeout | Periodic が readiness 待機中に接続操作の既存 deadline を超える | timeout として失敗し、cleanup する | 300 msを別 budget として加算しない |
|
|
117
|
+
| cancellation | readiness 待機中の接続 task を cancel する | readiness waiter と接続処理を停止し、既存 cancellation / cleanup semantics を維持する | background waiter を残さない |
|
|
118
|
+
| disconnect | readiness 公開前に link が切れる | 接続成功を返さず、失敗として待機 API を起こす | stale deadline を次 session へ持ち越さない |
|
|
119
|
+
| session reset | close 後に再度 open / pair / reconnect する | 前 session の holdoff deadline と readiness を再利用しない | sender は session 単位 |
|
|
120
|
+
| 50 ms入力 | 既定 8 ms Periodic の接続 API 完了直後に press、50 ms後に release | 初期化 holdoff に全 cadence を抑止されず、press state の periodic `0x30` が1件以上観測できる | 50 msという検証条件であり、任意の短時間入力保証ではない |
|
|
121
|
+
|
|
122
|
+
## 7. TDD Test List
|
|
123
|
+
|
|
124
|
+
| status | item | type | layer | hardware | notes |
|
|
125
|
+
|---|---|---|---|---|---|
|
|
126
|
+
| green | reply 受理直後の Periodic 通常入力 readiness は holdoff 期限前に成立せず、境界時刻で成立する | new | unit | no | 注入時計で wall clock 非依存に確認 |
|
|
127
|
+
| green | readiness 待機中に追加 reply を受理すると、古い期限では成立せず最新期限まで待つ | edge | unit | no | deadline snapshot ではなく最新値を再評価 |
|
|
128
|
+
| green | protocol ready 後も holdoff 中の Periodic `pair()` は完了せず、期限到達後に完了する | regression | integration | no | controlled readiness gate で Pair 経路を確認 |
|
|
129
|
+
| green | Periodic active reconnect は protocol ready 後の holdoff 終了まで `status="connected"` を返さない | regression | integration | no | controlled readiness gate で `try_reconnect()` を確認 |
|
|
130
|
+
| green | Direct の Pair / active reconnect は protocol ready で完了し、holdoff 経過や automatic `0x30` を要求しない | regression | integration | no | Pro / Joy-Con L/R を parameterize |
|
|
131
|
+
| green | `connect()`、`try_connect()`、`create_profile()` は選択した Pair / reconnect と同じ通常入力 readiness を使う | regression | integration | no | connect 2入口と6具象create_profileのpair委譲を確認 |
|
|
132
|
+
| green | Periodic の接続完了直後に50 ms保持した stateが通常 cadence の `0x30` に現れる | regression | integration | no | 既定8 msのButton Aとneutralを確認。全transient配送へ一般化しない |
|
|
133
|
+
| green | readiness 待機中の timeout は成功を返さず既存 cleanup を完了する | edge | integration | no | timeout 後close、`stage=input_readiness`、次回Pairのfresh readinessを確認 |
|
|
134
|
+
| green | readiness 待機中の cancellation / disconnect は waiter を残さず、次 session が stale readiness を再利用しない | edge | integration | no | cancellation red後にwaiter回収を追加。disconnect失敗の`stage=input_readiness`も確認 |
|
|
135
|
+
| green | Pro Controller の Pair または active reconnect 完了直後の50 ms Button Aがperiodic `0x30`とSwitch UIに反映される | characterization | hardware | yes | fresh PairでA付き周期`0x30`を7件記録し、利用者が対象機器側の反映を確認 |
|
|
136
|
+
|
|
137
|
+
## 8. 文書検証計画
|
|
138
|
+
|
|
139
|
+
| document | audience / task | source of truth | mechanical check | review result | unresolved |
|
|
140
|
+
|---|---|---|---|---|---|
|
|
141
|
+
| `spec/initial/api.md` | 接続 API 完了後に入力を開始する利用者 | 本仕様 §6 | `uv run --group docs mkdocs build --strict` | pass | Periodic / Direct 共通契約と方式差を反映。未解決なし |
|
|
142
|
+
| `spec/initial/architecture.md` | runtime と report loop の所有境界を確認する maintainer | 本仕様 §6 / §9 | `uv run --group docs mkdocs build --strict` | pass | report loop の開始時点を通常入力 readiness と一致。未解決なし |
|
|
143
|
+
| `spec/initial/lifecycle.md` | maintainer が protocol ready と通常入力 readiness の順序を追う | 本仕様 §6 / §9 | `uv run --group docs mkdocs build --strict` | pass | timeout / disconnect を含む状態遷移を反映。未解決なし |
|
|
144
|
+
| `spec/initial/testing.md` | fake / hardware test の分担を確認する maintainer | 本仕様 §7 | `uv run --group docs mkdocs build --strict` | pass | 50 ms は代表条件であり全 transient 保証ではないと明記。未解決なし |
|
|
145
|
+
| public API docstring / `docs/api.md` / `docs/usage.md` / `docs/release-notes.md` / `docs/hardware.md` | 接続後に入力する利用者と実機確認担当者 | 本仕様 §6 / §7、`spec/hardware-test-log.md` | docs build + `docs-quality-review` | pass | 契約、非保証、50 ms実機観測、未確認範囲を照合。must-fix なし |
|
|
146
|
+
|
|
147
|
+
自然言語の意味要件を固定語句の存在・不在 assertion に置き換えない。公開文書の事実性、
|
|
148
|
+
操作順、未保証範囲は正本との照合と `docs-quality-review` で確認する。
|
|
149
|
+
|
|
150
|
+
## 9. 設計メモ
|
|
151
|
+
|
|
152
|
+
### 9.1 共通契約
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
connection API success
|
|
156
|
+
implies
|
|
157
|
+
the reporting mode's normal input path is not blocked
|
|
158
|
+
by a holdoff already created during connection initialization
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
「通常入力経路」は reporting mode ごとに次を指す。
|
|
162
|
+
|
|
163
|
+
| reporting mode | 通常入力経路 | readiness の具体条件 |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| Periodic | local latest stateを通常 cadence で送る `ReportLoop` | readiness 公開前に受理された最新 reply の automatic input holdoff が終了済み |
|
|
166
|
+
| Direct | `send()` と意味的 input operation による明示送信 | protocol ready で明示 input sender が利用可能 |
|
|
167
|
+
|
|
168
|
+
この違いは公開契約の差ではなく、送信所有者の違いである。
|
|
169
|
+
|
|
170
|
+
### 9.2 `connected` の意味
|
|
171
|
+
|
|
172
|
+
`connected` と接続 API の正常終了は、protocol ready だけでなく通常入力 readiness も満たす。
|
|
173
|
+
diagnostics では次を分ける。
|
|
174
|
+
|
|
175
|
+
- `protocol_ready`: handshake predicate を成立させた reply が受理され、handshake task を
|
|
176
|
+
停止・回収した時点。
|
|
177
|
+
- `input_ready`: reporting mode ごとの通常入力 readiness が成立した時点。
|
|
178
|
+
- `active_reconnect_result(status="connected")`: `input_ready` 後。
|
|
179
|
+
|
|
180
|
+
Direct では `protocol_ready` と `input_ready` が連続して記録される。Periodic では通常、
|
|
181
|
+
最後の初期化 reply が設定した holdoff の残り時間だけ間隔が空く。
|
|
182
|
+
|
|
183
|
+
`input_ready` を接続成功の linearization point とする。sender の同期境界でこれより前に
|
|
184
|
+
受理された reply は readiness 待機へ反映し、これより後に受理された reply は接続後の
|
|
185
|
+
通常処理として扱う。coroutine を再開する wall-clock 上の瞬間と Bluetooth event の到着を
|
|
186
|
+
完全に排他する保証は置かない。
|
|
187
|
+
|
|
188
|
+
### 9.3 holdoff と readiness の同期
|
|
189
|
+
|
|
190
|
+
readiness 判定は、holdoff deadline の単発 snapshot や `sleep(0.3)` で実装しない。
|
|
191
|
+
subcommand reply の transport 受理、deadline 更新、readiness の再評価を同じ sender の
|
|
192
|
+
同期境界で順序付ける。
|
|
193
|
+
|
|
194
|
+
readiness 公開前に追加 reply が受理された場合、その reply が更新した deadline を待つ。
|
|
195
|
+
readiness 公開後に受理された reply は既存の automatic input holdoff として扱う。本仕様は
|
|
196
|
+
ready 後 holdoff の廃止や initializing 限定化を行わない。
|
|
197
|
+
|
|
198
|
+
### 9.4 ReportLoop の開始
|
|
199
|
+
|
|
200
|
+
Periodic の `ReportLoop` は通常入力 readiness 成立後に開始する。接続完了確認のための
|
|
201
|
+
neutral probe は送らない。loop の最初の deadline は開始時刻から `report_period_us` 後とし、
|
|
202
|
+
接続完了直後の `apply()` はその時点の latest state を次回 cadence の候補にする。
|
|
203
|
+
|
|
204
|
+
Direct は lifecycle 全体で通常 `ReportLoop` を持たない。handshake 中の
|
|
205
|
+
`handshake_bootstrap` / `handshake_report_mode` は `ProtocolHandshake` が所有する内部
|
|
206
|
+
automatic neutral であり、Direct の通常入力には数えない。
|
|
207
|
+
|
|
208
|
+
### 9.5 transient input の境界
|
|
209
|
+
|
|
210
|
+
Periodic は latest-state model を維持する。複数の `apply()` が同じ通常 cadence より前に
|
|
211
|
+
完了した場合、中間 state は後続 state に統合され得る。これを欠落防止 queue へ変更しない。
|
|
212
|
+
|
|
213
|
+
Issue #149 の 50 ms / 8 ms は通常なら複数 cadence を含むため、接続初期化 holdoff による
|
|
214
|
+
全機会の抑止を検出する代表条件として使う。50 msを任意の環境、任意の period に対する
|
|
215
|
+
最小配送時間として公開しない。
|
|
216
|
+
|
|
217
|
+
## 10. 対象ファイル
|
|
218
|
+
|
|
219
|
+
| path | change | 内容 |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `src/swbt/report_loop.py` | modify | automatic input readiness の待機と reply deadline 更新の同期 |
|
|
222
|
+
| `src/swbt/gamepad/runtime.py` | modify | protocol ready 後の mode 別 readiness、event、timeout、cleanup、diagnostics |
|
|
223
|
+
| `src/swbt/gamepad/interface.py` | modify | 公開接続 API docstring の readiness 契約 |
|
|
224
|
+
| `tests/unit/test_report_loop.py` | modify | deadline 境界と追加 reply の決定的 unit test |
|
|
225
|
+
| `tests/integration/test_switch_gamepad_fake_transport.py` | modify | Pair / reconnect / Direct / Periodic / failure lifecycle |
|
|
226
|
+
| `tests/hardware/test_reply_holdoff.py` | modify | fresh Pair 完了直後50 ms入力の実機 gate |
|
|
227
|
+
| `spec/initial/api.md` | modify | 接続成功後の通常入力契約 |
|
|
228
|
+
| `spec/initial/architecture.md` | modify | ReportLoop の生成時点と runtime の wait 所有 |
|
|
229
|
+
| `spec/initial/lifecycle.md` | modify | protocol ready と input ready の状態遷移 |
|
|
230
|
+
| `spec/initial/protocol.md` | modify | holdoff 対象となる ReportLoop の開始境界を明確化 |
|
|
231
|
+
| `spec/initial/testing.md` | modify | fake / hardware completion gate |
|
|
232
|
+
| `docs/api.md` | modify | 利用者向け接続 API 説明 |
|
|
233
|
+
| `docs/usage.md` | modify | 接続後の入力開始手順と latest-state の非保証 |
|
|
234
|
+
| `docs/release-notes.md` | modify | 修正内容、互換境界、実機未確認範囲 |
|
|
235
|
+
| `docs/hardware.md` | modify | `protocol_ready` と `input_ready` の診断手順 |
|
|
236
|
+
| `spec/hardware-test-log.md` | modify | 承認後の実機条件と結果 |
|
|
237
|
+
|
|
238
|
+
実装時に実ファイル構成を再確認し、内部 helper 名をこの表へ合わせるためだけの変更は行わない。
|
|
239
|
+
|
|
240
|
+
## 11. 検証
|
|
241
|
+
|
|
242
|
+
| command | result | notes |
|
|
243
|
+
|---|---|---|
|
|
244
|
+
| `git diff --no-index --check -- NUL spec/complete/unit_086/NORMAL_INPUT_READINESS.md` | pass | 新規 untracked spec に whitespace error なし。差分ありを表す exit 1、error output なし |
|
|
245
|
+
| `uv run pytest tests/unit/test_report_loop.py::test_automatic_input_readiness_waits_until_reply_holdoff_boundary -q` | pass | red は `_sleep` 未対応の `TypeError`、green は `1 passed` |
|
|
246
|
+
| `uv run pytest tests/unit/test_report_loop.py -q` | pass | first cycle 後 `11 passed` |
|
|
247
|
+
| `uv run pytest tests/unit/test_report_loop.py::test_additional_reply_extends_automatic_input_readiness_wait -q` | pass | first cycle の再評価 loop で green、`1 passed` |
|
|
248
|
+
| targeted Pair / Direct readiness integration | pass | Periodic red は waiter 未呼び出しで timeout。runtime 分離後、既存境界を含め `9 passed` |
|
|
249
|
+
| targeted active reconnect readiness integration | pass | Periodic `1 passed`、Direct Pro / Joy-Con L/R `3 passed` |
|
|
250
|
+
| `uv run pytest tests/integration/test_switch_gamepad_fake_transport.py::test_periodic_input_after_pair_is_not_blocked_by_initialization_holdoff -q` | pass | 接続完了後50 msのButton Aと後続neutralをperiodic `0x30`で確認 |
|
|
251
|
+
| targeted timeout / cancellation / disconnect readiness integration | pass | timeout後の再Pair、task cancellation、disconnect、既存reconnect cancellationを含む `4 passed` |
|
|
252
|
+
| targeted connect / create_profile delegation integration | pass | connect 2入口と6具象create_profileのpair委譲、計 `8 passed` |
|
|
253
|
+
| `uv run ruff format --check .` | pass | `106 files already formatted` |
|
|
254
|
+
| `uv run ruff check .` | pass | `All checks passed!` |
|
|
255
|
+
| `uv run ty check --no-progress` | pass | `All checks passed!` |
|
|
256
|
+
| `uv run pytest tests/unit` | pass | final gateは`450 passed in 2.09s` |
|
|
257
|
+
| `uv run pytest tests/integration` | pass | final gateは`165 passed in 3.05s` |
|
|
258
|
+
| `uv run --group docs mkdocs build --strict` | pass | strict build 成功 |
|
|
259
|
+
| `uv run pytest --collect-only tests/hardware/test_reply_holdoff.py -q` | pass | 修正後harnessを含む10件を収集。adapter / Switch は開いていない |
|
|
260
|
+
| approved Pro Controller fresh Pair hardware gate | observed-pass | commandはdiagnostics reasonのtest bugで`1 failed in 5.58s`。artifactはA付き周期`0x30`を7件、neutral、cleanupを記録し、利用者がUI反映を確認。test bugは`reason=periodic`へ修正 |
|
|
261
|
+
| hardware artifact review | pass | debug PDUのtimer `0x15`–`0x1B`でButton A bitを7件、次のtimer `0x1C`でneutralを確認 |
|
|
262
|
+
|
|
263
|
+
## 12. 実機実行条件
|
|
264
|
+
|
|
265
|
+
| 項目 | 内容 |
|
|
266
|
+
|---|---|
|
|
267
|
+
| 実機要否 | required for completion |
|
|
268
|
+
| 承認範囲 | Pro Controller の Pair または active reconnect、HID advertising、subcommand handling、通常 periodic report、50 ms Button A press / release、neutral close、adapter release |
|
|
269
|
+
| adapter | 実行直前に対象 adapter、identity、driver を確認する。過去の `usb:0` / CSR8510 A10 / WinUSB を現在値として仮定しない |
|
|
270
|
+
| 実行遮断 | 環境変数による遮断は採用しない。明示承認、対象 adapter、command、Switch-facing 動作、cleanup plan で管理する |
|
|
271
|
+
| log / artifact | OS、Python / Bumble / swbt-python version、Switch model / firmware、profile / route、`protocol_ready`、`input_ready`、reply、periodic `0x30`、UI 観測を保存する |
|
|
272
|
+
| cleanup | neutral、ReportLoop停止、disconnect、transport close、adapter release。失敗時も同じ項目を確認する |
|
|
273
|
+
| 実行結果 | fresh Pairでobserved-pass。詳細は`spec/hardware-test-log.md`の2026-07-26 unit_086記録 |
|
|
274
|
+
|
|
275
|
+
実機 test は自動 trace の periodic `0x30` と利用者による Switch UI 観測を分けて記録する。
|
|
276
|
+
明示承認なしに `bumble` / `hardware` marker を実行しない。
|
|
277
|
+
|
|
278
|
+
## 13. 先送り事項
|
|
279
|
+
|
|
280
|
+
- ready 後 subcommand の発生条件と、steady-state holdoff の必要性。観測できた場合は unit_082
|
|
281
|
+
の後続として別 work unit / Issue に分ける。
|
|
282
|
+
- 各 Periodic state 遷移を配送する queue。latest-state API の別契約になるため本仕様には含めない。
|
|
283
|
+
- report period に対する最小 transient input duration の公開保証。OS / scheduler / transport を
|
|
284
|
+
含む保証設計が必要なため本仕様には含めない。
|
|
285
|
+
|
|
286
|
+
## 14. チェックリスト
|
|
287
|
+
|
|
288
|
+
- [x] 対象範囲と対象外を確認した
|
|
289
|
+
- [x] Periodic / Direct に等価な公開契約を定義した
|
|
290
|
+
- [x] 「最初の periodic `0x30`」を共通 completion gate から除外した
|
|
291
|
+
- [x] transient input の全配送を対象外として明記した
|
|
292
|
+
- [x] TDD Test List を作成した
|
|
293
|
+
- [x] 必要な根拠監査を記録した
|
|
294
|
+
- [x] 実機実行条件を記録した
|
|
295
|
+
- [x] 実装と local gate を完了した
|
|
296
|
+
- [x] 公開文書を更新し `docs-quality-review` を完了した
|
|
297
|
+
- [x] 明示承認付き実機 gate を完了した
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Dev Journal
|
|
2
|
+
|
|
3
|
+
swbt-python の設計観測、未解決事項、先送り判断の記録。
|
|
4
|
+
|
|
5
|
+
## 2026-07-26: VID:PID 33FA:0010 の HCI extended-features 応答
|
|
6
|
+
|
|
7
|
+
### 現状
|
|
8
|
+
|
|
9
|
+
Windows 11 / WinUSB / libwdi / Bumble 0.0.233 で検出した `33FA:0010` は、Bumble の `Read Local Extended Features` (`0x1004`) に対する応答を event length `0x01` として返し、通常の `power_on()` を停止させた。
|
|
10
|
+
|
|
11
|
+
### 観察
|
|
12
|
+
|
|
13
|
+
実験用に `0x1004` の対応判定を抑止すると、Bumble は既存の `0x1003` 代替経路を使い、HID advertising、fresh pairing、protocol ready、Button A の Switch UI 反映、neutral close まで成功した。active reconnect は同条件で2回、`host_connection` 後かつ L2CAP 前に Switch reason `19` で切断された。実験用コードは main に取り込まない。
|
|
14
|
+
|
|
15
|
+
### 方針
|
|
16
|
+
|
|
17
|
+
この adapter を正式対応にしない。再検討する場合は、Bumble の upstream driver / quirk として扱える根拠、または複数個体・別 OS/driver での再現を先に集める。観測 artifact と実行条件は `spec/hardware-test-log.md` を正本とする。
|
|
@@ -2372,3 +2372,139 @@ Bumble adapter と対象機器に依存する観測を記録する正本であ
|
|
|
2372
2372
|
- `artifact` には、diagnostics trace、pytest log、手元記録など、後から結果を辿れる場所を書く。
|
|
2373
2373
|
- `cleanup` には、neutral、report loop stop、transport close、adapter release など実施した後始末と結果を書く。
|
|
2374
2374
|
- link key、secret、個人環境に固有の token は記録しない。
|
|
2375
|
+
|
|
2376
|
+
## 2026-07-25: VID:PID 33FA:0010 Bumble adapter open-only
|
|
2377
|
+
|
|
2378
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2379
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2380
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`, bus 5 / address 20)
|
|
2381
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2382
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2383
|
+
- command / test: `uv run pytest tests/hardware/test_context_manager_resource_scope.py -m bumble --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-open-check-20260725 -q -s`
|
|
2384
|
+
- approval: 利用者承認下で Bumble adapter open、Bluetooth Classic / HID Device 初期化、close / adapter release のみ。advertising、pairing、HID channel、report loop、Switch-facing message は実行しない。
|
|
2385
|
+
- result: `1 passed in 0.35s`。`transport_open_complete` と `transport_close_complete` を記録し、adapter open は成功。
|
|
2386
|
+
- artifact: `tmp/hardware/dongle-open-check-20260725/resource-open-only.jsonl`
|
|
2387
|
+
- cleanup: `disconnect_request(status=unavailable, reason=channels_not_connected)` の後に `transport_close_complete`。HID channel 未接続のため neutral report は未送信。
|
|
2388
|
+
- notes: 別アプリで観測した不正な HCI event length の原因は、この検査だけでは確定しない。
|
|
2389
|
+
|
|
2390
|
+
## 2026-07-25: VID:PID 33FA:0010 Bumble advertising smoke timeout
|
|
2391
|
+
|
|
2392
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2393
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2394
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`)
|
|
2395
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2396
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2397
|
+
- command / test: `uv run pytest tests/hardware/test_bumble_transport.py -m bumble --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-advertising-smoke-20260725 -q -s`
|
|
2398
|
+
- approval: 利用者承認下で Bumble adapter open、Bluetooth Classic / HID Device 初期化、HID advertising、close / adapter release。pairing、HID channel、report loop、Switch-facing message は実行しない。
|
|
2399
|
+
- result: 64.2 秒で command timeout。`transport_open_complete` までは記録したが `advertising_start` は記録されず、`start_advertising()` が完了しなかった。
|
|
2400
|
+
- artifact: `tmp/hardware/dongle-advertising-smoke-20260725/bumble-hid-advertising-smoke.jsonl`
|
|
2401
|
+
- cleanup: timeout 後に今回の pytest process PID 3852 / 4216 を終了。続く `tests/hardware/test_context_manager_resource_scope.py -m bumble --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-post-timeout-open-check-20260725 -q -s` は `1 passed in 0.33s` で、adapter open / close の回復を確認した。
|
|
2402
|
+
- notes: Bumble の HID advertising 開始とこの adapter / controller の組合せに問題がある。Switch pairing には進まない。
|
|
2403
|
+
|
|
2404
|
+
## 2026-07-25: VID:PID 33FA:0010 Bumble power-on HCI response failure
|
|
2405
|
+
|
|
2406
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2407
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2408
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`)
|
|
2409
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2410
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2411
|
+
- command / test: temporary power-on probe。`BumbleHidTransport.open()` 後、advertising を有効化せず `runtime.device.power_on()` を10秒で制限して実行。
|
|
2412
|
+
- approval: 利用者承認下で Bumble adapter open、Bluetooth Classic / HID Device 初期化、power-on、close / adapter release。advertising、pairing、HID channel、report loop、Switch-facing message は実行しない。
|
|
2413
|
+
- result: `power_on()` が timeout。stderr に `--- Ignoring event [0x00]: 0e01041000010200000000000000` が出力され、Bumble の `Device.power_on()` → `Host.reset()` → HCI synchronous command response 待機で停止した。
|
|
2414
|
+
- artifact: `tmp/hardware/dongle-power-on-probe-20260725/power-on.jsonl`
|
|
2415
|
+
- cleanup: `transport_close_complete` を記録し、残存する workspace Python process はなかった。
|
|
2416
|
+
- notes: event 列は今回の Bumble 実行でも再現した。HID advertising や Switch pairing の問題ではなく、adapter が HCI 初期化中に返す event framing が Bumble と互換でない。
|
|
2417
|
+
|
|
2418
|
+
## 2026-07-25: VID:PID 33FA:0010 extended-features workaround advertising smoke
|
|
2419
|
+
|
|
2420
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2421
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2422
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`)
|
|
2423
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2424
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2425
|
+
- command / test: `uv run pytest tests/hardware/test_bumble_transport.py -m bumble --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-extended-features-workaround-20260725 -q -s`
|
|
2426
|
+
- approval: 利用者承認下で Bumble adapter open、Bluetooth Classic / HID Device 初期化、HID advertising、close / adapter release。pairing、HID channel、report loop、Switch-facing message は実行しない。
|
|
2427
|
+
- result: `1 passed in 0.58s`。`hci_workaround_enabled(suppressed_command=0x1004)`、`local_bluetooth_address_configured`、`classic_link_policy_configured(settings=0x0005)`、`advertising_start`、`transport_close_complete` を記録した。
|
|
2428
|
+
- artifact: `tmp/hardware/dongle-extended-features-workaround-20260725/bumble-hid-advertising-smoke.jsonl`
|
|
2429
|
+
- cleanup: `transport_close_complete`。pairing、HID channel、report loop、input report は未実行。
|
|
2430
|
+
- notes: この結果は VID:PID `33FA:0010`、WinUSB / libwdi、Bumble 0.0.233 の組合せに限定する。pairing、reconnect、Switch UI 入力反映は未検証。
|
|
2431
|
+
|
|
2432
|
+
## 2026-07-25: VID:PID 33FA:0010 extended-features workaround fresh pairing
|
|
2433
|
+
|
|
2434
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2435
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2436
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`)
|
|
2437
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2438
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2439
|
+
- command / test: `uv run pytest tests/hardware/test_pairing_profile.py::test_switch_adapter_default_profile_fresh_pairing_and_close -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-33fa-pairing-20260725 -q -s`
|
|
2440
|
+
- approval: 利用者承認下で Bumble adapter open、advertising、fresh pairing、HID control / interrupt channel、neutral-only report、close / adapter release。non-neutral input、BD_ADDR 書換え、active reconnect は実行しない。
|
|
2441
|
+
- result: `1 passed in 4.31s`。`hci_workaround_enabled(suppressed_command=0x1004)`、Classic pairing、link key 保存、control / interrupt L2CAP open、`protocol_ready`、neutral input report、channel close、disconnect terminal `closed`、`transport_close_complete` を記録した。利用者が pairing 成功を確認した。
|
|
2442
|
+
- artifact: `tmp/hardware/dongle-33fa-pairing-20260725/pairing-profile-adapter-default-fresh-pairing.jsonl` と adapter-default profile
|
|
2443
|
+
- cleanup: interrupt、control channel を閉じ、disconnect terminal `closed` と `transport_close_complete` を確認。profile の link key は artifact 内に保持し、内容はログに転載しない。
|
|
2444
|
+
- notes: この結果は VID:PID `33FA:0010`、WinUSB / libwdi、Bumble 0.0.233 の組合せに限定する。active reconnect と Switch UI 入力反映は未検証。
|
|
2445
|
+
|
|
2446
|
+
## 2026-07-26: VID:PID 33FA:0010 extended-features workaround active reconnect failure
|
|
2447
|
+
|
|
2448
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2449
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2450
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`)
|
|
2451
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2452
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2453
|
+
- command / test: `uv run pytest tests/hardware/test_pairing_profile.py::test_switch_adapter_default_profile_reuses_address_after_normal_close -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-33fa-pairing-20260725 -q -s`
|
|
2454
|
+
- approval: 利用者承認下で Bumble adapter open、active reconnect、HID control / interrupt channel、neutral close / adapter release。re-pairing、non-neutral input、BD_ADDR 書換えは実行しない。
|
|
2455
|
+
- result: fail。`hci_workaround_enabled(suppressed_command=0x1004)` 後に保存済み peer へ active reconnect を開始し、`host_connection` まで到達したが、L2CAP channel open と protocol ready の前に Switch 側 reason `19` で切断された。`active_reconnect_result(status=failed, failure_reason=transport_error)` を記録した。
|
|
2456
|
+
- artifact: `tmp/hardware/dongle-33fa-pairing-20260725/pairing-profile-adapter-default-reconnect.jsonl`
|
|
2457
|
+
- cleanup: `disconnect_request(status=unavailable, reason=transport_closed)` と `transport_close_complete`。残存 workspace Python process はない。
|
|
2458
|
+
- notes: active reconnect 接続失敗のため Button A を送信しなかった。reason `19` の原因はこの一回の観測では未確定であり、adapter workaround の成功・失敗と同一視しない。
|
|
2459
|
+
|
|
2460
|
+
## 2026-07-26: VID:PID 33FA:0010 extended-features workaround fresh pairing and Button A
|
|
2461
|
+
|
|
2462
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2463
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2464
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`)
|
|
2465
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2466
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2467
|
+
- command / test: `uv run pytest tests/hardware/test_close_disconnect.py::test_switch_close_after_full_handshake_and_a_exit_for_manual_ui_confirmation -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-33fa-input-20260726 -q -s -W error`
|
|
2468
|
+
- approval: 利用者承認下で Bumble adapter open、fresh pairing、HID control / interrupt channel、full handshake、Button A を0.35秒、neutral report、close / adapter release。BD_ADDR 書換えと他入力は実行しない。
|
|
2469
|
+
- result: `1 passed in 7.61s`。`hci_workaround_enabled(suppressed_command=0x1004)`、full handshake、Button A 後の periodic `0x30` report、neutral、disconnect terminal `closed`、`transport_close_complete` を記録した。利用者が Switch 画面上の Button A 反応を確認した。
|
|
2470
|
+
- artifact: `tmp/hardware/dongle-33fa-input-20260726/post-handshake-a-close.jsonl`
|
|
2471
|
+
- cleanup: Button A 後に neutral state を確認し、trailing neutral `0x30`、interrupt / control channel close、disconnect terminal `closed`、adapter release を完了。
|
|
2472
|
+
- notes: 画面反応はこの Windows / WinUSB / libwdi / Bumble / `33FA:0010` の構成における hardware observation。active reconnect は別 run で reason `19` により未解決。
|
|
2473
|
+
|
|
2474
|
+
## 2026-07-26: VID:PID 33FA:0010 extended-features workaround active reconnect retry
|
|
2475
|
+
|
|
2476
|
+
- OS: Windows-11-10.0.26200-SP0
|
|
2477
|
+
- environment: swbt-python 0.5.3, Bumble 0.0.233, Python 3.13.5
|
|
2478
|
+
- adapter: `usb:0` (`USB2.0-BT`, VID:PID `33FA:0010`)
|
|
2479
|
+
- dongle: 専用 USB Bluetooth dongle として利用者が接続
|
|
2480
|
+
- driver: WinUSB, libwdi 6.1.7600.16385, `oem93.inf`
|
|
2481
|
+
- command / test: `uv run pytest tests/hardware/test_pairing_profile.py::test_switch_adapter_default_profile_reuses_address_after_normal_close -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/dongle-33fa-pairing-20260725 -q -s`
|
|
2482
|
+
- approval: 利用者承認下で Bumble adapter open、active reconnect、HID control / interrupt channel、neutral close / adapter release。re-pairing、input、BD_ADDR 書換えは実行しない。
|
|
2483
|
+
- result: fail(`1 failed in 2.58s`)。初回と同じく `hci_workaround_enabled`、selected bonded peer、`host_connection` の後、L2CAP channel open と protocol ready の前に Switch 側 reason `19` で切断された。`active_reconnect_result(status=failed, failure_reason=transport_error)` を記録した。
|
|
2484
|
+
- artifact: `tmp/hardware/dongle-33fa-pairing-20260725/pairing-profile-adapter-default-reconnect.jsonl`
|
|
2485
|
+
- cleanup: `disconnect_request(status=unavailable, reason=transport_closed)` と `transport_close_complete`。残存 workspace Python process はない。
|
|
2486
|
+
- notes: 同条件の active reconnect failure を2回観測した。fresh pairing と Button A UI 反映は成功しているため、HCI `0x1004` workaround の検証とは別の reconnect 問題として扱う。
|
|
2487
|
+
|
|
2488
|
+
## 2026-07-26: VID:PID 33FA:0010 experiment disposition
|
|
2489
|
+
|
|
2490
|
+
- result: temporary `0x1004` suppression proved that fresh pairing と Button A UI 反映は可能だったが、正式な workaround 実装は main に取り込まない。
|
|
2491
|
+
- artifact: prior entries の `tmp/hardware/dongle-extended-features-workaround-20260725/`、`tmp/hardware/dongle-33fa-pairing-20260725/`、`tmp/hardware/dongle-33fa-input-20260726/`
|
|
2492
|
+
- notes: ここまでの結果は hardware observation であり、adapter 互換性または Bumble の一般契約を表さない。再検討条件は `spec/dev-journal.md` に記録する。
|
|
2493
|
+
|
|
2494
|
+
## 2026-07-26: unit_086 fresh pairing直後の50 ms Button A
|
|
2495
|
+
|
|
2496
|
+
- OS: Windows 11 `Windows-11-10.0.26200-SP0`
|
|
2497
|
+
- environment: `spec/issue-149-normal-input-readiness` branch、commit `730e5bc` と未コミットのunit_086実装。Python 3.13.5 / Bumble 0.0.233 / swbt-python 0.5.3
|
|
2498
|
+
- adapter: dedicated `usb:0`。no-open列挙でCSR8510 A10、VID:PID `0A12:0001`、bus 5 / device 22 / port 9.1を確認
|
|
2499
|
+
- dongle: CSR8510 A10。過去の`33FA:0010`個体ではなく、実行直前に列挙した専用個体
|
|
2500
|
+
- driver: WinUSB / libwdi 6.1.7600.16385、`oem75.inf`
|
|
2501
|
+
- Switch model: 今回は再確認していない
|
|
2502
|
+
- Switch firmware: 今回は再確認していない
|
|
2503
|
+
- report period: 既定 8000 us
|
|
2504
|
+
- command / test: `uv run pytest tests/hardware/test_reply_holdoff.py::test_switch_periodic_fresh_pairing_allows_immediate_50ms_a_input -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir tmp/hardware/unit_086/normal-input-readiness-fresh-20260726-213142 --log-file tmp/hardware/unit_086/normal-input-readiness-fresh-20260726-213142/pytest-debug.log --log-file-level=DEBUG -q -s -p no:cacheprovider --basetemp tmp/hardware/unit_086/normal-input-readiness-fresh-20260726-213142/pytest-tmp`
|
|
2505
|
+
- approval: 利用者がSwitch側の既存登録を削除して「持ちかた/順番を変える」画面を準備し、専用`usb:0`のadapter open、HID advertising、fresh pairing、subcommand handling、周期送信、接続完了直後の50 ms Button A、neutral close、adapter releaseを明示承認
|
|
2506
|
+
- command result: `1 failed in 5.58s`。hardware testが周期送信のdiagnostics reasonを`input`として数えたため、実際には送信済みの`reason=periodic`を0件と誤判定した。テストは`periodic`を数えるよう修正した
|
|
2507
|
+
- hardware result: observed-pass。`classic_pairing`、key store update、`protocol_ready` index 100、`input_ready(reporting_mode=periodic, route=pairing)` index 101を記録。50 ms入力窓にButton A bitを持つ周期`0x30`をtimer `0x15`から`0x1B`まで7件記録し、その後にneutral `0x30`を記録した。利用者が対象機器側のButton A反映を目視確認した
|
|
2508
|
+
- artifact: `tmp/hardware/unit_086/normal-input-readiness-fresh-20260726-213142/normal-input-readiness-pro.jsonl`、`pytest-debug.log`、pairing profile。profile SHA-256は`01B892090639D180DC39521997415C13E43D8E2307E266DA817F2FCD11EDC6CE`。link keyは転記しない
|
|
2509
|
+
- cleanup: assertion failure後も`finally`で`close(neutral=True)`を実行。neutral `0x30`、interrupt / control channel close、disconnect terminal `closed`、`transport_close_complete` index 119を確認し、adapterを解放した
|
|
2510
|
+
- notes: hardware behaviorはtraceと利用者のUI観測で成立したが、修正後のpytest commandはfresh pairingを再実行していない。fake transport integrationはA付きreport byteを検査済み。今回の結果を任意の短時間入力、別adapter、別OS、別firmwareへ一般化しない
|
|
@@ -186,7 +186,8 @@ class DirectProController(DirectSwitchGamepad):
|
|
|
186
186
|
|
|
187
187
|
`create_profile()` は HID control / interrupt channel の接続だけではコントローラーオブジェクト
|
|
188
188
|
を返さない。同じ接続 session で `0x03 30` と 0 以外の `0x30` player lights を受信し、
|
|
189
|
-
各 reply の transport 送信が完了した protocol ready
|
|
189
|
+
各 reply の transport 送信が完了した protocol ready へ進む。その後、通常入力経路が
|
|
190
|
+
初期化中に設定された holdoff に抑止されない状態になってから返す。この公開契約は
|
|
190
191
|
Pro Controller、Joy-Con L/R、Periodic / Direct で共通とする。
|
|
191
192
|
|
|
192
193
|
| 引数 | 意味 |
|
|
@@ -232,7 +233,9 @@ async def try_connect(
|
|
|
232
233
|
async def close(self, *, neutral: bool = True) -> None: ...
|
|
233
234
|
```
|
|
234
235
|
|
|
235
|
-
`open()` は transport、callback、diagnostics、共通 sender を準備する。Periodic
|
|
236
|
+
`open()` は transport、callback、diagnostics、共通 sender を準備する。Periodic の
|
|
237
|
+
`ReportLoop` は通常入力 readiness の成立時に作成し、Direct は通常入力用の周期 task を
|
|
238
|
+
作らない。`open()` だけでは HID advertising、pairing、reconnect を開始しない。
|
|
236
239
|
|
|
237
240
|
`pair()` は初回 pairing のための入口である。内部では HID advertising と incoming 接続待ちを開始する。
|
|
238
241
|
|
|
@@ -240,9 +243,15 @@ async def close(self, *, neutral: bool = True) -> None: ...
|
|
|
240
243
|
|
|
241
244
|
`connect()` は通常利用向けの入口である。保存済み bond があれば `reconnect()` を優先し、bond がない場合は `allow_pairing=True` のときだけ `pair()` へ進む。
|
|
242
245
|
|
|
246
|
+
接続 API の正常終了は、選択された reporting type の通常入力経路が利用可能であることを
|
|
247
|
+
意味する。Periodic は protocol ready 後、readiness 公開前に受理された最新 reply の
|
|
248
|
+
automatic input holdoff が終了してから `ReportLoop` を開始する。Direct の明示入力は
|
|
249
|
+
automatic input holdoff の対象外なので、protocol ready で通常入力 readiness を満たす。
|
|
250
|
+
Direct に待機確認用の `0x30` は送らない。
|
|
251
|
+
|
|
243
252
|
`close()` は Periodic の送信 loop と共通 transport を停止する。`neutral=True` かつ接続中の場合、Direct でも終了処理の例外としてニュートラル入力を1件送信し、成功後に state を確定する。`neutral=False` は終了用入力レポートを追加しない。
|
|
244
253
|
|
|
245
|
-
`connect()` / `reconnect()`
|
|
254
|
+
`connect()` / `reconnect()` は通常入力 readiness まで成功した場合だけ戻る。接続できない場合は `ConnectionFailedError`、timeout は `ConnectionTimeoutError` を投げる。接続失敗の詳細 status が必要な場合は `try_connect()` / `try_reconnect()` を使い、`ConnectionResult` を読む。`pair()` は初回 pairing の明示入口であり、接続戦略の選択結果は返さない。
|
|
246
255
|
|
|
247
256
|
`ConnectionResult.status` は `"connected"`、`"no_bond"`、`"timeout"`、`"failed"` のいずれかである。current peer が複数ある key store は旧形式または不正形式として扱い、`InvalidKeyStoreError` を投げる。これは接続失敗ではなく永続状態の形式不一致であるため、`try_reconnect()` でも `ConnectionResult` へ畳み込まない。
|
|
248
257
|
|
|
@@ -13,7 +13,7 @@ SwitchGamepad public ABC / runtime delegation
|
|
|
13
13
|
↓
|
|
14
14
|
ControllerRuntime + InputStateStore
|
|
15
15
|
├─ ProtocolHandshake [initializing中だけ]
|
|
16
|
-
├─ PeriodicSwitchGamepad → ReportLoop [
|
|
16
|
+
├─ PeriodicSwitchGamepad → ReportLoop [通常入力 readiness 成立時から]
|
|
17
17
|
└─ DirectSwitchGamepad → input operation lock
|
|
18
18
|
↓
|
|
19
19
|
ReportSender ← OutputReportDispatcher
|
|
@@ -86,11 +86,11 @@ resource scope の `open()` / `close()`、明示接続 API の `pair()` / `conne
|
|
|
86
86
|
|
|
87
87
|
`SwitchGamepad` は共通 public method と `ControllerRuntime` への参照を所有する。公開 method の実装は、lifecycle、connection、意味的入力、status、snapshot を runtime へ委譲する。`SwitchGamepad` は第三者実装用の runtime 非依存 interface とは扱わない。
|
|
88
88
|
|
|
89
|
-
stateful owner は `ControllerRuntime` とする。runtime は内部に `InputStateStore`、`ReportSender`、`SwitchHidProtocol`、`HidDeviceTransport` を保持する。link接続からprotocol readyまでは、同じsessionとsenderを借用する期限付き`ProtocolHandshake`を保持する。Periodic の runtime
|
|
89
|
+
stateful owner は `ControllerRuntime` とする。runtime は内部に `InputStateStore`、`ReportSender`、`SwitchHidProtocol`、`HidDeviceTransport` を保持する。link接続からprotocol readyまでは、同じsessionとsenderを借用する期限付き`ProtocolHandshake`を保持する。Periodic の runtime は最新replyのautomatic input holdoff終了後に`ReportLoop`を開始して通常入力 readiness を公開し、Directは全lifecycleで生成しない。利用者に内部コンポーネントを直接操作させない。
|
|
90
90
|
|
|
91
91
|
各具象 gamepad は controller profile を class 属性として所有する。公開 constructor は profile default と明示引数を内部設定型 `_GamepadConfig` へ正規化し、`ControllerRuntime` の唯一の constructor を呼ぶ。runtime に transport が注入されていればその instance を使い、未指定なら open 時に `create_default_transport()` を直接呼ぶ。transport factory object、constructor 回避、production package 内の test 用 factory は置かない。Bumble transport の import は `create_default_transport()` の関数内に閉じ込める。
|
|
92
92
|
|
|
93
|
-
`ControllerRuntime` は reconnect と no-bond 時の optional pairing fallback も所有する。transport は current bonded peer の address または `None` を返し、複数 current peer は `InvalidKeyStoreError` とする。runtime の状態、protocol
|
|
93
|
+
`ControllerRuntime` は reconnect と no-bond 時の optional pairing fallback も所有する。transport は current bonded peer の address または `None` を返し、複数 current peer は `InvalidKeyStoreError` とする。runtime の状態、protocol readyと通常入力 readiness のwait、cleanup を callback object に再包装しない。
|
|
94
94
|
|
|
95
95
|
### 2.2 `InputState`
|
|
96
96
|
|
|
@@ -108,7 +108,7 @@ stateful owner は `ControllerRuntime` とする。runtime は内部に `InputSt
|
|
|
108
108
|
|
|
109
109
|
`ProtocolHandshake` はlink接続直後のbootstrap neutralと、supported report modeからreadyまでのneutralを送る。readyまたはfailureで停止・破棄し、sender、session、dispatcherはRuntimeに残る。
|
|
110
110
|
|
|
111
|
-
`ReportLoop` は Periodic
|
|
111
|
+
`ReportLoop` は Periodic だけが通常入力 readiness 成立時から所有する scheduler であり、一定周期で current state を `ReportSender` へ渡す。Direct は `ReportLoop` を生成せず、input operation lock 内で候補 state を `ReportSender` へ渡す。output report / subcommand は両型で自動処理し、同じ `ReportSender` へ入る。
|
|
112
112
|
|
|
113
113
|
送信周期の初期値は `8000us` とする。ただし、この値は既定値であり、全環境での最適値とは扱わない。実送信時刻は diagnostics に記録する。
|
|
114
114
|
|