Skip to content

Commit 35c44ec

Browse files
committed
samples: bluetooth: HID SCI support in peripheral HID samples
This commit support for the HID SCI characteristics in the peripheral_hids_mouse and peripheral_hids_keyboard samples. Signed-off-by: Artur Hadasz <artur.hadasz@nordicsemi.no>
1 parent 0bad07f commit 35c44ec

15 files changed

Lines changed: 635 additions & 3 deletions

samples/bluetooth/peripheral_hids_keyboard/README.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@ User interface
125125
LED 3:
126126
Indicates if an NFC field is present.
127127

128+
HID Shorter Connection Intervals (SCI)
129+
--------------------------------------
130+
131+
If the sample is built with ``-DFILE_SUFFIX=hid_sci``, support for HID Shorter Connection Intervals (SCI) is enabled.
132+
This feature allows the device to enter a specific HID SCI mode when requested by the central.
133+
The HID SCI modes are sets of connection parameters which can be used to optimize the connection for the specific use case.
134+
For example, the FAST mode is used to achieve the shortest connection intervals, allowing for minimum latency and maximum throughput.
135+
128136
Configuration
129137
*************
130138

@@ -154,6 +162,8 @@ Building and running
154162

155163
.. include:: /includes/ipc_radio_conf.txt
156164

165+
To build the sample with HID SCI support, build with ``-DFILE_SUFFIX=hid_sci``
166+
157167
Testing
158168
=======
159169

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#
2+
# Copyright (c) 2026 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
# The radio notification connection callbacks are not available
8+
# from the nRF5340 application core.
9+
CONFIG_BT_RADIO_NOTIFICATION_CONN_CB=n
10+
11+
# 1000 us minimum connection interval - local controller minimum for nRF5340
12+
CONFIG_BT_HIDS_SCI_FAST_INTERVAL_MIN_125US=8
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#
2+
# Copyright (c) 2026 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
# TF-M profile has to be properly configured to be able to run
8+
# the Bluetooth stack which uses PSA crypto API as minimal TF-M
9+
# profile cannot be used.
10+
CONFIG_TFM_PROFILE_TYPE_SMALL=y
11+
12+
# The radio notification connection callbacks are not available
13+
# from the nRF5340 application core.
14+
CONFIG_BT_RADIO_NOTIFICATION_CONN_CB=n
15+
16+
# 1000 us minimum connection interval - local controller minimum for nRF5340
17+
CONFIG_BT_HIDS_SCI_FAST_INTERVAL_MIN_125US=8
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#
2+
# Copyright (c) 2026 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
CONFIG_NCS_SAMPLES_DEFAULTS=y
7+
8+
CONFIG_BT=y
9+
CONFIG_BT_MAX_CONN=1
10+
CONFIG_BT_MAX_PAIRED=1
11+
CONFIG_BT_SMP=y
12+
CONFIG_BT_ATT_TX_COUNT=5
13+
CONFIG_BT_PERIPHERAL=y
14+
CONFIG_BT_DEVICE_NAME="Nordic_HIDS_keyboard"
15+
CONFIG_BT_DEVICE_APPEARANCE=961
16+
17+
# Disable automatic initiation of PHY updates and the SMP Security Requests.
18+
# Workaround to prevent disconnection with the following disconnect reasons:
19+
# - 0x08 (BT_HCI_ERR_CONN_TIMEOUT)
20+
# - 0x13 (BT_HCI_ERR_REMOTE_USER_TERM_CONN)
21+
# - 0x23 (BT_HCI_ERR_LL_PROC_COLLISION)
22+
# - 0x2A (BT_HCI_ERR_DIFF_TRANS_COLLISION)
23+
# Some laptop Bluetooth controllers may simultaneously trigger two Link Layer
24+
# procedures which results in a procedure collision and disconnection.
25+
CONFIG_BT_GATT_AUTO_SEC_REQ=n
26+
CONFIG_BT_AUTO_PHY_UPDATE=n
27+
28+
CONFIG_BT_BAS=y
29+
CONFIG_BT_HIDS=y
30+
CONFIG_BT_HIDS_INPUT_REP_MAX=1
31+
CONFIG_BT_HIDS_OUTPUT_REP_MAX=1
32+
CONFIG_BT_HIDS_FEATURE_REP_MAX=0
33+
CONFIG_BT_HIDS_MAX_CLIENT_COUNT=1
34+
CONFIG_BT_HIDS_DEFAULT_PERM_RW_ENCRYPT=y
35+
CONFIG_BT_GATT_UUID16_POOL_SIZE=40
36+
CONFIG_BT_GATT_CHRC_POOL_SIZE=20
37+
38+
CONFIG_BT_CONN_CTX=y
39+
40+
CONFIG_BT_DIS=y
41+
CONFIG_BT_DIS_MANUF_NAME=y
42+
CONFIG_BT_DIS_MANUF_NAME_STR="NordicSemiconductor"
43+
CONFIG_BT_DIS_PNP=y
44+
CONFIG_BT_DIS_PNP_VID_SRC=2
45+
CONFIG_BT_DIS_PNP_VID=0x1915
46+
CONFIG_BT_DIS_PNP_PID=0xEEEF
47+
CONFIG_BT_DIS_PNP_VER=0x0100
48+
49+
CONFIG_MAIN_STACK_SIZE=2048
50+
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
51+
52+
CONFIG_BT_SETTINGS=y
53+
CONFIG_FLASH=y
54+
CONFIG_FLASH_PAGE_LAYOUT=y
55+
CONFIG_FLASH_MAP=y
56+
57+
CONFIG_DK_LIBRARY=y
58+
59+
# HID SCI configuration
60+
CONFIG_BT_HIDS_ATTR_MAX=30
61+
62+
CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=n
63+
64+
CONFIG_BT_SUBRATING=y
65+
CONFIG_BT_LE_EXTENDED_FEAT_SET=y
66+
67+
CONFIG_BT_SHORTER_CONNECTION_INTERVALS=y
68+
69+
CONFIG_BT_HIDS_SCI=y
70+
71+
# Optimize for best possible performance in HID SCI FAST mode
72+
73+
# 875 us minimum connection interval
74+
CONFIG_BT_HIDS_SCI_FAST_INTERVAL_MIN_125US=7
75+
76+
# Keep the maximum connection event below the minimum connection interval of 875 us
77+
# Without this, the effective minimum connection interval would be 1125 us.
78+
CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=750

samples/bluetooth/peripheral_hids_keyboard/sample.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,16 @@ tests:
3939
- "Starting Bluetooth Peripheral HIDS keyboard sample"
4040
- "Bluetooth initialized"
4141
timeout: 15
42+
sample.bluetooth.peripheral_hids_keyboard.hid_sci:
43+
harness: console
44+
extra_args: FILE_SUFFIX=hid_sci
45+
integration_platforms:
46+
- nrf54l15dk/nrf54l05/cpuapp
47+
- nrf54lm20dk/nrf54lm20a/cpuapp
48+
- nrf54lm20dk/nrf54lm20b/cpuapp
49+
- nrf54lv10dk/nrf54lv10a/cpuapp
50+
platform_allow:
51+
- nrf54l15dk/nrf54l05/cpuapp
52+
- nrf54lm20dk/nrf54lm20a/cpuapp
53+
- nrf54lm20dk/nrf54lm20b/cpuapp
54+
- nrf54lv10dk/nrf54lv10a/cpuapp

samples/bluetooth/peripheral_hids_keyboard/src/main.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static const struct bt_data sd[] = {
131131
static struct conn_mode {
132132
struct bt_conn *conn;
133133
bool in_boot_mode;
134+
enum bt_hids_sci_mode_value requested_sci_mode;
134135
} conn_mode[CONFIG_BT_HIDS_MAX_CLIENT_COUNT];
135136

136137
static const uint8_t hello_world_str[] = {
@@ -269,6 +270,9 @@ static void connected(struct bt_conn *conn, uint8_t err)
269270
if (!conn_mode[i].conn) {
270271
conn_mode[i].conn = conn;
271272
conn_mode[i].in_boot_mode = false;
273+
if (IS_ENABLED(CONFIG_BT_HIDS_SCI)) {
274+
conn_mode[i].requested_sci_mode = BT_HIDS_SCI_MODE_NONE;
275+
}
272276
break;
273277
}
274278
}
@@ -342,10 +346,95 @@ static void security_changed(struct bt_conn *conn, bt_security_t level,
342346
}
343347
}
344348

349+
#ifdef CONFIG_BT_HIDS_SCI
350+
static const char *sci_mode_to_string(enum bt_hids_sci_mode_value mode)
351+
{
352+
switch (mode) {
353+
case BT_HIDS_SCI_MODE_NONE:
354+
return "NONE";
355+
case BT_HIDS_SCI_MODE_DEFAULT:
356+
return "DEFAULT";
357+
case BT_HIDS_SCI_MODE_FAST:
358+
return "FAST";
359+
case BT_HIDS_SCI_MODE_LOW_POWER:
360+
return "LOW_POWER";
361+
case BT_HIDS_SCI_MODE_FULL_RANGE:
362+
return "FULL_RANGE";
363+
}
364+
365+
return "UNKNOWN";
366+
}
367+
368+
static void conn_rate_changed(struct bt_conn *conn, uint8_t status,
369+
const struct bt_conn_le_conn_rate_changed *params)
370+
{
371+
size_t i;
372+
enum bt_hids_sci_mode_value requested_sci_mode;
373+
bool mode_changed = false;
374+
375+
for (i = 0; i < ARRAY_SIZE(conn_mode); i++) {
376+
if (conn_mode[i].conn == conn) {
377+
break;
378+
}
379+
}
380+
381+
if (i >= ARRAY_SIZE(conn_mode)) {
382+
return;
383+
}
384+
385+
printk(
386+
"\nConnection rate changed:\n"
387+
" interval us: %d\n"
388+
" subrate factor: %d\n"
389+
" peripheral latency: %d\n"
390+
" continuation number: %d\n"
391+
" supervision timeout (10ms units): %d\n",
392+
params->interval_us,
393+
params->subrate_factor,
394+
params->peripheral_latency,
395+
params->continuation_number,
396+
params->supervision_timeout_10ms
397+
);
398+
399+
requested_sci_mode = conn_mode[i].requested_sci_mode;
400+
conn_mode[i].requested_sci_mode = BT_HIDS_SCI_MODE_NONE;
401+
402+
/* In case a connection rate change is received without a prior HID SCI mode change request,
403+
* or if a HID SCI mode change was requested but the new connection rate parameters
404+
* are not valid for the requested mode,
405+
* this sample simply ignores the event and does not update the HID SCI mode.
406+
* In a real application a different approach might be chosen, e.g. cycling through the
407+
* available SCI modes to determine which mode the new parameters are compatible with,
408+
* or default to the FULL_RANGE mode.
409+
*/
410+
if (requested_sci_mode == BT_HIDS_SCI_MODE_NONE) {
411+
printk("No pending HID SCI mode change request\n");
412+
} else if (bt_hids_sci_mode_validate(requested_sci_mode, params)) {
413+
int err = bt_hids_sci_mode_updated(conn, requested_sci_mode);
414+
415+
if (!err) {
416+
mode_changed = true;
417+
} else {
418+
printk("Failed to update SCI mode: %d\n", err);
419+
}
420+
} else {
421+
printk("Invalid SCI mode parameters for mode %d\n", requested_sci_mode);
422+
}
423+
424+
if (mode_changed) {
425+
printk("SCI mode updated to: %s for connection %zu\n",
426+
sci_mode_to_string(requested_sci_mode), i);
427+
}
428+
}
429+
#endif
430+
345431
BT_CONN_CB_DEFINE(conn_callbacks) = {
346432
.connected = connected,
347433
.disconnected = disconnected,
348434
.security_changed = security_changed,
435+
#ifdef CONFIG_BT_HIDS_SCI
436+
.conn_rate_changed = conn_rate_changed,
437+
#endif /* CONFIG_BT_HIDS_SCI */
349438
};
350439

351440

@@ -426,6 +515,62 @@ static void hids_pm_evt_handler(enum bt_hids_pm_evt evt,
426515
}
427516
}
428517

518+
static void conn_cp_evt_handler(enum bt_hids_cp_evt evt, struct bt_conn *conn)
519+
{
520+
const char *evt_str = "UNKNOWN";
521+
enum bt_hids_sci_mode_value new_mode = BT_HIDS_SCI_MODE_NONE;
522+
size_t i;
523+
524+
for (i = 0; i < ARRAY_SIZE(conn_mode); i++) {
525+
if (conn_mode[i].conn == conn) {
526+
break;
527+
}
528+
}
529+
530+
if (i >= ARRAY_SIZE(conn_mode)) {
531+
return;
532+
}
533+
534+
switch (evt) {
535+
case BT_HIDS_CP_EVT_HOST_SUSP:
536+
evt_str = "SUSP";
537+
break;
538+
case BT_HIDS_CP_EVT_HOST_EXIT_SUSP:
539+
evt_str = "EXIT_SUSP";
540+
break;
541+
case BT_HIDS_CP_EVT_HOST_SCI_DEFAULT_REQ:
542+
evt_str = "SCI_DEFAULT_REQ";
543+
new_mode = BT_HIDS_SCI_MODE_DEFAULT;
544+
break;
545+
case BT_HIDS_CP_EVT_HOST_SCI_FAST_REQ:
546+
evt_str = "SCI_FAST_REQ";
547+
new_mode = BT_HIDS_SCI_MODE_FAST;
548+
break;
549+
case BT_HIDS_CP_EVT_HOST_SCI_LOW_POWER_REQ:
550+
evt_str = "SCI_LOW_POWER_REQ";
551+
new_mode = BT_HIDS_SCI_MODE_LOW_POWER;
552+
break;
553+
case BT_HIDS_CP_EVT_HOST_SCI_FULL_RANGE_REQ:
554+
evt_str = "SCI_FULL_RANGE_REQ";
555+
new_mode = BT_HIDS_SCI_MODE_FULL_RANGE;
556+
break;
557+
default:
558+
evt_str = "UNKNOWN";
559+
break;
560+
}
561+
562+
printk("Control point event received for connection %u: %s\n", i, evt_str);
563+
564+
if (new_mode != BT_HIDS_SCI_MODE_NONE) {
565+
int err = bt_hids_sci_mode_change_request(conn, new_mode);
566+
567+
if (!err) {
568+
conn_mode[i].requested_sci_mode = new_mode;
569+
} else {
570+
printk("Failed to request SCI mode change: %d\n", err);
571+
}
572+
}
573+
}
429574

430575
static void hid_init(void)
431576
{
@@ -508,6 +653,9 @@ static void hid_init(void)
508653
hids_init_obj.is_kb = true;
509654
hids_init_obj.boot_kb_outp_rep_handler = hids_boot_kb_outp_rep_handler;
510655
hids_init_obj.pm_evt_handler = hids_pm_evt_handler;
656+
if (IS_ENABLED(CONFIG_BT_HIDS_SCI)) {
657+
hids_init_obj.conn_cp_evt_handler = conn_cp_evt_handler;
658+
}
511659

512660
err = bt_hids_init(&hids_obj, &hids_init_obj);
513661
__ASSERT(err == 0, "HIDS initialization failed\n");
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# Copyright (c) 2026 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
CONFIG_HEAP_MEM_POOL_SIZE=8192
8+
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
9+
10+
CONFIG_MBOX=y
11+
CONFIG_IPC_SERVICE=y
12+
13+
CONFIG_BT=y
14+
CONFIG_BT_HCI_RAW=y
15+
#CONFIG_BT_MAX_CONN=16
16+
17+
# 254 is the minimum CONFIG_BT_BUF_EVT_RX_SIZE to support bt_conn_le_read_min_conn_interval_groups.
18+
# This function is used by in order to load HID SCI information.
19+
CONFIG_BT_BUF_EVT_RX_SIZE=254
20+
21+
CONFIG_BT_MAX_CONN=1
22+
CONFIG_BT_CENTRAL=n
23+
24+
CONFIG_IPC_RADIO_BT=y
25+
CONFIG_IPC_RADIO_BT_HCI_IPC=y
26+
27+
CONFIG_BT_CTLR_EXTENDED_FEAT_SET=y
28+
CONFIG_BT_CTLR_SUBRATING=y
29+
CONFIG_BT_CTLR_SHORTER_CONNECTION_INTERVALS=y
30+
31+
# Optimize for best possible performance in HID SCI FAST mode
32+
33+
# Keep the maximum connection event below the minimum connection interval of 875 us
34+
# Without this, the effective minimum connection interval is 1125 us.
35+
CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=750

samples/bluetooth/peripheral_hids_mouse/README.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,14 @@ The high-duty cycle directed advertising has a timeout of 1.28 seconds defined b
147147
If the timeout occurs, the device starts directed advertising to the next bonded peer.
148148
If all bonding information is used and there is still no connection, the regular advertising starts.
149149

150+
HID Shorter Connection Intervals (SCI)
151+
--------------------------------------
152+
153+
If the sample is built with ``-DFILE_SUFFIX=hid_sci``, support for HID Shorter Connection Intervals (SCI) is enabled.
154+
This feature allows the device to enter a specific HID SCI mode when requested by the central.
155+
The HID SCI modes are sets of connection parameters which can be used to optimize the connection for the specific use case.
156+
For example, the FAST mode is used to achieve the shortest connection intervals, allowing for minimum latency and maximum throughput.
157+
150158
Building and running
151159
********************
152160

@@ -161,6 +169,8 @@ Building and running
161169

162170
.. _peripheral_hids_mouse_bt_rpc_build:
163171

172+
To build the sample with HID SCI support, build with ``-DFILE_SUFFIX=hid_sci``
173+
164174
Bluetooth RPC build
165175
===================
166176

0 commit comments

Comments
 (0)