Skip to content

Commit f222a3f

Browse files
committed
Add supervisor.set_next_code() function (prototype).
Fixes #1084.
1 parent 8eda917 commit f222a3f

File tree

4 files changed

+99
-10
lines changed

4 files changed

+99
-10
lines changed

main.c

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@
8181
#include "supervisor/shared/bluetooth.h"
8282
#endif
8383

84+
typedef struct {
85+
uint8_t options;
86+
char filename[];
87+
} next_code_info_t;
88+
89+
static supervisor_allocation* next_code_allocation;
90+
8491
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
8592
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
8693
if (lex == NULL) {
@@ -211,7 +218,21 @@ bool maybe_run_list(const char * const * filenames, pyexec_result_t* exec_result
211218
return true;
212219
}
213220

214-
void cleanup_after_vm(supervisor_allocation* heap) {
221+
bool cleanup_after_vm(supervisor_allocation* heap) {
222+
// Get any info on what code to run next off the heap.
223+
next_code_info_t* next_code = NULL;
224+
size_t next_code_len = 0;
225+
if (MP_STATE_VM(supervisor_next_code)) {
226+
size_t len;
227+
mp_obj_t* items;
228+
mp_obj_tuple_get(MP_STATE_VM(supervisor_next_code), &len, &items);
229+
const char* filename = mp_obj_str_get_data(items[0], &len);
230+
next_code_len = sizeof(uint8_t) + len; // termination not needed here, saves a byte of stack
231+
next_code = alloca(next_code_len);
232+
next_code->options = (uint8_t)MP_OBJ_SMALL_INT_VALUE(items[1]);
233+
memcpy(&next_code->filename, filename, len);
234+
MP_STATE_VM(supervisor_next_code) = NULL;
235+
}
215236
// Reset port-independent devices, like CIRCUITPY_BLEIO_HCI.
216237
reset_devices();
217238
// Turn off the display and flush the fileystem before the heap disappears.
@@ -232,6 +253,21 @@ void cleanup_after_vm(supervisor_allocation* heap) {
232253
#endif
233254
reset_board();
234255
reset_status_led();
256+
257+
// Save next code info.
258+
if (next_code) {
259+
if (next_code_allocation) {
260+
free_memory(next_code_allocation);
261+
}
262+
// TODO do I need to increase CIRCUITPY_SUPERVISOR_ALLOC_COUNT for this?
263+
next_code_allocation = allocate_memory((next_code_len + 1 + 3) & ~3, false);
264+
if (next_code_allocation) {
265+
memcpy(next_code_allocation->ptr, next_code, next_code_len);
266+
((char*)next_code_allocation->ptr)[next_code_len] = '\0';
267+
return true;
268+
}
269+
}
270+
return false;
235271
}
236272

237273
bool run_code_py(safe_mode_t safe_mode) {
@@ -274,17 +310,42 @@ bool run_code_py(safe_mode_t safe_mode) {
274310
filesystem_flush();
275311
supervisor_allocation* heap = allocate_remaining_memory();
276312
start_mp(heap);
277-
found_main = maybe_run_list(supported_filenames, &result);
278-
#if CIRCUITPY_FULL_BUILD
279-
if (!found_main){
280-
found_main = maybe_run_list(double_extension_filenames, &result);
281-
if (found_main) {
282-
serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
313+
uint8_t next_code_options = 0;
314+
if (next_code_allocation) {
315+
next_code_options = ((next_code_info_t*)next_code_allocation->ptr)->options;
316+
const char* next_list[] = {((next_code_info_t*)next_code_allocation->ptr)->filename, ""};
317+
found_main = maybe_run_list(next_list, &result);
318+
if (!found_main) {
319+
serial_write(((next_code_info_t*)next_code_allocation->ptr)->filename);
320+
serial_write_compressed(translate(" not found.\n"));
283321
}
284322
}
285-
#endif
286-
cleanup_after_vm(heap);
323+
if (!found_main) {
324+
found_main = maybe_run_list(supported_filenames, &result);
325+
#if CIRCUITPY_FULL_BUILD
326+
if (!found_main){
327+
found_main = maybe_run_list(double_extension_filenames, &result);
328+
if (found_main) {
329+
serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
330+
}
331+
}
332+
#endif
333+
}
334+
bool new_next_code = cleanup_after_vm(heap);
335+
// - If a new next code file was set, honor that in any case.
336+
// - Otherwise: If a reload was requested by a USB file write, we want to run the same file
337+
// again, preserve any next-code info. Currently that also covers a reload requested by
338+
// supervisor.reload(), or do we want to treat that differently by turning
339+
// reload_requested into an enum?
340+
// - Otherwise: Clear any leftover next-code info and restart at code.py/main.py.
341+
if (!new_next_code && !reload_requested) {
342+
free_memory(next_code_allocation);
343+
next_code_allocation = NULL;
344+
}
287345

346+
if (result.return_code == 0 && (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS)) {
347+
return true;
348+
}
288349
if (result.return_code & PYEXEC_FORCED_EXIT) {
289350
return reload_requested;
290351
}

py/circuitpy_mpconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,7 @@ extern const struct _mp_obj_module_t wifi_module;
849849
FLASH_ROOT_POINTERS \
850850
MEMORYMONITOR_ROOT_POINTERS \
851851
NETWORK_ROOT_POINTERS \
852+
mp_obj_t supervisor_next_code; \
852853

853854
void supervisor_run_background_tasks_if_tick(void);
854855
#define RUN_BACKGROUND_TASKS (supervisor_run_background_tasks_if_tick())

shared-bindings/supervisor/__init__.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "py/obj.h"
2727
#include "py/runtime.h"
2828
#include "py/reload.h"
29+
#include "py/objstr.h"
2930

3031
#include "lib/utils/interrupt_char.h"
3132
#include "supervisor/shared/autoreload.h"
@@ -109,6 +110,28 @@ STATIC mp_obj_t supervisor_set_next_stack_limit(mp_obj_t size_obj) {
109110
}
110111
MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_next_stack_limit_obj, supervisor_set_next_stack_limit);
111112

113+
STATIC mp_obj_t supervisor_set_next_code_file(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
114+
static const mp_arg_t allowed_args[] = {
115+
{ MP_QSTR_filename, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
116+
{ MP_QSTR_reload_on_success, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
117+
};
118+
struct {
119+
mp_arg_val_t filename;
120+
mp_arg_val_t reload_on_success;
121+
} args;
122+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t*)&args);
123+
if (!MP_OBJ_IS_STR_OR_BYTES(args.filename.u_obj)) {
124+
mp_raise_TypeError(translate("argument has wrong type"));
125+
}
126+
mp_obj_t items[] = {
127+
args.filename.u_obj,
128+
args.reload_on_success.u_bool ? MP_OBJ_NEW_SMALL_INT(SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS) : MP_OBJ_NEW_SMALL_INT(0)
129+
};
130+
MP_STATE_VM(supervisor_next_code) = mp_obj_new_tuple(MP_ARRAY_SIZE(items), items);
131+
return mp_const_none;
132+
}
133+
MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_next_code_file_obj, 1, supervisor_set_next_code_file);
134+
112135
STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
113136
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) },
114137
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_autoreload), MP_ROM_PTR(&supervisor_enable_autoreload_obj) },
@@ -117,7 +140,7 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
117140
{ MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) },
118141
{ MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&supervisor_reload_obj) },
119142
{ MP_ROM_QSTR(MP_QSTR_set_next_stack_limit), MP_ROM_PTR(&supervisor_set_next_stack_limit_obj) },
120-
143+
{ MP_ROM_QSTR(MP_QSTR_set_next_code_file), MP_ROM_PTR(&supervisor_set_next_code_file_obj) },
121144
};
122145

123146
STATIC MP_DEFINE_CONST_DICT(supervisor_module_globals, supervisor_module_globals_table);

supervisor/shared/autoreload.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929

3030
#include <stdbool.h>
3131

32+
enum {
33+
SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS = 0x1
34+
};
35+
3236
extern volatile bool reload_requested;
3337

3438
void autoreload_tick(void);

0 commit comments

Comments
 (0)