Merge pull request #6132 from dhalbert/fix-autoreload

Make autoreload checking more robust
This commit is contained in:
Scott Shawcroft 2022-03-09 14:02:15 -08:00 committed by GitHub
commit 0957c1546f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 100 additions and 101 deletions

23
main.c
View File

@ -124,7 +124,7 @@ static void reset_devices(void) {
}
STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
autoreload_stop();
autoreload_reset();
supervisor_workflow_reset();
// Stack limit should be less than real stack size, so we have a chance
@ -329,7 +329,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
result.exception = MP_OBJ_NULL;
result.exception_line = 0;
bool skip_repl;
bool skip_repl = false;
bool skip_wait = false;
bool found_main = false;
uint8_t next_code_options = 0;
@ -389,13 +389,13 @@ 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 (reload_requested && result.return_code == PYEXEC_EXCEPTION) {
if (result.return_code == PYEXEC_RELOAD) {
serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
} else {
serial_write_compressed(translate("\nCode done running.\n"));
}
// Finished executing python code. Cleanup includes a board reset.
// Finished executing python code. Cleanup includes filesystem flush and a board reset.
cleanup_after_vm(heap, result.exception);
// If a new next code file was set, that is a reason to keep it (obviously). Stuff this into
@ -407,8 +407,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
next_code_options |= SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
}
if (reload_requested) {
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) {
@ -426,7 +428,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
}
}
if (result.return_code & PYEXEC_FORCED_EXIT) {
skip_repl = reload_requested;
skip_repl = false;
skip_wait = true;
}
}
@ -473,7 +475,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
RUN_BACKGROUND_TASKS;
// If a reload was requested by the supervisor or autoreload, return
if (reload_requested) {
if (result.return_code & PYEXEC_RELOAD) {
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
@ -627,13 +629,14 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
}
}
// Done waiting, start the board back up.
// free code allocation if unused
if ((next_code_options & next_code_stickiness_situation) == 0) {
free_memory(next_code_allocation);
next_code_allocation = NULL;
}
// Done waiting, start the board back up.
#if CIRCUITPY_STATUS_LED
if (led_active) {
new_status_color(BLACK);
@ -757,7 +760,7 @@ STATIC int run_repl(bool first_run) {
usb_setup_with_vm();
#endif
autoreload_suspend(AUTORELOAD_LOCK_REPL);
autoreload_suspend(AUTORELOAD_SUSPEND_REPL);
// Set the status LED to the REPL color before running the REPL. For
// NeoPixels and DotStars this will be sticky but for PWM or single LED it
@ -787,7 +790,7 @@ STATIC int run_repl(bool first_run) {
status_led_deinit();
#endif
autoreload_resume(AUTORELOAD_LOCK_REPL);
autoreload_resume(AUTORELOAD_SUSPEND_REPL);
return exit_code;
}

View File

@ -129,8 +129,9 @@
#include "common-hal/_pew/PewPew.h"
#endif
static volatile bool sleep_ok = true;
#ifdef SAMD21
static uint8_t _tick_event_channel = 0;
uint8_t _tick_event_channel;
// Sleeping requires a register write that can stall interrupt handling. Turning
// off sleeps allows for more accurate interrupt timing. (Python still thinks
@ -142,7 +143,13 @@ void rtc_start_pulse(void) {
void rtc_end_pulse(void) {
sleep_ok = true;
}
#endif
#endif // SAMD21
static void reset_ticks(void) {
#ifdef SAMD21
_tick_event_channel = EVSYS_SYNCH_NUM;
#endif
}
extern volatile bool mp_msc_enabled;
@ -426,9 +433,7 @@ void reset_port(void) {
#endif
reset_event_system();
#ifdef SAMD21
_tick_event_channel = EVSYS_SYNCH_NUM;
#endif
reset_ticks();
reset_all_pins();
@ -498,7 +503,7 @@ uint32_t port_get_saved_word(void) {
static volatile uint64_t overflowed_ticks = 0;
static uint32_t _get_count(uint64_t *overflow_count) {
while(1) {
while (1) {
// Disable interrupts so we can grab the count and the overflow atomically.
common_hal_mcu_disable_interrupts();
@ -521,7 +526,7 @@ static uint32_t _get_count(uint64_t *overflow_count) {
return count;
}
// Try again if overflow hasn't been processed yet.
// Try again if overflow hasn't been processed yet.
}
}
@ -620,7 +625,7 @@ void port_enable_tick(void) {
RTC->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_PER2;
#endif
#ifdef SAMD21
// SAMD21 ticks won't survive port_reset(). This *should* be ok since it'll
// SAMD21 ticks won't survive reset_port(). This *should* be ok since it'll
// be triggered by ticks and no Python will be running.
if (_tick_event_channel >= EVSYS_SYNCH_NUM) {
turn_on_event_system();
@ -653,6 +658,7 @@ void port_disable_tick(void) {
uint8_t value = 1 << _tick_event_channel;
EVSYS->INTENCLR.reg = EVSYS_INTENSET_EVD(value);
}
_tick_event_channel = EVSYS_SYNCH_NUM;
#endif
}

View File

@ -54,8 +54,6 @@
#define BOARD_USER_SAFE_MODE_ACTION translate("pressing the left button at start up\n")
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)

View File

@ -3,8 +3,6 @@
#define MICROPY_HW_BOARD_NAME "Arduino Nano 33 BLE"
#define MICROPY_HW_MCU_NAME "nRF52840"
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#define DEFAULT_I2C_BUS_SCL (&pin_P0_02)
#define DEFAULT_I2C_BUS_SDA (&pin_P0_31)

View File

@ -3,8 +3,6 @@
#define MICROPY_HW_BOARD_NAME "BastBLE"
#define MICROPY_HW_MCU_NAME "nRF52840"
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#if QSPI_FLASH_FILESYSTEM
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 30)
#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(0, 29)

View File

@ -53,8 +53,6 @@
#define SPI_FLASH_CS_PIN &pin_P0_20
#endif
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)

View File

@ -5,8 +5,6 @@
#define MICROPY_HW_LED_STATUS (&pin_P0_27)
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)

View File

@ -24,8 +24,6 @@
#define SPI_FLASH_CS_PIN &pin_P0_23
#endif
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)

View File

@ -5,8 +5,6 @@
#define MICROPY_HW_LED_STATUS (&pin_P0_12)
#define CIRCUITPY_AUTORELOAD_DELAY_MS 500
#define CIRCUITPY_INTERNAL_NVM_SIZE (4096)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x4000 - CIRCUITPY_INTERNAL_NVM_SIZE)

View File

@ -42,8 +42,6 @@
#define SPI_FLASH_SCK_PIN (&pin_PB13)
#define SPI_FLASH_CS_PIN (&pin_PB12)
#define CIRCUITPY_AUTORELOAD_DELAY_MS (500)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
#define AUTORESET_DELAY_MS (500)

View File

@ -45,8 +45,6 @@
#define DEFAULT_I2C_BUS_SCL (&pin_PB06)
#define DEFAULT_I2C_BUS_SDA (&pin_PB07)
#define CIRCUITPY_AUTORELOAD_DELAY_MS (500)
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
#define AUTORESET_DELAY_MS (500)

View File

@ -49,6 +49,4 @@
#define BOARD_FLASH_SIZE (FLASH_SIZE - 0x2000 - 0xC000)
#define AUTORESET_DELAY_MS (500)
#define MICROPY_FATFS_EXFAT 0

View File

@ -95,7 +95,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_s
//| ...
//|
STATIC mp_obj_t supervisor_reload(void) {
reload_requested = true;
supervisor_set_run_reason(RUN_REASON_SUPERVISOR_RELOAD);
mp_raise_reload_exception();
return mp_const_none;

View File

@ -174,12 +174,13 @@ STATIC int parse_compile_execute(const void *source, mp_parse_input_kind_t input
} else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type((mp_obj_t)nlr.ret_val)), &mp_type_DeepSleepRequest)) {
ret = PYEXEC_DEEP_SLEEP;
#endif
} else if ((mp_obj_t)nlr.ret_val == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
ret = PYEXEC_RELOAD;
} else {
if ((mp_obj_t)nlr.ret_val != MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) {
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
}
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
ret = PYEXEC_EXCEPTION;
}
}
if (result != NULL) {
result->return_code = ret;

View File

@ -49,6 +49,7 @@ extern int pyexec_system_exit;
#define PYEXEC_FORCED_EXIT (0x100)
#define PYEXEC_EXCEPTION (0x200)
#define PYEXEC_DEEP_SLEEP (0x400)
#define PYEXEC_RELOAD (0x800)
int pyexec_raw_repl(void);
int pyexec_friendly_repl(void);

View File

@ -33,67 +33,76 @@
supervisor_allocation *next_code_allocation;
#include "shared-bindings/supervisor/Runtime.h"
static volatile uint32_t autoreload_delay_ms = 0;
static bool autoreload_enabled = false;
static size_t autoreload_suspended = 0;
static volatile uint32_t autoreload_countdown_ms = 0;
// True if user has disabled autoreload.
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 autoreload has been triggered. Wait for CIRCUITPY_AUTORELOAD_DELAY_MS before doing the
// autoreload, in case further writes arrive.
static bool autoreload_countdown = false;
// True if something has requested a reload/restart.
volatile bool reload_requested = false;
void autoreload_reset() {
if (autoreload_countdown) {
supervisor_disable_tick();
autoreload_countdown = false;
}
autoreload_countdown_ms = 0;
reload_requested = false;
}
inline void autoreload_tick() {
if (autoreload_delay_ms == 0) {
if (!autoreload_countdown) {
return;
}
if (autoreload_delay_ms == 1 && autoreload_enabled &&
autoreload_suspended == 0 && !reload_requested) {
mp_raise_reload_exception();
reload_requested = true;
supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD);
supervisor_disable_tick();
if (autoreload_countdown_ms > 0) {
autoreload_countdown_ms--;
}
if (autoreload_countdown_ms == 0 && autoreload_enabled &&
autoreload_suspended == 0 && !reload_requested) {
reload_requested = true;
autoreload_countdown = false;
supervisor_disable_tick();
supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD);
mp_raise_reload_exception();
}
autoreload_delay_ms--;
}
void autoreload_enable() {
autoreload_enabled = true;
reload_requested = false;
autoreload_countdown = false;
}
void autoreload_disable() {
autoreload_enabled = false;
autoreload_countdown = false;
}
void autoreload_suspend(size_t lock_mask) {
autoreload_suspended |= lock_mask;
void autoreload_suspend(uint32_t suspend_reason_mask) {
autoreload_suspended |= suspend_reason_mask;
}
void autoreload_resume(size_t lock_mask) {
autoreload_suspended &= ~lock_mask;
void autoreload_resume(uint32_t suspend_reason_mask) {
autoreload_suspended &= ~suspend_reason_mask;
}
inline bool autoreload_is_enabled() {
return autoreload_enabled;
}
void autoreload_start() {
// Enable ticks if we haven't been tracking an autoreload delay. We check
// our current state so that we only turn ticks on once. Multiple starts
// can occur before we reload and then turn ticks off.
if (autoreload_delay_ms == 0) {
void autoreload_start_countdown() {
// Avoid multiple tick enables.
if (!autoreload_countdown) {
supervisor_enable_tick();
autoreload_countdown = true;
}
autoreload_delay_ms = CIRCUITPY_AUTORELOAD_DELAY_MS;
}
void autoreload_stop() {
autoreload_delay_ms = 0;
reload_requested = false;
}
void autoreload_now() {
if (!autoreload_enabled || autoreload_suspended || reload_requested) {
return;
}
mp_raise_reload_exception();
reload_requested = true;
supervisor_set_run_reason(RUN_REASON_AUTO_RELOAD);
// Start or restart the countdown interval.
autoreload_countdown_ms = CIRCUITPY_AUTORELOAD_DELAY_MS;
}

View File

@ -41,8 +41,8 @@ enum {
};
enum {
AUTORELOAD_LOCK_REPL = 0x1,
AUTORELOAD_LOCK_BLE = 0x2
AUTORELOAD_SUSPEND_REPL = 0x1,
AUTORELOAD_SUSPEND_BLE = 0x2
};
typedef struct {
@ -56,16 +56,16 @@ extern volatile bool reload_requested;
void autoreload_tick(void);
void autoreload_start(void);
void autoreload_stop(void);
void autoreload_start_countdown(void);
void autoreload_reset(void);
void autoreload_enable(void);
void autoreload_disable(void);
bool autoreload_is_enabled(void);
// Temporarily turn it off. Used during the REPL.
void autoreload_suspend(size_t lock_mask);
void autoreload_resume(size_t lock_mask);
// Temporarily turn autoreload off, for the given reason(s). 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).
void autoreload_resume(uint32_t suspend_reason_mask);
void autoreload_now(void);
#endif // MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H

View File

@ -326,7 +326,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
// 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_start_countdown();
return ANY_COMMAND;
}
@ -384,7 +384,7 @@ STATIC uint8_t _process_write_data(const uint8_t *raw_buf, size_t command_len) {
// 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_start_countdown();
return ANY_COMMAND;
}
return WRITE_DATA;
@ -466,7 +466,7 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
// 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_start_countdown();
}
return ANY_COMMAND;
}
@ -521,7 +521,7 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) {
// 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_start_countdown();
}
return ANY_COMMAND;
}
@ -669,7 +669,7 @@ STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) {
// 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_start_countdown();
}
return ANY_COMMAND;
}
@ -692,7 +692,7 @@ void supervisor_bluetooth_file_transfer_background(void) {
if (size == 0) {
break;
}
autoreload_suspend(AUTORELOAD_LOCK_BLE);
autoreload_suspend(AUTORELOAD_SUSPEND_BLE);
// TODO: If size < 0 return an error.
current_offset += size;
#if CIRCUITPY_VERBOSE_BLE
@ -710,7 +710,7 @@ void supervisor_bluetooth_file_transfer_background(void) {
response[0] = next_command;
response[1] = STATUS_ERROR_PROTOCOL;
common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, response, 2, NULL, 0);
autoreload_resume(AUTORELOAD_LOCK_BLE);
autoreload_resume(AUTORELOAD_SUSPEND_BLE);
break;
}
switch (current_state) {
@ -744,7 +744,7 @@ void supervisor_bluetooth_file_transfer_background(void) {
current_offset = 0;
}
if (next_command == ANY_COMMAND) {
autoreload_resume(AUTORELOAD_LOCK_BLE);
autoreload_resume(AUTORELOAD_SUSPEND_BLE);
}
}
running = false;
@ -754,5 +754,5 @@ void supervisor_bluetooth_file_transfer_disconnected(void) {
next_command = ANY_COMMAND;
current_offset = 0;
f_close(&active_file);
autoreload_resume(AUTORELOAD_LOCK_BLE);
autoreload_resume(AUTORELOAD_SUSPEND_BLE);
}

View File

@ -113,7 +113,7 @@ static mp_uint_t flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t n
return supervisor_flash_read_blocks(dest, block_num - PART1_START_BLOCK, num_blocks);
}
volatile bool filesystem_dirty = false;
static volatile bool filesystem_dirty = false;
static mp_uint_t flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {
if (block_num == 0) {

View File

@ -66,7 +66,9 @@ static volatile uint64_t PLACE_IN_DTCM_BSS(background_ticks);
static background_callback_t tick_callback;
volatile uint64_t last_finished_tick = 0;
static volatile uint64_t last_finished_tick = 0;
static volatile size_t tick_enable_count = 0;
static void supervisor_background_tasks(void *unused) {
port_start_background_task();
@ -160,8 +162,7 @@ void mp_hal_delay_ms(mp_uint_t delay_ms) {
}
}
volatile size_t tick_enable_count = 0;
extern void supervisor_enable_tick(void) {
void supervisor_enable_tick(void) {
common_hal_mcu_disable_interrupts();
if (tick_enable_count == 0) {
port_enable_tick();
@ -170,7 +171,7 @@ extern void supervisor_enable_tick(void) {
common_hal_mcu_enable_interrupts();
}
extern void supervisor_disable_tick(void) {
void supervisor_disable_tick(void) {
common_hal_mcu_disable_interrupts();
if (tick_enable_count > 0) {
tick_enable_count--;

View File

@ -170,7 +170,6 @@ bool tud_msc_is_writable_cb(uint8_t lun) {
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
(void)lun;
(void)offset;
const uint32_t block_count = bufsize / MSC_FLASH_BLOCK_SIZE;
@ -216,7 +215,7 @@ void tud_msc_write10_complete_cb(uint8_t lun) {
(void)lun;
// This write is complete, start the autoreload clock.
autoreload_start();
autoreload_start_countdown();
}
// Invoked when received SCSI_CMD_INQUIRY