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 ;
@@ -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+
194357static 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