Files
esp-idf/components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c
T
2025-12-26 11:56:40 +08:00

700 lines
23 KiB
C

/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "dfu_slot.h"
#include "dfu.h"
#include "net.h"
#include "transport.h"
#include "mesh_v1.1/dfu/dfd.h"
#include "mesh_v1.1/dfu/dfu_cli.h"
#include "mesh_v1.1/mbt/blob_srv.h"
#include "btc_ble_mesh_dfu_model.h"
#include "mesh_v1.1/dfu/dfd_cli.h"
#if CONFIG_BLE_MESH_DFD_CLI
static const bt_mesh_client_op_pair_t dfd_cli_pair[] = {
{BLE_MESH_DFD_OP_RECEIVERS_ADD, BLE_MESH_DFD_OP_RECEIVERS_STATUS},
{BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, BLE_MESH_DFD_OP_RECEIVERS_STATUS},
{BLE_MESH_DFD_OP_RECEIVERS_GET, BLE_MESH_DFD_OP_RECEIVERS_LIST},
{BLE_MESH_DFD_OP_CAPABILITIES_GET, BLE_MESH_DFD_OP_CAPABILITIES_STATUS},
{BLE_MESH_DFD_OP_GET, BLE_MESH_DFD_OP_STATUS},
{BLE_MESH_DFD_OP_START, BLE_MESH_DFD_OP_STATUS},
{BLE_MESH_DFD_OP_SUSPEND, BLE_MESH_DFD_OP_STATUS},
{BLE_MESH_DFD_OP_CANCEL, BLE_MESH_DFD_OP_STATUS},
{BLE_MESH_DFD_OP_APPLY, BLE_MESH_DFD_OP_STATUS},
{BLE_MESH_DFD_OP_UPLOAD_GET, BLE_MESH_DFD_OP_UPLOAD_STATUS},
{BLE_MESH_DFD_OP_UPLOAD_START, BLE_MESH_DFD_OP_UPLOAD_STATUS},
{BLE_MESH_DFD_OP_UPLOAD_START_OOB, BLE_MESH_DFD_OP_UPLOAD_STATUS},
{BLE_MESH_DFD_OP_UPLOAD_CANCEL, BLE_MESH_DFD_OP_UPLOAD_STATUS},
{BLE_MESH_DFD_OP_FW_GET, BLE_MESH_DFD_OP_FW_STATUS},
{BLE_MESH_DFD_OP_FW_GET_BY_INDEX, BLE_MESH_DFD_OP_FW_STATUS},
{BLE_MESH_DFD_OP_FW_DELETE, BLE_MESH_DFD_OP_FW_STATUS},
{BLE_MESH_DFD_OP_FW_DELETE_ALL, BLE_MESH_DFD_OP_FW_STATUS},
};
static bt_mesh_mutex_t dfd_client_lock;
static void timeout_handler(struct k_work *work)
{
struct k_delayed_work *timer = NULL;
bt_mesh_client_node_t *node = NULL;
BT_WARN("DFDRspTmo");
bt_mesh_mutex_lock(&dfd_client_lock);
timer = CONTAINER_OF(work, struct k_delayed_work, work);
if (timer && !k_delayed_work_free(timer)) {
node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work);
if (node) {
bt_mesh_dfd_client_cb_evt_to_btc(BTC_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT, node->model, &node->ctx, NULL, 0);
bt_mesh_client_free_node(node);
}
}
bt_mesh_mutex_unlock(&dfd_client_lock);
return;
}
static void dfd_client_recv_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
void *status, size_t len)
{
bt_mesh_client_node_t *node = NULL;
struct net_buf_simple buf = {0};
btc_ble_mesh_dfd_client_cb_evt_t evt = 0;
if (!model || !ctx) {
BT_ERR("%s,InvParam", __func__);
return;
}
buf.data = (uint8_t *)status;
buf.len = (uint16_t)len;
bt_mesh_mutex_lock(&dfd_client_lock);
node = bt_mesh_is_client_recv_publish_msg(model, ctx, &buf, true);
if (!node) {
BT_DBG("UnexpDfdStus:0x%04x", ctx->recv_op);
} else {
switch (ctx->recv_op) {
case BLE_MESH_DFD_OP_RECEIVERS_STATUS:
case BLE_MESH_DFD_OP_CAPABILITIES_GET:
case BLE_MESH_DFD_OP_RECEIVERS_LIST:
case BLE_MESH_DFD_OP_CAPABILITIES_STATUS:
case BLE_MESH_DFD_OP_STATUS:
case BLE_MESH_DFD_OP_UPLOAD_STATUS:
case BLE_MESH_DFD_OP_FW_STATUS:
evt = BTC_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP;
break;
default:
BT_ERR("UnkwnOpc:%04x", node->opcode);
break;
}
if (!k_delayed_work_free(&node->timer)) {
bt_mesh_dfd_client_cb_evt_to_btc(evt, model, ctx, (const uint8_t *)status, len);
bt_mesh_client_free_node(node);
}
}
bt_mesh_mutex_unlock(&dfd_client_lock);
}
static void handle_receiver_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
dfd_status_t status = {0};
status.receiver_status.status = net_buf_simple_pull_u8(buf);
if (status.receiver_status.status > BLE_MESH_DFD_ERR_SUSPEND_FAILED) {
BT_ERR("InvSrvStu:%d", status.receiver_status.status);
return;
}
if (status.receiver_status.status != BLE_MESH_DFD_SUCCESS) {
BT_ERR("StusErr:%d", status);
return;
}
status.receiver_status.receiver_list_cnt = net_buf_simple_pull_le16(buf);
BT_DBG("RecvLstCnt:%d", status.receiver_status.receiver_list_cnt);
dfd_client_recv_status(model, ctx, &status, sizeof(status.receiver_status));
}
static void handle_receiver_list(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
int i = 0;
uint32_t target_info = 0;
dfd_status_t status = {0};
status.receiver_list.entries_cnt = net_buf_simple_pull_le16(buf);
status.receiver_list.first_index = net_buf_simple_pull_le16(buf);
status.receiver_list.entries = bt_mesh_calloc(status.receiver_list.entries_cnt * sizeof(target_node_entry_t));
for (i = 0; i < status.receiver_list.entries_cnt; i++) {
target_info = net_buf_simple_pull_le32(buf);
status.receiver_list.entries[i].addr = TARGET_ADDR(target_info);
status.receiver_list.entries[i].retrieved_update_phase = TARGET_UPDATE_PHASE(target_info);
status.receiver_list.entries[i].update_status = TARGET_UPDATE_STATUS(target_info);
status.receiver_list.entries[i].transfer_status = TARGET_TRANSFER_STATUS(target_info);
status.receiver_list.entries[i].transfer_progress = TARGET_TRANSFER_PROGRESS(target_info);
status.receiver_list.entries[i].update_fw_idx = net_buf_simple_pull_u8(buf);
}
dfd_client_recv_status(model, ctx, &status, sizeof(status.receiver_list));
bt_mesh_free(status.receiver_list.entries);
return;
}
static void handle_capabilities(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
dfd_status_t status = {0};
struct net_buf_simple url_scheme_names = {0};
status.dist_caps.max_receiver_list_sz = net_buf_simple_pull_le16(buf);
status.dist_caps.max_fw_list_sz = net_buf_simple_pull_le16(buf);
status.dist_caps.max_fw_sz = net_buf_simple_pull_le32(buf);
status.dist_caps.max_upload_space = net_buf_simple_pull_le32(buf);
status.dist_caps.remaining_upload_space = net_buf_simple_pull_le32(buf);
status.dist_caps.oob_retrieval_supported = net_buf_simple_pull_le32(buf);
if (buf->len) {
status.dist_caps.supported_url_scheme_names = &url_scheme_names;
net_buf_simple_init_with_data(status.dist_caps.supported_url_scheme_names, buf->data, buf->len);
net_buf_simple_pull_mem(buf, buf->len);
}
dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_caps));
return;
}
static void handle_dfd_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
dfd_status_t status = {0};
uint8_t trans_mode_policy = 0;
status.dist_status.status = net_buf_simple_pull_u8(buf);
status.dist_status.dist_phase = net_buf_simple_pull_u8(buf);
if (buf->len != 0 && buf->len != 10) {
BT_ERR("Invalid data");
return;
}
status.dist_status.multicast_address = net_buf_simple_pull_le16(buf);
status.dist_status.appkey_idx = net_buf_simple_pull_le16(buf);
status.dist_status.ttl = net_buf_simple_pull_u8(buf);
status.dist_status.timeout_base = net_buf_simple_pull_le16(buf);
trans_mode_policy = net_buf_simple_pull_u8(buf);
if ((trans_mode_policy & ~(BIT6 - 1)) != 0) {
BT_ERR("RFU should be zero");
return;
}
status.dist_status.trans_mode = trans_mode_policy >> 6;
status.dist_status.update_policy = (trans_mode_policy >> 5) & 0x01;
status.dist_status.RFU = trans_mode_policy & 0x1f;
status.dist_status.fw_idx = net_buf_simple_pull_le16(buf);
dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_status));
return;
}
static void handle_upload_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
dfd_status_t status = {0};
uint8_t progress_type = 0;
struct net_buf_simple buf_cache = {0};
status.upload_status.status = net_buf_simple_pull_u8(buf);
status.upload_status.upload_phase = net_buf_simple_pull_u8(buf);
if (buf->len == 0) {
status.upload_status.upload_progress = UPLOAD_PROGRESS_UNSET;
dfd_client_recv_status(model, ctx, &status, sizeof(status.upload_status));
return;
}
progress_type = net_buf_simple_pull_u8(buf);
status.upload_status.upload_progress = progress_type>>1;
if (status.upload_status.upload_progress >= UPLOAD_PROGRESS_UNSET) {
BT_ERR("Invalid upload progress");
return;
}
if (buf->len == 0) {
BT_ERR("InvFwID");
return;
}
status.upload_status.upload_type = progress_type & 0x01;
if (status.upload_status.upload_type == UPLOAD_IN_BAND) {
status.upload_status.fwid = &buf_cache;
net_buf_simple_init_with_data(status.upload_status.fwid, buf->data, buf->len);
net_buf_simple_pull_mem(buf, buf->len);
} else if (status.upload_status.upload_type == UPLOAD_OOB){
status.upload_status.oob_fwid = &buf_cache;
net_buf_simple_init_with_data(status.upload_status.oob_fwid, buf->data, buf->len);
net_buf_simple_pull_mem(buf, buf->len);
} else {
BT_ERR("Invalid upload type:%d", status.upload_status.upload_type);
return;
}
dfd_client_recv_status(model, ctx, &status, sizeof(status.upload_status));
return;
}
static void handle_fw_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
dfd_status_t status = {0};
struct net_buf_simple buf_cache = {0};
status.firmware_status.status = net_buf_simple_pull_u8(buf);
status.firmware_status.entry_cnt = net_buf_simple_pull_le16(buf);
status.firmware_status.firmware_image_index = net_buf_simple_pull_le16(buf);
if (buf->len) {
status.firmware_status.fwid = &buf_cache;
net_buf_simple_init_with_data(status.firmware_status.fwid, buf->data, buf->len);
net_buf_simple_pull_mem(buf, buf->len);
}
dfd_client_recv_status(model, ctx, &status, sizeof(status.firmware_status));
return;
}
const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[] = {
{ BLE_MESH_DFD_OP_RECEIVERS_STATUS, 3, handle_receiver_status },
{ BLE_MESH_DFD_OP_RECEIVERS_LIST, 4 , handle_receiver_list },
{ BLE_MESH_DFD_OP_CAPABILITIES_STATUS, 17, handle_capabilities },
{ BLE_MESH_DFD_OP_STATUS, 2, handle_dfd_status },
{ BLE_MESH_DFD_OP_UPLOAD_STATUS, 2, handle_upload_status },
{ BLE_MESH_DFD_OP_FW_STATUS, 5, handle_fw_status },
};
int bt_mesh_dfd_cli_receivers_add(bt_mesh_client_common_param_t *param, dfd_cli_receiver_entry_t *receivers, uint16_t receivers_cnt)
{
uint16_t msg_length = 2;
struct net_buf_simple *msg = NULL;
dfd_cli_receiver_entry_t *entry = NULL;
int err = 0;
if (param == NULL) {
BT_ERR("Invalid param");
return -EINVAL;
}
BT_INFO("AddedValidCnt:%d", receivers_cnt);
msg_length += (receivers_cnt * 3);
/* needs to confirm long or short mic */
if (msg_length > BLE_MESH_MAX_PDU_LEN_WITH_SMIC) {
BT_ERR("Too much receivers added once time");
return -EINVAL;
}
msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT);
if (!msg) {
BT_ERR("Failed to alloc buffer to send message");
return -EINVAL;
}
bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_RECEIVERS_ADD);
for (int i = 0; i < receivers_cnt; i++) {
entry = &receivers[i];
if (BLE_MESH_ADDR_IS_UNICAST(entry->addr)) {
net_buf_simple_add_le16(msg, entry->addr);
net_buf_simple_add_u8(msg, entry->fw_idx);
BT_INFO("AddedUnicastAddr:0x%04x,FwIdx:%d", entry->addr, entry->fw_idx);
}
}
err = bt_mesh_client_send_msg(param, msg, true, timeout_handler);
bt_mesh_free_buf(msg);
return err;
}
int bt_mesh_dfd_cli_receivers_delete_all(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, 0);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_receivers_get(bt_mesh_client_common_param_t *param, uint16_t first_index, uint16_t entries_limit)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_RECEIVERS_GET, 4);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_RECEIVERS_GET);
net_buf_simple_add_le16(&msg, first_index);
net_buf_simple_add_le16(&msg, entries_limit);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_capabilities_get(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_CAPABILITIES_GET, 0);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_CAPABILITIES_GET);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_get(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_GET, 0);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_GET);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_start(bt_mesh_client_common_param_t *param,
dfd_cli_dist_start_t *start)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_START, 2 + 1 + 2 + 1 + 2 + 16);
if (!param || !start) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_START);
net_buf_simple_add_le16(&msg, start->app_idx);
net_buf_simple_add_u8(&msg, start->ttl);
net_buf_simple_add_le16(&msg, start->timeout_base);
net_buf_simple_add_u8(&msg, ((start->trans_mode) << 6) | ((start->update_policy) << 5));
net_buf_simple_add_le16(&msg, start->fw_idx);
if (start->is_va) {
net_buf_simple_add_mem(&msg, &(start->label_uuid), 16);
} else {
net_buf_simple_add_le16(&msg, start->group_addr);
}
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_suspend(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_SUSPEND, 0);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_SUSPEND);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_cancel(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_CANCEL, 0);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_CANCEL);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_apply(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_APPLY, 0);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_APPLY);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_upload_get(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_UPLOAD_GET, 0);
if (!param) {
BT_ERR("Invalid param");
return -EINVAL;
}
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_UPLOAD_GET);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_distribution_upload_start(bt_mesh_client_common_param_t *param,
dfd_cli_dist_upload_start_t *start)
{
struct net_buf_simple *msg = NULL;
uint16_t msg_length = 2;
int err = 0;
if (!param || !start) {
BT_ERR("Invalid param");
return -EINVAL;
}
msg_length += (1 + 2 + 8 + 4 + 1 + start->fwid->len);
if (start->fw_metadata) {
msg_length += start->fw_metadata->len;
}
msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT);
if (!msg) {
BT_ERR("Failed to alloc buffer to send message");
return -EINVAL;
}
bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_UPLOAD_START);
net_buf_simple_add_u8(msg, start->ttl);
net_buf_simple_add_le16(msg, start->timeout_base);
net_buf_simple_add_le64(msg, start->blob_id);
net_buf_simple_add_le32(msg, start->fw_size);
if (start->fw_metadata) {
net_buf_simple_add_u8(msg, start->fw_metadata->len);
net_buf_simple_add_mem(msg, start->fw_metadata->data, start->fw_metadata->len);
} else {
net_buf_simple_add_u8(msg, 0);
}
net_buf_simple_add_mem(msg, start->fwid->data, start->fwid->len);
err = bt_mesh_client_send_msg(param, msg, true, timeout_handler);
bt_mesh_free_buf(msg);
return err;
}
int bt_mesh_dfd_cli_distribution_upload_oob_start(bt_mesh_client_common_param_t *param,
dfd_cli_dist_upload_oob_start_t *start)
{
int err = 0;
struct net_buf_simple *msg = NULL;
uint16_t msg_length = 2;
if (!param || !start) {
BT_ERR("Invalid param");
return -1;
}
if (!start->url) {
BT_ERR("Null url info");
return -1;
}
if (!start->fwid) {
BT_ERR("Invalid firmware id");
return -1;
}
msg_length += (1 + start->url->len + start->fwid->len);
msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT);
if (!msg) {
BT_ERR("Failed to alloc buffer to send message");
return -EINVAL;
}
bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_UPLOAD_START_OOB);
net_buf_simple_add_u8(msg, start->url->len);
net_buf_simple_add_mem(msg, start->url->data, start->url->len);
net_buf_simple_add_mem(msg, start->fwid->data, start->fwid->len);
err = bt_mesh_client_send_msg(param, msg, true, timeout_handler);
bt_mesh_free_buf(msg);
return err;
}
int bt_mesh_dfd_cli_distribution_upload_oob_cancel(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_UPLOAD_CANCEL, 0);
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_UPLOAD_CANCEL);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_firmware_get(bt_mesh_client_common_param_t *param, struct net_buf_simple *fwid)
{
struct net_buf_simple *msg = NULL;
uint16_t msg_length = 2;
int err;
if (!fwid) {
BT_ERR("NULL Firmware id");
return -EINVAL;
}
msg_length += fwid->len;
msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT);
if (!msg) {
BT_ERR("Failed to alloc buffer to send message");
return -EINVAL;
}
bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_FW_GET);
net_buf_simple_add_mem(msg, fwid->data, fwid->len);
err = bt_mesh_client_send_msg(param, msg, true, timeout_handler);
bt_mesh_free_buf(msg);
return err;
}
int bt_mesh_dfd_cli_firmware_get_by_index(bt_mesh_client_common_param_t *param, uint16_t fw_id_index)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_FW_GET_BY_INDEX, 2);
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_FW_GET_BY_INDEX);
net_buf_simple_add_le16(&msg, fw_id_index);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
int bt_mesh_dfd_cli_firmware_get_delete(bt_mesh_client_common_param_t *param, struct net_buf_simple *fwid)
{
struct net_buf_simple *msg = NULL;
uint16_t msg_length = 2;
int err;
if (!fwid) {
BT_ERR("NULL Firmware id");
return -EINVAL;
}
msg_length += fwid->len;
msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT);
if (!msg) {
BT_ERR("Failed to alloc buffer to send message");
return -EINVAL;
}
bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_FW_DELETE);
net_buf_simple_add_mem(msg, fwid->data, fwid->len);
err = bt_mesh_client_send_msg(param, msg, true, timeout_handler);
bt_mesh_free_buf(msg);
return err;
}
int bt_mesh_dfd_cli_firmware_delete_all(bt_mesh_client_common_param_t *param)
{
BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_FW_DELETE_ALL, 0);
bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_FW_DELETE_ALL);
return bt_mesh_client_send_msg(param, &msg, true, timeout_handler);
}
static int dfd_cli_init(struct bt_mesh_model *model)
{
bt_mesh_dfd_client_t *client = NULL;
dfd_internal_data_t *internal = NULL;
if (!model) {
BT_ERR("Invalid Device Firmware Distribution Client model");
return -EINVAL;
}
if (!bt_mesh_model_in_primary(model)) {
BT_ERR("Device Firmware Distribution Client only allowed in primary element");
return -EINVAL;
}
client = (bt_mesh_dfd_client_t *)model->user_data;
if (!client) {
BT_ERR("No Device Firmware Distribution Client context provided");
return -EINVAL;
}
if (client->internal_data) {
BT_WARN("%s, Already", __func__);
return -EALREADY;
}
internal = bt_mesh_calloc(sizeof(dfd_internal_data_t));
if (!internal) {
BT_ERR("%s, Out of memory", __func__);
return -ENOMEM;
}
sys_slist_init(&internal->queue);
client->model = model;
client->op_pair_size = ARRAY_SIZE(dfd_cli_pair);
client->op_pair = dfd_cli_pair;
client->internal_data = internal;
BT_INFO("Dfd client initialized");
bt_mesh_mutex_create(&dfd_client_lock);
return 0;
}
#if CONFIG_BLE_MESH_DEINIT
static int dfd_cli_deinit(struct bt_mesh_model *model)
{
bt_mesh_dfd_client_t *client = NULL;
if (!model) {
BT_ERR("Invalid Device Firmware Distribution Client model");
return -EINVAL;
}
client = (bt_mesh_dfd_client_t *)model->user_data;
if (!client) {
BT_ERR("No Device Firmware Distribution Client context provided");
return -EINVAL;
}
if (client->internal_data) {
/* Remove items from the list */
bt_mesh_client_clear_list(client->internal_data);
/* Free the allocated internal data */
bt_mesh_free(client->internal_data);
client->internal_data = NULL;
}
bt_mesh_mutex_free(&dfd_client_lock);
return 0;
}
#endif
const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb = {
.init = dfd_cli_init,
#if CONFIG_BLE_MESH_DEINIT
.deinit = dfd_cli_deinit,
#endif /* CONFIG_BLE_MESH_DEINIT */
};
#endif