Skip to content

Commit 32ac396

Browse files
committed
Further refine autoreload
This unifies the delay into the post-run delay that also waits for user input and fake sleep. This ensures we always delay. Previous code would only delay if the code.py was running when autoreload was triggered. Now it will always delay. We also now suspend autoreload when a USB write starts and then resume on completion. This should prevent reloading in between sectors of a single write.
1 parent 7cb66dd commit 32ac396

File tree

8 files changed

+82
-57
lines changed

8 files changed

+82
-57
lines changed

locale/circuitpython.pot

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ msgstr ""
2525
#: main.c
2626
msgid ""
2727
"\n"
28-
"Code stopped by auto-reload.\n"
28+
"Code stopped by auto-reload. Reloading soon.\n"
2929
msgstr ""
3030

3131
#: supervisor/shared/safe_mode.c
@@ -584,10 +584,6 @@ msgstr ""
584584
msgid "Brightness must be 0-1.0"
585585
msgstr ""
586586

587-
#: shared-bindings/supervisor/__init__.c
588-
msgid "Brightness must be between 0 and 255"
589-
msgstr ""
590-
591587
#: shared-bindings/displayio/Display.c
592588
#: shared-bindings/framebufferio/FramebufferDisplay.c
593589
msgid "Brightness not adjustable"
@@ -688,6 +684,7 @@ msgstr ""
688684
msgid "Can only alarm on two low pins from deep sleep."
689685
msgstr ""
690686

687+
#: ports/espressif/common-hal/_bleio/Characteristic.c
691688
#: ports/nrf/common-hal/_bleio/Characteristic.c
692689
msgid "Can't set CCCD on local Characteristic"
693690
msgstr ""
@@ -1605,6 +1602,7 @@ msgstr ""
16051602
msgid "Nimble out of memory"
16061603
msgstr ""
16071604

1605+
#: ports/espressif/common-hal/_bleio/Characteristic.c
16081606
#: ports/nrf/common-hal/_bleio/Characteristic.c
16091607
msgid "No CCCD for this Characteristic"
16101608
msgstr ""
@@ -3642,7 +3640,7 @@ msgstr ""
36423640
msgid "matrix is not positive definite"
36433641
msgstr ""
36443642

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

@@ -4061,13 +4059,15 @@ msgstr ""
40614059
#: ports/espressif/boards/adafruit_metro_esp32s2/mpconfigboard.h
40624060
#: ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h
40634061
#: ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h
4062+
#: ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.h
40644063
#: ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.h
40654064
#: ports/espressif/boards/ai_thinker_esp_12k_nodemcu/mpconfigboard.h
40664065
#: ports/espressif/boards/artisense_rd00/mpconfigboard.h
40674066
#: ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h
40684067
#: ports/espressif/boards/crumpspace_crumps2/mpconfigboard.h
40694068
#: ports/espressif/boards/electroniccats_bastwifi/mpconfigboard.h
40704069
#: ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.h
4070+
#: ports/espressif/boards/espressif_esp32s2_devkitc_1_n4r2/mpconfigboard.h
40714071
#: ports/espressif/boards/espressif_esp32s3_box/mpconfigboard.h
40724072
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8/mpconfigboard.h
40734073
#: ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2/mpconfigboard.h
@@ -4083,6 +4083,7 @@ msgstr ""
40834083
#: ports/espressif/boards/gravitech_cucumber_ms/mpconfigboard.h
40844084
#: ports/espressif/boards/gravitech_cucumber_r/mpconfigboard.h
40854085
#: ports/espressif/boards/gravitech_cucumber_rs/mpconfigboard.h
4086+
#: ports/espressif/boards/hiibot_iots2/mpconfigboard.h
40864087
#: ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
40874088
#: ports/espressif/boards/lolin_s2_mini/mpconfigboard.h
40884089
#: ports/espressif/boards/lolin_s2_pico/mpconfigboard.h

main.c

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ static void reset_devices(void) {
124124
}
125125

126126
STATIC void start_mp(supervisor_allocation *heap, bool first_run) {
127-
autoreload_reset();
128127
supervisor_workflow_reset();
129128

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

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

348-
stack_resize();
349-
filesystem_flush();
350353
supervisor_allocation *heap = allocate_remaining_memory();
351354

352355
// Prepare the VM state. Includes an alarm check/reset for sleep.
@@ -390,22 +393,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
390393
// Print done before resetting everything so that we get the message over
391394
// BLE before it is reset and we have a delay before reconnect.
392395
if ((result.return_code & PYEXEC_RELOAD) && supervisor_get_run_reason() == RUN_REASON_AUTO_RELOAD) {
393-
serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
394-
395-
// Wait for autoreload interval before reloading
396-
uint64_t start_ticks = 0;
397-
do {
398-
// Start waiting, or restart interval if another reload request was initiated
399-
// while we were waiting.
400-
if (reload_requested) {
401-
reload_requested = false;
402-
start_ticks = supervisor_ticks_ms64();
403-
}
404-
RUN_BACKGROUND_TASKS;
405-
} while (supervisor_ticks_ms64() - start_ticks < CIRCUITPY_AUTORELOAD_DELAY_MS);
406-
407-
// Restore request for use below.
408-
reload_requested = true;
396+
serial_write_compressed(translate("\nCode stopped by auto-reload. Reloading soon.\n"));
409397
} else {
410398
serial_write_compressed(translate("\nCode done running.\n"));
411399
}
@@ -425,8 +413,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
425413

426414
if (result.return_code & PYEXEC_RELOAD) {
427415
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
428-
skip_repl = true;
429-
skip_wait = true;
430416
} else if (result.return_code == 0) {
431417
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
432418
if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) {
@@ -484,22 +470,27 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re
484470
size_t total_time = blink_time + LED_SLEEP_TIME_MS;
485471
#endif
486472

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

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

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

528519
// If messages haven't been printed yet, print them
529-
if (!printed_press_any_key && serial_connected()) {
520+
if (!printed_press_any_key && serial_connected() && !autoreload_pending()) {
530521
if (!serial_connected_at_start) {
531522
print_code_py_status_message(safe_mode);
532523
}

ports/stm/supervisor/port.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,6 @@ void port_enable_tick(void) {
346346
stm32_peripherals_rtc_assign_wkup_callback(supervisor_tick);
347347
stm32_peripherals_rtc_enable_wakeup_timer();
348348
}
349-
// TODO: what is this? can I get rid of it?
350-
extern volatile uint32_t autoreload_delay_ms;
351349

352350
// Disable 1/1024 second tick.
353351
void port_disable_tick(void) {

shared-module/displayio/__init__.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void displayio_background(void) {
8282
if (mp_hal_is_interrupted()) {
8383
return;
8484
}
85-
if (reload_requested) {
85+
if (autoreload_ready()) {
8686
// Reload is about to happen, so don't redisplay.
8787
return;
8888
}

supervisor/shared/bluetooth/file_transfer.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) {
325325
if (chunk_size == 0) {
326326
// Don't reload until everything is written out of the packet buffer.
327327
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
328-
// Trigger an autoreload
329-
autoreload_start();
328+
autoreload_trigger();
330329
return ANY_COMMAND;
331330
}
332331

@@ -383,8 +382,7 @@ STATIC uint8_t _process_write_data(const uint8_t *raw_buf, size_t command_len) {
383382
#endif
384383
// Don't reload until everything is written out of the packet buffer.
385384
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
386-
// Trigger an autoreload
387-
autoreload_start();
385+
autoreload_trigger();
388386
return ANY_COMMAND;
389387
}
390388
return WRITE_DATA;
@@ -465,8 +463,7 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) {
465463
if (result == FR_OK) {
466464
// Don't reload until everything is written out of the packet buffer.
467465
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
468-
// Trigger an autoreload
469-
autoreload_start();
466+
autoreload_trigger();
470467
}
471468
return ANY_COMMAND;
472469
}
@@ -520,8 +517,7 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) {
520517
if (result == FR_OK) {
521518
// Don't reload until everything is written out of the packet buffer.
522519
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
523-
// Trigger an autoreload
524-
autoreload_start();
520+
autoreload_trigger();
525521
}
526522
return ANY_COMMAND;
527523
}
@@ -668,8 +664,7 @@ STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) {
668664
if (result == FR_OK) {
669665
// Don't reload until everything is written out of the packet buffer.
670666
common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer);
671-
// Trigger an autoreload
672-
autoreload_start();
667+
autoreload_trigger();
673668
}
674669
return ANY_COMMAND;
675670
}

supervisor/shared/reload.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,9 @@ static bool autoreload_enabled = false;
4040
// Non-zero if autoreload is temporarily off, due to an AUTORELOAD_SUSPEND_... reason.
4141
static uint32_t autoreload_suspended = 0;
4242

43-
// True if something has requested a reload/restart.
44-
volatile bool reload_requested = false;
43+
volatile uint32_t last_autoreload_trigger = 0;
4544

4645
void reload_initiate(supervisor_run_reason_t run_reason) {
47-
reload_requested = true;
4846
supervisor_set_run_reason(run_reason);
4947

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

5957
void autoreload_reset() {
60-
reload_requested = false;
58+
last_autoreload_trigger = 0;
6159
}
6260

6361
void autoreload_enable() {
6462
autoreload_enabled = true;
65-
reload_requested = false;
63+
last_autoreload_trigger = 0;
6664
}
6765

6866
void autoreload_disable() {
@@ -81,8 +79,35 @@ inline bool autoreload_is_enabled() {
8179
return autoreload_enabled;
8280
}
8381

84-
void autoreload_start() {
85-
if (autoreload_enabled && autoreload_suspended == 0) {
82+
void autoreload_trigger() {
83+
if (autoreload_enabled) {
84+
last_autoreload_trigger = supervisor_ticks_ms32();
85+
// Guard against the rare time that ticks is 0;
86+
if (last_autoreload_trigger == 0) {
87+
last_autoreload_trigger += 1;
88+
}
89+
// Initiate a reload of the VM immediately. Later code will pause to
90+
// wait for the autoreload to become ready. Doing the VM exit
91+
// immediately is clearer for the user.
8692
reload_initiate(RUN_REASON_AUTO_RELOAD);
8793
}
8894
}
95+
96+
bool autoreload_ready() {
97+
if (last_autoreload_trigger == 0 || autoreload_suspended != 0) {
98+
return false;
99+
}
100+
// Wait for autoreload interval before reloading
101+
uint32_t now = supervisor_ticks_ms32();
102+
uint32_t diff;
103+
if (now >= last_autoreload_trigger) {
104+
diff = now - last_autoreload_trigger;
105+
} else {
106+
diff = now + (0xffffffff - last_autoreload_trigger);
107+
}
108+
return diff > CIRCUITPY_AUTORELOAD_DELAY_MS;
109+
}
110+
111+
bool autoreload_pending(void) {
112+
return last_autoreload_trigger != 0;
113+
}

supervisor/shared/reload.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ enum {
4242

4343
enum {
4444
AUTORELOAD_SUSPEND_REPL = 0x1,
45-
AUTORELOAD_SUSPEND_BLE = 0x2
45+
AUTORELOAD_SUSPEND_BLE = 0x2,
46+
AUTORELOAD_SUSPEND_USB = 0x4
4647
};
4748

4849
typedef struct {
@@ -52,17 +53,29 @@ typedef struct {
5253

5354
extern supervisor_allocation *next_code_allocation;
5455

55-
extern volatile bool reload_requested;
56-
56+
// Helper for exiting the VM and reloading immediately.
5757
void reload_initiate(supervisor_run_reason_t run_reason);
5858

59-
void autoreload_start(void);
60-
void autoreload_reset(void);
59+
// Enabled state is user controllable and very sticky. We don't reset it.
6160
void autoreload_enable(void);
6261
void autoreload_disable(void);
6362
bool autoreload_is_enabled(void);
6463

65-
// Temporarily turn autoreload off, for the given reason(s).
64+
// Start the autoreload process.
65+
void autoreload_trigger(void);
66+
// True when the autoreload should occur. (A trigger happened and the delay has
67+
// passed.)
68+
bool autoreload_ready(void);
69+
// Reset the autoreload timer in preparation for another trigger. Call when the
70+
// last trigger starts being executed.
71+
void autoreload_reset(void);
72+
// True when a trigger has occurred but we're still delaying in case another
73+
// trigger occurs.
74+
bool autoreload_pending(void);
75+
76+
// Temporarily turn autoreload off, for the given reason(s). Autoreload triggers
77+
// will still be tracked so resuming with autoreload ready with cause an
78+
// immediate reload.
6679
// Used during the REPL or during parts of BLE workflow.
6780
void autoreload_suspend(uint32_t suspend_reason_mask);
6881
// Allow autoreloads again, for the given reason(s).

supervisor/shared/usb/usb_msc_flash.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buff
185185
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
186186
(void)lun;
187187
(void)offset;
188+
autoreload_suspend(AUTORELOAD_SUSPEND_USB);
188189

189190
const uint32_t block_count = bufsize / MSC_FLASH_BLOCK_SIZE;
190191

@@ -215,7 +216,8 @@ void tud_msc_write10_complete_cb(uint8_t lun) {
215216
(void)lun;
216217

217218
// This write is complete; initiate an autoreload.
218-
autoreload_start();
219+
autoreload_trigger();
220+
autoreload_resume(AUTORELOAD_SUSPEND_USB);
219221
}
220222

221223
// Invoked when received SCSI_CMD_INQUIRY

0 commit comments

Comments
 (0)