AC63_BT_SDK/apps/mesh/MshMDL/dfu_target.c

317 lines
8.6 KiB
C
Raw Normal View History

2025-02-18 15:40:42 +08:00
/** @file
* @brief Bluetooth Mesh DFU Target role handler
*/
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include "btstack/bluetooth.h"
#include "system/includes.h"
#include "bt_common.h"
#include "api/sig_mesh_api.h"
#include "model_api.h"
#include "adaptation.h"
#include "mesh_target_node_ota.h"
#include "dfu_target.h"
#define LOG_TAG "[Mesh-DFU_Target]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#if (CONFIG_BT_MESH_DFU_TARGET)
/**
* @brief MCUboot image header representation for image version
*
* The header for an MCUboot firmware image contains an embedded
* version number, in semantic versioning format. This structure
* represents the information it contains.
*/
struct mcuboot_img_sem_ver {
uint8_t major;
uint8_t minor;
uint16_t revision;
uint32_t build_num;
};
struct target_img_t target_img;
static struct bt_mesh_blob_io_flash *blob_flash_stream;
static enum bt_mesh_dfu_effect img_effect = BT_MESH_DFU_EFFECT_NONE;
static struct bt_mesh_dfu_img dfu_imgs[] = { {
.fwid = &((struct mcuboot_img_sem_ver) {}),
.fwid_len = sizeof(struct mcuboot_img_sem_ver),
}
};
#if (CONFIG_BT_MESH_DFU_METADATA)
static size_t flash_area_size_get(uint8_t area_id)
{
const struct flash_area *area;
size_t fa_size;
int err;
fa_size = 307200; //300K
return fa_size;
}
#endif
static bool is_firmware_newer(struct mcuboot_img_sem_ver *new, struct mcuboot_img_sem_ver *cur)
{
if (new->major > cur->major) {
return true;
} else if (new->major < cur->major) {
return false;
}
if (new->minor > cur->minor) {
return true;
} else if (new->minor > cur->minor) {
return false;
}
if (new->revision > cur->revision) {
return true;
} else if (new->revision > cur->revision) {
return false;
}
//if (new->build_num > cur->build_num) {
//return true;
//}
return false;
}
static int dfu_meta_check(struct bt_mesh_dfu_srv *srv,
const struct bt_mesh_dfu_img *img,
struct net_buf_simple *metadata_raw,
enum bt_mesh_dfu_effect *effect)
{
#if (CONFIG_BT_MESH_DFU_METADATA)
struct mcuboot_img_sem_ver *img_ver = (struct mcuboot_img_sem_ver *) dfu_imgs[0].fwid;
struct bt_mesh_dfu_metadata metadata;
uint8_t key[16] = {};
uint32_t hash;
uint16_t temp_crc;
int err;
err = bt_mesh_dfu_metadata_decode(metadata_raw, &metadata);
if (err) {
log_error("Unable to decode metadata: %d", err);
return -EINVAL;
}
log_info("Received firmware metadata:");
log_info("\tVersion: %u.%u.%u+%u", metadata.fw_ver.major, metadata.fw_ver.minor,
metadata.fw_ver.revision, metadata.fw_ver.build_num);
log_info("\tSize: %u", metadata.fw_size);
log_info("\tCore Type: 0x%x", metadata.fw_core_type);
if (metadata.fw_core_type & BT_MESH_DFU_FW_CORE_TYPE_APP) {
log_info("\tComposition data hash: 0x%x", metadata.comp_hash);
log_info("\tElements: %u", metadata.elems);
}
if (metadata.user_data_len > 0) {
size_t len;
uint8_t user_data[2 * (CONFIG_BT_MESH_DFU_METADATA_MAXLEN - 18) + 1];
len = bin2hex(metadata.user_data, metadata.user_data_len, user_data,
(sizeof(user_data) - 1));
user_data[len] = '\0';
log_info("\tUser data: %s", user_data);
}
log_info("\tUser data length: %u", metadata.user_data_len);
if (!is_firmware_newer((struct mcuboot_img_sem_ver *) &metadata.fw_ver, img_ver)) {
log_error("New firmware version is older");
return -EINVAL;
}
target_img.fwid[0] = metadata.fw_ver.major;
target_img.fwid[1] = metadata.fw_ver.minor;
target_img.fwid[2] = (metadata.fw_ver.revision >> 8) & 0xFF;
target_img.fwid[3] = metadata.fw_ver.revision & 0xFF;
target_img.fwid[4] = 0x00;//(metadata.fw_ver.build_num >> 24) & 0xFF;
target_img.fwid[5] = 0x00;//(metadata.fw_ver.build_num >> 16) & 0xFF;
target_img.fwid[6] = 0x00;//(metadata.fw_ver.build_num >> 8) & 0xFF;
target_img.fwid[7] = 0x00;//metadata.fw_ver.build_num & 0xFF;
mesh_targe_ota_process(DFU_NODE_OTA_REQ, &(metadata.fw_ver.major), 0, 0, 0);
if (!(metadata.fw_core_type & BT_MESH_DFU_FW_CORE_TYPE_APP)) {
log_error("Only application core firmware is supported by the sample");
return -EINVAL;
}
if (flash_area_size_get(0) < metadata.fw_size ||
flash_area_size_get(1) < metadata.fw_size) {
log_error("New firmware won't fit into flash.");
return -EINVAL;
}
temp_crc = (metadata.fw_ver.build_num >> 16) & 0xFFFF;
mesh_targe_ota_process(DFU_NODE_OTA_FILE_INFO, NULL, metadata.fw_size, temp_crc, 0);
err = bt_mesh_dfu_metadata_comp_hash_local_get(key, &hash);
if (err) {
log_error("Failed to compute composition data hash: %d", err);
return -EINVAL;
}
log_info("Current composition data hash: 0x%x", hash);
if (hash == metadata.comp_hash) {
img_effect = BT_MESH_DFU_EFFECT_NONE;
} else {
img_effect = BT_MESH_DFU_EFFECT_UNPROV;
}
#else
img_effect = BT_MESH_DFU_EFFECT_UNPROV;
#endif /* CONFIG_BT_MESH_DFU_METADATA */
log_info("Metadata check succeeded, effect: %d", img_effect);
*effect = img_effect;
return 0;
}
static int dfu_start(struct bt_mesh_dfu_srv *srv,
const struct bt_mesh_dfu_img *img,
struct net_buf_simple *metadata,
const struct bt_mesh_blob_io **io)
{
log_info("Firmware upload started");
*io = &blob_flash_stream->io;
return 0;
}
static void dfu_end(struct bt_mesh_dfu_srv *srv, const struct bt_mesh_dfu_img *img, bool success)
{
log_info("Firmware upload %s", success ? "succeeded" : "failed");
if (!success) {
mesh_targe_ota_exit();
return;
}
/* TODO: Add verification code here. */
bt_mesh_dfu_srv_verified(srv);
mesh_targe_ota_process(DFU_NODE_OTA_END, NULL, 0, 0, 0);
}
static int dfu_recover(struct bt_mesh_dfu_srv *srv,
const struct bt_mesh_dfu_img *img,
const struct bt_mesh_blob_io **io)
{
log_info("Recovering the firmware upload");
/* TODO: Need to recover the effect. */
#if (CONFIG_BT_MESH_DFD_SRV)
return -ENOTSUP;
#else
*io = &blob_flash_stream->io;
return 0;
#endif
}
static void do_reboot(struct k_work *work)
{
cpu_reset();
}
static int dfu_apply(struct bt_mesh_dfu_srv *srv, const struct bt_mesh_dfu_img *img)
{
static struct k_work_delayable pending_reboot;
log_info("Applying the new firmware");
store_pending_target_cfg();
if (img_effect == BT_MESH_DFU_EFFECT_UNPROV) {
bt_mesh_reset();
log_info("Pending the mesh settings to cleared before rebooting...");
/* Let the mesh reset its settings before rebooting the device. */
k_work_init_delayable(&pending_reboot, do_reboot);
k_work_schedule(&pending_reboot, K_MSEC(1));
} else {
/* No need to unprovision device. Reboot immediately. */
cpu_reset();
}
return 0;
}
static const struct bt_mesh_dfu_srv_cb dfu_handlers = {
.check = dfu_meta_check,
.start = dfu_start,
.end = dfu_end,
.apply = dfu_apply,
.recover = dfu_recover,
};
struct bt_mesh_dfu_srv dfu_srv =
BT_MESH_DFU_SRV_INIT(&dfu_handlers, dfu_imgs, ARRAY_SIZE(dfu_imgs));
extern struct file_parameter_t file_parameter;
static void image_version_load(void)
{
struct mcuboot_img_sem_ver *img_ver = (struct mcuboot_img_sem_ver *) dfu_imgs[0].fwid;
target_cfg_set();
img_ver->major = target_img.fwid[0];
img_ver->minor = target_img.fwid[1];
img_ver->revision = (target_img.fwid[2] << 8) | target_img.fwid[3];
img_ver->build_num = (target_img.fwid[4] << 24) | (target_img.fwid[5] << 16) | \
(target_img.fwid[6] << 8) | target_img.fwid[7];
log_info("Current image version: %u.%u.%u+%u\n", img_ver->major, img_ver->minor,
img_ver->revision, img_ver->build_num);
}
int dfu_target_init(struct bt_mesh_blob_io_flash *flash_stream)
{
blob_flash_stream = flash_stream;
image_version_load();
return 0;
}
void dfu_target_image_confirm(void)
{
int err = 0;
// err = boot_write_img_confirmed(); //check the image for update.
if (err) {
log_error("Failed to confirm image: %d\n", err);
}
/* Switch DFU Server state to the Idle state if it was in the Applying state. */
bt_mesh_dfu_srv_applied(&dfu_srv);
}
#endif