From c98c128fe885e539ecd73843756340f8950115c8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 6 May 2015 00:02:58 +0100 Subject: [PATCH] pyexec: Make raw REPL work with event-driven version of pyexec. esp8266 port now has working raw and friendly REPL, as well as working soft reset (CTRL-D at REPL, or raise SystemExit). tools/pyboard.py now works with esp8266 port. --- esp8266/main.c | 34 +++--- esp8266/uart.c | 10 +- minimal/main.c | 6 +- stmhal/pyexec.c | 272 +++++++++++++++++++++++++++++------------------- stmhal/pyexec.h | 4 +- 5 files changed, 192 insertions(+), 134 deletions(-) diff --git a/esp8266/main.c b/esp8266/main.c index b6024f3c57..a3878c0e75 100644 --- a/esp8266/main.c +++ b/esp8266/main.c @@ -39,8 +39,7 @@ STATIC char heap[16384]; -void user_init(void) { -soft_reset: +STATIC void mp_reset(void) { mp_stack_set_limit(10240); mp_hal_init(); gc_init(heap, heap + sizeof(heap)); @@ -48,29 +47,20 @@ soft_reset: mp_init(); mp_obj_list_init(mp_sys_path, 0); mp_obj_list_init(mp_sys_argv, 0); +} - printf("\n"); +void soft_reset(void) { + mp_hal_stdout_tx_str("PYB: soft reset\r\n"); + mp_hal_udelay(10000); // allow UART to flush output + mp_reset(); + pyexec_event_repl_init(); +} -#if MICROPY_REPL_EVENT_DRIVEN - pyexec_friendly_repl_init(); +void user_init(void) { + mp_reset(); + mp_hal_stdout_tx_str("\r\n"); + pyexec_event_repl_init(); uart_task_init(); - return; - goto soft_reset; -#else - for (;;) { - if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { - if (pyexec_raw_repl() != 0) { - break; - } - } else { - if (pyexec_friendly_repl() != 0) { - break; - } - } - } - - goto soft_reset; -#endif } mp_lexer_t *mp_lexer_new_from_file(const char *filename) { diff --git a/esp8266/uart.c b/esp8266/uart.c index 6087668a70..87bbb7c92e 100644 --- a/esp8266/uart.c +++ b/esp8266/uart.c @@ -200,10 +200,16 @@ void ICACHE_FLASH_ATTR uart_reattach() { // Task-based UART interface -int pyexec_friendly_repl_process_char(int c); +#include "py/obj.h" +#include "stmhal/pyexec.h" + +void soft_reset(void); void uart_task_handler(os_event_t *evt) { - pyexec_friendly_repl_process_char(evt->par); + int ret = pyexec_event_repl_process_char(evt->par); + if (ret & PYEXEC_FORCED_EXIT) { + soft_reset(); + } } void uart_task_init() { diff --git a/minimal/main.c b/minimal/main.c index 29b5af1af7..f6041267a2 100644 --- a/minimal/main.c +++ b/minimal/main.c @@ -41,10 +41,10 @@ int main(int argc, char **argv) { #endif mp_init(); #if MICROPY_REPL_EVENT_DRIVEN - pyexec_friendly_repl_init(); + pyexec_event_repl_init(); for (;;) { - int c = stdin_rx_chr(); - if (pyexec_friendly_repl_process_char(c)) { + int c = mp_hal_stdin_rx_chr(); + if (pyexec_event_repl_process_char(c)) { break; } } diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index 1a121ce3e5..aa7e353905 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -118,6 +118,172 @@ STATIC int parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_ki return ret; } +#if MICROPY_REPL_EVENT_DRIVEN + +typedef struct _repl_t { + // XXX line holds a root pointer! + vstr_t line; + bool cont_line; +} repl_t; + +repl_t repl; + +STATIC int pyexec_raw_repl_process_char(int c); +STATIC int pyexec_friendly_repl_process_char(int c); + +void pyexec_event_repl_init(void) { + vstr_init(&repl.line, 32); + repl.cont_line = false; + readline_init(&repl.line, ">>> "); + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + pyexec_raw_repl_process_char(CHAR_CTRL_A); + } else { + pyexec_friendly_repl_process_char(CHAR_CTRL_B); + } +} + +STATIC int pyexec_raw_repl_process_char(int c) { + if (c == CHAR_CTRL_A) { + // reset raw REPL + mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); + goto reset; + } else if (c == CHAR_CTRL_B) { + // change to friendly REPL + pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; + repl.cont_line = false; + pyexec_friendly_repl_process_char(CHAR_CTRL_B); + return 0; + } else if (c == CHAR_CTRL_C) { + // clear line + vstr_reset(&repl.line); + return 0; + } else if (c == CHAR_CTRL_D) { + // input finished + } else { + // let through any other raw 8-bit value + vstr_add_byte(&repl.line, c); + return 0; + } + + // indicate reception of command + mp_hal_stdout_tx_str("OK"); + + if (repl.line.len == 0) { + // exit for a soft reset + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(&repl.line); + return PYEXEC_FORCED_EXIT; + } + + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, repl.line.buf, repl.line.len, 0); + if (lex == NULL) { + mp_hal_stdout_tx_str("\x04MemoryError\r\n\x04"); + } else { + int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + } + +reset: + vstr_reset(&repl.line); + mp_hal_stdout_tx_str(">"); + + return 0; +} + +STATIC int pyexec_friendly_repl_process_char(int c) { + int ret = readline_process_char(c); + + if (!repl.cont_line) { + + if (ret == CHAR_CTRL_A) { + // change to raw REPL + pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; + mp_hal_stdout_tx_str("\r\n"); + pyexec_raw_repl_process_char(CHAR_CTRL_A); + return 0; + } else if (ret == CHAR_CTRL_B) { + // reset friendly REPL + mp_hal_stdout_tx_str("\r\n"); + mp_hal_stdout_tx_str("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); + mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); + goto input_restart; + } else if (ret == CHAR_CTRL_C) { + // break + mp_hal_stdout_tx_str("\r\n"); + goto input_restart; + } else if (ret == CHAR_CTRL_D) { + // exit for a soft reset + mp_hal_stdout_tx_str("\r\n"); + vstr_clear(&repl.line); + return PYEXEC_FORCED_EXIT; + } + + if (ret < 0) { + return 0; + } + + if (!mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) { + goto exec; + } + + vstr_add_byte(&repl.line, '\n'); + repl.cont_line = true; + readline_note_newline("... "); + return 0; + + } else { + + if (ret == CHAR_CTRL_C) { + // cancel everything + mp_hal_stdout_tx_str("\r\n"); + repl.cont_line = false; + goto input_restart; + } else if (ret == CHAR_CTRL_D) { + // stop entering compound statement + goto exec; + } + + if (ret < 0) { + return 0; + } + + if (mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) { + vstr_add_byte(&repl.line, '\n'); + readline_note_newline("... "); + return 0; + } + +exec: ; + mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&repl.line), vstr_len(&repl.line), 0); + if (lex == NULL) { + printf("MemoryError\n"); + } else { + int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL); + if (ret & PYEXEC_FORCED_EXIT) { + return ret; + } + } + +input_restart: + vstr_reset(&repl.line); + repl.cont_line = false; + readline_init(&repl.line, ">>> "); + return 0; + } +} + +int pyexec_event_repl_process_char(int c) { + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + return pyexec_raw_repl_process_char(c); + } else { + return pyexec_friendly_repl_process_char(c); + } +} + +#else // MICROPY_REPL_EVENT_DRIVEN + int pyexec_raw_repl(void) { vstr_t line; vstr_init(&line, 32); @@ -173,110 +339,6 @@ raw_repl_reset: } } -#if MICROPY_REPL_EVENT_DRIVEN - -typedef struct _friendly_repl_t { - vstr_t line; - bool cont_line; -} friendly_repl_t; - -friendly_repl_t repl; - -void pyexec_friendly_repl_init(void) { - vstr_init(&repl.line, 32); - repl.cont_line = false; - readline_init(&repl.line, ">>> "); -} - -void pyexec_friendly_repl_reset(void) { - vstr_reset(&repl.line); - repl.cont_line = false; - readline_init(&repl.line, ">>> "); -} - -int pyexec_friendly_repl_process_char(int c) { - int ret = readline_process_char(c); - - if (!repl.cont_line) { - - if (ret == CHAR_CTRL_A) { - // change to raw REPL - pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; - mp_hal_stdout_tx_str("\r\n"); - vstr_clear(&repl.line); - return PYEXEC_SWITCH_MODE; - } else if (ret == CHAR_CTRL_B) { - // reset friendly REPL - mp_hal_stdout_tx_str("\r\n"); - goto friendly_repl_reset; - } else if (ret == CHAR_CTRL_C) { - // break - mp_hal_stdout_tx_str("\r\n"); - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // exit for a soft reset - mp_hal_stdout_tx_str("\r\n"); - vstr_clear(&repl.line); - return PYEXEC_FORCED_EXIT; - } else if (vstr_len(&repl.line) == 0) { - //goto input_restart; - } - - if (ret < 0) { - return 0; - } - - if (!mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) { - goto exec; - } - - vstr_add_byte(&repl.line, '\n'); - repl.cont_line = true; - readline_note_newline("... "); - return 0; - - } else { - - if (ret == CHAR_CTRL_C) { - // cancel everything - mp_hal_stdout_tx_str("\r\n"); - repl.cont_line = false; - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // stop entering compound statement - goto exec; - } - - if (ret < 0) { - return 0; - } - - if (mp_repl_continue_with_input(vstr_null_terminated_str(&repl.line))) { - vstr_add_byte(&repl.line, '\n'); - readline_note_newline("... "); - return 0; - } - -exec: ; - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&repl.line), vstr_len(&repl.line), 0); - if (lex == NULL) { - printf("MemoryError\n"); - } else { - int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL); - if (ret & PYEXEC_FORCED_EXIT) { - return ret; - } - } - -friendly_repl_reset: // TODO -input_restart: - pyexec_friendly_repl_reset(); - return 0; - } -} - -#else //MICROPY_REPL_EVENT_DRIVEN - int pyexec_friendly_repl(void) { vstr_t line; vstr_init(&line, 32); @@ -376,7 +438,7 @@ friendly_repl_reset: } } -#endif //MICROPY_REPL_EVENT_DRIVEN +#endif // MICROPY_REPL_EVENT_DRIVEN int pyexec_file(const char *filename) { mp_lexer_t *lex = mp_lexer_new_from_file(filename); diff --git a/stmhal/pyexec.h b/stmhal/pyexec.h index d01d505a78..0728b91333 100644 --- a/stmhal/pyexec.h +++ b/stmhal/pyexec.h @@ -37,7 +37,7 @@ extern pyexec_mode_kind_t pyexec_mode_kind; int pyexec_raw_repl(void); int pyexec_friendly_repl(void); int pyexec_file(const char *filename); -void pyexec_friendly_repl_init(void); -int pyexec_friendly_repl_process_char(int c); +void pyexec_event_repl_init(void); +int pyexec_event_repl_process_char(int c); MP_DECLARE_CONST_FUN_OBJ(pyb_set_repl_info_obj);