Skip to content

Commit

Permalink
dfu: dfu_target: New DFU target SMP
Browse files Browse the repository at this point in the history
Added new DFU SMP target for update image to external MCU by using
MCUMGR SMP client.

Signed-off-by: Juha Heiskanen <juha.heiskanen@nordicsemi.no>
  • Loading branch information
Juha Heiskanen committed Aug 18, 2023
1 parent a741296 commit 9611516
Show file tree
Hide file tree
Showing 7 changed files with 538 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,10 @@ See the changelog for each library in the :doc:`nrfxlib documentation <nrfxlib:R
DFU libraries
-------------

|no_changes_yet_note|
* Added:

* A new DFU SMP target for the image update to an external MCU by using the MCUmgr SMP Client.


Scripts
=======
Expand Down
15 changes: 15 additions & 0 deletions include/dfu/dfu_target.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ enum dfu_target_image_type {
DFU_TARGET_IMAGE_TYPE_MODEM_DELTA = 2,
/** Full update image for modem */
DFU_TARGET_IMAGE_TYPE_FULL_MODEM = 4,
/** SMP external MCU */
DFU_TARGET_IMAGE_TYPE_SMP = 8,
/** Any application image type */
DFU_TARGET_IMAGE_TYPE_ANY_APPLICATION = DFU_TARGET_IMAGE_TYPE_MCUBOOT,
/** Any modem image */
Expand Down Expand Up @@ -75,6 +77,19 @@ struct dfu_target {
**/
enum dfu_target_image_type dfu_target_img_type(const void *const buf, size_t len);

/**
* @brief Find the image type for the buffer of bytes received. Used to validate type for
* DFU SMP target to initialize.
*
* @param[in] buf A buffer of bytes which are the start of a binary firmware
* image.
* @param[in] len The length of the provided buffer.
*
* @return DFU_TARGET_IMAGE_TYPE_SMP or DFU_TARGET_IMAGE_TYPE_NONE if
* image type is not recognized.
**/
enum dfu_target_image_type dfu_target_smp_img_type_check(const void *const buf, size_t len);

/**
* @brief Initialize the resources needed for the specific image type DFU
* target.
Expand Down
151 changes: 151 additions & 0 deletions include/dfu/dfu_target_smp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

/** @file dfu_target_smp.h
*
* @defgroup dfu_target_SMP SMP external MCU target
* @{
* @brief DFU Target for upgrades performed by SMP Client.
*/

#ifndef DFU_TARGET_SMP_H__
#define DFU_TARGET_SMP_H__

#include <stddef.h>
#include <dfu/dfu_target.h>
#include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief DFU target reset callback for activating MCUboot serial recovery mode.
*
* @return 0 on success, negative errno otherwise.
*/
typedef int (*dfu_target_reset_cb_t)(void);

/**
* @brief Register recovery mode reset callback.
*
* Function that boots the target in MCUboot serial recovery mode, needed before sending
* SMP commands.
*
* @param[in] cb User defined target reset function for entering recovery mode.
*
* @return 0 on success, negative errno otherwise.
*/
int dfu_target_smp_recovery_mode_enable(dfu_target_reset_cb_t cb);

/**
* @brief Initialize dfu target SMP client.
*
* @retval 0 on success, negative errno otherwise.
*/
int dfu_target_smp_client_init(void);

/**
* @brief Read image list.
*
* @param res_buf Image list buffer.
*
* @return 0 on success, negative errno otherwise.
*/
int dfu_target_smp_image_list_get(struct mcumgr_image_state *res_buf);

/**
* @brief Reboot SMP target device, and apply new image.
*
* @return 0 on success, negative errno otherwise.
*/
int dfu_target_smp_reboot(void);

/**
* @brief Confirm new image activation after reset command.
*
* Use only without MCUboot recovery mode.
*
* @return 0 on success, negative errno otherwise.
*/
int dfu_target_smp_confirm_image(void);

/**
* @brief Check if data in buffer indicates MCUboot style upgrade.
*
* @retval true if data matches, false otherwise.
*/
bool dfu_target_smp_identify(const void *const buf);

/**
* @brief Initialize DFU target, perform steps necessary to receive firmware.
*
* @param[in] file_size Size of the current file being downloaded.
* @param[in] img_num Image pair index.
* @param[in] cb Callback for signaling events (unused).
*
* @retval 0 on success, negative errno otherwise.
*/
int dfu_target_smp_init(size_t file_size, int img_num, dfu_target_callback_t cb);

/**
* @brief Get offset of firmware.
*
* @param[out] offset Returns the offset of the firmware upgrade.
*
* @return 0 on success, otherwise negative value if unable to get the offset.
*/
int dfu_target_smp_offset_get(size_t *offset);

/**
* @brief Write firmware data.
*
* @param[in] buf Pointer to data that should be written.
* @param[in] len Length of data to write.
*
* @return 0 on success, negative errno otherwise.
*/
int dfu_target_smp_write(const void *const buf, size_t len);

/**
* @brief Deinitialize resources and finalize firmware upgrade if successful.
*
* @param[in] successful Indicate whether the firmware was successfully received.
*
* @return 0 on success, negative errno otherwise.
*/
int dfu_target_smp_done(bool successful);

/**
* @brief Schedule update of image.
*
* This call requests image update. The update will be performed after
* the device resets.
*
* @param[in] img_num Given image pair index or -1 for all
* of image pair indexes.
*
* @return 0 for a successful request or a negative error
* code identicating reason of failure.
**/
int dfu_target_smp_schedule_update(int img_num);

/**
* @brief Release resources and erase the download area.
*
* Cancels any ongoing updates.
*
* @return 0 on success, negative errno otherwise.
*/
int dfu_target_smp_reset(void);

#ifdef __cplusplus
}
#endif

#endif /* DFU_TARGET_SMP_H__ */

/**@} */
3 changes: 3 additions & 0 deletions subsys/dfu/dfu_target/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ zephyr_library_sources_ifdef(CONFIG_DFU_TARGET_FULL_MODEM
zephyr_library_sources_ifdef(CONFIG_DFU_TARGET_MCUBOOT
src/dfu_target_mcuboot.c
)
zephyr_library_sources_ifdef(CONFIG_DFU_TARGET_SMP
src/dfu_target_smp.c
)
20 changes: 20 additions & 0 deletions subsys/dfu/dfu_target/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,26 @@ config DFU_TARGET_MCUBOOT
help
Enable support for updates that are performed by MCUboot.

config DFU_TARGET_SMP
bool "DFU SMP target for external update support"
depends on SMP_CLIENT
depends on MCUMGR_GRP_IMG_CLIENT
depends on MCUMGR_GRP_OS_CLIENT
select MCUMGR_GRP_OS_CLIENT_RESET
select MCUMGR_GRP_OS_CLIENT_ECHO
help
Enable support for Update external MCU by SMP client.

if DFU_TARGET_SMP

config DFU_TARGET_SMP_IMAGE_LIST_SIZE
int "Supported Image list size"
default 2
help
Define size for Image cache list.

endif

config DFU_TARGET_STREAM
bool "Generic DFU stream target"
depends on STREAM_FLASH_ERASE
Expand Down
29 changes: 26 additions & 3 deletions subsys/dfu/dfu_target/src/dfu_target.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ DEF_DFU_TARGET(mcuboot);
#include "dfu/dfu_target_full_modem.h"
DEF_DFU_TARGET(full_modem);
#endif
#ifdef CONFIG_DFU_TARGET_SMP
#include "dfu/dfu_target_smp.h"
DEF_DFU_TARGET(smp);
#endif

#define MIN_SIZE_IDENTIFY_BUF 32

Expand Down Expand Up @@ -62,6 +66,20 @@ enum dfu_target_image_type dfu_target_img_type(const void *const buf, size_t len
return DFU_TARGET_IMAGE_TYPE_NONE;
}

enum dfu_target_image_type dfu_target_smp_img_type_check(const void *const buf, size_t len)
{
#ifdef CONFIG_DFU_TARGET_SMP
if (len < MIN_SIZE_IDENTIFY_BUF) {
return DFU_TARGET_IMAGE_TYPE_NONE;
}
if (dfu_target_smp_identify(buf)) {
return DFU_TARGET_IMAGE_TYPE_SMP;
}
#endif
LOG_ERR("No supported image type found");
return DFU_TARGET_IMAGE_TYPE_NONE;
}

int dfu_target_init(int img_type, int img_num, size_t file_size, dfu_target_callback_t cb)
{
const struct dfu_target *new_target = NULL;
Expand All @@ -81,6 +99,12 @@ int dfu_target_init(int img_type, int img_num, size_t file_size, dfu_target_call
new_target = &dfu_target_full_modem;
}
#endif
#ifdef CONFIG_DFU_TARGET_SMP
if (img_type == DFU_TARGET_IMAGE_TYPE_SMP) {
new_target = &dfu_target_smp;
}
#endif

if (new_target == NULL) {
LOG_ERR("Unknown image type");
return -ENOTSUP;
Expand All @@ -93,9 +117,8 @@ int dfu_target_init(int img_type, int img_num, size_t file_size, dfu_target_call
* modem_delta upgrades to re-open the DFU socket that is closed on
* abort and to change the image number.
*/
if (new_target == current_target
&& img_type != DFU_TARGET_IMAGE_TYPE_MODEM_DELTA
&& current_img_num == img_num) {
if (new_target == current_target && img_type != DFU_TARGET_IMAGE_TYPE_MODEM_DELTA &&
img_type != DFU_TARGET_IMAGE_TYPE_SMP && current_img_num == img_num) {
return 0;
}

Expand Down
Loading

0 comments on commit 9611516

Please sign in to comment.