mirror of
https://github.com/espressif/esp-idf.git
synced 2026-01-15 10:15:32 +00:00
Merge branch 'fix/ble_mesh_blob_issue_fix' into 'master'
fix(ble_mesh): Miscellaneous fixes for blob Closes BLERP-2503 See merge request espressif/esp-idf!44663
This commit is contained in:
@@ -73,7 +73,8 @@ esp_err_t esp_ble_mesh_dfu_cli_img_send(esp_ble_mesh_dfu_cli_t *cli,
|
||||
arg.send_arg.xfer = xfer;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfu_client_args_t),
|
||||
NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
btc_ble_mesh_dfu_client_arg_deep_copy,
|
||||
btc_ble_mesh_dfu_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
uint8_t esp_ble_mesh_dfu_cli_progress(esp_ble_mesh_dfu_cli_t *cli)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -81,6 +81,11 @@ void btc_ble_mesh_dfu_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND:
|
||||
/* That will be freed when dfu completed or failed not on btc deep free */
|
||||
dst->send_arg.inputs =(struct esp_ble_mesh_blob_cli_inputs *)
|
||||
dfu_targets_alloc((struct bt_mesh_blob_cli_inputs *)src->send_arg.inputs);
|
||||
break;
|
||||
default:
|
||||
BT_DBG("%s, Unknown act %d", __func__, msg->act);
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA
|
||||
* SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileContributor: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -64,6 +64,83 @@ static struct {
|
||||
sys_slist_t list;
|
||||
} dfu_req_list;
|
||||
|
||||
static struct bt_mesh_blob_cli_inputs cur_targets = {0};
|
||||
|
||||
/**
|
||||
* inputs list must point to a list of bt_mesh_dfu_target nodes.
|
||||
* That was required by dfu api
|
||||
*/
|
||||
void dfu_targets_free(void)
|
||||
{
|
||||
sys_snode_t *n, *sn;
|
||||
struct bt_mesh_dfu_target *target;
|
||||
struct bt_mesh_blob_cli_inputs *inputs = &cur_targets;
|
||||
|
||||
if (cur_targets.targets.head == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
SYS_SLIST_FOR_EACH_NODE_SAFE(&inputs->targets, n, sn) {
|
||||
target = (struct bt_mesh_dfu_target *)n;
|
||||
if (target->blob.pull) {
|
||||
bt_mesh_free(target->blob.pull);
|
||||
}
|
||||
bt_mesh_free(target);
|
||||
}
|
||||
|
||||
inputs->app_idx = 0;
|
||||
inputs->group = 0;
|
||||
inputs->ttl = 0;
|
||||
inputs->timeout_base = 0;
|
||||
|
||||
sys_slist_init(&inputs->targets);
|
||||
}
|
||||
|
||||
struct bt_mesh_blob_cli_inputs *dfu_targets_alloc(struct bt_mesh_blob_cli_inputs *src)
|
||||
{
|
||||
sys_snode_t *node;
|
||||
struct bt_mesh_dfu_target *target_src = NULL;
|
||||
struct bt_mesh_dfu_target *target_dst = NULL;
|
||||
struct bt_mesh_blob_cli_inputs *dst = &cur_targets;
|
||||
|
||||
if (cur_targets.targets.head != NULL ||
|
||||
cur_targets.targets.tail != NULL) {
|
||||
BT_WARN("DFU targets busy");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dst->app_idx = src->app_idx;
|
||||
dst->group = src->group;
|
||||
dst->ttl = src->ttl;
|
||||
dst->timeout_base = src->timeout_base;
|
||||
|
||||
sys_slist_init(&dst->targets);
|
||||
|
||||
SYS_SLIST_FOR_EACH_NODE(&src->targets, node) {
|
||||
target_src = (struct bt_mesh_dfu_target *)node;
|
||||
target_dst = bt_mesh_calloc(sizeof(struct bt_mesh_dfu_target));
|
||||
if (!target_dst) {
|
||||
dfu_targets_free();
|
||||
return NULL;
|
||||
}
|
||||
memcpy(target_dst, target_src, sizeof(struct bt_mesh_dfu_target));
|
||||
if (target_dst->blob.pull) {
|
||||
target_dst->blob.pull = bt_mesh_calloc(sizeof(struct bt_mesh_blob_target_pull));
|
||||
if (!target_dst->blob.pull) {
|
||||
dfu_targets_free();
|
||||
return NULL;
|
||||
}
|
||||
memcpy(target_dst->blob.pull, target_src->blob.pull, sizeof(struct bt_mesh_blob_target_pull));
|
||||
} else {
|
||||
target_dst->blob.pull = NULL;
|
||||
}
|
||||
target_dst->blob.n.next = NULL;
|
||||
sys_slist_append(&dst->targets, &target_dst->blob.n);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfu_cli *cli,
|
||||
uint16_t addr)
|
||||
{
|
||||
@@ -277,6 +354,8 @@ static void dfu_failed(struct bt_mesh_dfu_cli *cli,
|
||||
if (cli->cb && cli->cb->ended) {
|
||||
cli->cb->ended(cli, reason);
|
||||
}
|
||||
|
||||
dfu_targets_free();
|
||||
}
|
||||
|
||||
static int req_setup(struct bt_mesh_dfu_cli *cli, enum req type,
|
||||
@@ -341,8 +420,21 @@ static void blob_caps(struct bt_mesh_blob_cli *b,
|
||||
}
|
||||
|
||||
cli->xfer.blob.block_size_log = caps->max_block_size_log;
|
||||
#if CONFIG_BLE_MESH_LONG_PACKET
|
||||
if (cli->xfer.blob.chunk_enh_params.long_pkt_cfg_used) {
|
||||
cli->xfer.blob.chunk_size = MIN(caps->max_chunk_size, BLOB_TX_CHUNK_SIZE);
|
||||
} else {
|
||||
#if CONFIG_BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \
|
||||
CONFIG_BLE_MESH_TX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BLE_MESH_EXT_TX_SDU_MAX)
|
||||
cli->xfer.blob.chunk_size = MIN(caps->max_chunk_size, BLOB_CHUNK_SIZE_MAX(BLE_MESH_TX_SDU_MAX));
|
||||
#else
|
||||
cli->xfer.blob.chunk_size = MIN(caps->max_chunk_size,
|
||||
CONFIG_BLE_MESH_TX_BLOB_CHUNK_SIZE);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
cli->xfer.blob.chunk_size = caps->max_chunk_size;
|
||||
|
||||
#endif
|
||||
/* If mode is not already set and server reported it supports all modes
|
||||
* default to PUSH, otherwise set value reported by server. If mode
|
||||
* was set and server supports all modes, keep old value; set
|
||||
@@ -826,6 +918,7 @@ static void confirmed(struct bt_mesh_blob_cli *b)
|
||||
if (cli->cb && cli->cb->confirmed) {
|
||||
cli->cb->confirmed(cli);
|
||||
}
|
||||
dfu_targets_free();
|
||||
} else {
|
||||
dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL);
|
||||
}
|
||||
@@ -887,15 +980,16 @@ static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx
|
||||
rsp->timeout_base = net_buf_simple_pull_le16(buf);
|
||||
rsp->blob_id = net_buf_simple_pull_le64(buf);
|
||||
rsp->img_idx = net_buf_simple_pull_u8(buf);
|
||||
} else if (buf->len) {
|
||||
} else if (buf->len == 0) {
|
||||
rsp->ttl = 0U;
|
||||
rsp->effect = BLE_MESH_DFU_EFFECT_NONE;
|
||||
rsp->timeout_base = 0U;
|
||||
rsp->blob_id = 0U;
|
||||
rsp->img_idx = 0U;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rsp->ttl = 0U;
|
||||
rsp->effect = BLE_MESH_DFU_EFFECT_NONE;
|
||||
rsp->timeout_base = 0U;
|
||||
rsp->blob_id = 0U;
|
||||
rsp->img_idx = 0U;
|
||||
}
|
||||
bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP,
|
||||
req->dfu_cli->mod, &req->ctx, req->params,
|
||||
@@ -904,6 +998,7 @@ static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx
|
||||
bt_mesh_dfu_cli_rm_req_from_list(req);
|
||||
k_delayed_work_cancel(&req->timer);
|
||||
req_free(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cli->op != BLE_MESH_DFU_OP_UPDATE_STATUS) {
|
||||
@@ -965,6 +1060,17 @@ static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx
|
||||
if (phase != BLE_MESH_DFU_PHASE_APPLYING &&
|
||||
(target->effect == BLE_MESH_DFU_EFFECT_UNPROV ||
|
||||
phase != BLE_MESH_DFU_PHASE_IDLE)) {
|
||||
/**
|
||||
* If user quickly enter the APPLY state from REFRESH,
|
||||
* protocol may receive the last round of REFRESH info
|
||||
* packets from the network. Therefore, in order to avoid
|
||||
* misjudgment, the previous round of data packets are
|
||||
* ignored here.
|
||||
*/
|
||||
if (phase == BLE_MESH_DFU_PHASE_VERIFY_OK) {
|
||||
BT_DBG("MaybeReceivedOutdatedMsg");
|
||||
return 0;
|
||||
}
|
||||
BT_WARN("Target 0x%04x in phase %u after apply",
|
||||
target->blob.addr, phase);
|
||||
target_failed(cli, target, BLE_MESH_DFU_ERR_WRONG_PHASE);
|
||||
@@ -1187,6 +1293,12 @@ static void dfu_cli_reset(struct bt_mesh_model *mod)
|
||||
{
|
||||
struct bt_mesh_dfu_cli *cli = mod->user_data;
|
||||
|
||||
if (cli->xfer.state == STATE_IDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
dfu_targets_free();
|
||||
|
||||
bt_mesh_dfu_req_list_free();
|
||||
cli->req = NULL;
|
||||
cli->xfer.state = STATE_IDLE;
|
||||
|
||||
@@ -530,8 +530,13 @@ static void blob_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success)
|
||||
BT_DBG("success: %u", success);
|
||||
|
||||
if (!success) {
|
||||
srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR;
|
||||
/**
|
||||
* Changed by Espressif,
|
||||
* The xfer_failed must be executed before updating the state;
|
||||
* otherwise, the end_cb inside xfer_failed will never be delivered.
|
||||
*/
|
||||
xfer_failed(srv);
|
||||
srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,6 +261,9 @@ struct bt_mesh_dfu_cli_xfer {
|
||||
const struct bt_mesh_dfu_cli_xfer_blob_params *blob_params;
|
||||
};
|
||||
|
||||
void dfu_targets_free(void);
|
||||
struct bt_mesh_blob_cli_inputs *dfu_targets_alloc(struct bt_mesh_blob_cli_inputs *src);
|
||||
|
||||
/** @brief Start distributing a DFU.
|
||||
*
|
||||
* Starts distribution of the firmware in the given slot to the list of DFU
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA
|
||||
* SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileContributor: 2025-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -53,6 +53,7 @@ _Static_assert((BLOB_BLOCK_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLO
|
||||
|
||||
NET_BUF_SIMPLE_DEFINE_STATIC(chunk_buf, BLOB_CHUNK_SDU_LEN(CHUNK_SIZE_MAX));
|
||||
static bool chunk_sending;
|
||||
static bool last_chunk_sent;
|
||||
|
||||
struct block_status {
|
||||
enum bt_mesh_blob_status status;
|
||||
@@ -568,7 +569,8 @@ void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli,
|
||||
|
||||
void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli)
|
||||
{
|
||||
if (!cli->tx.ctx.is_inited) {
|
||||
if (!cli->tx.ctx.is_inited &&
|
||||
cli->state != BT_MESH_BLOB_CLI_STATE_SUSPENDED) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -656,8 +658,11 @@ static void xfer_start_tx(struct bt_mesh_blob_cli *cli, uint16_t dst)
|
||||
net_buf_simple_add_le32(&buf, cli->xfer->size);
|
||||
net_buf_simple_add_u8(&buf, cli->xfer->block_size_log);
|
||||
#if CONFIG_BLE_MESH_LONG_PACKET
|
||||
/* todo: could let user select methold */
|
||||
net_buf_simple_add_le16(&buf, BLE_MESH_EXT_TX_SDU_MAX);
|
||||
if (cli->xfer->chunk_enh_params.long_pkt_cfg_used) {
|
||||
net_buf_simple_add_le16(&buf, BLE_MESH_EXT_TX_SDU_MAX);
|
||||
} else {
|
||||
net_buf_simple_add_le16(&buf, BLE_MESH_TX_SDU_MAX);
|
||||
}
|
||||
#else
|
||||
net_buf_simple_add_le16(&buf, BLE_MESH_TX_SDU_MAX);
|
||||
#endif
|
||||
@@ -708,6 +713,13 @@ static void chunk_tx(struct bt_mesh_blob_cli *cli, uint16_t dst)
|
||||
chunk.offset = cli->xfer->chunk_size * cli->chunk_idx;
|
||||
chunk.data = net_buf_simple_add(&chunk_buf, chunk.size);
|
||||
|
||||
if ((cli->block.number == cli->block_count - 1) &&
|
||||
(cli->chunk_idx < cli->block.chunk_count)) {
|
||||
last_chunk_sent = true;
|
||||
} else {
|
||||
last_chunk_sent = false;
|
||||
}
|
||||
|
||||
err = cli->io->rd(cli->io, cli->xfer, &cli->block, &chunk);
|
||||
if (err || cli->state == BT_MESH_BLOB_CLI_STATE_NONE) {
|
||||
bt_mesh_blob_cli_cancel(cli);
|
||||
@@ -1616,6 +1628,16 @@ int bt_mesh_blob_cli_suspend(struct bt_mesh_blob_cli *cli)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* After the last chunk data is sent, if the server
|
||||
* successfully receives the chunk, it will be in the
|
||||
* complete state. At this time, if the client resumes
|
||||
* from suspend and restarts the transmission, an error
|
||||
* will occur, resulting in lost target */
|
||||
if (last_chunk_sent) {
|
||||
BT_WARN("About to end, refuse to suspend");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED;
|
||||
(void)k_work_cancel_delayable(&cli->tx.retry);
|
||||
cli->tx.ctx.is_inited = 0;
|
||||
|
||||
@@ -751,6 +751,11 @@ static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
|
||||
chunk.data = net_buf_simple_pull_mem(buf, chunk.size);
|
||||
chunk.offset = idx * srv->state.xfer.chunk_size;
|
||||
|
||||
if (!bt_mesh_blob_srv_is_busy(srv)) {
|
||||
BT_ERR("Discord chunk(%d), because the blob server is not busy(%d)", idx, srv->phase);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK ||
|
||||
srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) {
|
||||
// This Block is already complete received.
|
||||
@@ -777,9 +782,7 @@ static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
|
||||
|
||||
if (idx == srv->block.chunk_count - 1) {
|
||||
expected_size = srv->block.size % srv->state.xfer.chunk_size;
|
||||
}
|
||||
|
||||
if (expected_size == 0) {
|
||||
} else {
|
||||
expected_size = srv->state.xfer.chunk_size;
|
||||
}
|
||||
|
||||
@@ -804,7 +807,11 @@ static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
|
||||
* complete.
|
||||
*/
|
||||
if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) {
|
||||
phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK);
|
||||
if(missing_chunks(&srv->block)) {
|
||||
phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK);
|
||||
} else {
|
||||
phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
BT_INFO("%u/%u (%u bytes)", idx + 1, srv->block.chunk_count,
|
||||
|
||||
Reference in New Issue
Block a user