Files
nuttx-apps/examples/mcuboot/update_agent_local/mcuboot_local_agent_main.c
Filipe Cavalcanti d27d6e635f 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>
2025-07-16 09:49:45 +08:00

299 lines
7.7 KiB
C

/****************************************************************************
* 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;
}