swbt-python 0.2.0__tar.gz → 0.4.0__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.2.0 → swbt_python-0.4.0}/AGENTS.md +10 -1
- {swbt_python-0.2.0 → swbt_python-0.4.0}/PKG-INFO +2 -3
- {swbt_python-0.2.0 → swbt_python-0.4.0}/README.md +1 -2
- {swbt_python-0.2.0 → swbt_python-0.4.0}/pyproject.toml +1 -1
- swbt_python-0.4.0/spec/complete/unit_047/VIRTUAL_GYRO_CALIBRATION.md +272 -0
- swbt_python-0.4.0/spec/complete/unit_048/VIRTUAL_ACCELEROMETER_CALIBRATION.md +131 -0
- swbt_python-0.4.0/spec/complete/unit_049/IMU_SESSION_AND_ENCODING_REDESIGN.md +427 -0
- swbt_python-0.4.0/spec/complete/unit_050/DIRECT_REPORTING_TYPES.md +260 -0
- swbt_python-0.4.0/spec/dev-journal.md +3 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/hardware-test-log.md +60 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/api.md +116 -61
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/architecture.md +26 -16
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/lifecycle.md +20 -14
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/protocol.md +18 -5
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/testing.md +44 -8
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/__init__.py +10 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/_testing/gamepad.py +72 -1
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/__init__.py +12 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/core.py +105 -28
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/interface.py +55 -26
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/output.py +16 -5
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/runtime.py +161 -20
- swbt_python-0.4.0/src/swbt/imu.py +116 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/input.py +122 -0
- swbt_python-0.4.0/src/swbt/protocol/imu_report.py +186 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/input_report.py +21 -18
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/profiles/base.py +8 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/profiles/joycon.py +3 -3
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/profiles/pro_controller.py +1 -1
- swbt_python-0.4.0/src/swbt/protocol/session.py +112 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/spi.py +12 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/subcommand.py +45 -40
- swbt_python-0.4.0/src/swbt/report_loop.py +200 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_controller_colors.py +36 -2
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_input_operations.py +190 -1
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_joycon_profile.py +42 -9
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/integration/test_switch_gamepad_fake_transport.py +701 -3
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/fixtures/source_audit/switch_protocol_values.toml +48 -4
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_gamepad_output_dispatcher.py +10 -1
- swbt_python-0.4.0/tests/unit/test_imu_report.py +149 -0
- swbt_python-0.4.0/tests/unit/test_input_report.py +423 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_input_state.py +71 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_package_import.py +10 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_protocol_profile.py +35 -0
- swbt_python-0.4.0/tests/unit/test_protocol_session.py +91 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_public_api_boundary.py +58 -2
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_publish_workflow.py +45 -25
- swbt_python-0.4.0/tests/unit/test_report_loop.py +127 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_source_audit_fixtures.py +59 -2
- swbt_python-0.4.0/tests/unit/test_subcommand_responder.py +373 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_virtual_spi_flash.py +46 -3
- swbt_python-0.2.0/spec/dev-journal.md +0 -23
- swbt_python-0.2.0/src/swbt/report_loop.py +0 -115
- swbt_python-0.2.0/tests/unit/test_docs_workflow.py +0 -68
- swbt_python-0.2.0/tests/unit/test_hardware_test_log_docs.py +0 -73
- swbt_python-0.2.0/tests/unit/test_input_report.py +0 -200
- swbt_python-0.2.0/tests/unit/test_mkdocs_site.py +0 -46
- swbt_python-0.2.0/tests/unit/test_public_api_docstrings.py +0 -243
- swbt_python-0.2.0/tests/unit/test_public_docs.py +0 -361
- swbt_python-0.2.0/tests/unit/test_readme_docs.py +0 -133
- swbt_python-0.2.0/tests/unit/test_release_gate_docs.py +0 -76
- swbt_python-0.2.0/tests/unit/test_report_loop.py +0 -62
- swbt_python-0.2.0/tests/unit/test_subcommand_responder.py +0 -239
- {swbt_python-0.2.0 → swbt_python-0.4.0}/LICENSE +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/examples/hardware_bringup.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/examples/pairing_probe.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/examples/tap_a.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_001/M0_PROTOCOL_CORE.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_002/M1_SWITCH_GAMEPAD_FAKE_TRANSPORT.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_003/M2_BUMBLE_HID_TRANSPORT.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_004/M3_PAIRING_L2CAP.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_005/M4_SUBCOMMAND_RESPONDER_HARDWARE.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_006/M5_INPUT_OPERATION_API.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_007/M6_RECONNECT_KEYSTORE_DIAGNOSTICS.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_008/M7_PACKAGING_EXAMPLES_CLI.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_009/PORTING_SOURCE_AUDIT.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_010/DIAGNOSTICS_TRACE_SCHEMA.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_011/HARDWARE_TEST_LOG_MATRIX.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_012/INITIAL_RELEASE_GATE.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_013/POST_M5_INPUT_SEMANTIC_CHARACTERIZATION.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_014/DEVICE_CLOSE_GRACEFUL_DISCONNECT.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_015/CONTEXT_MANAGER_RESOURCE_SCOPE.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_016/JSON_KEY_STORE_CURRENT_PREVIOUS.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_017/SWITCH_GAMEPAD_API_HARDENING.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_018/KEY_STORE_TRANSPORT_BOUNDARY.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_019/TRANSPORT_RECONNECT_CONTRACT.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_020/STRUCTURAL_REFACTOR_BOUNDARIES.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_021/SWITCH_GAMEPAD_INPUT_API_CONTRACT.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_022/PUBLIC_API_USAGE_HARDWARE_DOCS.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_023/MKDOCS_DOCUMENTATION_SITE.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_024/STICK_INPUT_SHORTHAND_API.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_025/IMU_INPUT_SHORTHAND_API.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_026/LINUX_MACOS_ADAPTER_EXPERIMENTAL.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_027/ADAPTER_DISCOVERY_API.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_028/CONTROLLER_PROFILE_CUSTOMIZATION.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_029/CONTROLLER_PROFILE_INJECTION.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_030/JOYCON_PROFILE_IDENTITY_SPI.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_031/JOYCON_INPUT_REPORT_MAPPING.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_032/PROFILE_AWARE_SUBCOMMAND_STATE.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_033/PROFILE_AWARE_BUMBLE_SDP.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_034/JOYCON_CONVENIENCE_API_DOCS.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_035/JOYCON_DEVICE_INFO_ADDRESS_WIRING.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_036/JOYCON_SDP_IDENTITY_POLICY.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_037/JOYCON_DEFAULT_CONTROLLER_COLORS.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_038/REARCHITECTURE_DECISION_BOUNDARY_TESTS.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_039/CONTROLLER_RUNTIME_EXTRACTION.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_040/PUBLIC_CONTROLLER_API_MODEL.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_041/CONTROLLER_CONFIG_PROFILE_OWNERSHIP.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_042/INTERNAL_TRANSPORT_FACTORY.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_043/PROTOCOL_PROFILE_MODULE_SPLIT.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_044/REARCHITECTURE_DOCS_RELEASE_MATRIX.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_045/INTERNAL_API_BOUNDARY_CLEANUP.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/complete/unit_046/HARDWARE_PROFILE_TEST_SCENARIOS.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/README.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/naming.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/risks.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/roadmap.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/initial/transport-bumble.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/rearchitecture/01-design-change-overview.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/rearchitecture/02-as-is-to-be.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/rearchitecture/03-public-api-config-profile.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/rearchitecture/04-runtime-profile-transport-details.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/rearchitecture/05-milestones-implementation.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/rearchitecture/README.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/spec/rearchitecture/mkdocs-nav-snippet.yml +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/_testing/__init__.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/adapter_discovery.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/diagnostics.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/errors.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/_config.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/connection.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/constants.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/gamepad/transport_factory.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/probe.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/__init__.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/buttons.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/descriptors.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/output_report.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/profiles/__init__.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/protocol/rumble.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/py.typed +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/state_store.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/__init__.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/_bumble_acl.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/_bumble_hidp.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/_bumble_key_store.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/_bumble_lifecycle.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/_bumble_sdp.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/_bumble_usb_devices.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/base.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/bumble.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/src/swbt/transport/fake.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/conftest.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/README.md +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_bumble_transport.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_close_disconnect.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_context_manager_resource_scope.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_pairing_l2cap.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/hardware/test_reconnect_keystore.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/integration/test_examples.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_adapter_discovery.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_bumble_acl.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_bumble_hidp.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_bumble_key_store_metadata.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_bumble_lifecycle.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_bumble_sdp.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_bumble_transport.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_ci_workflow.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_diagnostics.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_gamepad_connection_workflow.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_gamepad_transport_factory.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_output_report.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_package_metadata.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_probe_cli.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_protocol_boundary.py +0 -0
- {swbt_python-0.2.0 → swbt_python-0.4.0}/tests/unit/test_rumble_state.py +0 -0
|
@@ -77,10 +77,18 @@
|
|
|
77
77
|
| 実機観測 | `spec/hardware-test-log.md` |
|
|
78
78
|
| 初期設計 | `spec/initial/` |
|
|
79
79
|
|
|
80
|
-
作業仕様には、対象範囲、対象外、関連 docs、根拠監査、TDD Test List
|
|
80
|
+
作業仕様には、対象範囲、対象外、関連 docs、根拠監査、TDD Test List または文書検証計画、検証、実機実行条件、先送り事項、チェックリストを含める。
|
|
81
81
|
|
|
82
82
|
複数の作業仕様から参照する安定した判断は、既存の `spec/initial/` を更新するか、必要に応じて `spec/` 配下へ分ける。未確定の観測は `spec/dev-journal.md` に置く。
|
|
83
83
|
|
|
84
|
+
## 文書の検証
|
|
85
|
+
|
|
86
|
+
- 自然言語の意味要件を、固定語句の存在・不在 assertion に置き換えない。正しい言い換えを落とす検査、または誤った説明を通す検査は追加しない。
|
|
87
|
+
- 自動検査の対象は、生成、構造、リンク、参照先、front matter、構造化データ、生成元との対応など、機械的に観測でき、失敗原因を切り分けられる契約に限る。
|
|
88
|
+
- 説明の事実性、読者が手順を完了するための前提・操作・終了後の復帰手順、未検証範囲の伝達は、正本との照合を伴うレビューで検証する。pytest の成功をその根拠にしない。
|
|
89
|
+
- docs / spec / skill だけの作業では、TDD Test List と pytest を必須にしない。選んだ自動検査、レビュー、未実行の検証を理由付きで記録する。
|
|
90
|
+
- README、利用者向け docs、公開 API docstring、release notes を変更した場合は `docs-quality-review` を使い、未解決の修正必須事項を handoff または PR 本文に残す。
|
|
91
|
+
|
|
84
92
|
## Agent Skills
|
|
85
93
|
|
|
86
94
|
repo-local skill は `.agents/skills` を正本として管理する。`.github/skills` には重複配置しない。
|
|
@@ -92,6 +100,7 @@ repo-local skill は `.agents/skills` を正本として管理する。`.github/
|
|
|
92
100
|
- `spec-format`: `spec/wip` / `spec/complete` の作業仕様を作成、更新、完了移動する。
|
|
93
101
|
- `dev-journal`: 小さい設計観測や先送り事項を `spec/dev-journal.md` に記録する。
|
|
94
102
|
- `docs-wording`: README、docs、release notes の文言整理で、swbt-python 固有の訳語と残す英語表記をそろえる。
|
|
103
|
+
- `docs-quality-review`: README、利用者向け docs、公開 API docstring、release notes を、対象読者の利用手順、根拠、未検証範囲、読みやすさの観点で確認する。
|
|
95
104
|
- `source-audit`: Switch HID、Bumble、既存実装、実機ログ由来の値を根拠分類して記録する。
|
|
96
105
|
- `hardware-harness`: Bumble adapter、Bluetooth dongle、Switch 実機を使う検証の承認境界と記録項目を確認する。
|
|
97
106
|
- `tdd-workflow`: TDD Test List から red / green / refactor を進める。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swbt-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
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
|
|
@@ -83,7 +83,6 @@ asyncio.run(main())
|
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
Pro Controller 相当の仮想デバイスを作成し、ペアリング後に A ボタン入力を送信するコードの例です。
|
|
86
|
-
接続情報ファイルの形式、入力 API の使い分けなどに関する詳しい説明は [Usage Guide](https://niart120.github.io/swbt-python/usage/) にあります。
|
|
87
86
|
|
|
88
87
|
### Joy-Con L/R
|
|
89
88
|
|
|
@@ -129,7 +128,7 @@ macOS 15.7.7 / CSR8510 A10 では、Pro Controller のペアリング、保存
|
|
|
129
128
|
|
|
130
129
|
### 実験的構成
|
|
131
130
|
|
|
132
|
-
Linux は experimental です。手順は Hardware Guide に整備されていますが、専用 USB Bluetooth ドングルにアクセスできるか、ペアリングできるか、入力が反映されるかは未確認です。macOS は Pro Controller
|
|
131
|
+
Linux は experimental です。手順は Hardware Guide に整備されていますが、専用 USB Bluetooth ドングルにアクセスできるか、ペアリングできるか、入力が反映されるかは未確認です。macOS は Pro Controller の一部挙動のみ検証済みです。Joy-Con、別ドングル、別ファームウェアでの互換性は未確認です。
|
|
133
132
|
|
|
134
133
|
## 開発
|
|
135
134
|
|
|
@@ -57,7 +57,6 @@ asyncio.run(main())
|
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
Pro Controller 相当の仮想デバイスを作成し、ペアリング後に A ボタン入力を送信するコードの例です。
|
|
60
|
-
接続情報ファイルの形式、入力 API の使い分けなどに関する詳しい説明は [Usage Guide](https://niart120.github.io/swbt-python/usage/) にあります。
|
|
61
60
|
|
|
62
61
|
### Joy-Con L/R
|
|
63
62
|
|
|
@@ -103,7 +102,7 @@ macOS 15.7.7 / CSR8510 A10 では、Pro Controller のペアリング、保存
|
|
|
103
102
|
|
|
104
103
|
### 実験的構成
|
|
105
104
|
|
|
106
|
-
Linux は experimental です。手順は Hardware Guide に整備されていますが、専用 USB Bluetooth ドングルにアクセスできるか、ペアリングできるか、入力が反映されるかは未確認です。macOS は Pro Controller
|
|
105
|
+
Linux は experimental です。手順は Hardware Guide に整備されていますが、専用 USB Bluetooth ドングルにアクセスできるか、ペアリングできるか、入力が反映されるかは未確認です。macOS は Pro Controller の一部挙動のみ検証済みです。Joy-Con、別ドングル、別ファームウェアでの互換性は未確認です。
|
|
107
106
|
|
|
108
107
|
## 開発
|
|
109
108
|
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Virtual Gyroscope Calibration 仕様書
|
|
2
|
+
|
|
3
|
+
## 1. 概要
|
|
4
|
+
|
|
5
|
+
### 1.1 目的
|
|
6
|
+
|
|
7
|
+
仮想 Pro Controller が Switch へ返す factory 6-axis calibration のジャイロ部分と、利用者が物理角速度から `IMUFrame` を生成する変換尺度を一元化する。
|
|
8
|
+
|
|
9
|
+
### 1.2 起点 / source
|
|
10
|
+
|
|
11
|
+
| source | 内容 | path |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| GitHub Issue #69 | `ControllerProfile` による校正値所有、SPI `0x602C-0x6037`、固定尺度 `0.070 dps/raw`、物理角速度 API、実機回帰の完了条件 | https://github.com/niart120/swbt-python/issues/69 |
|
|
14
|
+
| user follow-up | Joy-Con L/R profile も同じ仮想ジャイロ校正値を SPI に設定する | 2026-07-11 conversation |
|
|
15
|
+
| hardware observation | ZL は反映されたが、IMU有効化・gyro PDU送信・静止加速度追加後もスプラトゥーン3のカメラは動かなかった。Switchが一括取得したfactory 6-axis calibrationのaccel側は全て `FF` だった | `build/hardware/issue-69-gyro-calibration-20260712/` |
|
|
16
|
+
| upstream reverse-engineering notes | 6-axis factory calibration は 4 組の XYZ Int16LE。後半 2 組が gyro zero / reference で、既定 reference は `0x343B` | https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/spi_flash_notes.md |
|
|
17
|
+
| upstream IMU notes | saturation-free LSM6DS3 ±2000 dps の尺度は `0.070 dps/raw`。SPI 校正の gyro zero は静止時 offset | https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/imu_sensor_notes.md |
|
|
18
|
+
| MissionControl mode dispatch / packing | subcommand `0x40`の`0x01`は標準形式、`0x02-0x05`はquaternion形式。packing mode 2の36 byte layoutと姿勢更新 | https://github.com/ndeadly/MissionControl/tree/d3941d433f15827de8aea116d61ea17bb61d0bcc/mc_mitm/source/controllers |
|
|
19
|
+
| completed unit | 既存 `IMUFrame.raw()` / `gyro()` / `with_gyro()` と signed int16 validation | `spec/complete/unit_025/IMU_INPUT_SHORTHAND_API.md` |
|
|
20
|
+
| current implementation | SPI は device type、color flag、controller colors のみ profile から seed し、6-axis calibration は erased のまま | `src/swbt/protocol/spi.py` |
|
|
21
|
+
|
|
22
|
+
### 1.3 use case
|
|
23
|
+
|
|
24
|
+
| actor / boundary | 入力または状態 | 期待する観測結果 | 制約 |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| Switch host | factory SPI `0x602C` から 12 bytes を読む | 仮想ジャイロの zero XYZ と reference XYZ を取得する | signed int16 little-endian、軸順 XYZ |
|
|
27
|
+
| library user | 3 軸の角速度を rad/s で指定する | 同じ校正定義で raw へ変換した `IMUFrame` を得る | 単位は rad/s、尺度は `0.070 dps/raw` 固定 |
|
|
28
|
+
| diagnostics | raw gyro を持つ `IMUFrame` を逆変換する | 3 軸の角速度を rad/s で得る | SPI と同じ zero と尺度を使う |
|
|
29
|
+
| existing user | `IMUFrame.raw()` / `IMUFrame.gyro()` を使う | 従来どおり signed int16 raw 値を設定できる | 既存 API を変更しない |
|
|
30
|
+
|
|
31
|
+
### 1.4 Intent Delta
|
|
32
|
+
|
|
33
|
+
当初はIssue #69どおりfactory 6-axis calibrationのgyro部分だけを対象とした。実機ではSwitchが`0x6020`から24 bytesを一括取得し、accel側12 bytesが全て`FF`の状態では、gyro値と静止加速度を正しくpackしてもスプラトゥーン3のカメラ反映を確認できなかった。
|
|
34
|
+
|
|
35
|
+
6-axis calibrationブロック全体を有効にするため、factory accel calibrationはIssue #70と`spec/complete/unit_048/VIRTUAL_ACCELEROMETER_CALIBRATION.md`で実装する。本 unit はその校正値と共存するgyro側の契約を追跡する。
|
|
36
|
+
|
|
37
|
+
実機再試験ではSwitch 2 firmware 22.1.0がsubcommand `0x40` payload `0x02`を送り、swbt-pythonは従来の3×6-axis形式を返していた。正負Z rawの閾値的な反応と乱回転を校正値で解消できなかった後、MissionControlがmode `0x02-0x05`をquaternion形式へ切り替える実装を確認した。
|
|
38
|
+
|
|
39
|
+
このため本unitへhost IMU modeに応じた36 byte packingを追加する。mode `0x01`の従来形式とpublic raw/rad/s APIは維持し、mode `0x02-0x05`だけ状態を持つquaternion packing mode 2へ変換する。Pro Controller、Joy-Con L、Joy-Con Rは同じmode分岐とwire packerを使う。
|
|
40
|
+
|
|
41
|
+
## 2. 対象範囲
|
|
42
|
+
|
|
43
|
+
- `ControllerProfile` が仮想ジャイロ校正情報を所有する。
|
|
44
|
+
- Pro Controller、Joy-Con L、Joy-Con R の具象 profile が同じ既定校正を共有する。
|
|
45
|
+
- 既定校正を全軸 zero raw `0`、reference raw `0x343B`、`0.070 dps/raw` とする。
|
|
46
|
+
- `VirtualSpiFlash` が profile の校正情報から `0x602C-0x6037` を生成する。
|
|
47
|
+
- `VirtualSpiFlash` が profile の校正情報から accel側 `0x6020-0x602B` も生成し、factory 6-axis calibration 24 bytesを完成させる。
|
|
48
|
+
- `IMUFrame.gyro_rate(x_rad_s=..., y_rad_s=..., z_rad_s=...)` を追加する。
|
|
49
|
+
- `IMUFrame.with_gyro_rate(...)` と `IMUFrame.to_gyro_rate()` を追加する。
|
|
50
|
+
- rad/s と raw の相互変換、3 軸、signed int16 境界、範囲外を unit test で固定する。
|
|
51
|
+
- public docs、docstring、initial design を更新する。
|
|
52
|
+
- Pro Controller のジャイロ入力を Switch 実機で回帰確認し、結果を記録する。
|
|
53
|
+
- subcommand sessionのIMU modeをinput report builderと共有する。
|
|
54
|
+
- mode `0x01`では既存の3×6-axis Int16LE形式を維持する。
|
|
55
|
+
- Pro Controller、Joy-Con L、Joy-Con Rのmode `0x02-0x05`では、加速度3 sampleと積分済み姿勢をpacking mode 2の36 byteへ格納する。
|
|
56
|
+
|
|
57
|
+
## 3. 対象外
|
|
58
|
+
|
|
59
|
+
- 加速度センサーの校正、G単位変換、公開API。Issue #70 / unit_048で扱う。
|
|
60
|
+
- `0.070 dps/raw` 以外の尺度を選ぶ設定。
|
|
61
|
+
- full-span から尺度を算出する方式。
|
|
62
|
+
- `816` / `936` を conversion 定数として使う方式。
|
|
63
|
+
- 加速度とジャイロを融合する姿勢推定、ノイズや温度ドリフトの再現。mode `0x02-0x05`に必要な角速度積分だけを行う。
|
|
64
|
+
- マウス入力から角速度を生成する処理。
|
|
65
|
+
- ユーザー向け校正 GUI。
|
|
66
|
+
- Joy-Con の加速度校正、スティック校正、固有の軸反転、実機回帰。Joy-Con L/Rのジャイロ校正seedとPro Controller共通のquaternion wire packingは対象に含む。
|
|
67
|
+
|
|
68
|
+
## 4. 関連 docs
|
|
69
|
+
|
|
70
|
+
- `spec/initial/api.md`
|
|
71
|
+
- `spec/initial/architecture.md`
|
|
72
|
+
- `spec/initial/protocol.md`
|
|
73
|
+
- `spec/initial/testing.md`
|
|
74
|
+
- `spec/complete/unit_025/IMU_INPUT_SHORTHAND_API.md`
|
|
75
|
+
- `spec/complete/unit_028/CONTROLLER_PROFILE_CUSTOMIZATION.md`
|
|
76
|
+
- `spec/hardware-test-log.md`
|
|
77
|
+
- `docs/api.md`
|
|
78
|
+
- `docs/usage.md`
|
|
79
|
+
- `docs/agent-brief.md`
|
|
80
|
+
|
|
81
|
+
## 5. 根拠監査
|
|
82
|
+
|
|
83
|
+
| 項目 | 要否 | 状態 | 根拠 / 理由 |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| Switch HID / report bytes | required | done | dekuNukem `spi_flash_notes.md` は 6-axis calibration を 4 組の XYZ Int16LE とし、後半 2 組を gyro calibration、reference 既定値を各軸 `0x343B` と記録する。従って gyro 部分は `0x602C-0x6037`、zero XYZ の後に reference XYZ とする |
|
|
86
|
+
| gyro conversion scale | required | done | dekuNukem `imu_sensor_notes.md` は saturation-free LSM6DS3 ±2000 dps を `0.070 dps/raw` とする。Issue #69 はこの尺度を固定し、full-span 換算と `816` / `936` の直接利用を明示的に除外する |
|
|
87
|
+
| factory accel calibration | required | done | dekuNukem `spi_flash_notes.md` は6-axis calibration前半2 groupsをAccel XYZ origin/reference、既定referenceを各軸`0x4000`とする。virtual zeroは各軸`0`とし、物理加速度APIには拡大しない |
|
|
88
|
+
| IMU mode `0x02-0x05` packing | required | done | MissionControlはmode `0x01`を標準形式、`0x02-0x05`をQuaternionMotionPackerへ分岐し、packing mode 2のbitfieldを定義する。commit `d3941d433f15827de8aea116d61ea17bb61d0bcc`をsource-audit fixtureへ固定した |
|
|
89
|
+
| Bumble / transport | not applicable | not applicable | report packing、transport、advertising、L2CAP は変更しない |
|
|
90
|
+
| OS / driver / adapter | required | done | Windows 11 / CSR8510 A10 / WinUSB / Bumble `usb:0` で実行し、環境とcleanupをhardware logへ記録した |
|
|
91
|
+
|
|
92
|
+
### 5.1 監査値
|
|
93
|
+
|
|
94
|
+
| 項目 | 値 | 根拠分類 | source | status |
|
|
95
|
+
|---|---:|---|---|---|
|
|
96
|
+
| factory 6-axis calibration layout | `0x6020-0x6037`, 4 groups of XYZ Int16LE | source fact | dekuNukem `spi_flash_notes.md` | stable |
|
|
97
|
+
| factory accel calibration layout | `0x6020-0x6025` zero XYZ、`0x6026-0x602B` reference XYZ | source fact / implementation policy | dekuNukem `spi_flash_notes.md`, hardware observation | source-audit fixtureとunit testで固定済み |
|
|
98
|
+
| factory gyro calibration layout | `0x602C-0x6031` zero XYZ、`0x6032-0x6037` reference XYZ | inference | 上記 layout と「後半 2 groups は Gyro cal」の記述から導出 | source-audit fixture と unit test で固定済み |
|
|
99
|
+
| gyro zero raw | `0, 0, 0` | implementation policy | Issue #69 | stable virtual default |
|
|
100
|
+
| gyro reference raw | `0x343B, 0x343B, 0x343B` | source fact / implementation policy | dekuNukem `spi_flash_notes.md`, Issue #69 | stable virtual default |
|
|
101
|
+
| gyro scale | `0.070 dps/raw` | source fact / implementation policy | dekuNukem `imu_sensor_notes.md`, Issue #69 | stable fixed scale |
|
|
102
|
+
| SensorSleep mode dispatch | `0x01` standard、`0x02-0x05` quaternion | implementation fact | MissionControl `emulated_switch_controller.cpp` | source fixtureとunit testで固定済み |
|
|
103
|
+
| quaternion packing mode 2 | accel 3×XYZ Int16LE、最大成分を除くsigned 21-bit 3成分、11-bit timestamp、sample count `3` | implementation fact / hardware observation | MissionControl `switch_motion_packing.hpp/.cpp`、Switch 2実機trace | 3 profile共通のwire packingをsource fixtureとunit testで固定。Switch 2 / スプラトゥーン3の正負Zと静止はPro Controllerのみ確認済み |
|
|
104
|
+
|
|
105
|
+
## 6. 振る舞い仕様
|
|
106
|
+
|
|
107
|
+
| 振る舞い | 入力・状態 | 期待結果 | 備考 |
|
|
108
|
+
|---|---|---|---|
|
|
109
|
+
| profile ownership | Pro Controller / Joy-Con L / Joy-Con R の既定 profile | zero `(0, 0, 0)`、reference `(13371, 13371, 13371)`、scale `0.070` の校正情報を共有する | profile と SPI の共有元 |
|
|
110
|
+
| SPI encoding | 各既定 profile で `read(0x602C, 12)` | `00 00 00 00 00 00 3b 34 3b 34 3b 34` | XYZ zero、XYZ reference、Int16LE |
|
|
111
|
+
| rate factory | rad/s の X/Y/Z | `degrees(value) / 0.070` を zero raw へ加え、最も近い整数 raw に丸めた `IMUFrame` | accel はゼロ |
|
|
112
|
+
| rate replacement | accel を持つ frame と rad/s の X/Y/Z | accel を維持し gyro raw だけを置換した frame | immutable copy |
|
|
113
|
+
| inverse conversion | gyro raw の X/Y/Z | `(raw - zero) * 0.070` を degree/s から rad/s へ変換した tuple | 3 軸同じ定義 |
|
|
114
|
+
| signed int16 boundary | raw `-32768` / `32767` に正確に対応する rad/s | 境界 raw を持つ frame | clamp しない |
|
|
115
|
+
| out of range | 丸め後 raw が signed int16 外 | `InvalidInputError` | 既存 raw API と同じ例外方針 |
|
|
116
|
+
| existing raw API | `raw()` / `gyro()` / `with_gyro()` | 既存の結果と validation を維持する | regression test |
|
|
117
|
+
|
|
118
|
+
| standard mode packing | session IMU mode `0x01` | 既存の3×(accel XYZ + gyro XYZ) Int16LE | 既存互換 |
|
|
119
|
+
| quaternion mode packing | Pro Controller / Joy-Con L / Joy-Con Rのsession IMU mode `0x02-0x05` | 3つのraw gyroをprofile校正でrad/sへ戻し、時系列順にreport間隔の3等分ずつ姿勢へ積分してpacking mode 2へ格納する | 3 acceleration sampleは維持する。Joy-Con軸方向は実機未検証 |
|
|
120
|
+
| quaternion sign | 同じ絶対値の正負Z角速度 | packing済みquaternionのZ対応成分が反対符号になる | artificial SPI offsetは使わない |
|
|
121
|
+
|
|
122
|
+
## 7. TDD Test List
|
|
123
|
+
|
|
124
|
+
| status | item | type | layer | hardware | notes |
|
|
125
|
+
|---|---|---|---|---|---|
|
|
126
|
+
| refactor-skipped | source-audit fixture が `0x602C-0x6037` の軸順、Int16LE、zero/reference、固定尺度を保持する | new | unit | no | 25 passed。既存 fixture 形式に沿っており追加の構造変更なし |
|
|
127
|
+
| refactor-skipped | source-audit fixture が `0x6020-0x602B` のaccel軸順、Int16LE、zero/referenceを保持する | new | unit | no | 26 passed。既存fixture形式に沿っており追加の構造変更なし |
|
|
128
|
+
| refactor-skipped | factory accel calibrationとG単位APIを実装する | new | unit | no | Issue #70 / unit_048で実装・検証済み |
|
|
129
|
+
| refactor-skipped | `ControllerProfile` が既定の仮想ジャイロ校正情報を所有する | new | unit | no | 39 passed。immutable な共有既定値を field で所有し、追加の構造変更なし |
|
|
130
|
+
| refactor-skipped | `VirtualSpiFlash` が profile 由来の factory gyro calibration bytes を返す | new | unit | no | 51 passed。校正値側で Int16LE serialize し、SPI は profile 値を seed。追加の構造変更なし |
|
|
131
|
+
| refactor-done | Joy-Con L/R profile も共通の factory gyro calibration bytes を返す | new | unit | no | 52 passed。共有既定値を base profile へ移し、3 profile の重複定義を避けた |
|
|
132
|
+
| refactor-skipped | `IMUFrame.gyro_rate()` が rad/s から 3 軸 raw を生成し、`to_gyro_rate()` が逆変換する | new | unit | no | 63 passed。変換を校正値へ集約済みで追加の構造変更なし |
|
|
133
|
+
| refactor-skipped | `IMUFrame.with_gyro_rate()` が accel を維持して gyro だけを物理角速度から置換する | new | unit | no | 64 passed。既存 `with_gyro()` へ委譲し追加の構造変更なし |
|
|
134
|
+
| refactor-skipped | 物理角速度 API が signed int16 境界を受理し、範囲外を `InvalidInputError` にする | edge | unit | no | 65 passed。finite validation を校正変換へ集約し、追加の構造変更なし |
|
|
135
|
+
| refactor-skipped | 既存 `IMUFrame.raw()` / `gyro()` / `with_gyro()` の raw 入力契約を維持する | regression | unit | no | 既存 5 tests が pass。実装変更不要 |
|
|
136
|
+
| refactor-skipped | public docstring と docs が rad/s API、固定尺度、範囲外例外、raw API との使い分けを説明する | docs | unit | no | 14 passed。公開 docs と initial design を追従し追加の構造変更なし |
|
|
137
|
+
| refactor-skipped | source-audit fixtureがmode `0x01`と`0x02-0x05`のpacking分岐、packing mode 2の主要fieldを保持する | new | unit | no | 27 passed。MissionControl commitを固定し、Switch 2実機観測を追記 |
|
|
138
|
+
| refactor-skipped | mode `0x02`のidentity姿勢がaccel 3 sample、packing mode `2`、max index `w`、sample count `3`をpackする | new | unit | no | `test_input_report.py` pass |
|
|
139
|
+
| refactor-skipped | 同じ絶対値の正負Z角速度がpacking済みquaternionの反対符号になる | regression | unit | no | deterministic clockでpass |
|
|
140
|
+
| refactor-skipped | Pro Controllerのmode `0x02` quaternionがSwitch実機で正負方向へ反映される | regression | hardware | yes | production factory calibrationで左回転、停止、右回転、停止を観測。traceとcleanupをhardware logへ記録済み |
|
|
141
|
+
| refactor-skipped | Joy-Con L/Rがmode `0x02-0x05`を受理し、Pro Controllerと同じquaternion packerを使う | regression | unit | no | profile、subcommand、input reportのunit testで固定。Joy-Con実機検証は手段がないため未実行 |
|
|
142
|
+
| refactor-skipped | mode `0x02-0x05`で異なる3つのgyro sampleがすべて姿勢更新へ寄与する | regression | unit | no | fake clockで非ゼロsampleの3位置と同一sample時の総積分角を固定 |
|
|
143
|
+
| refactor-done | 同じIMU modeの再要求がquaternion姿勢をリセットする | regression | unit | no | revision番号比較を1回消費型のmotion reset要求へ置換 |
|
|
144
|
+
| refactor-done | profileのfactory gyro calibrationをSPIへ必ずseedする | regression | unit | no | 非optionalなprofile契約に合わせて到達不能なNone分岐を除去 |
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
## 8. 設計メモ
|
|
148
|
+
|
|
149
|
+
- 校正値オブジェクトは zero/reference の XYZ tuple と固定 `0.070 dps/raw` を一つに束ね、`ControllerProfile` と `IMUFrame` conversion が同じ既定定義を参照する。
|
|
150
|
+
- base `ControllerProfile` が共通の既定校正 field を所有し、Pro Controller、Joy-Con L、Joy-Con R が同じ immutable 値を継承する。加速度校正はunit_048で3 profileへ適用し、スティック校正はerasedのまま維持する。
|
|
151
|
+
- SPI の reference 値から conversion scale を再計算しない。Issue #69 が指定する `0.070 dps/raw` を正本とし、`816` / `936` は実装に置かない。
|
|
152
|
+
- rad/s から raw への変換は `round()` で最も近い整数にする。変換後に signed int16 validation を通し、範囲外は clamp せず `InvalidInputError` にする。
|
|
153
|
+
- `IMUFrame` の rate API は呼び出し側から校正値や尺度を受け取らない。今回の profile は尺度変更を提供しないため、既定 profile と public conversion は同じ固定定義を共有する。
|
|
154
|
+
- Joy-Con の物理軸方向はこの unit では確定しない。Pro Controllerと同じwire packingを使うが、軸反転は追加しない。公開 conversion は report 上の X/Y/Z を変換する。
|
|
155
|
+
- `SubcommandSessionState`はresponderと`InputReportBuilder`で同じinstanceを共有する。subcommandはIMU modeとmotion reset要求を記録し、builderがreset要求を一度だけ消費する。profileは固定identity、IMU modeはsession mutable stateという既存境界を維持する。
|
|
156
|
+
- quaternion packerはreport生成時のmonotonic clock差分を3等分し、3つのraw gyroを時系列順に積分する。加速度とのfusionは行わず、最大絶対値のquaternion成分を省略した残り3成分だけをfixed point化する。
|
|
157
|
+
- 3 profileともmode `0x02-0x05`はpacking mode 2を使う。MissionControlも4つのDscale modeを同じpackerへ分岐し、single orientation sampleのdeltaをゼロにしている。swbt-pythonは公開APIの3 gyro sampleを単一の出力姿勢へ統合する。
|
|
158
|
+
|
|
159
|
+
## 9. 対象ファイル
|
|
160
|
+
|
|
161
|
+
| path | change | 内容 |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| `src/swbt/imu.py` | new | 仮想ジャイロ校正値と rad/s ↔ raw 変換 |
|
|
164
|
+
| `src/swbt/input.py` | modify | `IMUFrame` の物理角速度 API |
|
|
165
|
+
| `src/swbt/protocol/profiles/base.py` | modify | `ControllerProfile` の校正値所有 |
|
|
166
|
+
| `src/swbt/protocol/spi.py` | modify | factory gyro calibration seed |
|
|
167
|
+
| `tests/unit/fixtures/source_audit/switch_protocol_values.toml` | modify | layout と尺度の根拠 fixture |
|
|
168
|
+
| `tests/unit/test_source_audit_fixtures.py` | modify | source fixture contract |
|
|
169
|
+
| `tests/unit/test_protocol_profile.py` | modify | profile ownership |
|
|
170
|
+
| `src/swbt/protocol/motion.py` | new | mode `0x02-0x05` quaternion積分とpacking mode 2 |
|
|
171
|
+
| `src/swbt/protocol/input_report.py` | modify | session IMU modeに応じた36 byte packing切替 |
|
|
172
|
+
| `src/swbt/gamepad/runtime.py` | modify | responderとinput report builderのsession state共有 |
|
|
173
|
+
| `tests/unit/test_input_report.py`, `tests/integration/test_switch_gamepad_fake_transport.py` | modify | bitfield、正負符号、runtime mode切替 |
|
|
174
|
+
| `tests/unit/test_virtual_spi_flash.py` | modify | SPI bytes fixture |
|
|
175
|
+
| `tests/unit/test_input_state.py` | modify | conversion、境界、raw regression |
|
|
176
|
+
| `tests/hardware/test_input_operations.py` | modify | Pro Controller gyro manual reflection |
|
|
177
|
+
| `spec/initial/*.md` | modify | API、protocol、testing、architecture の追従 |
|
|
178
|
+
| `docs/api.md`, `docs/usage.md`, `docs/agent-brief.md` | modify | public API の説明と例 |
|
|
179
|
+
| `spec/hardware-test-log.md` | modify | 承認済み実機回帰結果 |
|
|
180
|
+
|
|
181
|
+
## 10. 検証
|
|
182
|
+
|
|
183
|
+
| command | result | notes |
|
|
184
|
+
|---|---|---|
|
|
185
|
+
| `uv run pytest tests/unit/test_source_audit_fixtures.py -q` | red | 2 failed, 23 passed。`factory_gyro_calibration_layout` が fixture に未登録であることを確認 |
|
|
186
|
+
| `uv run pytest tests/unit/test_source_audit_fixtures.py -q` | pass | 25 passed。layout、axis order、Int16LE、zero/reference、固定尺度と source classification を確認 |
|
|
187
|
+
| `uv run pytest tests/unit/test_source_audit_fixtures.py -q` | red | 2 failed, 24 passed。`factory_accelerometer_calibration_layout`がfixtureに未登録であることを確認 |
|
|
188
|
+
| `uv run pytest tests/unit/test_source_audit_fixtures.py -q` | pass | 26 passed。accel layout、axis order、Int16LE、zero/referenceとsource classificationを確認 |
|
|
189
|
+
| `uv run pytest tests/unit/test_protocol_profile.py::test_pro_controller_profile_owns_default_virtual_gyro_calibration -q` | red | collection error。`swbt.imu` が未実装であることを確認 |
|
|
190
|
+
| `uv run pytest tests/unit/test_protocol_profile.py -q` | pass | 39 passed。profile ownership と既存 profile contract を確認 |
|
|
191
|
+
| `uv run pytest tests/unit/test_virtual_spi_flash.py::test_virtual_spi_flash_seeds_factory_gyro_calibration_from_profile -q` | red | 1 failed。`0x602C` が erased byte `ff` のままであることを確認 |
|
|
192
|
+
| `uv run pytest tests/unit/test_virtual_spi_flash.py tests/unit/test_protocol_profile.py -q` | pass | 51 passed。default/custom Pro profile の gyro bytes と当時の既存 profile contract を確認 |
|
|
193
|
+
| `uv run pytest tests/unit/test_input_state.py::test_imu_frame_converts_three_axis_gyro_rates_between_rad_s_and_raw -q` | red | 1 failed。`IMUFrame.gyro_rate` が未実装の `AttributeError` を確認 |
|
|
194
|
+
| `uv run pytest tests/unit/test_input_state.py -q` | pass | 63 passed。3 軸の rad/s → raw と raw → rad/s、および既存 input model test を確認 |
|
|
195
|
+
| `uv run pytest tests/unit/test_input_state.py::test_imu_frame_with_gyro_rate_preserves_accelerometer_axes -q` | red | 1 failed。`with_gyro_rate` が未実装の `AttributeError` を確認 |
|
|
196
|
+
| `uv run pytest tests/unit/test_input_state.py -q` | pass | 64 passed。物理角速度による gyro 置換と accel 保持を確認 |
|
|
197
|
+
| `uv run pytest tests/unit/test_input_state.py::test_imu_frame_gyro_rate_accepts_i16_boundaries_and_rejects_out_of_range -q` | red | 1 failed。infinity が `OverflowError` になる未統一を確認 |
|
|
198
|
+
| `uv run pytest tests/unit/test_input_state.py -q` | pass | 65 passed。signed int16 両端、有限の範囲外、NaN、infinity と `InvalidInputError` 方針を確認 |
|
|
199
|
+
| `uv run pytest tests/unit/test_input_state.py::test_imu_frame_raw_defaults_to_neutral_and_sets_accel_and_gyro_axes tests/unit/test_input_state.py::test_imu_frame_raw_rejects_values_outside_i16_range tests/unit/test_input_state.py::test_imu_frame_gyro_and_accel_shorthands_match_raw_construction tests/unit/test_input_state.py::test_imu_frame_update_helpers_preserve_the_opposite_sensor_axes -q` | pass | 5 passed。既存 raw API の生成、範囲、shorthand、部分更新を確認 |
|
|
200
|
+
| `uv run pytest tests/unit/test_public_api_docstrings.py tests/unit/test_public_docs.py -q` | red | 4 failed, 10 passed。固定尺度の docstring と API / usage / agent docs が未記載であることを確認 |
|
|
201
|
+
| `uv run pytest tests/unit/test_public_api_docstrings.py tests/unit/test_public_docs.py -q` | pass | 14 passed。rad/s API、`0.070 dps/raw`、範囲外例外、raw API の使い分けを確認 |
|
|
202
|
+
| `uv run pytest tests/unit/test_virtual_spi_flash.py::test_virtual_spi_flash_seeds_gyro_calibration_for_joycon_profiles -q` | red | 2 failed。Joy-Con L/R の `gyro_calibration` が `None` であることを確認 |
|
|
203
|
+
| `uv run pytest tests/unit/test_virtual_spi_flash.py tests/unit/test_protocol_profile.py -q` | pass | 52 passed。Pro / Joy-Con L / Joy-Con R の共通校正 seed と既存 profile / SPI contract を確認 |
|
|
204
|
+
| `uv run pytest tests/hardware/test_input_operations.py::test_switch_gyro_rate_after_active_reconnect_for_manual_reflection --collect-only -q` | pass | 1 test collected。adapter open、接続、report loop は未実行 |
|
|
205
|
+
| `uv run pytest tests/unit/test_protocol_profile.py tests/unit/test_virtual_spi_flash.py tests/unit/test_input_state.py -q` | pass | 117 passed |
|
|
206
|
+
| `uv sync --dev` | pass | Resolved 53 packages |
|
|
207
|
+
| `uv run ruff format --check .` | pass | 90 files already formatted |
|
|
208
|
+
| `uv run ruff check .` | pass | All checks passed |
|
|
209
|
+
| `uv run ty check --no-progress` | pass | All checks passed |
|
|
210
|
+
| `uv run pytest tests/unit -q` | pass | 376 passed |
|
|
211
|
+
| `uv run pytest tests/integration -q` | pass | 93 passed |
|
|
212
|
+
| `uv run pytest tests/unit/test_input_report.py -q` | red | 2 failed, 33 passed。`InputReportBuilder`がsession stateとclockを受けず、mode `0x02` packing未実装を確認 |
|
|
213
|
+
| `uv run pytest tests/unit/test_input_report.py tests/unit/test_report_loop.py -q` | pass | 38 passed。標準形式回帰、identity packing、正負Z quaternionを確認 |
|
|
214
|
+
| `uv run pytest tests/integration/test_switch_gamepad_fake_transport.py::test_imu_mode_02_output_switches_periodic_input_to_quaternion_motion -q` | pass | subcommand `0x40 02`後のruntime reportがpacking mode 2へ切り替わることを確認 |
|
|
215
|
+
| `uv run pytest tests/unit/test_source_audit_fixtures.py -q` | pass | 27 passed。MissionControl commit、mode分岐、主要bitfieldを固定 |
|
|
216
|
+
| `uv run ruff check ...` / `uv run ty check --no-progress` | pass | 新規protocol実装、runtime配線、testsのlint/typeを確認 |
|
|
217
|
+
| `uv run ruff format --check .` | pass | 91 files already formatted |
|
|
218
|
+
| `uv run ruff check .` / `uv run ty check --no-progress` | pass | All checks passed |
|
|
219
|
+
| `uv run pytest tests/unit -q` | pass | 395 passed |
|
|
220
|
+
| `uv run pytest tests/integration -q` | pass | 94 passed |
|
|
221
|
+
| `uv run pytest tests/hardware/test_input_operations.py::test_switch_gyro_rate_after_active_reconnect_for_manual_reflection --collect-only -q` | pass | 1 test collected。adapter open、Switch接続、report送信は未実行 |
|
|
222
|
+
| `uv run pytest tests\hardware\test_input_operations.py::test_switch_gyro_rate_after_active_reconnect_for_manual_reflection -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir build\hardware\issue-69-gyro-calibration-20260712 --log-file build\hardware\issue-69-gyro-calibration-20260712\gyro-rate-quaternion-z-pytest-debug.log --log-file-level=DEBUG -q -s` | pass | `1 passed in 17.99s`。Switch 2 / スプラトゥーン3で左回転、停止、右回転、停止を観測。traceはmode `0x02`、正負Z、neutral、transport closeを記録 |
|
|
223
|
+
| `uv run pytest tests/unit/test_protocol_profile.py::test_controller_profiles_accept_standard_and_quaternion_imu_modes tests/unit/test_subcommand_responder.py::test_joycon_profiles_accept_quaternion_imu_modes -q` | red | 8 failed, 3 passed。Joy-Con L/Rがmode `0x03-0x05`を拒否する既存profile契約を確認 |
|
|
224
|
+
| 同上 | pass | 11 passed。Joy-Con L/Rがmode `0x02-0x05`をACKし、session stateへ保持することを確認 |
|
|
225
|
+
| `uv run pytest tests/unit/test_protocol_profile.py tests/unit/test_subcommand_responder.py tests/unit/test_input_report.py tests/unit/test_source_audit_fixtures.py tests/unit/test_public_docs.py -q` | pass | 161 passed。Joy-Con profile、subcommand、packing、source-audit、公開文書の契約を確認 |
|
|
226
|
+
| `uv run ruff format --check .` | pass | 91 files already formatted |
|
|
227
|
+
| `uv run ruff check .` / `uv run ty check --no-progress` | pass | All checks passed |
|
|
228
|
+
| `uv run pytest tests/unit -q` / `uv run pytest tests/integration -q` | pass | 414 passed / 94 passed |
|
|
229
|
+
| `uv run pytest tests/unit/test_input_report.py::test_quaternion_mode_integrates_all_three_gyro_samples -q` | red | 1 failed。末尾sampleだけを使う既存実装を確認 |
|
|
230
|
+
| `uv run pytest tests/unit/test_input_report.py -q` | pass | 48 passed。3 sampleの各位置、総積分角、既存packing回帰を確認 |
|
|
231
|
+
| `uv run pytest tests/unit/test_input_report.py::test_repeated_imu_mode_02_request_resets_quaternion_orientation tests/unit/test_subcommand_responder.py::test_enable_imu_updates_session_state -q` | red | 2 failed。revision依存のsession stateを確認 |
|
|
232
|
+
| `uv run pytest tests/unit/test_input_report.py tests/unit/test_subcommand_responder.py -q` | pass | 83 passed。reset要求の記録・一回消費と繰り返しmode requestを確認 |
|
|
233
|
+
| `uv run pytest tests/unit/test_virtual_spi_flash.py -q` | pass | 15 passed。None分岐除去前後でfactory SPI bytes不変 |
|
|
234
|
+
| standard gate after mode 2 cleanup | pass | format、lint、ty、unit 418件、integration 94件 |
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
## 11. 実機実行条件
|
|
238
|
+
|
|
239
|
+
| 項目 | 内容 |
|
|
240
|
+
|---|---|
|
|
241
|
+
| 実機要否 | required |
|
|
242
|
+
| 承認範囲 | 2026-07-12に明示承認済み。Bumble adapter open、既存bondによるactive reconnect、periodic report loop、ZL、正負Z gyro report、neutral、closeを実行。意図的なpairing / advertisingは対象外 |
|
|
243
|
+
| adapter | `usb:0`。専用 CSR8510 A10 / WinUSBを実行直前に確認済み |
|
|
244
|
+
| 実行 command | `uv run pytest tests\hardware\test_input_operations.py::test_switch_gyro_rate_after_active_reconnect_for_manual_reflection -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir build\hardware\issue-69-gyro-calibration-20260712 --log-file build\hardware\issue-69-gyro-calibration-20260712\gyro-rate-quaternion-z-pytest-debug.log --log-file-level=DEBUG -q -s` |
|
|
245
|
+
| 実行遮断 | 環境変数による遮断は採用しない。明示承認、対象 adapter、command、Switch-facing 動作、cleanup plan で管理する |
|
|
246
|
+
| log / artifact | `build/hardware/` 配下の JSONL trace と pytest debug log、`spec/hardware-test-log.md` |
|
|
247
|
+
| cleanup | gyro 入力後に neutral frame を送り、report loop を停止し、transport を close して adapter を解放する |
|
|
248
|
+
|
|
249
|
+
## 12. 先送り事項
|
|
250
|
+
|
|
251
|
+
- none
|
|
252
|
+
|
|
253
|
+
## 13. チェックリスト
|
|
254
|
+
|
|
255
|
+
- [x] Issue #69 の対象範囲と対象外を確認した
|
|
256
|
+
- [x] TDD Test List の初期案を作成した
|
|
257
|
+
- [x] 必要な根拠監査を記録した
|
|
258
|
+
- [x] 実機実行条件と未承認状態を記録した
|
|
259
|
+
- [x] source-audit fixture を更新した
|
|
260
|
+
- [x] profile と SPI の校正共有を実装した
|
|
261
|
+
- [x] rad/s ↔ raw の公開 API と境界方針を実装した
|
|
262
|
+
- [x] raw API の回帰を確認した
|
|
263
|
+
- [x] docs と initial design を更新した
|
|
264
|
+
- [x] Pro Controller 実機回帰を実行して結果を記録した
|
|
265
|
+
- [x] 標準 gate の結果を記録した
|
|
266
|
+
- [x] IMU mode `0x02-0x05`のquaternion形式を根拠監査した
|
|
267
|
+
- [x] session-aware quaternion packingとfake transport回帰を実装した
|
|
268
|
+
- [x] Joy-Con L/RにPro Controllerと同じmode `0x02-0x05` quaternion packingを適用する
|
|
269
|
+
- [x] production factory calibrationで正負ZのSwitch 2実機回帰を確認する
|
|
270
|
+
- [x] mode `0x02-0x05`で3つのgyro sampleを時系列順に積分する
|
|
271
|
+
- [x] IMU mode再要求を一回消費型のmotion reset要求として扱う
|
|
272
|
+
- [x] factory gyro calibrationの到達不能なNone分岐を除去する
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Virtual Accelerometer Calibration 仕様書
|
|
2
|
+
|
|
3
|
+
## 1. 概要
|
|
4
|
+
|
|
5
|
+
### 1.1 目的
|
|
6
|
+
|
|
7
|
+
仮想 Pro Controller / Joy-Con の factory accelerometer calibration と、G 単位から `IMUFrame` を生成する変換尺度を一元化する。
|
|
8
|
+
|
|
9
|
+
### 1.2 起点 / source
|
|
10
|
+
|
|
11
|
+
| source | 内容 | path |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| GitHub Issue #70 | profile 所有、SPI `0x6020-0x602B`、固定尺度 `1/4096 G/raw`、G API、Pro/Joy-Con 実機回帰 | https://github.com/niart120/swbt-python/issues/70 |
|
|
14
|
+
| unit_047 実機観測 | Switch は `0x6020` から 24 bytes を読み、accel 側が全て `FF` の場合はジャイロのカメラ反映を確認できなかった | `spec/complete/unit_047/VIRTUAL_GYRO_CALIBRATION.md` |
|
|
15
|
+
|
|
16
|
+
### 1.3 use case
|
|
17
|
+
|
|
18
|
+
| actor / boundary | 入力または状態 | 期待する観測結果 | 制約 |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Switch host | factory SPI `0x6020` から 12 bytes を読む | zero XYZ と reference XYZ を取得する | signed int16 little-endian、軸順 XYZ |
|
|
21
|
+
| library user | X/Y/Z の加速度を G で指定する | 同じ校正定義で raw へ変換した `IMUFrame` を得る | `1/4096 G/raw` 固定 |
|
|
22
|
+
| diagnostics | raw accel を持つ frame | G 単位の 3 軸値を得る | SPI と同じ zero と尺度 |
|
|
23
|
+
|
|
24
|
+
## 2. 対象範囲
|
|
25
|
+
|
|
26
|
+
- `ControllerProfile` が zero `(0,0,0)`、reference `(0x4000,0x4000,0x4000)`、reference acceleration `4.0 G` の校正値を所有する。
|
|
27
|
+
- Pro Controller、Joy-Con L、Joy-Con R が同じ既定値を使う。
|
|
28
|
+
- `VirtualSpiFlash` が `0x6020-0x602B` を profile から生成し、gyro と合わせて `0x6020-0x6037` を完成させる。
|
|
29
|
+
- `IMUFrame.accel_g()`、`with_accel_g()`、`to_accel_g()` を追加する。
|
|
30
|
+
- 3 軸、signed int16 境界、非有限値と範囲外、raw/gyro API 回帰を unit test で固定する。
|
|
31
|
+
- public docs、docstring、initial design を更新する。
|
|
32
|
+
- Pro Controller と Joy-Con の SPI read 実機回帰を記録する。
|
|
33
|
+
|
|
34
|
+
## 3. 対象外
|
|
35
|
+
|
|
36
|
+
- 重力方向や姿勢の生成、並進加速度、遠心力、ノイズの模擬。
|
|
37
|
+
- user calibration `0x8028-0x803F`、horizontal offset `0x6080-0x6085`。
|
|
38
|
+
- 個体別校正と利用者向け校正設定。
|
|
39
|
+
|
|
40
|
+
## 4. 関連 docs
|
|
41
|
+
|
|
42
|
+
- `spec/complete/unit_047/VIRTUAL_GYRO_CALIBRATION.md`
|
|
43
|
+
- `spec/initial/api.md`
|
|
44
|
+
- `spec/initial/protocol.md`
|
|
45
|
+
- `spec/initial/testing.md`
|
|
46
|
+
- `docs/api.md`
|
|
47
|
+
- `docs/usage.md`
|
|
48
|
+
|
|
49
|
+
## 5. 根拠監査
|
|
50
|
+
|
|
51
|
+
| 項目 | 要否 | 状態 | 根拠 / 理由 |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| Switch HID / report bytes | required | done | Issue #70 と source-audit fixture が layout、Int16LE、zero/reference を固定する |
|
|
54
|
+
| G conversion scale | required | done | Issue #70 が reference acceleration `4.0 G`、尺度 `1/4096 G/raw` を指定する |
|
|
55
|
+
| Bumble / transport | not applicable | not applicable | transport と report packing は変更しない |
|
|
56
|
+
| OS / driver / adapter | required | done / not run | Pro ControllerはWindows 11 / CSR8510 A10 / WinUSB / `usb:0`で記録済み。Joy-Conは検証手段がないためnot run |
|
|
57
|
+
|
|
58
|
+
## 6. 振る舞い仕様
|
|
59
|
+
|
|
60
|
+
| 振る舞い | 入力・状態 | 期待結果 | 備考 |
|
|
61
|
+
|---|---|---|---|
|
|
62
|
+
| profile/SPI | 3 種の既定 profile | `00 00` × 3、`00 40` × 3 | `0x6020` から 12 bytes |
|
|
63
|
+
| G factory/inverse | X/Y/Z の G 値 | `round(G * 4096)` と逆変換 | zero raw を加減する |
|
|
64
|
+
| G replacement | gyro を持つ frame | gyro を維持して accel だけ置換 | immutable copy |
|
|
65
|
+
| boundary/error | signed int16 境界、範囲外、NaN、inf | 境界を受理し、範囲外は `InvalidInputError` | clamp しない |
|
|
66
|
+
| full calibration | `read(0x6020, 24)` | accel 12 bytes と gyro 12 bytes が連続する | 両 Issue の共存 |
|
|
67
|
+
|
|
68
|
+
## 7. TDD Test List
|
|
69
|
+
|
|
70
|
+
| status | item | type | layer | hardware | notes |
|
|
71
|
+
|---|---|---|---|---|---|
|
|
72
|
+
| refactor-skipped | source fixture が layout、軸順、Int16LE、zero/reference、4.0 G、`1/4096 G/raw` を保持する | new | unit | no | fixture は unit_047 で先行追加。Issue #70 の全契約へ更新する |
|
|
73
|
+
| refactor-done | 3 profile と SPI が同じ加速度校正値を共有する | new | unit | no | gyroと共通の3軸校正モデルへ集約 |
|
|
74
|
+
| refactor-skipped | `accel_g()` と `to_accel_g()` が 3 軸を相互変換する | new | unit | no | 68 input tests pass |
|
|
75
|
+
| refactor-skipped | `with_accel_g()` が gyro を維持する | new | unit | no | 反対側sensor保持を確認 |
|
|
76
|
+
| refactor-skipped | G API が signed int16 境界を受理し範囲外を統一例外にする | edge | unit | no | NaN/infを含め確認 |
|
|
77
|
+
| refactor-skipped | factory 24 bytes と既存 raw/gyro API が共存する | regression | unit | no | 24-byte fixtureと既存API tests pass |
|
|
78
|
+
| refactor-skipped | 公開 docs と initial design が G API と固定尺度を説明する | docs | unit | no | public docs tests pass |
|
|
79
|
+
| refactor-skipped | Pro Controller と Joy-Con の SPI read結果を記録する | regression | hardware | yes | Proは`0x6020` 24-byte応答を記録。Joy-Conは検証手段がないためnot runと記録 |
|
|
80
|
+
|
|
81
|
+
## 8. 設計メモ
|
|
82
|
+
|
|
83
|
+
- G API は校正値を引数に取らず、profile と共有する既定定義を使う。
|
|
84
|
+
- raw 変換は `round()` 後に signed int16 を検証し、clamp しない。
|
|
85
|
+
- gyro 校正と共通化できる serialize・検証処理は green 後の refactor で判断する。
|
|
86
|
+
|
|
87
|
+
## 9. 対象ファイル
|
|
88
|
+
|
|
89
|
+
| path | change | 内容 |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `src/swbt/imu.py` | modify | 加速度校正と G↔raw 変換 |
|
|
92
|
+
| `src/swbt/input.py` | modify | 公開 G API |
|
|
93
|
+
| `src/swbt/protocol/profiles/base.py` | modify | profile 所有 |
|
|
94
|
+
| `src/swbt/protocol/spi.py` | modify | factory accel seed |
|
|
95
|
+
| `tests/unit/` | modify | source、profile、SPI、API、回帰 |
|
|
96
|
+
| `tests/hardware/` | modify | Pro/Joy-Con SPI read 回帰 |
|
|
97
|
+
| `spec/initial/`, `docs/` | modify | 公開契約の追従 |
|
|
98
|
+
|
|
99
|
+
## 10. 検証
|
|
100
|
+
|
|
101
|
+
| command | result | notes |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `uv run pytest tests/unit/test_source_audit_fixtures.py -q` | pass | 27 passed。layout、尺度、mode 2 packingの根拠fixtureを確認 |
|
|
104
|
+
| `uv run pytest tests\hardware\test_input_operations.py::test_switch_gyro_rate_after_active_reconnect_for_manual_reflection -m hardware --swbt-bumble-adapter usb:0 --swbt-hardware-artifact-dir build\hardware\issue-69-gyro-calibration-20260712 --log-file build\hardware\issue-69-gyro-calibration-20260712\gyro-rate-quaternion-z-pytest-debug.log --log-file-level=DEBUG -q -s` | pass / not run | Proは`1 passed in 17.99s`でfactory `0x6020` 24-byte応答を記録。Joy-Conは検証手段がないためnot run |
|
|
105
|
+
| standard gate | pass | format、lint、ty、unit 418件、integration 94件 |
|
|
106
|
+
|
|
107
|
+
## 11. 実機実行条件
|
|
108
|
+
|
|
109
|
+
| 項目 | 内容 |
|
|
110
|
+
|---|---|
|
|
111
|
+
| 実機要否 | required |
|
|
112
|
+
| 承認範囲 | Proは2026-07-12に明示承認済みのunit_047実機試験でadapter open、active reconnect、SPI read、report loop、neutral、closeを実行。Joy-Conは検証手段がないためnot run |
|
|
113
|
+
| adapter | Pro実行時に`usb:0`の専用CSR8510 A10 / WinUSBを確認済み |
|
|
114
|
+
| 実行遮断 | 環境変数による遮断は採用しない。明示承認、対象 adapter、command、cleanup plan で管理する |
|
|
115
|
+
| log / artifact | `build/hardware/issue-69-gyro-calibration-20260712/active-reconnect-gyro-rate-quaternion-z.jsonl`、`spec/hardware-test-log.md` |
|
|
116
|
+
| cleanup | Pro実行はneutral、disconnect、`transport_close_complete`を記録しadapterを解放済み |
|
|
117
|
+
|
|
118
|
+
## 12. 先送り事項
|
|
119
|
+
|
|
120
|
+
- none
|
|
121
|
+
|
|
122
|
+
## 13. チェックリスト
|
|
123
|
+
|
|
124
|
+
- [x] Issue #70 の対象範囲と対象外を確認した
|
|
125
|
+
- [x] TDD Test List を作成した
|
|
126
|
+
- [x] 必要な根拠監査を記録した
|
|
127
|
+
- [x] 実機実行条件、Proの結果、Joy-Conの未実行理由を記録した
|
|
128
|
+
- [x] unit test と実装を完了した
|
|
129
|
+
- [x] docs と initial design を更新した
|
|
130
|
+
- [x] Pro実機回帰とJoy-Con未実行理由を記録した
|
|
131
|
+
- [x] 標準 gate を記録した
|