diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 9f4f051fd..df97a7343 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -35,15 +35,18 @@ #include "extmod/misc.h" #include "lib/utils/pyexec.h" -STATIC byte input_buf_array[256]; -ringbuf_t input_buf = {input_buf_array, sizeof(input_buf_array)}; +STATIC byte stdin_ringbuf_array[256]; +ringbuf_t stdin_ringbuf = {stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0}; void mp_hal_debug_tx_strn_cooked(void *env, const char *str, uint32_t len); const mp_print_t mp_debug_print = {NULL, mp_hal_debug_tx_strn_cooked}; +int uart_attached_to_dupterm; + void mp_hal_init(void) { //ets_wdt_disable(); // it's a pain while developing mp_hal_rtc_init(); uart_init(UART_BIT_RATE_115200, UART_BIT_RATE_115200); + uart_attached_to_dupterm = 0; } void mp_hal_delay_us(uint32_t us) { @@ -55,7 +58,7 @@ void mp_hal_delay_us(uint32_t us) { int mp_hal_stdin_rx_chr(void) { for (;;) { - int c = ringbuf_get(&input_buf); + int c = ringbuf_get(&stdin_ringbuf); if (c != -1) { return c; } @@ -80,19 +83,11 @@ void mp_hal_debug_str(const char *str) { #endif void mp_hal_stdout_tx_str(const char *str) { - const char *last = str; - while (*str) { - uart_tx_one_char(UART0, *str++); - } - mp_uos_dupterm_tx_strn(last, str - last); + mp_uos_dupterm_tx_strn(str, strlen(str)); } void mp_hal_stdout_tx_strn(const char *str, uint32_t len) { - const char *last = str; - while (len--) { - uart_tx_one_char(UART0, *str++); - } - mp_uos_dupterm_tx_strn(last, str - last); + mp_uos_dupterm_tx_strn(str, len); } void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { @@ -102,13 +97,11 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, uint32_t len) { if (str > last) { mp_uos_dupterm_tx_strn(last, str - last); } - uart_tx_one_char(UART0, '\r'); - uart_tx_one_char(UART0, '\n'); mp_uos_dupterm_tx_strn("\r\n", 2); ++str; last = str; } else { - uart_tx_one_char(UART0, *str++); + ++str; } } if (str > last) { @@ -166,7 +159,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) { if (c < 0) { break; } - ringbuf_put(&input_buf, c); + ringbuf_put(&stdin_ringbuf, c); } mp_hal_signal_input(); lock = 0; diff --git a/ports/esp8266/esp_mphal.h b/ports/esp8266/esp_mphal.h index 940ca4727..56d9fa35f 100644 --- a/ports/esp8266/esp_mphal.h +++ b/ports/esp8266/esp_mphal.h @@ -34,12 +34,15 @@ struct _mp_print_t; // Structure for UART-only output via mp_printf() extern const struct _mp_print_t mp_debug_print; -extern ringbuf_t input_buf; -// Call this after putting data to input_buf +extern ringbuf_t stdin_ringbuf; +// Call this after putting data to stdin_ringbuf void mp_hal_signal_input(void); // Call this when data is available in dupterm object void mp_hal_signal_dupterm_input(void); +// This variable counts how many times the UART is attached to dupterm +extern int uart_attached_to_dupterm; + void mp_hal_init(void); void mp_hal_rtc_init(void); diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index d2d2c34ec..975262fd1 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -33,6 +33,7 @@ #include "py/mperrno.h" #include "py/mphal.h" #include "py/gc.h" +#include "extmod/misc.h" #include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "gccollect.h" @@ -65,6 +66,25 @@ STATIC void mp_reset(void) { pyexec_file("main.py"); } #endif + + // Check if there are any dupterm objects registered and if not then + // activate UART(0), or else there will never be any chance to get a REPL + size_t idx; + for (idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) != MP_OBJ_NULL) { + break; + } + } + if (idx == MICROPY_PY_OS_DUPTERM) { + mp_obj_t args[2]; + args[0] = MP_OBJ_NEW_SMALL_INT(0); + args[1] = MP_OBJ_NEW_SMALL_INT(115200); + args[0] = pyb_uart_type.make_new(&pyb_uart_type, 2, 0, args); + args[1] = MP_OBJ_NEW_SMALL_INT(1); + extern mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args); + os_dupterm(2, args); + mp_hal_stdout_tx_str("Activated UART(0) for REPL\r\n"); + } } void soft_reset(void) { diff --git a/ports/esp8266/modules/inisetup.py b/ports/esp8266/modules/inisetup.py index af78dfad5..9184c6c39 100644 --- a/ports/esp8266/modules/inisetup.py +++ b/ports/esp8266/modules/inisetup.py @@ -44,6 +44,8 @@ def setup(): # This file is executed on every boot (including wake-boot from deepsleep) #import esp #esp.osdebug(None) +import uos, machine +uos.dupterm(machine.UART(0, 115200), 1) import gc #import webrepl #webrepl.start() diff --git a/ports/esp8266/moduos.c b/ports/esp8266/moduos.c index 93f7aa712..7a32c11c0 100644 --- a/ports/esp8266/moduos.c +++ b/ports/esp8266/moduos.c @@ -76,6 +76,19 @@ STATIC mp_obj_t os_urandom(mp_obj_t num) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_urandom_obj, os_urandom); +// We wrap the mp_uos_dupterm function to detect if a UART is attached or not +mp_obj_t os_dupterm(size_t n_args, const mp_obj_t *args) { + mp_obj_t prev_obj = mp_uos_dupterm_obj.fun.var(n_args, args); + if (mp_obj_get_type(args[0]) == &pyb_uart_type) { + ++uart_attached_to_dupterm; + } + if (mp_obj_get_type(prev_obj) == &pyb_uart_type) { + --uart_attached_to_dupterm; + } + return prev_obj; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(os_dupterm_obj, 1, 2, os_dupterm); + STATIC mp_obj_t os_dupterm_notify(mp_obj_t obj_in) { (void)obj_in; mp_hal_signal_dupterm_input(); @@ -88,7 +101,7 @@ STATIC const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_uname), MP_ROM_PTR(&os_uname_obj) }, { MP_ROM_QSTR(MP_QSTR_urandom), MP_ROM_PTR(&os_urandom_obj) }, #if MICROPY_PY_OS_DUPTERM - { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&mp_uos_dupterm_obj) }, + { MP_ROM_QSTR(MP_QSTR_dupterm), MP_ROM_PTR(&os_dupterm_obj) }, { MP_ROM_QSTR(MP_QSTR_dupterm_notify), MP_ROM_PTR(&os_dupterm_notify_obj) }, #endif #if MICROPY_VFS_FAT diff --git a/ports/esp8266/mpconfigport.h b/ports/esp8266/mpconfigport.h index 8de28eb96..ec347dae0 100644 --- a/ports/esp8266/mpconfigport.h +++ b/ports/esp8266/mpconfigport.h @@ -86,7 +86,7 @@ #define MICROPY_PY_WEBREPL_DELAY (20) #define MICROPY_PY_FRAMEBUF (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) -#define MICROPY_PY_OS_DUPTERM (1) +#define MICROPY_PY_OS_DUPTERM (2) #define MICROPY_CPYTHON_COMPAT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) diff --git a/ports/esp8266/uart.c b/ports/esp8266/uart.c index ec944a97c..52707f981 100644 --- a/ports/esp8266/uart.c +++ b/ports/esp8266/uart.c @@ -34,6 +34,11 @@ static int uart_os = UART_OS; static os_event_t uart_evt_queue[16]; #endif +// A small, static ring buffer for incoming chars +// This will only be populated if the UART is not attached to dupterm +static byte uart_ringbuf_array[16]; +static ringbuf_t uart_ringbuf = {uart_ringbuf_array, sizeof(uart_ringbuf_array), 0, 0}; + static void uart0_rx_intr_handler(void *para); void soft_reset(void); @@ -170,18 +175,26 @@ static void uart0_rx_intr_handler(void *para) { while (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) { uint8 RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xff; - if (RcvChar == mp_interrupt_char) { - mp_keyboard_interrupt(); + // For efficiency, when connected to dupterm we put incoming chars + // directly on stdin_ringbuf, rather than going via uart_ringbuf + if (uart_attached_to_dupterm) { + if (RcvChar == mp_interrupt_char) { + mp_keyboard_interrupt(); + } else { + ringbuf_put(&stdin_ringbuf, RcvChar); + } } else { - ringbuf_put(&input_buf, RcvChar); + ringbuf_put(&uart_ringbuf, RcvChar); } } - mp_hal_signal_input(); - // Clear pending FIFO interrupts WRITE_PERI_REG(UART_INT_CLR(UART_REPL), UART_RXFIFO_TOUT_INT_CLR | UART_RXFIFO_FULL_INT_ST); ETS_UART_INTR_ENABLE(); + + if (uart_attached_to_dupterm) { + mp_hal_signal_input(); + } } } @@ -190,7 +203,7 @@ static void uart0_rx_intr_handler(void *para) { bool uart_rx_wait(uint32_t timeout_us) { uint32_t start = system_get_time(); for (;;) { - if (input_buf.iget != input_buf.iput) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { return true; // have at least 1 char ready for reading } if (system_get_time() - start >= timeout_us) { @@ -201,7 +214,7 @@ bool uart_rx_wait(uint32_t timeout_us) { } int uart_rx_any(uint8 uart) { - if (input_buf.iget != input_buf.iput) { + if (uart_ringbuf.iget != uart_ringbuf.iput) { return true; // have at least 1 char ready for reading } return false; @@ -217,7 +230,7 @@ int uart_tx_any_room(uint8 uart) { // Returns char from the input buffer, else -1 if buffer is empty. int uart_rx_char(void) { - return ringbuf_get(&input_buf); + return ringbuf_get(&uart_ringbuf); } int uart_rx_one_char(uint8 uart_no) {