stm32/mboot: Decouple stream, filesystem and top-level loading code.
This commit factors the code for files and streaming to separate source files (vfs_fat.c and gzstream.c respectively) and introduces an abstract gzstream interface to make it easier to plug in different filesystems. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
763bd448a4
commit
390f32922d
|
@ -102,7 +102,8 @@ SRC_C = \
|
|||
main.c \
|
||||
elem.c \
|
||||
fsload.c \
|
||||
diskio.c \
|
||||
gzstream.c \
|
||||
vfs_fat.c \
|
||||
drivers/bus/softspi.c \
|
||||
drivers/bus/softqspi.c \
|
||||
drivers/memory/spiflash.c \
|
||||
|
|
|
@ -27,81 +27,18 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "extmod/uzlib/uzlib.h"
|
||||
#include "mboot.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#if MBOOT_FSLOAD
|
||||
|
||||
#define DICT_SIZE (1 << 15)
|
||||
|
||||
typedef struct _gz_stream_t {
|
||||
FIL fp;
|
||||
TINF_DATA tinf;
|
||||
uint8_t buf[512];
|
||||
uint8_t dict[DICT_SIZE];
|
||||
} gz_stream_t;
|
||||
|
||||
static gz_stream_t gz_stream SECTION_NOZERO_BSS;
|
||||
|
||||
static int gz_stream_read_src(TINF_DATA *tinf) {
|
||||
UINT n;
|
||||
FRESULT res = f_read(&gz_stream.fp, gz_stream.buf, sizeof(gz_stream.buf), &n);
|
||||
if (res != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
}
|
||||
tinf->source = gz_stream.buf + 1;
|
||||
tinf->source_limit = gz_stream.buf + n;
|
||||
return gz_stream.buf[0];
|
||||
}
|
||||
|
||||
static int gz_stream_open(FATFS *fatfs, const char *filename) {
|
||||
FRESULT res = f_open(fatfs, &gz_stream.fp, filename, FA_READ);
|
||||
if (res != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
memset(&gz_stream.tinf, 0, sizeof(gz_stream.tinf));
|
||||
gz_stream.tinf.readSource = gz_stream_read_src;
|
||||
|
||||
int st = uzlib_gzip_parse_header(&gz_stream.tinf);
|
||||
if (st != TINF_OK) {
|
||||
f_close(&gz_stream.fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uzlib_uncompress_init(&gz_stream.tinf, gz_stream.dict, DICT_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gz_stream_read(size_t len, uint8_t *buf) {
|
||||
gz_stream.tinf.dest = buf;
|
||||
gz_stream.tinf.dest_limit = buf + len;
|
||||
int st = uzlib_uncompress_chksum(&gz_stream.tinf);
|
||||
if (st == TINF_DONE) {
|
||||
return 0;
|
||||
}
|
||||
if (st < 0) {
|
||||
return st;
|
||||
}
|
||||
return gz_stream.tinf.dest - buf;
|
||||
}
|
||||
|
||||
static int fsload_program_file(FATFS *fatfs, const char *filename, bool write_to_flash) {
|
||||
int res = gz_stream_open(fatfs, filename);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fsload_program_file(bool write_to_flash) {
|
||||
// Parse DFU
|
||||
uint8_t buf[512];
|
||||
size_t file_offset;
|
||||
|
||||
// Read file header, <5sBIB
|
||||
res = gz_stream_read(11, buf);
|
||||
int res = gz_stream_read(11, buf);
|
||||
if (res != 11) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -204,26 +141,23 @@ static int fsload_program_file(FATFS *fatfs, const char *filename, bool write_to
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsload_process_fatfs(uint32_t base_addr, uint32_t byte_len, const char *fname) {
|
||||
fsload_bdev_t bdev = {base_addr, byte_len};
|
||||
FATFS fatfs;
|
||||
fatfs.drv = &bdev;
|
||||
FRESULT res = f_mount(&fatfs);
|
||||
if (res != FR_OK) {
|
||||
return -1;
|
||||
static int fsload_validate_and_program_file(void *stream, const stream_methods_t *meth, const char *fname) {
|
||||
// First pass verifies the file, second pass programs it
|
||||
for (unsigned int pass = 0; pass <= 1; ++pass) {
|
||||
led_state_all(pass == 0 ? 2 : 4);
|
||||
int res = meth->open(stream, fname);
|
||||
if (res == 0) {
|
||||
res = gz_stream_init(stream, meth->read);
|
||||
if (res == 0) {
|
||||
res = fsload_program_file(pass == 0 ? false : true);
|
||||
}
|
||||
}
|
||||
meth->close(stream);
|
||||
if (res != 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate firmware
|
||||
led_state_all(2);
|
||||
int r = fsload_program_file(&fatfs, fname, false);
|
||||
|
||||
if (r == 0) {
|
||||
// Firmware is valid, program it
|
||||
led_state_all(4);
|
||||
r = fsload_program_file(&fatfs, fname, true);
|
||||
}
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsload_process(void) {
|
||||
|
@ -250,7 +184,11 @@ int fsload_process(void) {
|
|||
uint32_t base_addr = get_le32(&elem[2]);
|
||||
uint32_t byte_len = get_le32(&elem[6]);
|
||||
if (elem[1] == ELEM_MOUNT_FAT) {
|
||||
int ret = fsload_process_fatfs(base_addr, byte_len, fname);
|
||||
vfs_fat_context_t ctx;
|
||||
int ret = vfs_fat_mount(&ctx, base_addr, byte_len);
|
||||
if (ret == 0) {
|
||||
ret = fsload_validate_and_program_file(&ctx, &vfs_fat_stream_methods, fname);
|
||||
}
|
||||
// Flash LEDs based on success/failure of update
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (ret == 0) {
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2020 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mphal.h"
|
||||
#include "extmod/uzlib/uzlib.h"
|
||||
#include "gzstream.h"
|
||||
#include "mboot.h"
|
||||
|
||||
#if MBOOT_FSLOAD
|
||||
|
||||
#define DICT_SIZE (1 << 15)
|
||||
|
||||
typedef struct _gz_stream_t {
|
||||
void *stream_data;
|
||||
stream_read_t stream_read;
|
||||
TINF_DATA tinf;
|
||||
uint8_t buf[512];
|
||||
uint8_t dict[DICT_SIZE];
|
||||
} gz_stream_t;
|
||||
|
||||
static gz_stream_t gz_stream SECTION_NOZERO_BSS;
|
||||
|
||||
static int gz_stream_read_src(TINF_DATA *tinf) {
|
||||
int n = gz_stream.stream_read(gz_stream.stream_data, gz_stream.buf, sizeof(gz_stream.buf));
|
||||
if (n < 0) {
|
||||
// Stream error
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) {
|
||||
// No data / EOF
|
||||
return -1;
|
||||
}
|
||||
|
||||
tinf->source = gz_stream.buf + 1;
|
||||
tinf->source_limit = gz_stream.buf + n;
|
||||
return gz_stream.buf[0];
|
||||
}
|
||||
|
||||
int gz_stream_init(void *stream_data, stream_read_t stream_read) {
|
||||
gz_stream.stream_data = stream_data;
|
||||
gz_stream.stream_read = stream_read;
|
||||
|
||||
memset(&gz_stream.tinf, 0, sizeof(gz_stream.tinf));
|
||||
gz_stream.tinf.readSource = gz_stream_read_src;
|
||||
|
||||
int st = uzlib_gzip_parse_header(&gz_stream.tinf);
|
||||
if (st != TINF_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uzlib_uncompress_init(&gz_stream.tinf, gz_stream.dict, DICT_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gz_stream_read(size_t len, uint8_t *buf) {
|
||||
gz_stream.tinf.dest = buf;
|
||||
gz_stream.tinf.dest_limit = buf + len;
|
||||
int st = uzlib_uncompress_chksum(&gz_stream.tinf);
|
||||
if (st == TINF_DONE) {
|
||||
return 0;
|
||||
}
|
||||
if (st < 0) {
|
||||
return st;
|
||||
}
|
||||
return gz_stream.tinf.dest - buf;
|
||||
}
|
||||
|
||||
#endif // MBOOT_FSLOAD
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2020 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STM32_MBOOT_GZSTREAM_H
|
||||
#define MICROPY_INCLUDED_STM32_MBOOT_GZSTREAM_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int (*stream_open_t)(void *stream, const char *fname);
|
||||
typedef void (*stream_close_t)(void *stream);
|
||||
typedef int (*stream_read_t)(void *stream, uint8_t *buf, size_t len);
|
||||
|
||||
typedef struct _stream_methods_t {
|
||||
stream_open_t open;
|
||||
stream_close_t close;
|
||||
stream_read_t read;
|
||||
} stream_methods_t;
|
||||
|
||||
int gz_stream_init(void *stream_data, stream_read_t stream_read);
|
||||
int gz_stream_read(size_t len, uint8_t *buf);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_MBOOT_GZSTREAM_H
|
|
@ -44,11 +44,6 @@ enum {
|
|||
ELEM_MOUNT_FAT = 1,
|
||||
};
|
||||
|
||||
typedef struct _fsload_bdev_t {
|
||||
uint32_t base_addr;
|
||||
uint32_t byte_len;
|
||||
} fsload_bdev_t;
|
||||
|
||||
extern uint8_t _estack[ELEM_DATA_SIZE];
|
||||
|
||||
uint32_t get_le32(const uint8_t *b);
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2020 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef MICROPY_INCLUDED_STM32_MBOOT_VFS_H
|
||||
#define MICROPY_INCLUDED_STM32_MBOOT_VFS_H
|
||||
|
||||
#include "lib/oofatfs/ff.h"
|
||||
#include "gzstream.h"
|
||||
|
||||
typedef struct _vfs_fat_context_t {
|
||||
uint32_t bdev_base_addr;
|
||||
uint32_t bdev_byte_len;
|
||||
FATFS fatfs;
|
||||
FIL fp;
|
||||
} vfs_fat_context_t;
|
||||
|
||||
extern const stream_methods_t vfs_fat_stream_methods;
|
||||
|
||||
int vfs_fat_mount(vfs_fat_context_t *ctx, uint32_t base_addr, uint32_t byte_len);
|
||||
|
||||
#endif // MICROPY_INCLUDED_STM32_MBOOT_VFS_H
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Damien P. George
|
||||
* Copyright (c) 2019-2020 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -28,6 +28,7 @@
|
|||
#include "lib/oofatfs/ff.h"
|
||||
#include "lib/oofatfs/diskio.h"
|
||||
#include "mboot.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#if MBOOT_FSLOAD
|
||||
|
||||
|
@ -38,10 +39,10 @@
|
|||
#endif
|
||||
|
||||
DRESULT disk_read(void *pdrv, BYTE *buf, DWORD sector, UINT count) {
|
||||
fsload_bdev_t *bdev = pdrv;
|
||||
vfs_fat_context_t *ctx = pdrv;
|
||||
|
||||
if (0 <= sector && sector < bdev->byte_len / 512) {
|
||||
do_read(bdev->base_addr + sector * SECSIZE, count * SECSIZE, buf);
|
||||
if (0 <= sector && sector < ctx->bdev_byte_len / 512) {
|
||||
do_read(ctx->bdev_base_addr + sector * SECSIZE, count * SECSIZE, buf);
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
|
@ -49,14 +50,14 @@ DRESULT disk_read(void *pdrv, BYTE *buf, DWORD sector, UINT count) {
|
|||
}
|
||||
|
||||
DRESULT disk_ioctl(void *pdrv, BYTE cmd, void *buf) {
|
||||
fsload_bdev_t *bdev = pdrv;
|
||||
vfs_fat_context_t *ctx = pdrv;
|
||||
|
||||
switch (cmd) {
|
||||
case CTRL_SYNC:
|
||||
return RES_OK;
|
||||
|
||||
case GET_SECTOR_COUNT:
|
||||
*((DWORD*)buf) = bdev->byte_len / SECSIZE;
|
||||
*((DWORD*)buf) = ctx->bdev_byte_len / SECSIZE;
|
||||
return RES_OK;
|
||||
|
||||
case GET_SECTOR_SIZE:
|
||||
|
@ -77,4 +78,45 @@ DRESULT disk_ioctl(void *pdrv, BYTE cmd, void *buf) {
|
|||
}
|
||||
}
|
||||
|
||||
int vfs_fat_mount(vfs_fat_context_t *ctx, uint32_t base_addr, uint32_t byte_len) {
|
||||
ctx->bdev_base_addr = base_addr;
|
||||
ctx->bdev_byte_len = byte_len;
|
||||
ctx->fatfs.drv = ctx;
|
||||
FRESULT res = f_mount(&ctx->fatfs);
|
||||
if (res != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfs_fat_stream_open(void *stream_in, const char *fname) {
|
||||
vfs_fat_context_t *stream = stream_in;
|
||||
FRESULT res = f_open(&stream->fatfs, &stream->fp, fname, FA_READ);
|
||||
if (res != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vfs_fat_stream_close(void *stream_in) {
|
||||
vfs_fat_context_t *stream = stream_in;
|
||||
f_close(&stream->fp);
|
||||
}
|
||||
|
||||
static int vfs_fat_stream_read(void *stream_in, uint8_t *buf, size_t len) {
|
||||
vfs_fat_context_t *stream = stream_in;
|
||||
UINT n;
|
||||
FRESULT res = f_read(&stream->fp, buf, len, &n);
|
||||
if (res != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
const stream_methods_t vfs_fat_stream_methods = {
|
||||
vfs_fat_stream_open,
|
||||
vfs_fat_stream_close,
|
||||
vfs_fat_stream_read,
|
||||
};
|
||||
|
||||
#endif // MBOOT_FSLOAD
|
Loading…
Reference in New Issue