85
85
#include "common-hal/canio/CAN.h"
86
86
#endif
87
87
88
+ typedef struct {
89
+ uint8_t options ;
90
+ char filename [];
91
+ } next_code_info_t ;
92
+
93
+ static supervisor_allocation * next_code_allocation ;
94
+
88
95
void do_str (const char * src , mp_parse_input_kind_t input_kind ) {
89
96
mp_lexer_t * lex = mp_lexer_new_from_str_len (MP_QSTR__lt_stdin_gt_ , src , strlen (src ), 0 );
90
97
if (lex == NULL ) {
@@ -215,7 +222,21 @@ bool maybe_run_list(const char * const * filenames, pyexec_result_t* exec_result
215
222
return true;
216
223
}
217
224
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
+ }
219
240
// Reset port-independent devices, like CIRCUITPY_BLEIO_HCI.
220
241
reset_devices ();
221
242
// Turn off the display and flush the fileystem before the heap disappears.
@@ -240,6 +261,24 @@ void cleanup_after_vm(supervisor_allocation* heap) {
240
261
#endif
241
262
reset_board ();
242
263
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;
243
282
}
244
283
245
284
bool run_code_py (safe_mode_t safe_mode ) {
@@ -282,17 +321,42 @@ bool run_code_py(safe_mode_t safe_mode) {
282
321
filesystem_flush ();
283
322
supervisor_allocation * heap = allocate_remaining_memory ();
284
323
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" ));
291
332
}
292
333
}
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
+ }
295
356
357
+ if (result .return_code == 0 && (next_code_options & SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS )) {
358
+ return true;
359
+ }
296
360
if (result .return_code & PYEXEC_FORCED_EXIT ) {
297
361
return reload_requested ;
298
362
}
0 commit comments