81
81
#include "supervisor/shared/bluetooth.h"
82
82
#endif
83
83
84
+ typedef struct {
85
+ uint8_t options ;
86
+ char filename [];
87
+ } next_code_info_t ;
88
+
89
+ static supervisor_allocation * next_code_allocation ;
90
+
84
91
void do_str (const char * src , mp_parse_input_kind_t input_kind ) {
85
92
mp_lexer_t * lex = mp_lexer_new_from_str_len (MP_QSTR__lt_stdin_gt_ , src , strlen (src ), 0 );
86
93
if (lex == NULL ) {
@@ -211,7 +218,21 @@ bool maybe_run_list(const char * const * filenames, pyexec_result_t* exec_result
211
218
return true;
212
219
}
213
220
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
+ }
215
236
// Reset port-independent devices, like CIRCUITPY_BLEIO_HCI.
216
237
reset_devices ();
217
238
// Turn off the display and flush the fileystem before the heap disappears.
@@ -232,6 +253,21 @@ void cleanup_after_vm(supervisor_allocation* heap) {
232
253
#endif
233
254
reset_board ();
234
255
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;
235
271
}
236
272
237
273
bool run_code_py (safe_mode_t safe_mode ) {
@@ -274,17 +310,42 @@ bool run_code_py(safe_mode_t safe_mode) {
274
310
filesystem_flush ();
275
311
supervisor_allocation * heap = allocate_remaining_memory ();
276
312
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" ));
283
321
}
284
322
}
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
+ }
287
345
346
+ if (result .return_code == 0 && (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS )) {
347
+ return true;
348
+ }
288
349
if (result .return_code & PYEXEC_FORCED_EXIT ) {
289
350
return reload_requested ;
290
351
}
0 commit comments