Merge pull request #5536 from jepler/better_boot_out_txt

main: redesign boot_out.txt writing
This commit is contained in:
Dan Halbert 2021-11-02 21:55:00 -04:00 committed by GitHub
commit 4770120c60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 76 deletions

120
main.c
View File

@ -635,7 +635,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
return skip_repl;
}
FIL* boot_output_file;
vstr_t *boot_output;
STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
// If not in safe mode, run boot before initing USB and capture output in a file.
@ -645,67 +645,12 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
&& safe_mode == NO_SAFE_MODE
&& MP_STATE_VM(vfs_mount_table) != NULL;
static const char * const boot_py_filenames[] = STRING_LIST("boot.py", "boot.txt");
bool skip_boot_output = false;
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
FIL file_pointer;
#endif
if (ok_to_run) {
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
boot_output_file = &file_pointer;
// Get the base filesystem.
FATFS *fs = &((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs;
bool have_boot_py = first_existing_file_in_list(boot_py_filenames) != NULL;
// If there's no boot.py file that might write some changing output,
// read the existing copy of CIRCUITPY_BOOT_OUTPUT_FILE and see if its contents
// match the version info we would print anyway. If so, skip writing CIRCUITPY_BOOT_OUTPUT_FILE.
// This saves wear and tear on the flash and also prevents filesystem damage if power is lost
// during the write, which may happen due to bobbling the power connector or weak power.
static const size_t NUM_CHARS_TO_COMPARE = 160;
if (!have_boot_py && f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
char file_contents[NUM_CHARS_TO_COMPARE];
UINT chars_read = 0;
f_read(boot_output_file, file_contents, NUM_CHARS_TO_COMPARE, &chars_read);
f_close(boot_output_file);
skip_boot_output =
// + 2 accounts for \r\n.
chars_read == strlen(MICROPY_FULL_VERSION_INFO) + 2 &&
strncmp(file_contents, MICROPY_FULL_VERSION_INFO, strlen(MICROPY_FULL_VERSION_INFO)) == 0;
}
if (!skip_boot_output) {
// Wait 1.5 seconds before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
// in case power is momentary or will fail shortly due to, say a low, battery.
if (common_hal_mcu_processor_get_reset_reason() == RESET_REASON_POWER_ON) {
mp_hal_delay_ms(1500);
}
// USB isn't up, so we can write the file.
filesystem_set_internal_writable_by_usb(false);
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
// Switch the filesystem back to non-writable by Python now instead of later,
// since boot.py might change it back to writable.
filesystem_set_internal_writable_by_usb(true);
// Write version info to boot_out.txt.
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
// Write the board ID (board directory and ID on circuitpython.org)
mp_hal_stdout_tx_str("\r\n" "Board ID:");
mp_hal_stdout_tx_str(CIRCUITPY_BOARD_ID);
mp_hal_stdout_tx_str("\r\n");
}
#endif
filesystem_flush();
if (!ok_to_run) {
return;
}
static const char * const boot_py_filenames[] = STRING_LIST("boot.py", "boot.txt");
// Do USB setup even if boot.py is not run.
supervisor_allocation* heap = allocate_remaining_memory();
@ -716,20 +661,55 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
usb_set_defaults();
#endif
pyexec_result_t result = {0, MP_OBJ_NULL, 0};
if (ok_to_run) {
bool found_boot = maybe_run_list(boot_py_filenames, &result);
(void) found_boot;
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
vstr_t boot_text;
vstr_init(&boot_text, 512);
boot_output = &boot_text;
#endif
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
if (!skip_boot_output) {
f_close(boot_output_file);
filesystem_flush();
// Write version info
mp_printf(&mp_plat_print, "%s\nBoard ID:%s\n", MICROPY_FULL_VERSION_INFO, CIRCUITPY_BOARD_ID);
pyexec_result_t result = {0, MP_OBJ_NULL, 0};
bool found_boot = maybe_run_list(boot_py_filenames, &result);
(void) found_boot;
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
// Get the base filesystem.
fs_user_mount_t *vfs = (fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj;
FATFS *fs = &vfs->fatfs;
boot_output = NULL;
bool write_boot_output = (common_hal_mcu_processor_get_reset_reason() == RESET_REASON_POWER_ON);
FIL boot_output_file;
if (f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
char *file_contents = m_new(char, boot_text.alloc);
UINT chars_read;
if (f_read(&boot_output_file, file_contents, 1+boot_text.len, &chars_read) == FR_OK) {
write_boot_output =
(chars_read != boot_text.len) || (memcmp(boot_text.buf, file_contents, chars_read) != 0);
}
boot_output_file = NULL;
#endif
// no need to f_close the file
}
if (write_boot_output) {
// Wait 1 second before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
// in case power is momentary or will fail shortly due to, say a low, battery.
mp_hal_delay_ms(1000);
// USB isn't up, so we can write the file.
// operating at the oofatfs (f_open) layer means the usb concurrent write permission
// is not even checked!
f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
UINT chars_written;
f_write(&boot_output_file, boot_text.buf, boot_text.len, &chars_written);
f_close(&boot_output_file);
filesystem_flush();
}
#endif
#if CIRCUITPY_USB
// Some data needs to be carried over from the USB settings in boot.py
// to the next VM, while the heap is still available.

View File

@ -107,7 +107,7 @@ def make_version_header(filename):
#define MICROPY_VERSION_MINOR (%s)
#define MICROPY_VERSION_MICRO (%s)
#define MICROPY_VERSION_STRING "%s"
#define MICROPY_FULL_VERSION_INFO ("Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME)
#define MICROPY_FULL_VERSION_INFO "Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME
""" % (
git_tag,
git_hash,

View File

@ -34,9 +34,9 @@
#include "py/mpconfig.h"
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
#include "lib/oofatfs/ff.h"
#include "py/misc.h"
extern FIL *boot_output_file;
extern vstr_t *boot_output;
#endif
void serial_early_init(void);

View File

@ -59,9 +59,14 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
toggle_tx_led();
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
if (boot_output_file != NULL) {
UINT bytes_written = 0;
f_write(boot_output_file, str, len, &bytes_written);
if (boot_output != NULL) {
// Ensure boot_out.txt is capped at 1 filesystem block and ends with a newline
if (len + boot_output->len > 508) {
vstr_add_str(boot_output, "...\n");
boot_output = NULL;
} else {
vstr_add_strn(boot_output, str, len);
}
}
#endif