Skip to content

Commit 4770120

Browse files
authored
Merge pull request #5536 from jepler/better_boot_out_txt
main: redesign boot_out.txt writing
2 parents ec7fc6f + efffb62 commit 4770120

File tree

4 files changed

+61
-76
lines changed

4 files changed

+61
-76
lines changed

main.c

Lines changed: 50 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
635635
return skip_repl;
636636
}
637637

638-
FIL* boot_output_file;
638+
vstr_t *boot_output;
639639

640640
STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
641641
// 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) {
645645
&& safe_mode == NO_SAFE_MODE
646646
&& MP_STATE_VM(vfs_mount_table) != NULL;
647647

648-
static const char * const boot_py_filenames[] = STRING_LIST("boot.py", "boot.txt");
649-
bool skip_boot_output = false;
650-
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
651-
FIL file_pointer;
652-
#endif
653-
654-
if (ok_to_run) {
655-
656-
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
657-
boot_output_file = &file_pointer;
658-
659-
// Get the base filesystem.
660-
FATFS *fs = &((fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj)->fatfs;
661-
662-
bool have_boot_py = first_existing_file_in_list(boot_py_filenames) != NULL;
663-
664-
// If there's no boot.py file that might write some changing output,
665-
// read the existing copy of CIRCUITPY_BOOT_OUTPUT_FILE and see if its contents
666-
// match the version info we would print anyway. If so, skip writing CIRCUITPY_BOOT_OUTPUT_FILE.
667-
// This saves wear and tear on the flash and also prevents filesystem damage if power is lost
668-
// during the write, which may happen due to bobbling the power connector or weak power.
669-
670-
static const size_t NUM_CHARS_TO_COMPARE = 160;
671-
if (!have_boot_py && f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
672-
673-
char file_contents[NUM_CHARS_TO_COMPARE];
674-
UINT chars_read = 0;
675-
f_read(boot_output_file, file_contents, NUM_CHARS_TO_COMPARE, &chars_read);
676-
f_close(boot_output_file);
677-
skip_boot_output =
678-
// + 2 accounts for \r\n.
679-
chars_read == strlen(MICROPY_FULL_VERSION_INFO) + 2 &&
680-
strncmp(file_contents, MICROPY_FULL_VERSION_INFO, strlen(MICROPY_FULL_VERSION_INFO)) == 0;
681-
}
682-
683-
if (!skip_boot_output) {
684-
// Wait 1.5 seconds before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
685-
// in case power is momentary or will fail shortly due to, say a low, battery.
686-
if (common_hal_mcu_processor_get_reset_reason() == RESET_REASON_POWER_ON) {
687-
mp_hal_delay_ms(1500);
688-
}
689-
// USB isn't up, so we can write the file.
690-
filesystem_set_internal_writable_by_usb(false);
691-
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
692-
693-
// Switch the filesystem back to non-writable by Python now instead of later,
694-
// since boot.py might change it back to writable.
695-
filesystem_set_internal_writable_by_usb(true);
696-
697-
// Write version info to boot_out.txt.
698-
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
699-
// Write the board ID (board directory and ID on circuitpython.org)
700-
mp_hal_stdout_tx_str("\r\n" "Board ID:");
701-
mp_hal_stdout_tx_str(CIRCUITPY_BOARD_ID);
702-
mp_hal_stdout_tx_str("\r\n");
703-
}
704-
#endif
705-
706-
filesystem_flush();
648+
if (!ok_to_run) {
649+
return;
707650
}
708651

652+
static const char * const boot_py_filenames[] = STRING_LIST("boot.py", "boot.txt");
653+
709654
// Do USB setup even if boot.py is not run.
710655

711656
supervisor_allocation* heap = allocate_remaining_memory();
@@ -716,20 +661,55 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
716661
usb_set_defaults();
717662
#endif
718663

664+
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
665+
vstr_t boot_text;
666+
vstr_init(&boot_text, 512);
667+
boot_output = &boot_text;
668+
#endif
669+
670+
// Write version info
671+
mp_printf(&mp_plat_print, "%s\nBoard ID:%s\n", MICROPY_FULL_VERSION_INFO, CIRCUITPY_BOARD_ID);
672+
719673
pyexec_result_t result = {0, MP_OBJ_NULL, 0};
720-
if (ok_to_run) {
721-
bool found_boot = maybe_run_list(boot_py_filenames, &result);
722-
(void) found_boot;
723-
724-
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
725-
if (!skip_boot_output) {
726-
f_close(boot_output_file);
727-
filesystem_flush();
674+
675+
bool found_boot = maybe_run_list(boot_py_filenames, &result);
676+
(void) found_boot;
677+
678+
679+
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
680+
// Get the base filesystem.
681+
fs_user_mount_t *vfs = (fs_user_mount_t *) MP_STATE_VM(vfs_mount_table)->obj;
682+
FATFS *fs = &vfs->fatfs;
683+
684+
boot_output = NULL;
685+
bool write_boot_output = (common_hal_mcu_processor_get_reset_reason() == RESET_REASON_POWER_ON);
686+
FIL boot_output_file;
687+
if (f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_READ) == FR_OK) {
688+
char *file_contents = m_new(char, boot_text.alloc);
689+
UINT chars_read;
690+
if (f_read(&boot_output_file, file_contents, 1+boot_text.len, &chars_read) == FR_OK) {
691+
write_boot_output =
692+
(chars_read != boot_text.len) || (memcmp(boot_text.buf, file_contents, chars_read) != 0);
728693
}
729-
boot_output_file = NULL;
730-
#endif
694+
// no need to f_close the file
731695
}
732696

697+
if (write_boot_output) {
698+
// Wait 1 second before opening CIRCUITPY_BOOT_OUTPUT_FILE for write,
699+
// in case power is momentary or will fail shortly due to, say a low, battery.
700+
mp_hal_delay_ms(1000);
701+
702+
// USB isn't up, so we can write the file.
703+
// operating at the oofatfs (f_open) layer means the usb concurrent write permission
704+
// is not even checked!
705+
f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
706+
UINT chars_written;
707+
f_write(&boot_output_file, boot_text.buf, boot_text.len, &chars_written);
708+
f_close(&boot_output_file);
709+
filesystem_flush();
710+
}
711+
#endif
712+
733713
#if CIRCUITPY_USB
734714
// Some data needs to be carried over from the USB settings in boot.py
735715
// to the next VM, while the heap is still available.

py/makeversionhdr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def make_version_header(filename):
107107
#define MICROPY_VERSION_MINOR (%s)
108108
#define MICROPY_VERSION_MICRO (%s)
109109
#define MICROPY_VERSION_STRING "%s"
110-
#define MICROPY_FULL_VERSION_INFO ("Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME)
110+
#define MICROPY_FULL_VERSION_INFO "Adafruit CircuitPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME
111111
""" % (
112112
git_tag,
113113
git_hash,

supervisor/serial.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@
3434
#include "py/mpconfig.h"
3535

3636
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
37-
#include "lib/oofatfs/ff.h"
37+
#include "py/misc.h"
3838

39-
extern FIL *boot_output_file;
39+
extern vstr_t *boot_output;
4040
#endif
4141

4242
void serial_early_init(void);

supervisor/shared/micropython.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,14 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
5959
toggle_tx_led();
6060

6161
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
62-
if (boot_output_file != NULL) {
63-
UINT bytes_written = 0;
64-
f_write(boot_output_file, str, len, &bytes_written);
62+
if (boot_output != NULL) {
63+
// Ensure boot_out.txt is capped at 1 filesystem block and ends with a newline
64+
if (len + boot_output->len > 508) {
65+
vstr_add_str(boot_output, "...\n");
66+
boot_output = NULL;
67+
} else {
68+
vstr_add_strn(boot_output, str, len);
69+
}
6570
}
6671
#endif
6772

0 commit comments

Comments
 (0)