From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ua2-f12.google.com (mail-ua2-f12.google.com [74.125.226.204]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6DA5D44065A for ; Thu, 24 Sep 2026 15:46:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.226.204 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790264812; cv=none; b=LoRd1wyfe60DeQLNDWg/enD9Ds8IdrmNOTmTCL2xrqkUs7G9sa8QhGhQNh0RulalJkYF7Ytn0G7/jwTBfxagReOatOx94Vrcuh2KMZxSA9sl8X9s2TT8p/Y+/tuv7r0mQN+gLDxueufn2jr+t4iirUX6Lk7qcS9xoKArW7YS4oA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790264812; c=relaxed/simple; bh=+deHzx2uhrIBNkhbfxIJJl7HGwF/qV9u0MQ5gnwvkVo=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ltU0uvldtcpII0deR8oFL+hhQsABg4mSAh+bLxo2QtE/vl6zoXHyLMZit7bw8Hx1OfLo0HEEh98gjEdIWmkg6lzInSAwv+FOMNu4PlnrQX8ZHrL5Y5MTpKG+Aog9hZMBZFm5LLIWkUjVM8OmM381JwWG07Sg/apyXquhwEZ4pbI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hdZ8KMFE; arc=none smtp.client-ip=74.125.226.204 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hdZ8KMFE" Received: by mail-ua2-f12.google.com with SMTP id a1e0cc1a2514c-97e7c62dde2so718219241.2 for ; Thu, 24 Sep 2026 08:46:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790264809; x=1790869609; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to:content-type; bh=X7TNVCO5X0IM2vYSTKR1bsaXci1daSisRKmHbRYJs0o=; b=hdZ8KMFE6tHLvNGqMc9mX/E4ifQytijmBSn94fAE37XjOwlEtYtccAE2Q0egeFBBP2 cqJNuBzh4SaRKi3nBott3APhfQENmQd3jR6PXLUEQAkeJSFILsmpSN4eLYsoRIsNYv5+ NvqaPePIow0wSFmr+zU3YvTJ1+WxWqcwm2WqAqtkmm3LginnI5PczIrjofT/lktXddeA fIDn6Knpyrb1ldzK1UbnyEvIgBRMveMrth/ynSQTFVKLOAnQ1TCMXgp66YjkX/Bvc3sI 20z1oQURf7Rb42sWWpmyi2g6j4s0b/P6KbKJDo/pG3DFvLf+dmFBu/aieCX5YL+0fatk pzdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790264809; x=1790869609; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to:content-type; bh=X7TNVCO5X0IM2vYSTKR1bsaXci1daSisRKmHbRYJs0o=; b=q9IUxEQsi7w87YXLw/C4iSHFKwTk6z1vQQ0ZbpZJDlzme6xk8OgARpaMWOpD6w50Sy sx2jOeAtouMy6z/EwpaFNjkM0BugVM45pDmnwu1GEoaYTEbWQvImpVVAqO5RLvN/+bbI nXWXQ2PcGfsj8oz3tUnxDfusGj02Gcml9eFWQKoHWURByEKzYJKEbCOL0IHQGkAy4gmo vb2cAu7MNXflkS4e25EVB7FE9V/8yDf130bJ6s4vaG4mUirZ7UnF4354y40hx4aiWrFG MVyA999ySvUZM2Q2qbm9bOMg+0KLm9z1ebYskalYKNLg7sI9N5J5PUaSM3CJ3YxVfYQi pNEA== X-Gm-Message-State: AFuF++mUfLXZqKWFgQSbIz7MYDpcPOAqEu/vQx+m5aABlWUTyiIXE1F8 zDCYvUhFnzeiqqSoGvxrEm99c/cWgldC2CfVtqPGGaw4EagfdIrSJLQTFAqtPQmaKBlkEA== X-Gm-Gg: AYBFou3yO18iHTT8atC8GdHZEALV6dWiiP4zcjdLp8oCEmZra6aw3SOCKgohoNpydT5 lDwTJhMUomAPcdQye2A8mFkS4h835DLnoDUhF2G48uczAKYDhMUSXjbOPmO5NM/9RBiOfxLDNd2 4DENlmS1dfOjY+LcEJVrCKtMGE7EbTgZutBYVHA8Lhx1efhXwjN9eBosr7jOFJX5nYjOYjtJGkS UxUhATUXgaeO6vq5Ofsm15sG18WzGavMCvBjnEfMxN6+hmLBDjXrUBf8+DJf9h7KuRaE2sCL1Nr E7c9/Dv/lxTwsBy+weAYdE2rOgLnpb2hZv503Y1OgFjXCxm7N093KIIw98nw6CxTv+bfVPIu8J1 cjUAwygMgiLeYqxmdSLwx1oJ4CK4Puhc15cgb40S2FMePrpdzcLlXjmHmbNptwVNqSkV8E3+juq 8/I5v8+vj1EhAr8Iccz0KUUyrAUcPBdIf1jvSUI0LQSH7xEJg21YBLGRvsD33tTl7ls6QnOpuXy j+6kpcL+unXVjzqitfwupWx8EXEF/8g9qR4CVCt7BsG/mP32eyzo+savnw0bU+2 X-Received: by 2002:a05:6102:3306:b0:7ae:c2ca:8e1 with SMTP id ada2fe7eead31-7af1cea4b73mr1169713137.11.1790264809042; Thu, 24 Sep 2026 08:46:49 -0700 (PDT) Received: from lvondent-mobl5 ([72.188.211.115]) by smtp.gmail.com with ESMTPSA id ada2fe7eead31-7abf5674f44sm7412428137.3.2026.09.24.08.46.48 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Sep 2026 08:46:48 -0700 (PDT) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ v3 7/9] doc: Add functional-hog documentation Date: Thu, 24 Sep 2026 11:46:29 -0400 Message-ID: <20260924154631.369299-8-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260924154631.369299-1-luiz.dentz@gmail.com> References: <20260924154631.369299-1-luiz.dentz@gmail.com> Precedence: bulk X-Mailing-List: linux-bluetooth@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Luiz Augusto von Dentz Document the HoG functional tests, where bluetoothctl registers a HID Service with and without Shorter Connection Interval (SCI) support using client/scripts/hog-device*.bt, and the HID host: - checks HID Information, HID SCI Mode and HID SCI Information with gatt.select-attribute/gatt.read - receives a few Input Reports notified by the HID device - changes the SCI mode, followed by the connection rate with mgmt.conn-subrate, and receives the notification from the HID device confirming the mode has been changed --- Makefile.am | 1 + doc/functional-hog.rst | 188 +++++++++++++++++++++++++++++++++++++ doc/functional-testing.rst | 1 + 3 files changed, 190 insertions(+) create mode 100644 doc/functional-hog.rst diff --git a/Makefile.am b/Makefile.am index 1d46b9b938cf..17348788a30b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -501,6 +501,7 @@ EXTRA_DIST += doc/assigned-numbers.rst doc/supported-features.txt \ doc/functional-a2dp.rst \ doc/functional-avrcp.rst \ doc/functional-bap.rst \ + doc/functional-hog.rst \ doc/functional-mpris-proxy.rst \ doc/functional-obex.rst \ doc/settings-storage.txt diff --git a/doc/functional-hog.rst b/doc/functional-hog.rst new file mode 100644 index 000000000000..d748f241a378 --- /dev/null +++ b/doc/functional-hog.rst @@ -0,0 +1,188 @@ +============== +functional-hog +============== + +DESCRIPTION +=========== + +HID over GATT (HoG) functional tests, `test/functional/test_hog.py`, +driven through **bluetoothctl(1)**. See **functional-testing(7)** for +the conventions used here, and **test-functional(1)** for how to run +the suite. + +SETUP +===== + +Two hosts, connected over LE, both running **bluetoothd(8)** with +``ControllerMode = le`` and ``ExportClaimedServices = read-write``, as +the HID Service is claimed by the input plugin of the HID host and +bluetoothctl has to write HID SCI Mode: + +.. code-block:: + + +------------------------+ +------------------------+ + | host0 | LE | host1 | + | central | --------------> | peripheral | + | bluetoothctl | | bluetoothctl | + | HID host | GATT (HIDS) | hog-device[-sci].bt | + | | <============== | HID Service | + +------------------------+ +------------------------+ + + --> connection is initiated by ==> reports flow towards + +host1 starts `bluetoothctl` with a script registering a HID Service +(HIDS, ``00001812-0000-1000-8000-00805f9b34fb``) acting as a keyboard, +through the ``gatt.register-service``, ``gatt.register-characteristic`` +and ``gatt.register-descriptor`` commands: + +``client/scripts/hog-device.bt`` + HIDS without Shorter Connection Interval (SCI) support: + + - HID Information (0x2A4A): ``11 01 00 02``, i.e. bcdHID 1.11, + bCountryCode 0x00 and Flags NormallyConnectable. + - Report Map (0x2A4B): keyboard with Report ID 1. + - Report (0x2A4D), with a Report Reference descriptor (0x2908) + ``01 01``, i.e. Report ID 1, Input Report. + - Protocol Mode (0x2A4E): ``01``, i.e. Report Protocol Mode. + - HID Control Point (0x2A4C). + +``client/scripts/hog-device-sci.bt`` + Same as above, with SCI support: + + - HID Information (0x2A4A): ``11 01 00 06``, i.e. the SCI + Supported flag (0x04) is set as well. + - HID SCI Mode (0x2C39): ``00``, i.e. None, with the notify + property so the HID device can confirm a mode change. + - HID SCI Information (0x2C3A): ``08 01 08 00 50 00 08 00``, i.e. + Minimum Supported Connection Interval 1 ms, and one subgroup + with Min 1 ms, Max 10 ms and Stride 1 ms (in units of 0.125 ms). + +Both scripts set the advertising data to the HIDS UUID and the +keyboard appearance (0x03C1). The same scripts can be used manually to +emulate a HoG device: + +.. code-block:: + + $ bluetoothctl --init-script client/scripts/hog-device-sci.bt + [bluetoothctl]> advertise on + +host0 runs a plain `bluetoothctl`, and both use +``-a auto:NoInputNoOutput`` so pairing is Just Works. + +TEST CASES +========== + +test_hog[no-sci] +---------------- + +:Setup: As above, with ``client/scripts/hog-device.bt`` on host1. + +:Steps: + 1. host1: start `bluetoothctl` with the script. + 2. host0: ``scan on``; host1: ``advertise on``. + 3. host0: ``pair ``. + 4. host0: ``info ``. + 5. host0: ``gatt.select-attribute 2a4a`` and ``gatt.read``. + 6. host0: ``gatt.select-attribute 2a4d`` and ``gatt.notify on``. + 7. host1: ``gatt.select-attribute local + /org/bluez/app/service0/chrc2``, then for each report + ``gatt.write ""``: ``00 00 04 00 00 00 00 00`` (a + pressed), ``02 00 05 00 00 00 00 00`` (Left Shift + b pressed) + and ``00 00 00 00 00 00 00 00`` (released). + +:Expected: + 1. ``Application registered`` on host1. + 2. ``Advertising object registered`` on host1 and the device found + on host0. + 3. ``Pairing successful`` and ``ServicesResolved: yes``. + 4. ``Human Interface Device (00001812-...)`` is listed in the UUIDs. + 5. HID Information reads ``11 01 00 02``: + + .. code-block:: + + [bluetoothctl]> gatt.select-attribute 2a4a + [bluetoothctl]> gatt.read + Attempting to read /org/bluez/hci0/dev_XX/service0013/char001e + 11 01 00 02 .... + + 6. ``Notify started``, and the Report subscribed on host1 + (``Notify sock acquired``, as the input plugin already + subscribed with AcquireNotify). + 7. Each report is notified to host0, in order: + + .. code-block:: + + [CHG] Attribute /org/bluez/hci0/dev_XX/service0013/char0018 Value: + 00 00 04 00 00 00 00 00 ........ + +:Notes: The service is checked at the GATT level only, so the test + does not depend on the kernel supporting uhid. The HID Service is + claimed by the input plugin on host0, but it is still exported + read-only over D-Bus by default (see ``ExportClaimedServices`` in + **bluetoothd(8)**), so it can be read with bluetoothctl. + +test_hog[sci] +------------- + +:Setup: As above, with ``client/scripts/hog-device-sci.bt`` on host1. + +:Steps: As for test_hog[no-sci], then: + + 8. host0: ``gatt.select-attribute 2c39`` and ``gatt.read``. + 9. host0: ``gatt.select-attribute 2c3a`` and ``gatt.read``. + 10. host0: ``gatt.select-attribute 2c39`` and ``gatt.notify on``. + 11. host0: ``gatt.write "0x03"``, i.e. SCI Fast Mode. + 12. host0: ``mgmt.conn-subrate 0x0008 0x0010 1 1 0 0 + 0x01f4``, i.e. interval 1 ms to 2 ms, within the range given in + HID SCI Information, no subrating, no latency and 5 s + supervision timeout. + 13. host1: ``gatt.select-attribute local + /org/bluez/app/service0/chrc5`` and ``gatt.write "0x03"``. + +:Expected: As for test_hog[no-sci], except HID Information reads + ``11 01 00 06``, then: + + 8. HID SCI Mode reads ``00``. + 9. HID SCI Information reads ``08 01 08 00 50 00 08 00``. + 10. ``Notify started`` and HID SCI Mode subscribed on host1. + 11. host1 receives the write: + + .. code-block:: + + [/org/bluez/app/service0/chrc5 (HID SCI Mode)] WriteValue: XX offset 0 link LE + 03 . + + 12. ``Connection Subrate loaded successfully``, then the MGMT + Connection Subrate event with the new interval on both hosts: + + .. code-block:: + + hci0 XX type LE Public connection subrate interval 0x0008 subrate 0x0001 latency 0x0000 cont_num 0x0000 timeout 0x01f4 + + 13. The new mode is notified to host0, confirming it has been + changed: + + .. code-block:: + + [CHG] Attribute /org/bluez/hci0/dev_XX/service0015/char0018 Value: + 03 . + + .. code-block:: + + [bluetoothctl]> gatt.select-attribute 2c39 + [bluetoothctl]> gatt.read + 00 . + + [bluetoothctl]> gatt.select-attribute 2c3a + [bluetoothctl]> gatt.read + 08 01 08 00 50 00 08 00 ....P... + +:Notes: As the SCI Supported flag is set, the input plugin on host0 + reads HID SCI Mode and HID SCI Information as well, which can be + seen in the **bluetoothd(8)** debug output (``SCI Mode:`` and + ``SCI Info:``). + + The kernel only issues the LE Connection Rate Request as central, + so the connection rate is changed by the HID host. This requires + the controllers to support Shorter Connection Intervals, which + btvirt emulates as a BR/EDR/LE 6.2 controller. diff --git a/doc/functional-testing.rst b/doc/functional-testing.rst index ca7bfa672a76..7b3cad1c66b1 100644 --- a/doc/functional-testing.rst +++ b/doc/functional-testing.rst @@ -15,6 +15,7 @@ are documented separately: - **functional-a2dp(7)**: `test/functional/test_a2dp.py` - **functional-avrcp(7)**: `test/functional/test_avrcp.py` - **functional-bap(7)**: `test/functional/test_bap.py` +- **functional-hog(7)**: `test/functional/test_hog.py` - **functional-mpris-proxy(7)**: `test/functional/test_mpris_proxy.py` - **functional-obex(7)**: `test/functional/test_obex.py` -- 2.55.0