Problem Description
Zephyr currently lacks a proper reusable HOGP (HID over GATT Profile) service implementation. The only HID-related code is the samples/bluetooth/peripheral_hids/ sample, which directly constructs GATT attributes inline — not reusable across products.
Meanwhile, the Bluetooth SIG has adopted HOGP 1.1 (https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile/ (https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile/)), which extends HOGP 1.0 with support for HID reports over LE Isochronous Channels (HID ISO). Combined with BT 6.2 Shorter Connection Intervals (SCI), this enables Ultra-Low Latency (ULL) HID — targeting ≤1ms latency and 1kHz+ report rates for gaming peripherals, VR controllers, and professional input devices.
Key gaps in Zephyr today:
- No subsys/bluetooth/services/hogp/ module (unlike BAS, DIS, HRS, OTS which all have proper service implementations)
- No HOGP Host (GATT client) role — needed for centrals that connect to HID peripherals
- No HID ISO Service support (HOGP 1.1 feature for reports over CIS)
- No SCI host-side plumbing (new HCI commands from BT 6.2: LE_Conn_Rate_Request, LE_Set_Default_Rate_Params, LE_Read_All_Remote_Features, LE_Read_Min_Supported_Conn_Interval)
Without these, Zephyr-based products cannot compete in the ULL HID market that is rapidly growing (gaming mice, keyboards, VR/AR controllers).
Proposed Change (Summary)
Add a complete HOGP 1.1 implementation under subsys/bluetooth/services/hogp/ with:
- HOGP Device role (GATT server): HID Service with Report Map, Input/Output/Feature Reports, HID Information, Protocol Mode
- HOGP Host role (GATT client): Service discovery state machine, report subscription, Get/Set Report operations
- HID ISO Service (optional, Kconfig-gated): Send/receive HID reports over LE Connected Isochronous Streams (CIS) for ultra-low latency
- SCI host support (optional, Kconfig-gated): BT 6.2 Shorter Connection Intervals HCI command/event handling
All new features are gated behind Kconfig options (CONFIG_BT_HOGP_DEVICE, CONFIG_BT_HOGP_HOST, CONFIG_BT_HOGP_DEVICE_ISO, CONFIG_BT_HOGP_HOST_ISO, CONFIG_BT_SHORTER_CONNECTION_INTERVALS).
Proposed Change (Detailed)
- Directory Structure
subsys/bluetooth/services/hogp/
├── Kconfig.hogp # Kconfig options
├── CMakeLists.txt # Build rules
├── hogp_device.c # HOGP Device (GATT server)
├── hogp_host.c # HOGP Host (GATT client)
└── hogp_internal.h # Shared internal definitions
include/zephyr/bluetooth/services/
├── hogp_device.h # Public HOGP Device API
└── hogp_host.h # Public HOGP Host API
- HOGP Device Role (GATT Server)
Implements HID Service (HIDS) per HOGP 1.1 §3:
- Report Map characteristic (read-only)
- HID Information characteristic
- HID Control Point characteristic
- Protocol Mode characteristic
- Input/Output/Feature Report characteristics with Report Reference descriptors
- Per-connection CCC tracking for notifications
- Boot Protocol support (optional, Kconfig-gated)
Public API:
int bt_hogp_device_register(const struct bt_hogp_device_param *param);
int bt_hogp_device_send_input_report(struct bt_conn *conn, uint8_t report_id,
const uint8_t *data, uint16_t len);
int bt_hogp_device_notify_battery(struct bt_conn *conn, uint8_t level);
- HOGP Host Role (GATT Client)
Implements HOGP Host per HOGP 1.1 §4:
- HID Service discovery state machine (discover services → characteristics → descriptors → read report map → subscribe)
- Multiple HID service instance support
- Battery Service (BAS) discovery and subscription
- Get Report / Set Report operations
- Protocol Mode read/write
Public API:
int bt_hogp_host_connect(struct bt_conn *conn, const struct bt_hogp_host_cb *cb);
int bt_hogp_host_disconnect(struct bt_conn *conn);
int bt_hogp_host_get_report(struct bt_conn *conn, uint8_t report_id,
uint8_t report_type, uint8_t *buf, uint16_t buf_len);
int bt_hogp_host_set_report(struct bt_conn *conn, uint8_t report_id,
uint8_t report_type, const uint8_t *data, uint16_t len);
- HID ISO Service (HOGP 1.1 Extension)
When CONFIG_BT_HOGP_DEVICE_ISO=y / CONFIG_BT_HOGP_HOST_ISO=y:
- HID ISO Service GATT characteristics (LE HID Operation Mode, ISO Parameters)
- CIG/CIS establishment for HID report transport
- ISO packet format: [length][seq_num][report_id][payload]
- Hybrid mode: reports sent over both GATT notifications and ISO simultaneously during transition
- Fallback to GATT-only if ISO setup fails
- SCI Host Support (BT 6.2)
When CONFIG_BT_SHORTER_CONNECTION_INTERVALS=y:
-
New HCI command definitions in hci_types.h:
- LE_Read_All_Remote_Features (opcode 0x2088)
- LE_Connection_Rate_Request (opcode 0x209F)
- LE_Set_Default_Rate_Params (opcode 0x20A1)
- LE_Read_Min_Supported_Conn_Interval (opcode 0x20A3)
-
Extended LE feature pages (page 0 + page 1) storage in struct bt_conn
-
conn_rate_changed callback in struct bt_conn_cb
-
SCI connection interval units: 0.125ms (vs standard 1.25ms)
- Kconfig Hierarchy
CONFIG_BT_HOGP_DEVICE (bool, depends on BT_PERIPHERAL)
CONFIG_BT_HOGP_DEVICE_MAX_CONNECTIONS (int, default 3)
CONFIG_BT_HOGP_DEVICE_MAX_REPORTS (int, default 8)
CONFIG_BT_HOGP_DEVICE_ISO (bool, depends on BT_ISO_CENTRAL or BT_ISO_PERIPHERAL)
CONFIG_BT_HOGP_HOST (bool, depends on BT_CENTRAL, BT_GATT_CLIENT)
CONFIG_BT_HOGP_HOST_MAX_CONNECTIONS (int, default 3)
CONFIG_BT_HOGP_HOST_ISO (bool, depends on BT_ISO_CENTRAL)
CONFIG_BT_SHORTER_CONNECTION_INTERVALS (bool, depends on BT_CONN)
CONFIG_BT_LE_EXTENDED_FEAT_SET (bool)
- Reference Implementation
A working implementation exists at: open-vela/external_zblue#226 (open-vela/external_zblue#226)
This RFC proposes to upstream a cleaned-up version that:
- Removes vendor-specific workarounds (BES controller hacks)
- Removes multi-controller extensions (not applicable to upstream Zephyr)
- Fixes known issues identified in code review (per-connection CCC, memory leak, build issues)
- Adds proper bsim tests and documentation
Dependencies
- Bluetooth Host (subsys/bluetooth/host/): SCI support adds new HCI event handlers in hci_core.c and new APIs in conn.c. These are additive and gated behind Kconfig.
- ISO subsystem (subsys/bluetooth/host/iso.c): HID ISO mode uses existing bt_iso_chan_connect() API. No changes to ISO core needed.
- GATT subsystem: Uses existing bt_gatt_service_register(), bt_gatt_notify(), bt_gatt_discover(), bt_gatt_subscribe() APIs. No changes needed.
- Controller: SCI requires controller support for BT 6.2 commands. The host-side code gracefully degrades if controller doesn't support SCI (checked via supported commands bitmask).
- Samples: New samples/bluetooth/peripheral_hogp/ and samples/bluetooth/central_hogp/ to demonstrate usage.
- Documentation: New pages under doc/connectivity/bluetooth/ for HOGP service API.
- Tests: bsim-based integration tests under tests/bsim/bluetooth/host/hogp/.
Concerns and Unresolved Questions
- SCI spec maturity: BT 6.2 SCI is relatively new. Controller support is limited (currently only a few vendors). Should SCI be in a separate RFC/PR series, or bundled with HOGP?
- HID ISO Service UUID assignment: The HOGP 1.1 spec defines the HID ISO Service, but some UUIDs may still be pending final SIG assignment. Need to confirm assigned numbers are finalized.
- Interaction with nRF Connect SDK: Nordic has their own HID service in NCS (subsys/bluetooth/services/hids/). How to coordinate so upstream HOGP doesn't conflict with NCS's existing implementation?
- Boot Protocol support: HOGP 1.0 mandates Boot Protocol for keyboards/mice. Should this be mandatory or optional (Kconfig-gated) in the upstream implementation?
- PTS test coverage: HOGP 1.1 has a new Test Suite. What level of PTS test pass rate is expected before merging?
- Security model for HID ISO Service: HOGP 1.1 spec says HID ISO Service characteristics have "Security Permissions = None", but this creates a mixed security model with HIDS (which requires encryption). Is
this acceptable, or should we enforce minimum security?
Alternatives Considered
-
Keep HID at sample level only (status quo)
- Pros: No maintenance burden
- Cons: Every product re-implements HID service; no code reuse; no path to ULL HID
- Rejected because: Inconsistent with how other SIG profiles (BAS, DIS, HRS, OTS, IAS) are handled in Zephyr
-
Implement only HOGP 1.0 (GATT-only, no ISO)
- Pros: Simpler, no ISO dependency
- Cons: Misses the primary value proposition of HOGP 1.1 (ULL HID); would need another RFC later for ISO
- Considered as a phased approach: HOGP 1.0 first, then 1.1 extension
-
Implement HOGP in application layer / external module
- Pros: No upstream review burden
- Cons: Fragmentation; each vendor implements differently; no interop testing
- Rejected because: HOGP is a SIG-adopted profile that belongs in the stack
-
Wait for other vendors to implement first
- Pros: Less risk
- Cons: Zephyr falls behind; gaming/VR market moves fast
- Rejected because: We have a working implementation ready to upstream
Chosen approach: Full HOGP 1.1 implementation, submitted as a phased PR series (HOGP 1.0 basics first, then ISO extension, then SCI), allowing incremental review and merge.
Problem Description
Zephyr currently lacks a proper reusable HOGP (HID over GATT Profile) service implementation. The only HID-related code is the samples/bluetooth/peripheral_hids/ sample, which directly constructs GATT attributes inline — not reusable across products.
Meanwhile, the Bluetooth SIG has adopted HOGP 1.1 (https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile/ (https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile/)), which extends HOGP 1.0 with support for HID reports over LE Isochronous Channels (HID ISO). Combined with BT 6.2 Shorter Connection Intervals (SCI), this enables Ultra-Low Latency (ULL) HID — targeting ≤1ms latency and 1kHz+ report rates for gaming peripherals, VR controllers, and professional input devices.
Key gaps in Zephyr today:
Without these, Zephyr-based products cannot compete in the ULL HID market that is rapidly growing (gaming mice, keyboards, VR/AR controllers).
Proposed Change (Summary)
Add a complete HOGP 1.1 implementation under subsys/bluetooth/services/hogp/ with:
All new features are gated behind Kconfig options (CONFIG_BT_HOGP_DEVICE, CONFIG_BT_HOGP_HOST, CONFIG_BT_HOGP_DEVICE_ISO, CONFIG_BT_HOGP_HOST_ISO, CONFIG_BT_SHORTER_CONNECTION_INTERVALS).
Proposed Change (Detailed)
subsys/bluetooth/services/hogp/
├── Kconfig.hogp # Kconfig options
├── CMakeLists.txt # Build rules
├── hogp_device.c # HOGP Device (GATT server)
├── hogp_host.c # HOGP Host (GATT client)
└── hogp_internal.h # Shared internal definitions
include/zephyr/bluetooth/services/
├── hogp_device.h # Public HOGP Device API
└── hogp_host.h # Public HOGP Host API
Implements HID Service (HIDS) per HOGP 1.1 §3:
Public API:
int bt_hogp_device_register(const struct bt_hogp_device_param *param);
int bt_hogp_device_send_input_report(struct bt_conn *conn, uint8_t report_id,
const uint8_t *data, uint16_t len);
int bt_hogp_device_notify_battery(struct bt_conn *conn, uint8_t level);
Implements HOGP Host per HOGP 1.1 §4:
Public API:
int bt_hogp_host_connect(struct bt_conn *conn, const struct bt_hogp_host_cb *cb);
int bt_hogp_host_disconnect(struct bt_conn *conn);
int bt_hogp_host_get_report(struct bt_conn *conn, uint8_t report_id,
uint8_t report_type, uint8_t *buf, uint16_t buf_len);
int bt_hogp_host_set_report(struct bt_conn *conn, uint8_t report_id,
uint8_t report_type, const uint8_t *data, uint16_t len);
When CONFIG_BT_HOGP_DEVICE_ISO=y / CONFIG_BT_HOGP_HOST_ISO=y:
When CONFIG_BT_SHORTER_CONNECTION_INTERVALS=y:
New HCI command definitions in hci_types.h:
Extended LE feature pages (page 0 + page 1) storage in struct bt_conn
conn_rate_changed callback in struct bt_conn_cb
SCI connection interval units: 0.125ms (vs standard 1.25ms)
CONFIG_BT_HOGP_DEVICE (bool, depends on BT_PERIPHERAL)
CONFIG_BT_HOGP_DEVICE_MAX_CONNECTIONS (int, default 3)
CONFIG_BT_HOGP_DEVICE_MAX_REPORTS (int, default 8)
CONFIG_BT_HOGP_DEVICE_ISO (bool, depends on BT_ISO_CENTRAL or BT_ISO_PERIPHERAL)
CONFIG_BT_HOGP_HOST (bool, depends on BT_CENTRAL, BT_GATT_CLIENT)
CONFIG_BT_HOGP_HOST_MAX_CONNECTIONS (int, default 3)
CONFIG_BT_HOGP_HOST_ISO (bool, depends on BT_ISO_CENTRAL)
CONFIG_BT_SHORTER_CONNECTION_INTERVALS (bool, depends on BT_CONN)
CONFIG_BT_LE_EXTENDED_FEAT_SET (bool)
A working implementation exists at: open-vela/external_zblue#226 (open-vela/external_zblue#226)
This RFC proposes to upstream a cleaned-up version that:
Dependencies
Concerns and Unresolved Questions
this acceptable, or should we enforce minimum security?
Alternatives Considered
Keep HID at sample level only (status quo)
Implement only HOGP 1.0 (GATT-only, no ISO)
- Pros: Simpler, no ISO dependency
- Cons: Misses the primary value proposition of HOGP 1.1 (ULL HID); would need another RFC later for ISO
- Considered as a phased approach: HOGP 1.0 first, then 1.1 extension
Implement HOGP in application layer / external module
- Pros: No upstream review burden
- Cons: Fragmentation; each vendor implements differently; no interop testing
- Rejected because: HOGP is a SIG-adopted profile that belongs in the stack
Wait for other vendors to implement first
- Pros: Less risk
- Cons: Zephyr falls behind; gaming/VR market moves fast
- Rejected because: We have a working implementation ready to upstream
Chosen approach: Full HOGP 1.1 implementation, submitted as a phased PR series (HOGP 1.0 basics first, then ISO extension, then SCI), allowing incremental review and merge.