Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main: redesign boot_out.txt writing #5536

Merged
merged 2 commits into from
Nov 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 50 additions & 70 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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();
Expand All @@ -716,20 +661,55 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
usb_set_defaults();
#endif

#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
vstr_t boot_text;
vstr_init(&boot_text, 512);
boot_output = &boot_text;
#endif

// 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};
if (ok_to_run) {
bool found_boot = maybe_run_list(boot_py_filenames, &result);
(void) found_boot;

#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
if (!skip_boot_output) {
f_close(boot_output_file);
filesystem_flush();

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.
Expand Down
2 changes: 1 addition & 1 deletion py/makeversionhdr.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions supervisor/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions supervisor/shared/micropython.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down