diff --git a/main.c b/main.c index d1fbc257a9..9f31153877 100644 --- a/main.c +++ b/main.c @@ -52,7 +52,7 @@ #include "supervisor/memory.h" #include "supervisor/port.h" #include "supervisor/serial.h" -#include "supervisor/shared/autoreload.h" +#include "supervisor/shared/reload.h" #include "supervisor/shared/safe_mode.h" #include "supervisor/shared/stack.h" #include "supervisor/shared/status_leds.h" @@ -389,12 +389,28 @@ 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) { + 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; } else { serial_write_compressed(translate("\nCode done running.\n")); } + // Finished executing python code. Cleanup includes filesystem flush and a board reset. cleanup_after_vm(heap, result.exception); @@ -474,8 +490,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re while (!skip_wait) { RUN_BACKGROUND_TASKS; - // If a reload was requested by the supervisor or autoreload, return - if (result.return_code & PYEXEC_RELOAD) { + // If a reload was requested by the supervisor or autoreload, return. + if (reload_requested) { 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 diff --git a/ports/atmel-samd/mphalport.c b/ports/atmel-samd/mphalport.c index e196312ca3..a039b5d258 100644 --- a/ports/atmel-samd/mphalport.c +++ b/ports/atmel-samd/mphalport.c @@ -34,7 +34,6 @@ #include "py/smallint.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" -#include "supervisor/shared/autoreload.h" #include "hal/include/hal_atomic.h" #include "hal/include/hal_delay.h" diff --git a/ports/raspberrypi/mphalport.c b/ports/raspberrypi/mphalport.c index 51d82a0514..b4ecbca49d 100644 --- a/ports/raspberrypi/mphalport.c +++ b/ports/raspberrypi/mphalport.c @@ -34,7 +34,6 @@ #include "py/smallint.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" -#include "supervisor/shared/autoreload.h" #include "mpconfigboard.h" #include "mphalport.h" diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 070403877f..aa60be693f 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -436,7 +436,7 @@ void supervisor_run_background_tasks_if_tick(void); // CIRCUITPY_AUTORELOAD_DELAY_MS = 0 will completely disable autoreload. #ifndef CIRCUITPY_AUTORELOAD_DELAY_MS -#define CIRCUITPY_AUTORELOAD_DELAY_MS 500 +#define CIRCUITPY_AUTORELOAD_DELAY_MS 750 #endif #ifndef CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS diff --git a/py/py.mk b/py/py.mk index db92ef3c02..f13a9d3786 100644 --- a/py/py.mk +++ b/py/py.mk @@ -159,7 +159,6 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ objzip.o \ opmethods.o \ proto.o \ - reload.o \ sequence.o \ stream.o \ binary.o \ diff --git a/py/reload.c b/py/reload.c deleted file mode 100644 index 996826b930..0000000000 --- a/py/reload.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 by Roy Hooper - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "reload.h" -#include "py/mpstate.h" - -void mp_raise_reload_exception(void) { - MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception)); - #if MICROPY_ENABLE_SCHEDULER - if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { - MP_STATE_VM(sched_state) = MP_SCHED_PENDING; - } - #endif - -} diff --git a/py/reload.h b/py/reload.h deleted file mode 100644 index 8e68ea3253..0000000000 --- a/py/reload.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 by Roy Hooper - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef CIRCUITPYTHON_RELOAD_H -#define CIRCUITPYTHON_RELOAD_H - -void mp_raise_reload_exception(void); - -#endif // CIRCUITPYTHON_RELOAD_H diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index 340a4ea679..9de8c294e9 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -25,7 +25,6 @@ */ #include "py/obj.h" -#include "py/reload.h" #include "py/runtime.h" #include "shared-bindings/alarm/__init__.h" @@ -35,7 +34,6 @@ #include "shared-bindings/alarm/touch/TouchAlarm.h" #include "shared-bindings/supervisor/Runtime.h" #include "shared-bindings/time/__init__.h" -#include "supervisor/shared/autoreload.h" #include "supervisor/shared/workflow.h" //| """Alarms and sleep diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index 1ed11a2ec5..08d68ec93f 100644 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -108,6 +108,14 @@ const mp_obj_property_t supervisor_runtime_serial_bytes_available_obj = { MP_ROM_NONE}, }; +supervisor_run_reason_t supervisor_get_run_reason(void) { + return _run_reason; +} + +void supervisor_set_run_reason(supervisor_run_reason_t run_reason) { + _run_reason = run_reason; +} + //| run_reason: RunReason //| """Returns why CircuitPython started running this particular time.""" //| @@ -123,10 +131,6 @@ const mp_obj_property_t supervisor_runtime_run_reason_obj = { MP_ROM_NONE}, }; -void supervisor_set_run_reason(supervisor_run_reason_t run_reason) { - _run_reason = run_reason; -} - STATIC const mp_rom_map_elem_t supervisor_runtime_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_usb_connected), MP_ROM_PTR(&supervisor_runtime_usb_connected_obj) }, { MP_ROM_QSTR(MP_QSTR_serial_connected), MP_ROM_PTR(&supervisor_runtime_serial_connected_obj) }, diff --git a/shared-bindings/supervisor/Runtime.h b/shared-bindings/supervisor/Runtime.h index 3a94a8fd5d..debc5ec79c 100644 --- a/shared-bindings/supervisor/Runtime.h +++ b/shared-bindings/supervisor/Runtime.h @@ -34,6 +34,7 @@ extern const mp_obj_type_t supervisor_runtime_type; +supervisor_run_reason_t supervisor_get_run_reason(void); void supervisor_set_run_reason(supervisor_run_reason_t run_reason); bool common_hal_supervisor_runtime_get_serial_connected(void); diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index 0d99277ba7..0b86b7b2a6 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -27,14 +27,13 @@ #include "py/obj.h" #include "py/runtime.h" -#include "py/reload.h" #include "py/objstr.h" #include "shared/runtime/interrupt_char.h" -#include "supervisor/shared/autoreload.h" #include "supervisor/shared/bluetooth/bluetooth.h" #include "supervisor/shared/display.h" #include "supervisor/shared/status_leds.h" +#include "supervisor/shared/reload.h" #include "supervisor/shared/stack.h" #include "supervisor/shared/traceback.h" #include "supervisor/shared/translate.h" @@ -95,8 +94,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_s //| ... //| STATIC mp_obj_t supervisor_reload(void) { - supervisor_set_run_reason(RUN_REASON_SUPERVISOR_RELOAD); - mp_raise_reload_exception(); + reload_initiate(RUN_REASON_SUPERVISOR_RELOAD); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(supervisor_reload_obj, supervisor_reload); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index d026d9f766..04171198cf 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -29,7 +29,6 @@ #include "shared-module/displayio/__init__.h" #include "shared/runtime/interrupt_char.h" -#include "py/reload.h" #include "py/runtime.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/displayio/Bitmap.h" @@ -37,8 +36,8 @@ #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/Palette.h" #include "shared-module/displayio/area.h" -#include "supervisor/shared/autoreload.h" #include "supervisor/shared/display.h" +#include "supervisor/shared/reload.h" #include "supervisor/memory.h" #include "supervisor/spi_flash_api.h" diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c index 9cbddc61ae..6715ee961b 100644 --- a/supervisor/shared/bluetooth/file_transfer.c +++ b/supervisor/shared/bluetooth/file_transfer.c @@ -43,7 +43,7 @@ #include "common-hal/_bleio/__init__.h" #include "supervisor/fatfs_port.h" -#include "supervisor/shared/autoreload.h" +#include "supervisor/shared/reload.h" #include "supervisor/shared/bluetooth/file_transfer.h" #include "supervisor/shared/bluetooth/file_transfer_protocol.h" #include "supervisor/shared/tick.h" @@ -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_countdown(); + autoreload_start(); 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_countdown(); + autoreload_start(); 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_countdown(); + autoreload_start(); } 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_countdown(); + autoreload_start(); } 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_countdown(); + autoreload_start(); } return ANY_COMMAND; } diff --git a/supervisor/shared/autoreload.c b/supervisor/shared/reload.c similarity index 63% rename from supervisor/shared/autoreload.c rename to supervisor/shared/reload.c index 1c85ddc5c4..b774074df6 100644 --- a/supervisor/shared/autoreload.c +++ b/supervisor/shared/reload.c @@ -24,65 +24,49 @@ * THE SOFTWARE. */ -#include "autoreload.h" +#include "reload.h" #include "py/mphal.h" -#include "py/reload.h" +#include "py/mpstate.h" +#include "supervisor/shared/reload.h" #include "supervisor/shared/tick.h" supervisor_allocation *next_code_allocation; #include "shared-bindings/supervisor/Runtime.h" -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; +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. + MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception)); + #if MICROPY_ENABLE_SCHEDULER + if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) { + MP_STATE_VM(sched_state) = MP_SCHED_PENDING; } - autoreload_countdown_ms = 0; - reload_requested = false; + #endif } -inline void autoreload_tick() { - if (!autoreload_countdown) { - return; - } - 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(); - } +void autoreload_reset() { + reload_requested = false; } void autoreload_enable() { autoreload_enabled = true; reload_requested = false; - autoreload_countdown = false; } void autoreload_disable() { autoreload_enabled = false; - autoreload_countdown = false; } void autoreload_suspend(uint32_t suspend_reason_mask) { @@ -97,12 +81,8 @@ inline bool autoreload_is_enabled() { return autoreload_enabled; } -void autoreload_start_countdown() { - // Avoid multiple tick enables. - if (!autoreload_countdown) { - supervisor_enable_tick(); - autoreload_countdown = true; +void autoreload_start() { + if (autoreload_enabled && autoreload_suspended == 0) { + reload_initiate(RUN_REASON_AUTO_RELOAD); } - // Start or restart the countdown interval. - autoreload_countdown_ms = CIRCUITPY_AUTORELOAD_DELAY_MS; } diff --git a/supervisor/shared/autoreload.h b/supervisor/shared/reload.h similarity index 89% rename from supervisor/shared/autoreload.h rename to supervisor/shared/reload.h index 2532965780..10b4bea00c 100644 --- a/supervisor/shared/autoreload.h +++ b/supervisor/shared/reload.h @@ -27,9 +27,9 @@ #ifndef MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H #define MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H -#include - #include "supervisor/memory.h" +#include "py/obj.h" +#include "shared-bindings/supervisor/RunReason.h" enum { SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS = 0x1, @@ -54,18 +54,18 @@ extern supervisor_allocation *next_code_allocation; extern volatile bool reload_requested; -void autoreload_tick(void); +void reload_initiate(supervisor_run_reason_t run_reason); -void autoreload_start_countdown(void); +void autoreload_start(void); void autoreload_reset(void); void autoreload_enable(void); void autoreload_disable(void); bool autoreload_is_enabled(void); -// Temporarily turn autoreload off, for the given reason(s). Used during the REPL or during parts of BLE workflow. +// 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); - #endif // MICROPY_INCLUDED_SUPERVISOR_AUTORELOAD_H diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c index 34b1897435..104083fb20 100644 --- a/supervisor/shared/tick.c +++ b/supervisor/shared/tick.c @@ -34,7 +34,6 @@ #include "supervisor/filesystem.h" #include "supervisor/background_callback.h" #include "supervisor/port.h" -#include "supervisor/shared/autoreload.h" #include "supervisor/shared/stack.h" #if CIRCUITPY_BLEIO_HCI @@ -103,10 +102,6 @@ void supervisor_tick(void) { filesystem_tick(); #endif - #ifdef CIRCUITPY_AUTORELOAD_DELAY_MS - autoreload_tick(); - #endif - #ifdef CIRCUITPY_GAMEPAD_TICKS if (!(port_get_raw_ticks(NULL) & CIRCUITPY_GAMEPAD_TICKS)) { #if CIRCUITPY_GAMEPADSHIFT diff --git a/supervisor/shared/tick.h b/supervisor/shared/tick.h index 3a01bd6222..d805aeb099 100644 --- a/supervisor/shared/tick.h +++ b/supervisor/shared/tick.h @@ -37,20 +37,23 @@ * interrupt context. */ extern void supervisor_tick(void); + /** @brief Get the lower 32 bits of the time in milliseconds * * This can be more efficient than supervisor_ticks_ms64, for sites where a wraparound * of ~49.5 days is not harmful. */ extern uint32_t supervisor_ticks_ms32(void); + /** @brief Get the full time in milliseconds * * Because common ARM mcus cannot atomically work with 64-bit quantities, this * function must briefly disable interrupts in order to return the value. If * only relative durations of less than about ~49.5 days need to be considered, - * then it may be possible to use supervisor_ticks_ms64 instead. + * then it may be possible to use supervisor_ticks_ms32() instead. */ extern uint64_t supervisor_ticks_ms64(void); + /** @brief Run background ticks, but only about every millisecond. * * Normally, this is not called directly. Instead use the RUN_BACKGROUND_TASKS diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index e5bed8442b..fbc9c2a1b4 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -36,7 +36,7 @@ #include "shared-module/storage/__init__.h" #include "supervisor/filesystem.h" -#include "supervisor/shared/autoreload.h" +#include "supervisor/shared/reload.h" #define MSC_FLASH_BLOCK_SIZE 512 @@ -214,8 +214,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t * void tud_msc_write10_complete_cb(uint8_t lun) { (void)lun; - // This write is complete, start the autoreload clock. - autoreload_start_countdown(); + // This write is complete; initiate an autoreload. + autoreload_start(); } // Invoked when received SCSI_CMD_INQUIRY diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index eed9f4dc47..8aaec79d92 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -1,7 +1,6 @@ SRC_SUPERVISOR = \ main.c \ supervisor/port.c \ - supervisor/shared/autoreload.c \ supervisor/shared/background_callback.c \ supervisor/shared/board.c \ supervisor/shared/cpu.c \ @@ -9,6 +8,7 @@ SRC_SUPERVISOR = \ supervisor/shared/lock.c \ supervisor/shared/memory.c \ supervisor/shared/micropython.c \ + supervisor/shared/reload.c \ supervisor/shared/safe_mode.c \ supervisor/shared/stack.c \ supervisor/shared/status_leds.c \