mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
Merge branch 'idf/ble_audio_mcc_fixes_v6.1' into 'release/v6.1'
fix(ble_audio): Fix mcc read may enter BUSY state while multiple notifications are received (v6.1) See merge request espressif/esp-idf!49776
This commit is contained in:
@@ -182,7 +182,7 @@ static const uint16_t ext_structs[] = {
|
||||
sizeof(struct bt_bond_info),
|
||||
};
|
||||
|
||||
#define LEA_VERSION (0x20260514)
|
||||
#define LEA_VERSION (0x20260616)
|
||||
|
||||
struct lib_ext_cfgs {
|
||||
/* BLE */
|
||||
@@ -2087,8 +2087,11 @@ int bt_le_audio_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
printf(BT_ISO_LOG_COLOR_I "BLE Audio lib commit: [%s]" \
|
||||
BT_ISO_LOG_RESET_COLOR "\n", lib_ext_commit_get());
|
||||
esp_log_write(ESP_LOG_INFO, LEA_TAG,
|
||||
BT_ISO_LOG_COLOR_I
|
||||
"I (%lu) %s: BLE Audio lib commit: [%s]"
|
||||
BT_ISO_LOG_RESET_COLOR "\n",
|
||||
esp_log_timestamp(), LEA_TAG, lib_ext_commit_get());
|
||||
|
||||
err = lib_resources_init();
|
||||
if (err) {
|
||||
|
||||
Submodule components/bt/esp_ble_audio/lib/lib updated: b9355d1a1c...77cf36bd77
@@ -78,7 +78,10 @@ struct gattc_list_node {
|
||||
sys_snode_t node;
|
||||
uint8_t type;
|
||||
union {
|
||||
struct bt_gatt_read_params *read_params;
|
||||
struct {
|
||||
struct bt_gatt_read_params *params;
|
||||
struct bt_gatt_read_params params_copy;
|
||||
} read;
|
||||
struct bt_gatt_write_params *write_params;
|
||||
};
|
||||
};
|
||||
@@ -93,9 +96,13 @@ static struct gattc_list_node *gattc_list_node_alloc(uint8_t type, void *params)
|
||||
}
|
||||
|
||||
op->type = type;
|
||||
/* Both arms of the union are pointer-typed and same size — assigning via
|
||||
* either field is equivalent. */
|
||||
op->read_params = params;
|
||||
|
||||
if (type == GATTC_OP_READ) {
|
||||
op->read.params_copy = *(struct bt_gatt_read_params *)params;
|
||||
op->read.params = params;
|
||||
} else {
|
||||
op->write_params = params;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
@@ -1503,6 +1510,7 @@ static void handle_gattc_disc_cmpl_event(struct bt_le_gattc_disc_cmpl_event *eve
|
||||
|
||||
static void handle_gattc_read_chrc_event(struct bt_le_gattc_read_chrc_event *event)
|
||||
{
|
||||
struct bt_gatt_read_params read_copy;
|
||||
struct bt_gatt_read_params *params;
|
||||
struct gatt_conn *gatt_conn;
|
||||
struct gattc_list_node *op;
|
||||
@@ -1542,47 +1550,42 @@ static void handle_gattc_read_chrc_event(struct bt_le_gattc_read_chrc_event *eve
|
||||
goto end;
|
||||
}
|
||||
|
||||
params = op->read_params;
|
||||
params = op->read.params;
|
||||
read_copy = op->read.params_copy;
|
||||
free(op);
|
||||
|
||||
if (params == NULL || params->func == NULL) {
|
||||
if (read_copy.func == NULL) {
|
||||
LOG_ERR("[B]GattcRdCharNoFunc");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((params->handle_count == 0 && (event->attr_handle < params->by_uuid.start_handle ||
|
||||
event->attr_handle > params->by_uuid.end_handle)) ||
|
||||
(params->handle_count == 1 && event->attr_handle != params->single.handle)) {
|
||||
if ((read_copy.handle_count == 0 &&
|
||||
(event->attr_handle < read_copy.by_uuid.start_handle ||
|
||||
event->attr_handle > read_copy.by_uuid.end_handle)) ||
|
||||
(read_copy.handle_count == 1 &&
|
||||
event->attr_handle != read_copy.single.handle)) {
|
||||
LOG_ERR("[B]GattcRdCharInvRsp[%u][%u][%u][%u][%u]",
|
||||
params->handle_count, event->attr_handle, params->by_uuid.start_handle,
|
||||
params->by_uuid.end_handle, params->single.handle);
|
||||
/* BTA fires READ_CHAR_EVT exactly once per read; the op was just
|
||||
* popped above so no further EVT will arrive. Fire func with err
|
||||
* so caller's state machine doesn't stall waiting forever. */
|
||||
params->func(conn, BT_ATT_ERR_UNLIKELY, params, NULL, 0);
|
||||
read_copy.handle_count, event->attr_handle,
|
||||
read_copy.by_uuid.start_handle,
|
||||
read_copy.by_uuid.end_handle, read_copy.single.handle);
|
||||
read_copy.func(conn, BT_ATT_ERR_UNLIKELY, params, NULL, 0);
|
||||
goto end;
|
||||
}
|
||||
|
||||
val = event->value;
|
||||
vlen = event->len;
|
||||
|
||||
/* Long read: BTA's auto Read-Blob already fetched the full value on the
|
||||
* BTU task; hand the caller only the requested [offset:] tail. */
|
||||
if (params->handle_count == 1 && params->single.offset != 0 && event->status == 0) {
|
||||
off = params->single.offset;
|
||||
if (read_copy.handle_count == 1 && read_copy.single.offset != 0 &&
|
||||
event->status == 0) {
|
||||
off = read_copy.single.offset;
|
||||
val = (off < event->len) ? event->value + off : NULL;
|
||||
vlen = (off < event->len) ? (event->len - off) : 0;
|
||||
}
|
||||
|
||||
ret = params->func(conn, event->status, params, val, vlen);
|
||||
ret = read_copy.func(conn, event->status, params, val, vlen);
|
||||
|
||||
/* (0, NULL, 0) is the success-completion signal per bt_gatt_read_func_t.
|
||||
* Skip it on error paths — the error call above is already terminal;
|
||||
* sending a follow-up "success" would let lib treat the read as OK and
|
||||
* keep stale data. Mirrors NimBLE nrp.c, which fires func(err, NULL, 0)
|
||||
* once on the default branch and never the success-completion. */
|
||||
if (ret == BT_GATT_ITER_CONTINUE && event->status == 0) {
|
||||
params->func(conn, 0, params, NULL, 0);
|
||||
read_copy.func(conn, 0, params, NULL, 0);
|
||||
}
|
||||
|
||||
end:
|
||||
@@ -2898,25 +2901,23 @@ int bt_le_bluedroid_gattc_read(struct bt_conn *conn, struct bt_gatt_read_params
|
||||
|
||||
conn_id = BTC_GATT_CREATE_CONN_ID(gattc_if, conn->handle);
|
||||
|
||||
if (params->handle_count == 0) {
|
||||
LOG_INF("[B]RdByTypeReq[0x%04x]", BT_UUID_16(params->by_uuid.uuid)->val);
|
||||
if (op->read.params_copy.handle_count == 0) {
|
||||
LOG_INF("[B]RdByTypeReq[0x%04x]",
|
||||
BT_UUID_16(op->read.params_copy.by_uuid.uuid)->val);
|
||||
|
||||
bt_le_bluedroid_gatt_uuid_convert(params->by_uuid.uuid, &uuid);
|
||||
bt_le_bluedroid_gatt_uuid_convert(op->read.params_copy.by_uuid.uuid, &uuid);
|
||||
|
||||
BTA_GATTC_Read_by_type(conn_id, params->by_uuid.start_handle,
|
||||
params->by_uuid.end_handle, &uuid,
|
||||
BTA_GATTC_Read_by_type(conn_id,
|
||||
op->read.params_copy.by_uuid.start_handle,
|
||||
op->read.params_copy.by_uuid.end_handle, &uuid,
|
||||
BTA_GATT_AUTH_REQ_NONE);
|
||||
} else {
|
||||
LOG_INF("[B]RdReq[%u][%u]", params->single.handle, params->single.offset);
|
||||
LOG_INF("[B]RdReq[%u][%u]",
|
||||
op->read.params_copy.single.handle,
|
||||
op->read.params_copy.single.offset);
|
||||
|
||||
/* A non-zero offset is a long read: the lib re-reads the remainder of
|
||||
* an ASE/BASS value whose notification was MTU-truncated. BTA's
|
||||
* ReadLongChar would run GATTC_Read inline on the ISO task, racing the
|
||||
* BTU task that owns gatt_cb. Always issue ReadCharacteristic instead
|
||||
* (GATT_READ_BY_HANDLE) — BTA auto-continues it with Read Blob on the
|
||||
* BTU task to fetch the full value, and handle_gattc_read_chrc_event
|
||||
* slices the requested [offset:] tail back to the caller. */
|
||||
BTA_GATTC_ReadCharacteristic(conn_id, params->single.handle,
|
||||
BTA_GATTC_ReadCharacteristic(conn_id,
|
||||
op->read.params_copy.single.handle,
|
||||
BTA_GATT_AUTH_REQ_NONE);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ struct gatt_nrp_node {
|
||||
} read_long;
|
||||
|
||||
struct {
|
||||
struct bt_gatt_read_params params_copy;
|
||||
struct bt_gatt_read_params *params;
|
||||
} read_single;
|
||||
|
||||
@@ -271,15 +272,20 @@ static int gattc_nrp_read_single_cb_safe(uint16_t conn_handle,
|
||||
struct ble_gatt_attr *attr,
|
||||
void *arg)
|
||||
{
|
||||
struct bt_gatt_read_params *read_params;
|
||||
struct bt_gatt_read_params *params_copy = arg;
|
||||
struct bt_gatt_read_params *original;
|
||||
struct gatt_nrp_node *nrp_node;
|
||||
bt_gatt_read_func_t func;
|
||||
struct bt_conn *conn;
|
||||
int rc = 0;
|
||||
|
||||
read_params = arg;
|
||||
assert(read_params);
|
||||
assert(read_params->func);
|
||||
assert(read_params->handle_count == 1);
|
||||
assert(read_params->single.offset == 0);
|
||||
nrp_node = CONTAINER_OF(params_copy, struct gatt_nrp_node, read_single.params_copy);
|
||||
original = nrp_node->read_single.params;
|
||||
func = params_copy->func;
|
||||
|
||||
assert(func);
|
||||
assert(params_copy->handle_count == 1);
|
||||
assert(params_copy->single.offset == 0);
|
||||
|
||||
LOG_DBG("[N]GattcNrpRdSingleCb[%u][%04x]", conn_handle, error->status);
|
||||
|
||||
@@ -292,8 +298,8 @@ static int gattc_nrp_read_single_cb_safe(uint16_t conn_handle,
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Shall be invoked before the read_params->func is invoked */
|
||||
bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_SINGLE, read_params, 0);
|
||||
/* Frees nrp_node (and params_copy); func and original are locals. */
|
||||
bt_le_nimble_gatt_nrp_remove(conn, GATTC_NRP_READ_SINGLE, original, 0);
|
||||
|
||||
switch (error->status) {
|
||||
case 0:
|
||||
@@ -301,27 +307,24 @@ static int gattc_nrp_read_single_cb_safe(uint16_t conn_handle,
|
||||
assert(attr->om);
|
||||
|
||||
LOG_DBG("[N]GattcNrpHdl[%u][%u]Len[%u]",
|
||||
attr->handle, read_params->single.handle, attr->om->om_len);
|
||||
attr->handle, original->single.handle, attr->om->om_len);
|
||||
|
||||
if (read_params->func(conn, 0, read_params,
|
||||
attr->om->om_data,
|
||||
attr->om->om_len) == BT_GATT_ITER_CONTINUE) {
|
||||
/* Workaround for completing the handling of ATT Read Response
|
||||
* by BAP Unicast Client.
|
||||
*/
|
||||
read_params->func(conn, 0, read_params, NULL, 0);
|
||||
if (func(conn, 0, original,
|
||||
attr->om->om_data,
|
||||
attr->om->om_len) == BT_GATT_ITER_CONTINUE) {
|
||||
func(conn, 0, original, NULL, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case BLE_HS_EDONE:
|
||||
read_params->func(conn, 0, read_params, NULL, 0);
|
||||
func(conn, 0, original, NULL, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_WRN("[N]GattcNrpStatus[%04x]", error->status);
|
||||
|
||||
if (error->status & BLE_HS_ERR_ATT_BASE) {
|
||||
read_params->func(conn, (uint8_t)error->status, read_params, NULL, 0);
|
||||
func(conn, (uint8_t)error->status, original, NULL, 0);
|
||||
}
|
||||
|
||||
rc = error->status;
|
||||
@@ -736,6 +739,7 @@ static int gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params)
|
||||
nrp_node->read_long.params = params;
|
||||
break;
|
||||
case GATTC_NRP_READ_SINGLE:
|
||||
nrp_node->read_single.params_copy = *(struct bt_gatt_read_params *)params;
|
||||
nrp_node->read_single.params = params;
|
||||
break;
|
||||
case GATTC_NRP_WRITE_REQ: {
|
||||
@@ -784,9 +788,10 @@ static int gatt_nrp_insert(struct bt_conn *conn, uint8_t type, void *params)
|
||||
LOG_DBG("[N]GattNrpListEmpty");
|
||||
|
||||
if (type == GATTC_NRP_READ_BY_UUID ||
|
||||
type == GATTC_NRP_READ_LONG ||
|
||||
type == GATTC_NRP_READ_SINGLE) {
|
||||
type == GATTC_NRP_READ_LONG) {
|
||||
rc = gattc_nrp_read(conn, params);
|
||||
} else if (type == GATTC_NRP_READ_SINGLE) {
|
||||
rc = gattc_nrp_read(conn, &nrp_node->read_single.params_copy);
|
||||
} else if (type == GATTC_NRP_WRITE_REQ) {
|
||||
rc = gattc_nrp_write(conn, params,
|
||||
nrp_node->write_req.data_copy,
|
||||
@@ -957,12 +962,13 @@ int bt_le_nimble_gatt_nrp_remove(struct bt_conn *conn, uint8_t type, void *param
|
||||
nrp_head->read_long.params->func(conn, rc, nrp_head->read_long.params, NULL, 0);
|
||||
}
|
||||
} else if (nrp_head->type == GATTC_NRP_READ_SINGLE) {
|
||||
rc = gattc_nrp_read(conn, nrp_head->read_single.params);
|
||||
rc = gattc_nrp_read(conn, &nrp_head->read_single.params_copy);
|
||||
if (rc) {
|
||||
LOG_ERR("[N]GattcNrpRdSingleFail[%d]", rc);
|
||||
|
||||
assert(nrp_head->read_single.params->func);
|
||||
nrp_head->read_single.params->func(conn, rc, nrp_head->read_single.params, NULL, 0);
|
||||
assert(nrp_head->read_single.params_copy.func);
|
||||
nrp_head->read_single.params_copy.func(conn, rc,
|
||||
nrp_head->read_single.params, NULL, 0);
|
||||
}
|
||||
} else if (nrp_head->type == GATTC_NRP_WRITE_REQ) {
|
||||
rc = gattc_nrp_write(conn, nrp_head->write_req.params,
|
||||
|
||||
Reference in New Issue
Block a user