Skip to content

Commit b037054

Browse files
Emil Obalskicarlescufi
authored andcommitted
mcumgr: Add latency control functionality
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]>
1 parent 557870c commit b037054

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
@@ -305,15 +305,63 @@ config MCUMGR_SMP_BT
305305
help
306306
Enables handling of SMP commands received over Bluetooth.
307307

308+
if MCUMGR_SMP_BT
309+
308310
config MCUMGR_SMP_BT_AUTHEN
309311
bool "Authenticated requirement for Bluetooth mcumgr SMP transport"
310-
depends on MCUMGR_SMP_BT
311312
select BT_SMP
312313
default y
313314
help
314315
Enables encrypted and authenticated connection requirement to
315316
Bluetooth SMP transport.
316317

318+
config MCUMGR_SMP_BT_LATENCY_CONTROL
319+
bool "Request low latency connection when handling SMP commands"
320+
depends on SYSTEM_WORKQUEUE_PRIORITY < 0
321+
help
322+
Enables support for requesting low latency connection parameter when
323+
SMP commands are handled. This option allows to speed up the command
324+
exchange process.
325+
Its recommended to enable this if SMP is used for DFU.
326+
327+
config MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY
328+
int "Default value for connection latency"
329+
depends on MCUMGR_SMP_BT_LATENCY_CONTROL
330+
default BT_PERIPHERAL_PREF_LATENCY if BT_GAP_PERIPHERAL_PREF_PARAMS
331+
default 99
332+
range 0 499
333+
help
334+
The value is a default connection latency that is used when restoring
335+
from low latency mode.
336+
337+
config MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME
338+
int "Connection latency restore time in milliseconds"
339+
depends on MCUMGR_SMP_BT_LATENCY_CONTROL
340+
default 5000
341+
range 1 65535
342+
help
343+
The value is a time after which connection latency is restored
344+
to default value
345+
(:kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY`). Latency
346+
restoration time could take up to twice as long as specified time.
347+
This is because of limiting CPU time needed to support this feature.
348+
The implementation periodically checks if the low latency is still
349+
needed every :kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_TIME`.
350+
The default latency is restored during check only if there was no SMP
351+
command exchanged in period before the check
352+
353+
config MCUMGR_SMP_BT_LATENCY_CONTROL_RESTORE_RETRY_TIME
354+
int "Connection latency restore retry time in milliseconds"
355+
depends on MCUMGR_SMP_BT_LATENCY_CONTROL
356+
default 1000
357+
range 1 5000
358+
help
359+
In case connection latency restoration fails due to an error, this
360+
option specifies the time after retry to set the default latency
361+
(:kconfig:`MCUMGR_SMP_BT_LATENCY_CONTROL_DEFAULT_LATENCY`) would be
362+
executed.
363+
364+
endif # MCUMGR_SMP_BT
317365

318366
config MCUMGR_SMP_SHELL
319367
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;
@@ -188,10 +299,66 @@ int smp_bt_unregister(void)
188299
return bt_gatt_service_unregister(&smp_bt_svc);
189300
}
190301

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

358+
if (IS_ENABLED(CONFIG_MCUMGR_SMP_BT_LATENCY_CONTROL)) {
359+
init_latency_control_support();
360+
}
361+
195362
zephyr_smp_transport_init(&smp_bt_transport, smp_bt_tx_pkt,
196363
smp_bt_get_mtu, smp_bt_ud_copy,
197364
smp_bt_ud_free);

0 commit comments

Comments
 (0)