Skip to content

Commit 3791175

Browse files
Emil Obalskirlubos
authored andcommitted
[nrf fromlist] mcumgr: Add latency control functionality
Upstream PR 39663 This change adds a posibility to enable low latency connection parameters for BT when SMP commands are handled. Support for this functionality is disabled by the default and can be enabled by CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL=y option. Signed-off-by: Emil Obalski <[email protected]> Signed-off-by: Robert Lubos <[email protected]>
1 parent e471a89 commit 3791175

File tree

2 files changed

+217
-2
lines changed

2 files changed

+217
-2
lines changed

subsys/mgmt/mcumgr/Kconfig

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,63 @@ config MCUMGR_SMP_BT
274274
help
275275
Enables handling of SMP commands received over Bluetooth.
276276

277+
if MCUMGR_SMP_BT
278+
277279
config MCUMGR_SMP_BT_AUTHEN
278280
bool "Authenticated requirement for Bluetooth mcumgr SMP transport"
279-
depends on MCUMGR_SMP_BT
280281
select BT_SMP
281282
default y
282283
help
283284
Enables encrypted and authenticated connection requirement to
284285
Bluetooth SMP transport.
285286

287+
config MCUMGR_SMP_BT_LATENCY_CONTROL
288+
bool "Request low latency connection when handling SMP commands"
289+
depends on SYSTEM_WORKQUEUE_PRIORITY < 0
290+
help
291+
Enables support for requesting low latency connection parameter when
292+
SMP commands are handled. This option allows to speed up the command
293+
exchange process.
294+
Its recommended to enable this if SMP is used for DFU.
295+
296+
config MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY
297+
int "Default value for connection latency"
298+
depends on MCUMGR_SMP_BT_LATENCY_CONTROL
299+
default BT_PERIPHERAL_PREF_LATENCY if BT_GAP_PERIPHERAL_PREF_PARAMS
300+
default 99
301+
range 0 499
302+
help
303+
The value is a default connection latency that is used when restoring
304+
from low latency mode.
305+
306+
config MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME
307+
int "Connection latency restore time in milliseconds"
308+
depends on MCUMGR_SMP_BT_LATENCY_CONTROL
309+
default 5000
310+
range 1 65535
311+
help
312+
The value is a time after which connection latency is restored
313+
to default value
314+
(:kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY`). Latency
315+
restoration time could take up to twice as long as specified time.
316+
This is because of limiting CPU time needed to support this feature.
317+
The implementation periodically checks if the low latency is still
318+
needed every :kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME`.
319+
The default latency is restored during check only if there was no SMP
320+
command exchanged in period before the check
321+
322+
config MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_RETRY_TIME
323+
int "Connection latency restore retry time in milliseconds"
324+
depends on MCUMGR_SMP_BT_LATENCY_CONTROL
325+
default 1000
326+
range 1 5000
327+
help
328+
In case connection latency restoration fails due to an error, this
329+
option specifies the time after retry to set the default latency
330+
(:kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY`) would be
331+
executed.
332+
333+
endif # MCUMGR_SMP_BT
286334

287335
config MCUMGR_SMP_SHELL
288336
bool "Shell mcumgr SMP transport"

subsys/mgmt/mcumgr/smp_bt.c

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,31 @@
2121

2222
#include <mgmt/mcumgr/smp.h>
2323

24-
struct device;
24+
#define RESTORE_TIME COND_CODE_1(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL, \
25+
(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME), (0))
26+
#define RESTORE_RETRY_TIME COND_CODE_1(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL, \
27+
(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_RETRY_TIME), (0))
28+
#define DEFAULT_LATENCY COND_CODE_1(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL, \
29+
(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY), (0))
30+
2531

2632
struct smp_bt_user_data {
2733
struct bt_conn *conn;
2834
};
2935

36+
enum {
37+
CONN_LOW_LATENCY_ENABLED = BIT(0),
38+
CONN_LOW_LATENCY_REQUIRED = BIT(1),
39+
};
40+
41+
struct conn_param_data {
42+
struct bt_conn *conn;
43+
struct k_work_delayable dwork;
44+
uint8_t latency_state;
45+
};
46+
3047
static struct zephyr_smp_transport smp_bt_transport;
48+
static struct conn_param_data conn_data[CONFIG_BT_MAX_CONN];
3149

3250
/* SMP service.
3351
* {8D53DC1D-1DB7-4CD3-868B-8A527460AA84}
@@ -41,6 +59,95 @@ static struct bt_uuid_128 smp_bt_svc_uuid = BT_UUID_INIT_128(
4159
static struct bt_uuid_128 smp_bt_chr_uuid = BT_UUID_INIT_128(
4260
BT_UUID_128_ENCODE(0xda2e7828, 0xfbce, 0x4e01, 0xae9e, 0x261174997c48));
4361

62+
/* Helper function that allocates conn_param_data for a conn. */
63+
static struct conn_param_data *alloc_conn_param_data(struct bt_conn *conn)
64+
{
65+
for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) {
66+
if (conn_data[i].conn == NULL) {
67+
conn_data[i].conn = conn;
68+
return &conn_data[i];
69+
}
70+
}
71+
72+
/* Conn data must exists. */
73+
__ASSERT_NO_MSG(false);
74+
return NULL;
75+
}
76+
77+
/* Helper function that returns conn_param_data associated with a conn. */
78+
static struct conn_param_data *get_conn_param_data(const struct bt_conn *conn)
79+
{
80+
for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) {
81+
if (conn_data[i].conn == conn) {
82+
return &conn_data[i];
83+
}
84+
}
85+
86+
/* Conn data must exists. */
87+
__ASSERT_NO_MSG(false);
88+
return NULL;
89+
}
90+
91+
/* Sets connection parameters for a given conn. */
92+
static void set_conn_latency(struct bt_conn *conn, bool low_latency)
93+
{
94+
struct bt_le_conn_param params;
95+
struct conn_param_data *cpd;
96+
struct bt_conn_info info;
97+
int ret = 0;
98+
99+
cpd = get_conn_param_data(conn);
100+
101+
ret = bt_conn_get_info(conn, &info);
102+
__ASSERT_NO_MSG(!ret);
103+
104+
if ((low_latency && (info.le.latency == 0)) ||
105+
((!low_latency) && (info.le.latency == DEFAULT_LATENCY))) {
106+
/* Already updated. */
107+
return;
108+
}
109+
110+
params.interval_min = info.le.interval;
111+
params.interval_max = info.le.interval;
112+
params.latency = (low_latency) ? (0) : (DEFAULT_LATENCY);
113+
params.timeout = info.le.timeout;
114+
115+
ret = bt_conn_le_param_update(cpd->conn, &params);
116+
if (ret && (ret != -EALREADY)) {
117+
if (!low_latency) {
118+
/* Try again to avoid stucking in low latency. */
119+
(void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_RETRY_TIME));
120+
}
121+
}
122+
}
123+
124+
125+
/* Work handler function for restoring the default latency for the connection. */
126+
static void restore_default_latency(struct k_work *work)
127+
{
128+
struct conn_param_data *cpd;
129+
130+
cpd = CONTAINER_OF(work, struct conn_param_data, dwork);
131+
132+
if (cpd->latency_state & CONN_LOW_LATENCY_REQUIRED) {
133+
cpd->latency_state &= ~CONN_LOW_LATENCY_REQUIRED;
134+
(void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_TIME));
135+
} else {
136+
set_conn_latency(cpd->conn, false);
137+
}
138+
}
139+
140+
static void enable_low_latency(struct bt_conn *conn)
141+
{
142+
struct conn_param_data *cpd = get_conn_param_data(conn);
143+
144+
if (cpd->latency_state & CONN_LOW_LATENCY_ENABLED) {
145+
cpd->latency_state |= CONN_LOW_LATENCY_REQUIRED;
146+
} else {
147+
set_conn_latency(conn, true);
148+
}
149+
}
150+
44151
/**
45152
* Write handler for the SMP characteristic; processes an incoming SMP request.
46153
*/
@@ -61,6 +168,10 @@ static ssize_t smp_bt_chr_write(struct bt_conn *conn,
61168
ud = net_buf_user_data(nb);
62169
ud->conn = bt_conn_ref(conn);
63170

171+
if (IS_ENABLED(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL)) {
172+
enable_low_latency(conn);
173+
}
174+
64175
zephyr_smp_rx_req(&smp_bt_transport, nb);
65176

66177
return len;
@@ -191,10 +302,66 @@ int smp_bt_unregister(void)
191302
return bt_gatt_service_unregister(&smp_bt_svc);
192303
}
193304

305+
/* BT connected callback. */
306+
static void connected(struct bt_conn *conn, uint8_t err)
307+
{
308+
if (err == 0) {
309+
alloc_conn_param_data(conn);
310+
}
311+
}
312+
313+
/* BT disconnected callback. */
314+
static void disconnected(struct bt_conn *conn, uint8_t reason)
315+
{
316+
struct conn_param_data *cpd = get_conn_param_data(conn);
317+
318+
/* Cancel work if ongoing. */
319+
(void)k_work_cancel_delayable(&cpd->dwork);
320+
321+
/* Clear cpd. */
322+
cpd->latency_state = 0;
323+
cpd->conn = NULL;
324+
}
325+
326+
/* BT LE connection parameters updated callback. */
327+
static void le_param_updated(struct bt_conn *conn, uint16_t interval,
328+
uint16_t latency, uint16_t timeout)
329+
{
330+
struct conn_param_data *cpd = get_conn_param_data(conn);
331+
332+
if (latency == 0) {
333+
cpd->latency_state |= CONN_LOW_LATENCY_ENABLED;
334+
cpd->latency_state &= ~CONN_LOW_LATENCY_REQUIRED;
335+
(void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_TIME));
336+
} else {
337+
cpd->latency_state &= ~CONN_LOW_LATENCY_ENABLED;
338+
(void)k_work_cancel_delayable(&cpd->dwork);
339+
}
340+
}
341+
342+
static void init_latency_control_support(void)
343+
{
344+
/* Register BT callbacks */
345+
static struct bt_conn_cb conn_callbacks = {
346+
.connected = connected,
347+
.disconnected = disconnected,
348+
.le_param_updated = le_param_updated,
349+
};
350+
bt_conn_cb_register(&conn_callbacks);
351+
352+
for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) {
353+
k_work_init_delayable(&conn_data[i].dwork, restore_default_latency);
354+
}
355+
}
356+
194357
static int smp_bt_init(const struct device *dev)
195358
{
196359
ARG_UNUSED(dev);
197360

361+
if (IS_ENABLED(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL)) {
362+
init_latency_control_support();
363+
}
364+
198365
zephyr_smp_transport_init(&smp_bt_transport, smp_bt_tx_pkt,
199366
smp_bt_get_mtu, smp_bt_ud_copy,
200367
smp_bt_ud_free);

0 commit comments

Comments
 (0)