This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push: new d27d6e635 examples/mcuboot: add example to update from binary in local storage d27d6e635 is described below commit d27d6e635fca59c4a89c94e830b2e06d62bd6b77 Author: Filipe Cavalcanti <filipe.cavalca...@espressif.com> AuthorDate: Mon Jul 14 21:46:08 2025 -0300 examples/mcuboot: add example to update from binary in local storage This example makes it possible to use a binary from local storage for MCUBoot update. It copies the binary file to the secondary slot instead of downloading from a remote URL. Can be used to update from a SD Card, for example. Signed-off-by: Filipe Cavalcanti <filipe.cavalca...@espressif.com> --- examples/mcuboot/update_agent_local/CMakeLists.txt | 33 +++ examples/mcuboot/update_agent_local/Kconfig | 41 +++ examples/mcuboot/update_agent_local/Make.defs | 25 ++ examples/mcuboot/update_agent_local/Makefile | 32 +++ .../update_agent_local/mcuboot_local_agent_main.c | 298 +++++++++++++++++++++ 5 files changed, 429 insertions(+) diff --git a/examples/mcuboot/update_agent_local/CMakeLists.txt b/examples/mcuboot/update_agent_local/CMakeLists.txt new file mode 100644 index 000000000..4b73b64fc --- /dev/null +++ b/examples/mcuboot/update_agent_local/CMakeLists.txt @@ -0,0 +1,33 @@ +# ############################################################################## +# apps/examples/mcuboot/update_agent_local/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +if(CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT) + nuttx_add_application( + NAME + ${CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT_PROGNAME} + SRCS + mcuboot_local_agent_main.c + STACKSIZE + ${CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT_STACKSIZE} + PRIORITY + ${CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT_PRIORITY}) +endif() diff --git a/examples/mcuboot/update_agent_local/Kconfig b/examples/mcuboot/update_agent_local/Kconfig new file mode 100644 index 000000000..4079c83fb --- /dev/null +++ b/examples/mcuboot/update_agent_local/Kconfig @@ -0,0 +1,41 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_MCUBOOT_LOCAL_AGENT + tristate "MCUBoot Local Update Agent" + default n + depends on BOOT_MCUBOOT + select BOARDCTL + select BOARDCTL_RESET + ---help--- + Enable the MCUBoot Local Update Agent example. + This application reads a firmware binary from local storage + and copies it to the MCUBoot secondary flash slot for update. + +if EXAMPLES_MCUBOOT_LOCAL_AGENT + +config EXAMPLES_MCUBOOT_LOCAL_AGENT_PROGNAME + string "Program name" + default "mcuboot_local_agent" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_MCUBOOT_LOCAL_AGENT_PRIORITY + int "MCUBoot Local Agent task priority" + default 100 + +config EXAMPLES_MCUBOOT_LOCAL_AGENT_STACKSIZE + int "MCUBoot Local Agent stack size" + default DEFAULT_TASK_STACKSIZE + +config EXAMPLES_MCUBOOT_LOCAL_AGENT_DEFAULT_PATH + string "Default firmware file path" + default "/mnt/sdcard/firmware.bin" + ---help--- + Default path to the firmware binary file on local storage. + This can be overridden by passing a path as a command line argument. + +endif # EXAMPLES_MCUBOOT_LOCAL_AGENT diff --git a/examples/mcuboot/update_agent_local/Make.defs b/examples/mcuboot/update_agent_local/Make.defs new file mode 100644 index 000000000..e7f7ff602 --- /dev/null +++ b/examples/mcuboot/update_agent_local/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/examples/mcuboot/update_agent_local/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT),) +CONFIGURED_APPS += $(APPDIR)/examples/mcuboot/update_agent_local +endif diff --git a/examples/mcuboot/update_agent_local/Makefile b/examples/mcuboot/update_agent_local/Makefile new file mode 100644 index 000000000..a730a662b --- /dev/null +++ b/examples/mcuboot/update_agent_local/Makefile @@ -0,0 +1,32 @@ +############################################################################ +# apps/examples/mcuboot/update_agent_local/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +MAINSRC = mcuboot_local_agent_main.c + +PROGNAME = $(CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_MCUBOOT_LOCAL_AGENT) + +include $(APPDIR)/Application.mk diff --git a/examples/mcuboot/update_agent_local/mcuboot_local_agent_main.c b/examples/mcuboot/update_agent_local/mcuboot_local_agent_main.c new file mode 100644 index 000000000..dd0c183fa --- /dev/null +++ b/examples/mcuboot/update_agent_local/mcuboot_local_agent_main.c @@ -0,0 +1,298 @@ +/**************************************************************************** + * apps/examples/mcuboot/update_agent_local/mcuboot_local_agent_main.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/boardctl.h> + +#include <bootutil/bootutil_public.h> + +#include "flash_map_backend/flash_map_backend.h" +#include "sysflash/sysflash.h" + +/**************************************************************************** + * Preprocessor Definitions + ****************************************************************************/ + +#define BUFFER_SIZE 4096 +#define DEFAULT_FW_PATH "/mnt/sdcard/firmware.bin" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct update_context_s +{ + FAR const struct flash_area *fa; + uint32_t fa_offset; + ssize_t image_size; + int fd; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static uint8_t g_buffer[BUFFER_SIZE]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: get_file_size + * + * Description: + * Retrieves the size of an open file descriptor. + * + * Input Parameters: + * fd - File descriptor of the open file. + * + * Returned Value: + * On success, returns the file size in bytes. + * On failure, returns -1. + * + ****************************************************************************/ + +static ssize_t get_file_size(int fd) +{ + struct stat st; + + if (fstat(fd, &st) < 0) + { + return -1; + } + + return st.st_size; +} + +/**************************************************************************** + * Name: copy_firmware_from_local + * + * Description: + * Copies a firmware binary from local storage to the secondary flash slot. + * + * Input Parameters: + * filepath - Path to the firmware binary file. + * + * Returned Value: + * On success, returns OK. + * On failure, returns an error code. + * + ****************************************************************************/ + +static int copy_firmware_from_local(FAR const char *filepath) +{ + int ret = OK; + struct update_context_s ctx; + ssize_t bytes_read; + uint32_t total_copied = 0; + uint32_t progress; + + /* Initialize context */ + + memset(&ctx, 0, sizeof(ctx)); + ctx.fa = NULL; + ctx.fa_offset = 0; + ctx.image_size = -1; + ctx.fd = -1; + + /* Open firmware file from local storage */ + + ctx.fd = open(filepath, O_RDONLY); + if (ctx.fd < 0) + { + fprintf(stderr, "Failed to open firmware file: %s\n", filepath); + ret = -errno; + goto exit; + } + + /* Get file size */ + + ctx.image_size = get_file_size(ctx.fd); + if (ctx.image_size < 0) + { + fprintf(stderr, "Failed to get file size\n"); + ret = -errno; + goto exit_close_file; + } + + printf("Firmware file size: %zd bytes\n", ctx.image_size); + + /* Open secondary flash area for MCUBoot */ + + ret = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(0), &ctx.fa); + if (ret != OK) + { + fprintf(stderr, "Failed to open secondary flash area: %d\n", ret); + goto exit_close_file; + } + + /* Check if file fits in secondary slot */ + + if (ctx.image_size > ctx.fa->fa_size) + { + fprintf(stderr, "Firmware file too large for secondary slot\n"); + fprintf(stderr, "File size: %zd, Slot size: %lu\n", + ctx.image_size, ctx.fa->fa_size); + ret = -EFBIG; + goto exit_close_flash; + } + + /* Erase secondary slot */ + + printf("Erasing secondary flash slot...\n"); + ret = flash_area_erase(ctx.fa, 0, ctx.fa->fa_size); + if (ret != OK) + { + fprintf(stderr, "Failed to erase secondary flash area: %d\n", ret); + goto exit_close_flash; + } + + /* Copy firmware from local storage to flash */ + + printf("Copying firmware to secondary slot...\n"); + + while (total_copied < ctx.image_size) + { + /* Read from local file */ + + bytes_read = read(ctx.fd, g_buffer, BUFFER_SIZE); + if (bytes_read < 0) + { + fprintf(stderr, "Failed to read from firmware file: %d\n", errno); + ret = -errno; + goto exit_close_flash; + } + + if (bytes_read == 0) + { + break; /* EOF reached */ + } + + /* Adjust bytes to write if near end of file */ + + if (total_copied + bytes_read > ctx.image_size) + { + bytes_read = ctx.image_size - total_copied; + } + + /* Write to flash */ + + ret = flash_area_write(ctx.fa, ctx.fa_offset, g_buffer, bytes_read); + if (ret != OK) + { + fprintf(stderr, "Failed to write to flash: %d\n", ret); + goto exit_close_flash; + } + + ctx.fa_offset += bytes_read; + total_copied += bytes_read; + + /* Show progress */ + + progress = (total_copied * 100) / ctx.image_size; + printf("Progress: %lu/%zd bytes [%lu%%]\n", + total_copied, ctx.image_size, progress); + } + + printf("Firmware copy completed successfully!\n"); + +exit_close_flash: + flash_area_close(ctx.fa); + +exit_close_file: + if (ctx.fd >= 0) + { + close(ctx.fd); + } + +exit: + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * mcuboot_local_agent_main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + int ret; + FAR const char *filepath; + + printf("MCUBoot Local Update Agent\n"); + + if (argc > 1) + { + filepath = argv[1]; + } + else + { + filepath = DEFAULT_FW_PATH; + } + + printf("Firmware file: %s\n", filepath); + + /* Copy firmware from local storage to secondary flash slot */ + + ret = copy_firmware_from_local(filepath); + if (ret != OK) + { + fprintf(stderr, "Firmware update failed: %d\n", ret); + return ERROR; + } + + printf("Firmware successfully copied to secondary slot!\n"); + + /* Mark image as pending for next boot */ + + boot_set_pending_multi(0, 0); + + printf("Update scheduled for next boot. Restarting...\n"); + + fflush(stdout); + fflush(stderr); + + usleep(1000000); /* Wait 1 second */ + + /* Restart system to apply update */ + + boardctl(BOARDIOC_RESET, 0); + + return OK; +}