Skip to content

Commit db9bcdc

Browse files
alexstanoev-nordiccarlescufi
authored andcommitted
bluetooth: host: Add support for LE Connection Subrating
Adds support for LE Connection Subrating as defined in Core 5.4 Vol 6, Part B, Section 5.1.19. As this is primarily a controller feature, the host support is mostly a wrapper around the relevant HCI commands. Note that subrating provides a new method to update the connection's peripheral latency and supervision timeout alongside subrating parameters. Signed-off-by: Aleksandar Stanoev <[email protected]>
1 parent c417bd2 commit db9bcdc

File tree

5 files changed

+302
-0
lines changed

5 files changed

+302
-0
lines changed

include/zephyr/bluetooth/conn.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,57 @@ struct bt_conn_le_data_len_param {
196196
BT_CONN_LE_DATA_LEN_PARAM(BT_GAP_DATA_LEN_MAX, \
197197
BT_GAP_DATA_TIME_MAX)
198198

199+
/** Connection subrating parameters for LE connections */
200+
struct bt_conn_le_subrate_param {
201+
/** Minimum subrate factor. */
202+
uint16_t subrate_min;
203+
/** Maximum subrate factor. */
204+
uint16_t subrate_max;
205+
/** Maximum Peripheral latency in units of subrated connection intervals. */
206+
uint16_t max_latency;
207+
/** Minimum number of underlying connection events to remain active
208+
* after a packet containing a Link Layer PDU with a non-zero Length
209+
* field is sent or received.
210+
*/
211+
uint16_t continuation_number;
212+
/** Connection Supervision timeout (N * 10 ms).
213+
* If using @ref bt_conn_le_subrate_set_defaults, this is the
214+
* maximum supervision timeout allowed in requests by a peripheral.
215+
*/
216+
uint16_t supervision_timeout;
217+
};
218+
219+
/** Subrating information for LE connections */
220+
struct bt_conn_le_subrating_info {
221+
/** Connection subrate factor. */
222+
uint16_t factor;
223+
/** Number of underlying connection events to remain active after
224+
* a packet containing a Link Layer PDU with a non-zero Length
225+
* field is sent or received.
226+
*/
227+
uint16_t continuation_number;
228+
};
229+
230+
/** Updated subrating connection parameters for LE connections */
231+
struct bt_conn_le_subrate_changed {
232+
/** HCI Status from LE Subrate Changed event.
233+
* The remaining parameters will be unchanged if status is not
234+
* BT_HCI_ERR_SUCCESS.
235+
*/
236+
uint8_t status;
237+
/** Connection subrate factor. */
238+
uint16_t factor;
239+
/** Number of underlying connection events to remain active after
240+
* a packet containing a Link Layer PDU with a non-zero Length
241+
* field is sent or received.
242+
*/
243+
uint16_t continuation_number;
244+
/** Peripheral latency in units of subrated connection intervals. */
245+
uint16_t peripheral_latency;
246+
/** Connection Supervision timeout (N * 10 ms). */
247+
uint16_t supervision_timeout;
248+
};
249+
199250
/** Connection Type */
200251
enum __packed bt_conn_type {
201252
/** LE Connection Type */
@@ -310,6 +361,11 @@ struct bt_conn_le_info {
310361
/* Connection maximum single fragment parameters */
311362
const struct bt_conn_le_data_len_info *data_len;
312363
#endif /* defined(CONFIG_BT_USER_DATA_LEN_UPDATE) */
364+
365+
#if defined(CONFIG_BT_SUBRATING)
366+
/* Connection subrating parameters */
367+
const struct bt_conn_le_subrating_info *subrate;
368+
#endif /* defined(CONFIG_BT_SUBRATING) */
313369
};
314370

315371
/** @brief Convert connection interval to milliseconds
@@ -676,6 +732,36 @@ int bt_conn_le_set_path_loss_mon_param(struct bt_conn *conn,
676732
*/
677733
int bt_conn_le_set_path_loss_mon_enable(struct bt_conn *conn, bool enable);
678734

735+
/** @brief Set Default Connection Subrating Parameters.
736+
*
737+
* Change the default subrating parameters for all future
738+
* ACL connections where the local device is the central.
739+
* This command does not affect any existing connection.
740+
* Parameters set for specific connection will always have precedence.
741+
*
742+
* @note To use this API @kconfig{CONFIG_BT_SUBRATING} and
743+
* @kconfig{CONFIG_BT_CENTRAL} must be set.
744+
*
745+
* @param params Subrating parameters.
746+
*
747+
* @return Zero on success or (negative) error code on failure.
748+
*/
749+
int bt_conn_le_subrate_set_defaults(const struct bt_conn_le_subrate_param *params);
750+
751+
/** @brief Request New Subrating Parameters.
752+
*
753+
* Request a change to the subrating parameters of a connection.
754+
*
755+
* @note To use this API @kconfig{CONFIG_BT_SUBRATING} must be set.
756+
*
757+
* @param conn Connection object.
758+
* @param params Subrating parameters.
759+
*
760+
* @return Zero on success or (negative) error code on failure.
761+
*/
762+
int bt_conn_le_subrate_request(struct bt_conn *conn,
763+
const struct bt_conn_le_subrate_param *params);
764+
679765
/** @brief Update the connection parameters.
680766
*
681767
* If the local device is in the peripheral role then updating the connection
@@ -1244,6 +1330,21 @@ struct bt_conn_cb {
12441330
const struct bt_conn_le_path_loss_threshold_report *report);
12451331
#endif /* CONFIG_BT_PATH_LOSS_MONITORING */
12461332

1333+
#if defined(CONFIG_BT_SUBRATING)
1334+
/** @brief LE Subrate Changed event.
1335+
*
1336+
* This callback notifies the application that the subrating parameters
1337+
* of the connection may have changed.
1338+
* The connection subrating parameters will be unchanged
1339+
* if status is not BT_HCI_ERR_SUCCESS.
1340+
*
1341+
* @param conn Connection object.
1342+
* @param params New subrating parameters.
1343+
*/
1344+
void (*subrate_changed)(struct bt_conn *conn,
1345+
const struct bt_conn_le_subrate_changed *params);
1346+
#endif /* CONFIG_BT_SUBRATING */
1347+
12471348
/** @internal Internally used field for list handling */
12481349
sys_snode_t _node;
12491350
};

include/zephyr/bluetooth/hci_types.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,26 @@ struct bt_hci_cp_le_set_path_loss_reporting_enable {
704704
#define BT_HCI_LE_PATH_LOSS_REPORTING_ENABLE 0x01
705705
#define BT_HCI_OP_LE_SET_PATH_LOSS_REPORTING_ENABLE BT_OP(BT_OGF_LE, 0x0079) /* 0x2079 */
706706

707+
struct bt_hci_cp_le_set_default_subrate {
708+
uint16_t subrate_min;
709+
uint16_t subrate_max;
710+
uint16_t max_latency;
711+
uint16_t continuation_number;
712+
uint16_t supervision_timeout;
713+
} __packed;
714+
715+
struct bt_hci_cp_le_subrate_request {
716+
uint16_t handle;
717+
uint16_t subrate_min;
718+
uint16_t subrate_max;
719+
uint16_t max_latency;
720+
uint16_t continuation_number;
721+
uint16_t supervision_timeout;
722+
} __packed;
723+
724+
#define BT_HCI_OP_LE_SET_DEFAULT_SUBRATE BT_OP(BT_OGF_LE, 0x007D) /* 0x207D */
725+
#define BT_HCI_OP_LE_SUBRATE_REQUEST BT_OP(BT_OGF_LE, 0x007E) /* 0x207E */
726+
707727
#define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00
708728
#define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01
709729
#define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031) /* 0x0c31 */
@@ -3098,6 +3118,16 @@ struct bt_hci_evt_le_biginfo_adv_report {
30983118
uint8_t encryption;
30993119
} __packed;
31003120

3121+
#define BT_HCI_EVT_LE_SUBRATE_CHANGE 0x23
3122+
struct bt_hci_evt_le_subrate_change {
3123+
uint8_t status;
3124+
uint16_t handle;
3125+
uint16_t subrate_factor;
3126+
uint16_t peripheral_latency;
3127+
uint16_t continuation_number;
3128+
uint16_t supervision_timeout;
3129+
} __packed;
3130+
31013131
/* Event mask bits */
31023132

31033133
#define BT_EVT_BIT(n) (1ULL << (n))
@@ -3178,6 +3208,7 @@ struct bt_hci_evt_le_biginfo_adv_report {
31783208
#define BT_EVT_MASK_LE_PATH_LOSS_THRESHOLD BT_EVT_BIT(31)
31793209
#define BT_EVT_MASK_LE_TRANSMIT_POWER_REPORTING BT_EVT_BIT(32)
31803210
#define BT_EVT_MASK_LE_BIGINFO_ADV_REPORT BT_EVT_BIT(33)
3211+
#define BT_EVT_MASK_LE_SUBRATE_CHANGE BT_EVT_BIT(34)
31813212

31823213
#define BT_EVT_MASK_LE_PER_ADV_SYNC_ESTABLISHED_V2 BT_EVT_BIT(35)
31833214
#define BT_EVT_MASK_LE_PER_ADVERTISING_REPORT_V2 BT_EVT_BIT(36)

subsys/bluetooth/host/conn.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2753,6 +2753,9 @@ int bt_conn_get_info(const struct bt_conn *conn, struct bt_conn_info *info)
27532753
#endif
27542754
#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
27552755
info->le.data_len = &conn->le.data_len;
2756+
#endif
2757+
#if defined(CONFIG_BT_SUBRATING)
2758+
info->le.subrate = &conn->le.subrate;
27562759
#endif
27572760
if (conn->le.keys && (conn->le.keys->flags & BT_KEYS_SC)) {
27582761
info->security.flags |= BT_SECURITY_FLAG_SC;
@@ -3038,6 +3041,109 @@ int bt_conn_le_set_path_loss_mon_enable(struct bt_conn *conn, bool reporting_ena
30383041
}
30393042
#endif /* CONFIG_BT_PATH_LOSS_MONITORING */
30403043

3044+
#if defined(CONFIG_BT_SUBRATING)
3045+
void notify_subrate_change(struct bt_conn *conn,
3046+
const struct bt_conn_le_subrate_changed params)
3047+
{
3048+
struct bt_conn_cb *callback;
3049+
3050+
SYS_SLIST_FOR_EACH_CONTAINER(&conn_cbs, callback, _node) {
3051+
if (callback->subrate_changed) {
3052+
callback->subrate_changed(conn, &params);
3053+
}
3054+
}
3055+
3056+
STRUCT_SECTION_FOREACH(bt_conn_cb, cb)
3057+
{
3058+
if (cb->subrate_changed) {
3059+
cb->subrate_changed(conn, &params);
3060+
}
3061+
}
3062+
}
3063+
3064+
static bool le_subrate_common_params_valid(const struct bt_conn_le_subrate_param *param)
3065+
{
3066+
/* All limits according to BT Core spec 5.4 [Vol 4, Part E, 7.8.123] */
3067+
3068+
if (param->subrate_min < 0x0001 || param->subrate_min > 0x01F4 ||
3069+
param->subrate_max < 0x0001 || param->subrate_max > 0x01F4 ||
3070+
param->subrate_min > param->subrate_max) {
3071+
return false;
3072+
}
3073+
3074+
if (param->max_latency > 0x01F3 ||
3075+
param->subrate_max * (param->max_latency + 1) > 500) {
3076+
return false;
3077+
}
3078+
3079+
if (param->continuation_number > 0x01F3 ||
3080+
param->continuation_number >= param->subrate_max) {
3081+
return false;
3082+
}
3083+
3084+
if (param->supervision_timeout < 0x000A ||
3085+
param->supervision_timeout > 0xC80) {
3086+
return false;
3087+
}
3088+
3089+
return true;
3090+
}
3091+
3092+
int bt_conn_le_subrate_set_defaults(const struct bt_conn_le_subrate_param *params)
3093+
{
3094+
struct bt_hci_cp_le_set_default_subrate *cp;
3095+
struct net_buf *buf;
3096+
3097+
if (!IS_ENABLED(CONFIG_BT_CENTRAL)) {
3098+
return -ENOTSUP;
3099+
}
3100+
3101+
if (!le_subrate_common_params_valid(params)) {
3102+
return -EINVAL;
3103+
}
3104+
3105+
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_DEFAULT_SUBRATE, sizeof(*cp));
3106+
if (!buf) {
3107+
return -ENOBUFS;
3108+
}
3109+
3110+
cp = net_buf_add(buf, sizeof(*cp));
3111+
cp->subrate_min = sys_cpu_to_le16(params->subrate_min);
3112+
cp->subrate_max = sys_cpu_to_le16(params->subrate_max);
3113+
cp->max_latency = sys_cpu_to_le16(params->max_latency);
3114+
cp->continuation_number = sys_cpu_to_le16(params->continuation_number);
3115+
cp->supervision_timeout = sys_cpu_to_le16(params->supervision_timeout);
3116+
3117+
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_DEFAULT_SUBRATE, buf, NULL);
3118+
}
3119+
3120+
int bt_conn_le_subrate_request(struct bt_conn *conn,
3121+
const struct bt_conn_le_subrate_param *params)
3122+
{
3123+
struct bt_hci_cp_le_subrate_request *cp;
3124+
struct net_buf *buf;
3125+
3126+
if (!le_subrate_common_params_valid(params)) {
3127+
return -EINVAL;
3128+
}
3129+
3130+
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SUBRATE_REQUEST, sizeof(*cp));
3131+
if (!buf) {
3132+
return -ENOBUFS;
3133+
}
3134+
3135+
cp = net_buf_add(buf, sizeof(*cp));
3136+
cp->handle = sys_cpu_to_le16(conn->handle);
3137+
cp->subrate_min = sys_cpu_to_le16(params->subrate_min);
3138+
cp->subrate_max = sys_cpu_to_le16(params->subrate_max);
3139+
cp->max_latency = sys_cpu_to_le16(params->max_latency);
3140+
cp->continuation_number = sys_cpu_to_le16(params->continuation_number);
3141+
cp->supervision_timeout = sys_cpu_to_le16(params->supervision_timeout);
3142+
3143+
return bt_hci_cmd_send_sync(BT_HCI_OP_LE_SUBRATE_REQUEST, buf, NULL);
3144+
}
3145+
#endif /* CONFIG_BT_SUBRATING */
3146+
30413147
int bt_conn_le_param_update(struct bt_conn *conn,
30423148
const struct bt_le_conn_param *param)
30433149
{

subsys/bluetooth/host/conn_internal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ struct bt_conn_le {
114114
#if defined(CONFIG_BT_USER_DATA_LEN_UPDATE)
115115
struct bt_conn_le_data_len_info data_len;
116116
#endif
117+
118+
#if defined(CONFIG_BT_SUBRATING)
119+
struct bt_conn_le_subrating_info subrate;
120+
#endif
117121
};
118122

119123
#if defined(CONFIG_BT_CLASSIC)
@@ -479,6 +483,9 @@ void notify_tx_power_report(struct bt_conn *conn,
479483
void notify_path_loss_threshold_report(struct bt_conn *conn,
480484
struct bt_conn_le_path_loss_threshold_report report);
481485

486+
void notify_subrate_change(struct bt_conn *conn,
487+
struct bt_conn_le_subrate_changed params);
488+
482489
#if defined(CONFIG_BT_SMP)
483490
/* If role specific LTK is present */
484491
bool bt_conn_ltk_present(const struct bt_conn *conn);

0 commit comments

Comments
 (0)