diff --git a/stmhal/main.c b/stmhal/main.c index 097b8ca853..0279e70b48 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -458,7 +458,11 @@ soft_reset: const char *boot_py = "boot.py"; FRESULT res = f_stat(boot_py, NULL); if (res == FR_OK) { - if (!pyexec_file(boot_py)) { + int ret = pyexec_file(boot_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { flash_error(4); } } @@ -517,7 +521,11 @@ soft_reset: } FRESULT res = f_stat(main_py, NULL); if (res == FR_OK) { - if (!pyexec_file(main_py)) { + int ret = pyexec_file(main_py); + if (ret & PYEXEC_FORCED_EXIT) { + goto soft_reset_exit; + } + if (!ret) { flash_error(3); } } @@ -537,6 +545,8 @@ soft_reset: } } +soft_reset_exit: + // soft reset printf("PYB: sync filesystems\n"); diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 04f47f2d3e..062202aade 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -88,6 +88,15 @@ STATIC NORETURN mp_obj_t pyb_bootloader(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_bootloader_obj, pyb_bootloader); +/// \function hard_reset() +/// Resets the pyboard in a manner similar to pushing the external RESET +/// button. +STATIC mp_obj_t pyb_hard_reset(void) { + NVIC_SystemReset(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_hard_reset_obj, pyb_hard_reset); + /// \function info([dump_alloc_table]) /// Print out lots of information about the board. STATIC mp_obj_t pyb_info(mp_uint_t n_args, const mp_obj_t *args) { @@ -443,6 +452,7 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, { MP_OBJ_NEW_QSTR(MP_QSTR_bootloader), (mp_obj_t)&pyb_bootloader_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_hard_reset), (mp_obj_t)&pyb_hard_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&pyb_unique_id_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&pyb_freq_obj }, diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index f458bd0ff3..c6b9b8b054 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -56,7 +56,7 @@ STATIC bool repl_display_debugging_info = 0; // parses, compiles and executes the code in the lexer // frees the lexer before returning -bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { +int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { mp_parse_error_kind_t parse_error_kind; mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind); qstr source_name = mp_lexer_source_name(lex); @@ -65,7 +65,7 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo // parse error mp_parse_show_exception(lex, parse_error_kind); mp_lexer_free(lex); - return false; + return 0; } mp_lexer_free(lex); @@ -74,24 +74,35 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo if (mp_obj_is_exception_instance(module_fun)) { mp_obj_print_exception(module_fun); - return false; + return 0; } nlr_buf_t nlr; - bool ret; + int ret; uint32_t start = HAL_GetTick(); if (nlr_push(&nlr) == 0) { usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us mp_call_function_0(module_fun); usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt nlr_pop(); - ret = true; + ret = 1; } else { // uncaught exception // FIXME it could be that an interrupt happens just before we disable it here usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt + // check for SystemExit + mp_obj_t exc = (mp_obj_t)nlr.ret_val; + if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { + // None is an exit value of 0; an int is its value; anything else is 1 + mp_obj_t exit_val = mp_obj_exception_get_value(exc); + mp_int_t val = 0; + if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) { + val = 1; + } + return PYEXEC_FORCED_EXIT | (val & 255); + } mp_obj_print_exception((mp_obj_t)nlr.ret_val); - ret = false; + ret = 0; } // display debugging info if wanted @@ -160,14 +171,17 @@ raw_repl_reset: // exit for a soft reset stdout_tx_str("\r\n"); vstr_clear(&line); - return 1; + return PYEXEC_FORCED_EXIT; } mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, 0); if (lex == NULL) { printf("MemoryError\n"); } else { - parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false); + int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } } // indicate end of output with EOF character @@ -229,7 +243,7 @@ friendly_repl_reset: // exit for a soft reset stdout_tx_str("\r\n"); vstr_clear(&line); - return 1; + return PYEXEC_FORCED_EXIT; } else if (vstr_len(&line) == 0) { continue; } @@ -247,7 +261,10 @@ friendly_repl_reset: if (lex == NULL) { printf("MemoryError\n"); } else { - parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true); + int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } } } } diff --git a/stmhal/pyexec.h b/stmhal/pyexec.h index ce9fe5cbc1..dec241deec 100644 --- a/stmhal/pyexec.h +++ b/stmhal/pyexec.h @@ -31,6 +31,8 @@ typedef enum { extern pyexec_mode_kind_t pyexec_mode_kind; +#define PYEXEC_FORCED_EXIT (0x100) + int pyexec_raw_repl(void); int pyexec_friendly_repl(void); bool pyexec_file(const char *filename); diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 314fceea5d..87020f4b8e 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -30,6 +30,7 @@ Q(help) Q(pyb) Q(unique_id) Q(bootloader) +Q(hard_reset) Q(info) Q(sd_test) Q(present)