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
2632struct 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+
3047static 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(
4159static 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+
191354static 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