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;
+}

Reply via email to