Skip to content

Commit c97078d

Browse files
committed
Add lots of options.
1 parent f72c3da commit c97078d

File tree

3 files changed

+84
-19
lines changed

3 files changed

+84
-19
lines changed

main.c

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,8 @@ bool cleanup_after_vm(supervisor_allocation* heap) {
281281
return false;
282282
}
283283

284-
void maybe_clear_next_code_info(bool new_next_code) {
285-
// - If a new next code file was set, honor that in any case.
286-
// - Otherwise: If a reload was requested by a USB file write, we want to run the same file
287-
// again, preserve any next-code info. Currently that also covers a reload requested by
288-
// supervisor.reload(), or do we want to treat that differently by turning
289-
// reload_requested into an enum?
290-
// - Otherwise: Clear any leftover next-code info and restart at code.py/main.py.
291-
if (!new_next_code && !reload_requested) {
284+
void maybe_clear_next_code_info(uint8_t reasons_to_keep) {
285+
if (reasons_to_keep == 0) {
292286
free_memory(next_code_allocation);
293287
next_code_allocation = NULL;
294288
}
@@ -317,7 +311,9 @@ bool run_code_py(safe_mode_t safe_mode) {
317311
result.exception_line = 0;
318312

319313
bool found_main = false;
320-
bool new_next_code = false;
314+
uint8_t next_code_options = 0;
315+
// Collects stickiness bits that apply in the current situation.
316+
uint8_t next_code_stickiness_situation = SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
321317

322318
if (safe_mode != NO_SAFE_MODE) {
323319
serial_write_compressed(translate("Running in safe mode! "));
@@ -335,7 +331,6 @@ bool run_code_py(safe_mode_t safe_mode) {
335331
filesystem_flush();
336332
supervisor_allocation* heap = allocate_remaining_memory();
337333
start_mp(heap);
338-
uint8_t next_code_options = 0;
339334
if (next_code_allocation) {
340335
next_code_options = ((next_code_info_t*)next_code_allocation->ptr)->options;
341336
const char* next_list[] = {((next_code_info_t*)next_code_allocation->ptr)->filename, ""};
@@ -356,14 +351,31 @@ bool run_code_py(safe_mode_t safe_mode) {
356351
}
357352
#endif
358353
}
359-
new_next_code = cleanup_after_vm(heap);
354+
bool new_next_code = cleanup_after_vm(heap);
360355

361-
if (result.return_code == 0 && (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS)) {
362-
maybe_clear_next_code_info(new_next_code);
363-
return true;
356+
// If a new next code file was set, that is a reason to keep it (obviously). Stuff this into
357+
// the options because it can be treated like any other reason-for-stickiness bit.
358+
if (new_next_code) next_code_options |= SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET;
359+
360+
if (reload_requested) {
361+
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
362+
}
363+
if (result.return_code == 0) {
364+
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
365+
if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) {
366+
maybe_clear_next_code_info(next_code_options & next_code_stickiness_situation);
367+
return true;
368+
}
369+
}
370+
else {
371+
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_ERROR;
372+
if (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_ERROR) {
373+
maybe_clear_next_code_info(next_code_options & next_code_stickiness_situation);
374+
return true;
375+
}
364376
}
365377
if (result.return_code & PYEXEC_FORCED_EXIT) {
366-
maybe_clear_next_code_info(new_next_code);
378+
maybe_clear_next_code_info(next_code_options & next_code_stickiness_situation);
367379
return reload_requested;
368380
}
369381
}
@@ -382,13 +394,14 @@ bool run_code_py(safe_mode_t safe_mode) {
382394
while (true) {
383395
RUN_BACKGROUND_TASKS;
384396
if (reload_requested) {
385-
// no need to call maybe_clear_next_code_info(), it would be a no-op
397+
next_code_stickiness_situation |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
398+
maybe_clear_next_code_info(next_code_options & next_code_stickiness_situation);
386399
reload_requested = false;
387400
return true;
388401
}
389402

390403
if (serial_connected() && serial_bytes_available()) {
391-
maybe_clear_next_code_info(new_next_code);
404+
maybe_clear_next_code_info(next_code_options & next_code_stickiness_situation);
392405
// Skip REPL if reload was requested.
393406
return (serial_read() == CHAR_CTRL_D);
394407
}

shared-bindings/supervisor/__init__.c

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,23 +110,70 @@ STATIC mp_obj_t supervisor_set_next_stack_limit(mp_obj_t size_obj) {
110110
}
111111
MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_next_stack_limit_obj, supervisor_set_next_stack_limit);
112112

113+
//| def set_next_code_file(filename: Optional[str], /, *, reload_on_success : bool = False, reload_on_error: bool = False, sticky_on_success: bool = False, sticky_on_error: bool = False, sticky_on_reload: bool = False) -> None:
114+
//| """Set what file to run on the next vm run.
115+
//|
116+
//| When not None, the given filename is inserted at the front of the usual ['code.py',
117+
//| 'main.py'] search sequence.
118+
//|
119+
//| The optional keyword arguments specify what happens after the specified file has run:
120+
//|
121+
//| sticky_on_… determine whether the newly set filename and options stay in effect: If True,
122+
//| further runs will continue to run that file (unless it says otherwise by calling
123+
//| set_next_code_filename() itself). If False, the settings will only affect one run and revert
124+
//| to the standard code.py/main.py afterwards.
125+
//|
126+
//| reload_on_… determine how to continue: If False, wait in the usual "Code done running.
127+
//| Waiting for reload. / Press any key to enter the REPL. Use CTRL-D to reload." state. If
128+
//| True, reload immediately as if CTRL-D was pressed.
129+
//|
130+
//| …_on_success take effect when the program runs to completion or calls sys.exit().
131+
//|
132+
//| …_on_error take effect when the program exits with an exception, including the
133+
//| KeyboardInterrupt caused by CTRL-C.
134+
//|
135+
//| …_on_reload take effect when the program is interrupted by files being written to the USB
136+
//| drive (auto-reload) or when it calls supervisor.reload().
137+
//|
138+
//| These settings are stored in RAM, not in persistent memory, and will therefore only affect
139+
//| soft reloads. Powering off or resetting the device will always revert to standard settings.
140+
//|
141+
//| When called multiple times in the same run, only the last call takes effect, replacing any
142+
//| settings made by previous ones. This is the main use of passing None as a filename: to
143+
//| reset to the standard search sequence."""
144+
//| ...
145+
//|
113146
STATIC mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
114147
static const mp_arg_t allowed_args[] = {
115148
{ MP_QSTR_filename, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
116149
{ MP_QSTR_reload_on_success, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
150+
{ MP_QSTR_reload_on_error, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
151+
{ MP_QSTR_sticky_on_success, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
152+
{ MP_QSTR_sticky_on_error, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
153+
{ MP_QSTR_sticky_on_reload, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
117154
};
118155
struct {
119156
mp_arg_val_t filename;
120157
mp_arg_val_t reload_on_success;
158+
mp_arg_val_t reload_on_error;
159+
mp_arg_val_t sticky_on_success;
160+
mp_arg_val_t sticky_on_error;
161+
mp_arg_val_t sticky_on_reload;
121162
} args;
122163
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
123164
if (!MP_OBJ_IS_STR_OR_BYTES(args.filename.u_obj) && args.filename.u_obj != mp_const_none) {
124165
mp_raise_TypeError(translate("argument has wrong type"));
125166
}
126167
if (args.filename.u_obj == mp_const_none) args.filename.u_obj = mp_const_empty_bytes;
168+
uint8_t options = 0;
169+
if (args.reload_on_success.u_bool) options |= SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS;
170+
if (args.reload_on_error.u_bool) options |= SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_ERROR;
171+
if (args.sticky_on_success.u_bool) options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS;
172+
if (args.sticky_on_error.u_bool) options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_ERROR;
173+
if (args.sticky_on_reload.u_bool) options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD;
127174
mp_obj_t items[] = {
128175
args.filename.u_obj,
129-
args.reload_on_success.u_bool ? MP_OBJ_NEW_SMALL_INT(SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) : MP_OBJ_NEW_SMALL_INT(0)
176+
MP_OBJ_NEW_SMALL_INT(options)
130177
};
131178
MP_STATE_VM(supervisor_next_code) = mp_obj_new_tuple(MP_ARRAY_SIZE(items), items);
132179
return mp_const_none;

supervisor/shared/autoreload.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@
3030
#include <stdbool.h>
3131

3232
enum {
33-
SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS = 0x1
33+
SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS = 0x1,
34+
SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_ERROR = 0x2,
35+
SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS = 0x4,
36+
SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_ERROR = 0x8,
37+
SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD = 0x10,
38+
SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET = 0x20,
3439
};
3540

3641
extern volatile bool reload_requested;

0 commit comments

Comments
 (0)