8000 Add supervisor.set_next_code() function (prototype). · cwalther/circuitpython@5408547 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5408547

Browse files
committed
Add supervisor.set_next_code() function (prototype).
Fixes adafruit#1084.
1 parent 551f78e commit 5408547

File tree

5 files changed

+108
-11
lines changed

5 files changed

+108
-11
lines changed

locale/circuitpython.pot

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ msgstr ""
3838
msgid " File \"%q\", line %d"
3939
msgstr ""
4040

41+
#: main.c
42+
msgid " not found.\n"
43+
msgstr ""
44+
4145
#: main.c
4246
msgid " output:\n"
4347
msgstr ""
@@ -1995,7 +1999,7 @@ msgstr ""
19951999
msgid "argsort argument must be an ndarray"
19962000
msgstr ""
19972001

1998-
#: py/runtime.c
2002+
#: py/runtime.c shared-bindings/supervisor/__init__.c
19992003
msgid "argument has wrong type"
20002004
msgstr ""
20012005

main.c

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@
8585
#include "common-hal/canio/CAN.h"
8686
#endif
8787

88+
typedef struct {
89+
uint8_t options;
90+
char filename[];
91+
} next_code_info_t;
92+
93+
static supervisor_allocation* next_code_allocation;
94+
8895
void do_str(const char *src, mp_parse_input_kind_t input_kind) {
8996
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
9097
if (lex == NULL) {
@@ -215,7 +222,21 @@ bool maybe_run_list(const char * const * filenames, pyexec_result_t* exec_result
215222
return true;
216223
}
217224

218-
void cleanup_after_vm(supervisor_allocation* heap) {
225+
bool cleanup_after_vm(supervisor_allocation* heap) {
226+
// Get any info on what code to run next off the heap.
227+
next_code_info_t* next_code = NULL;
228+
size_t next_code_len = 0;
229+
if (MP_STATE_VM(supervisor_next_code)) {
230+
size_t len;
231+
mp_obj_t* items;
232+
mp_obj_tuple_get(MP_STATE_VM(supervisor_next_code), &len, &items);
233+
const char* filename = mp_obj_str_get_data(items[0], &len);
234+
next_code_len = sizeof(uint8_t) + len; // termination not needed here, saves a byte of stack
235+
next_code = alloca(next_code_len);
236+
next_code->options = (uint8_t)MP_OBJ_SMALL_INT_VALUE(items[1]);
237+
memcpy(&next_code->filename, filename, len);
238+
MP_STATE_VM(supervisor_next_code) = NULL;
239+
}
219240
// Reset port-independent devices, like CIRCUITPY_BLEIO_HCI.
220241
reset_devices();
221242
// Turn off the display and flush the fileystem before the heap disappears.
@@ -240,6 +261,24 @@ void cleanup_after_vm(supervisor_allocation* heap) {
240261
#endif
241262
reset_board();
242263
reset_status_led();
264+
265+
// Save next code info.
266+
if (next_code) {
267+
if (next_code_allocation) {
268+
free_memory(next_code_allocation);
269+
}
270+
// empty filename and options 0 is equivalent to the default, no need to waste memory on that
271+
if (next_code_len > 1 || next_code->options != 0) {
272+
// TODO do I need to increase CIRCUITPY_SUPERVISOR_ALLOC_COUNT for this?
273+
next_code_allocation = allocate_memory((next_code_len + 1 + 3) & ~3, false);
274+
if (next_code_allocation) {
275+
memcpy(next_code_allocation->ptr, next_code, next_code_len);
276+
((char*)next_code_allocation->ptr)[next_code_len] = '\0';
277+
return true;
278+
}
279+
}
280+
}
281+
return false;
243282
}
244283

245284
bool run_code_py(safe_mode_t safe_mode) {
@@ -282,17 +321,42 @@ bool run_code_py(safe_mode_t safe_mode) {
282321
filesystem_flush();
283322
supervisor_allocation* heap = allocate_remaining_memory();
284323
start_mp(heap);
285-
found_main = maybe_run_list(supported_filenames, &result);
286-
#if CIRCUITPY_FULL_BUILD
287-
if (!found_main){
288-
found_main = maybe_run_list(double_extension_filenames, &result);
289-
if (found_main) {
290-
serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
324+
uint8_t next_code_options = 0;
325+
if (next_code_allocation) {
326+
next_code_options = ((next_code_info_t*)next_code_allocation->ptr)->options;
327+
const char* next_list[] = {((next_code_info_t*)next_code_allocation->ptr)->filename, ""};
328+
found_main = maybe_run_list(next_list, &result);
329+
if (!found_main) {
330+
serial_write(((next_code_info_t*)next_code_allocation->ptr)->filename);
331+
serial_write_compressed(translate(" not found.\n"));
291332
}
292333
}
293-
#endif
294-
cleanup_after_vm(heap);
334+
if (!found_main) {
335+
found_main = maybe_run_list(supported_filenames, &result);
336+
#if CIRCUITPY_FULL_BUILD
337+
if (!found_main){
338+
found_main = maybe_run_list(double_extension_filenames, &result);
339+
if (found_main) {
340+
serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
341+
}
342+
}
343+
#endif
344+
}
345+
bool new_next_code = cleanup_after_vm(heap);
346+
// - If a new next code file was set, honor that in any case.
347+
// - Otherwise: If a reload was requested by a USB file write, we want to run the same file
348+
// again, preserve any next-code info. Currently that also covers a reload requested by
349+
// supervisor.reload(), or do we want to treat that differently by turning
350+
// reload_requested into an enum?
351+
// - Otherwise: Clear any leftover next-code info and restart at code.py/main.py.
352+
if (!new_next_code && !reload_requested) {
353+
free_memory(next_code_allocation);
354+
next_code_allocation = NULL;
355+
}
295356

357+
if (result.return_code == 0 && (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS)) {
358+
return true;
359+
}
296360
if (result.return_code & PYEXEC_FORCED_EXIT) {
297361
return reload_requested;
298362
}

py/circuitpy_mpconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,7 @@ extern const struct _mp_obj_module_t wifi_module;
857857
FLASH_ROOT_POINTERS \
858858
MEMORYMONITOR_ROOT_POINTERS \
859859
NETWORK_ROOT_POINTERS \
860+
mp_obj_t supervisor_next_code; \
860861

861862
void supervisor_run_background_tasks_if_tick(void);
862863
#define RUN_BACKGROUND_TASKS (supervisor_run_background_tasks_if_tick())

shared-bindings/supervisor/__init__.c

Lines changed: 25 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,29 @@ 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) && args.filename.u_obj != mp_const_none) {
124+
mp_raise_TypeError(translate("argument has wrong type"));
125+
}
126+
if (args.filename.u_obj == mp_const_none) args.filename.u_obj = mp_const_empty_bytes;
127+
mp_obj_t items[] = {
128+
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)
130+
};
131+
MP_STATE_VM(supervisor_next_code) = mp_obj_new_tuple(MP_ARRAY_SIZE(items), items);
132+
return mp_const_none;
133+
}
134+
MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_next_code_file_obj, 1, supervisor_set_next_code_file);
135+
112136
STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
113137
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) },
114138
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_autoreload), MP_ROM_PTR(&supervisor_enable_autoreload_obj) },
@@ -117,7 +141,7 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
117141
{ MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) },
118142
{ MP_ROM_QSTR(MP_QSTR_reload), MP_ROM_PTR(&supervisor_reload_obj) },
119143
{ MP_ROM_QSTR(MP_QSTR_set_next_stack_limit), MP_ROM_PTR(&supervisor_set_next_stack_limit_obj) },
120-
144+
{ MP_ROM_QSTR(MP_QSTR_set_next_code_file), MP_ROM_PTR(&supervisor_set_next_code_file_obj) },
121145
};
122146

123147
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)
0