Skip to content

Further refine autoreload #6153

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

Merged
merged 1 commit into from
Mar 15, 2022
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
13 changes: 7 additions & 6 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ msgstr ""
#: main.c
msgid ""
"\n"
"Code stopped by auto-reload.\n"
"Code stopped by auto-reload. Reloading soon.\n"
msgstr ""

#: supervisor/shared/safe_mode.c
Expand Down Expand Up @@ -584,10 +584,6 @@ msgstr ""
msgid "Brightness must be 0-1.0"
msgstr ""

#: shared-bindings/supervisor/__init__.c
msgid "Brightness must be between 0 and 255"
msgstr ""

#: shared-bindings/displayio/Display.c
#: shared-bindings/framebufferio/FramebufferDisplay.c
msgid "Brightness not adjustable"
Expand Down Expand Up @@ -688,6 +684,7 @@ msgstr ""
msgid "Can only alarm on two low pins from deep sleep."
msgstr ""

#: ports/espressif/common-hal/_bleio/Characteristic.c
#: ports/nrf/common-hal/_bleio/Characteristic.c
msgid "Can't set CCCD on local Characteristic"
msgstr ""
Expand Down Expand Up @@ -1605,6 +1602,7 @@ msgstr ""
msgid "Nimble out of memory"
msgstr ""

#: ports/espressif/common-hal/_bleio/Characteristic.c
#: ports/nrf/common-hal/_bleio/Characteristic.c
msgid "No CCCD for this Characteristic"
msgstr ""
Expand Down Expand Up @@ -3642,7 +3640,7 @@ msgstr ""
msgid "matrix is not positive definite"
msgstr ""

#: shared-bindings/wifi/Radio.c
#: ports/espressif/common-hal/wifi/Radio.c
msgid "max_connections must be between 0 and 10"
msgstr ""

Expand Down Expand Up @@ -4061,13 +4059,15 @@ msgstr ""
#: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
#: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
#: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
#: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
#: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
#: ports/espressif/boards/artisense_rd00/mpconfigboard.h
#: ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h
#: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
#: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
Expand All @@ -4083,6 +4083,7 @@ msgstr ""
#: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
#: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
#: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
#: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
#: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
#: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h
Expand Down
39 changes: 15 additions & 24 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ static void reset_devices(void) {
}

STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
autoreload_reset();
supervisor_workflow_reset();

// Stack limit should be less than real stack size, so we have a chance
Expand Down Expand Up @@ -336,7 +335,13 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
// Collects stickiness bits that apply in the current situation.
uint8_t next_code_stickiness_situation = SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;

// Do the filesystem flush check before reload in case another write comes
// in while we're doing the flush.
if (safe_mode == NO_SAFE_MODE) {
stack_resize();
filesystem_flush();
}
if (safe_mode == NO_SAFE_MODE && !autoreload_pending()) {
static const char *const supported_filenames[] = STRING_LIST(
"code.txt", "code.py", "main.py", "main.txt");
#if CIRCUITPY_FULL_BUILD
Expand All @@ -345,8 +350,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
"main.txt.py", "main.py.txt", "main.txt.txt","main.py.py");
#endif

stack_resize();
filesystem_flush();
supervisor_allocation *heap = allocate_remaining_memory();

// Prepare the VM state. Includes an alarm check/reset for sleep.
Expand Down Expand Up @@ -390,22 +393,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
// Print done before resetting everything so that we get the message over
// BLE before it is reset and we have a delay before reconnect.
if ((result.return_code & PYEXEC_RELOAD) && supervisor_get_run_reason() == RUN_REASON_AUTO_RELOAD) {
serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));

// Wait for autoreload interval before reloading
uint64_t start_ticks = 0;
do {
// Start waiting, or restart interval if another reload request was initiated
// while we were waiting.
if (reload_requested) {
reload_requested = false;
start_ticks = supervisor_ticks_ms64();
}
RUN_BACKGROUND_TASKS;
} while (supervisor_ticks_ms64() - start_ticks < CIRCUITPY_AUTORELOAD_DELAY_MS);

// Restore request for use below.
reload_requested = true;
serial_write_compressed(translate("\nCode stopped by auto-reload. Reloading soon.\n"));
} else {
serial_write_compressed(translate("\nCode done running.\n"));
}
Expand All @@ -425,8 +413,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re

if (result.return_code & PYEXEC_RELOAD) {
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
skip_repl = true;
skip_wait = true;
} else if (result.return_code == 0) {
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) {
Expand Down Expand Up @@ -484,22 +470,27 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
size_t total_time = blink_time + LED_SLEEP_TIME_MS;
#endif

// This loop is waits after code completes. It waits for fake sleeps to
// finish, user input or autoreloads.
#if CIRCUITPY_ALARM
bool fake_sleeping = false;
#endif
while (!skip_wait) {
RUN_BACKGROUND_TASKS;

// If a reload was requested by the supervisor or autoreload, return.
if (reload_requested) {
if (autoreload_ready()) {
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
// Should the STICKY_ON_SUCCESS and STICKY_ON_ERROR bits be cleared in
// next_code_stickiness_situation? I can see arguments either way, but I'm deciding
// "no" for now, mainly because it's a bit less code. At this point, we have both a
// success or error and a reload, so let's have both of the respective options take
// effect (in OR combination).
reload_requested = false;
skip_repl = true;
// We're kicking off the autoreload process so reset now. If any
// other reloads trigger after this, then we'll want another wait
// period.
autoreload_reset();
break;
}

Expand All @@ -526,7 +517,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
#endif

// If messages haven't been printed yet, print them
if (!printed_press_any_key && serial_connected()) {
if (!printed_press_any_key && serial_connected() && !autoreload_pending()) {
if (!serial_connected_at_start) {
print_code_py_status_message(safe_mode);
}
Expand Down
2 changes: 0 additions & 2 deletions ports/stm/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,6 @@ void port_enable_tick(void) {
stm32_peripherals_rtc_assign_wkup_callback(supervisor_tick);
stm32_peripherals_rtc_enable_wakeup_timer();
}
// TODO: what is this? can I get rid of it?
extern volatile uint32_t autoreload_delay_ms;

// Disable 1/1024 second tick.
void port_disable_tick(void) {
Expand Down
2 changes: 1 addition & 1 deletion shared-module/displayio/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void displayio_background(void) {
if (mp_hal_is_interrupted()) {
return;
}
if (reload_requested) {
if (autoreload_ready()) {
// Reload is about to happen, so don't redisplay.
return;
}
Expand Down
15 changes: 5 additions & 10 deletions supervisor/shared/bluetooth/file_transfer.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,8 +325,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
if (chunk_size == 0) {
// Don't reload until everything is written out of the packet buffer.
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
// Trigger an autoreload
autoreload_start();
autoreload_trigger();
return ANY_COMMAND;
}

Expand Down Expand Up @@ -383,8 +382,7 @@ STATIC uint8_t _process_write_data(const uint8_t *raw_buf, size_t command_len) {
#endif
// Don't reload until everything is written out of the packet buffer.
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
// Trigger an autoreload
autoreload_start();
autoreload_trigger();
return ANY_COMMAND;
}
return WRITE_DATA;
Expand Down Expand Up @@ -465,8 +463,7 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
if (result == FR_OK) {
// Don't reload until everything is written out of the packet buffer.
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
// Trigger an autoreload
autoreload_start();
autoreload_trigger();
}
return ANY_COMMAND;
}
Expand Down Expand Up @@ -520,8 +517,7 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) {
if (result == FR_OK) {
// Don't reload until everything is written out of the packet buffer.
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
// Trigger an autoreload
autoreload_start();
autoreload_trigger();
}
return ANY_COMMAND;
}
Expand Down Expand Up @@ -668,8 +664,7 @@ STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) {
if (result == FR_OK) {
// Don't reload until everything is written out of the packet buffer.
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
// Trigger an autoreload
autoreload_start();
autoreload_trigger();
}
return ANY_COMMAND;
}
Expand Down
39 changes: 32 additions & 7 deletions supervisor/shared/reload.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,9 @@ static bool autoreload_enabled = false;
// Non-zero if autoreload is temporarily off, due to an AUTORELOAD_SUSPEND_... reason.
static uint32_t autoreload_suspended = 0;

// True if something has requested a reload/restart.
volatile bool reload_requested = false;
volatile uint32_t last_autoreload_trigger = 0;

void reload_initiate(supervisor_run_reason_t run_reason) {
reload_requested = true;
supervisor_set_run_reason(run_reason);

// Raise reload exception, in case code is running.
Expand All @@ -57,12 +55,12 @@ void reload_initiate(supervisor_run_reason_t run_reason) {
}

void autoreload_reset() {
reload_requested = false;
last_autoreload_trigger = 0;
}

void autoreload_enable() {
autoreload_enabled = true;
reload_requested = false;
last_autoreload_trigger = 0;
}

void autoreload_disable() {
Expand All @@ -81,8 +79,35 @@ inline bool autoreload_is_enabled() {
return autoreload_enabled;
}

void autoreload_start() {
if (autoreload_enabled && autoreload_suspended == 0) {
void autoreload_trigger() {
if (autoreload_enabled) {
last_autoreload_trigger = supervisor_ticks_ms32();
// Guard against the rare time that ticks is 0;
if (last_autoreload_trigger == 0) {
last_autoreload_trigger += 1;
}
// Initiate a reload of the VM immediately. Later code will pause to
// wait for the autoreload to become ready. Doing the VM exit
// immediately is clearer for the user.
reload_initiate(RUN_REASON_AUTO_RELOAD);
}
}

bool autoreload_ready() {
if (last_autoreload_trigger == 0 || autoreload_suspended != 0) {
return false;
}
// Wait for autoreload interval before reloading
uint32_t now = supervisor_ticks_ms32();
uint32_t diff;
if (now >= last_autoreload_trigger) {
diff = now - last_autoreload_trigger;
} else {
diff = now + (0xffffffff - last_autoreload_trigger);
}
return diff > CIRCUITPY_AUTORELOAD_DELAY_MS;
}

bool autoreload_pending(void) {
return last_autoreload_trigger != 0;
}
25 changes: 19 additions & 6 deletions supervisor/shared/reload.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ enum {

enum {
AUTORELOAD_SUSPEND_REPL = 0x1,
AUTORELOAD_SUSPEND_BLE = 0x2
AUTORELOAD_SUSPEND_BLE = 0x2,
AUTORELOAD_SUSPEND_USB = 0x4
};

typedef struct {
Expand All @@ -52,17 +53,29 @@ typedef struct {

extern supervisor_allocation *next_code_allocation;

extern volatile bool reload_requested;

// Helper for exiting the VM and reloading immediately.
void reload_initiate(supervisor_run_reason_t run_reason);

void autoreload_start(void);
void autoreload_reset(void);
// Enabled state is user controllable and very sticky. We don't reset it.
void autoreload_enable(void);
void autoreload_disable(void);
bool autoreload_is_enabled(void);

// Temporarily turn autoreload off, for the given reason(s).
// Start the autoreload process.
void autoreload_trigger(void);
// True when the autoreload should occur. (A trigger happened and the delay has
// passed.)
bool autoreload_ready(void);
// Reset the autoreload timer in preparation for another trigger. Call when the
// last trigger starts being executed.
void autoreload_reset(void);
// True when a trigger has occurred but we're still delaying in case another
// trigger occurs.
bool autoreload_pending(void);

// Temporarily turn autoreload off, for the given reason(s). Autoreload triggers
// will still be tracked so resuming with autoreload ready with cause an
// immediate reload.
// Used during the REPL or during parts of BLE workflow.
void autoreload_suspend(uint32_t suspend_reason_mask);
// Allow autoreloads again, for the given reason(s).
Expand Down
4 changes: 3 additions & 1 deletion supervisor/shared/usb/usb_msc_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
(void)lun;
(void)offset;
autoreload_suspend(AUTORELOAD_SUSPEND_USB);

const uint32_t block_count = bufsize / MSC_FLASH_BLOCK_SIZE;

Expand Down Expand Up @@ -215,7 +216,8 @@ void tud_msc_write10_complete_cb(uint8_t lun) {
(void)lun;

// This write is complete; initiate an autoreload.
autoreload_start();
autoreload_trigger();
autoreload_resume(AUTORELOAD_SUSPEND_USB);
}

// Invoked when received SCSI_CMD_INQUIRY
Expand Down