mirror of
https://github.com/apache/nuttx-apps.git
synced 2025-10-16 05:27:11 +08:00
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.cavalcanti@espressif.com>
This commit is contained in:

committed by
Xiang Xiao

parent
a7e4a2a30e
commit
d27d6e635f
33
examples/mcuboot/update_agent_local/CMakeLists.txt
Normal file
33
examples/mcuboot/update_agent_local/CMakeLists.txt
Normal file
@@ -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()
|
41
examples/mcuboot/update_agent_local/Kconfig
Normal file
41
examples/mcuboot/update_agent_local/Kconfig
Normal file
@@ -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
|
25
examples/mcuboot/update_agent_local/Make.defs
Normal file
25
examples/mcuboot/update_agent_local/Make.defs
Normal file
@@ -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
|
32
examples/mcuboot/update_agent_local/Makefile
Normal file
32
examples/mcuboot/update_agent_local/Makefile
Normal file
@@ -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
|
298
examples/mcuboot/update_agent_local/mcuboot_local_agent_main.c
Normal file
298
examples/mcuboot/update_agent_local/mcuboot_local_agent_main.c
Normal file
@@ -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;
|
||||||
|
}
|
Reference in New Issue
Block a user