From 37282f8fc135a16ff36e2afe0de907cbde531ed0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 13 Oct 2017 20:01:57 +1100 Subject: [PATCH] extmod/uos_dupterm: Update uos.dupterm() and helper funcs to have index. The uos.dupterm() signature and behaviour is updated to reflect the latest enhancements in the docs. It has minor backwards incompatibility in that it no longer accepts zero arguments. The dupterm_rx helper function is moved from esp8266 to extmod and generalised to support multiple dupterm slots. A port can specify multiple slots by defining the MICROPY_PY_OS_DUPTERM config macro to an integer, being the number of slots it wants to have; 0 means to disable the dupterm feature altogether. The unix and esp8266 ports are updated to work with the new interface and are otherwise unchanged with respect to functionality. --- extmod/misc.h | 3 +- extmod/uos_dupterm.c | 100 +++++++++++++++++++++++-------- ports/esp8266/esp_mphal.c | 37 +----------- ports/esp8266/main.c | 2 - ports/esp8266/modules/webrepl.py | 4 +- ports/unix/unix_mphal.c | 17 +++--- py/mpstate.h | 2 +- py/runtime.c | 7 +++ 8 files changed, 97 insertions(+), 75 deletions(-) diff --git a/extmod/misc.h b/extmod/misc.h index 6c13592c75..d6f6d859c6 100644 --- a/extmod/misc.h +++ b/extmod/misc.h @@ -35,8 +35,9 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM +int mp_uos_dupterm_rx_chr(void); void mp_uos_dupterm_tx_strn(const char *str, size_t len); -void mp_uos_deactivate(const char *msg, mp_obj_t exc); +void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc); #else #define mp_uos_dupterm_tx_strn(s, l) #endif diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c index 1d6f02dcea..d4326d3265 100644 --- a/extmod/uos_dupterm.c +++ b/extmod/uos_dupterm.c @@ -4,6 +4,7 @@ * The MIT License (MIT) * * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,12 +32,13 @@ #include "py/objtuple.h" #include "py/objarray.h" #include "py/stream.h" +#include "lib/utils/interrupt_char.h" #if MICROPY_PY_OS_DUPTERM -void mp_uos_deactivate(const char *msg, mp_obj_t exc) { - mp_obj_t term = MP_STATE_PORT(term_obj); - MP_STATE_PORT(term_obj) = NULL; +void mp_uos_deactivate(size_t dupterm_idx, const char *msg, mp_obj_t exc) { + mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]); + MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_OBJ_NULL; mp_printf(&mp_plat_print, msg); if (exc != MP_OBJ_NULL) { mp_obj_print_exception(&mp_plat_print, exc); @@ -44,48 +46,94 @@ void mp_uos_deactivate(const char *msg, mp_obj_t exc) { mp_stream_close(term); } +int mp_uos_dupterm_rx_chr(void) { + for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { + continue; + } + + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t readinto_m[3]; + mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_readinto, readinto_m); + readinto_m[2] = MP_STATE_VM(dupterm_arr_obj); + mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m); + if (res == mp_const_none) { + nlr_pop(); + } else if (res == MP_OBJ_NEW_SMALL_INT(0)) { + mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL); + nlr_pop(); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(MP_STATE_VM(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ); + nlr_pop(); + if (*(byte*)bufinfo.buf == mp_interrupt_char) { + // Signal keyboard interrupt to be raised as soon as the VM resumes + mp_keyboard_interrupt(); + return -2; + } + return *(byte*)bufinfo.buf; + } + } else { + mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", nlr.ret_val); + } + } + + // No chars available + return -1; +} + void mp_uos_dupterm_tx_strn(const char *str, size_t len) { - if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) { + for (size_t idx = 0; idx < MICROPY_PY_OS_DUPTERM; ++idx) { + if (MP_STATE_VM(dupterm_objs[idx]) == MP_OBJ_NULL) { + continue; + } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t write_m[3]; - mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_write, write_m); + mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_write, write_m); - mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); + mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj)); void *org_items = arr->items; arr->items = (void*)str; arr->len = len; - write_m[2] = MP_STATE_PORT(dupterm_arr_obj); + write_m[2] = MP_STATE_VM(dupterm_arr_obj); mp_call_method_n_kw(1, 0, write_m); - arr = MP_OBJ_TO_PTR(MP_STATE_PORT(dupterm_arr_obj)); + arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj)); arr->items = org_items; arr->len = 1; nlr_pop(); } else { - mp_uos_deactivate("dupterm: Exception in write() method, deactivating: ", nlr.ret_val); + mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", nlr.ret_val); } } } STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) { - if (n_args == 0) { - if (MP_STATE_PORT(term_obj) == MP_OBJ_NULL) { - return mp_const_none; - } else { - return MP_STATE_PORT(term_obj); - } - } else { - if (args[0] == mp_const_none) { - MP_STATE_PORT(term_obj) = MP_OBJ_NULL; - } else { - MP_STATE_PORT(term_obj) = args[0]; - if (MP_STATE_PORT(dupterm_arr_obj) == MP_OBJ_NULL) { - MP_STATE_PORT(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); - } - } - return mp_const_none; + mp_int_t idx = 0; + if (n_args == 2) { + idx = mp_obj_get_int(args[1]); } + + if (idx < 0 || idx >= MICROPY_PY_OS_DUPTERM) { + mp_raise_ValueError("invalid dupterm index"); + } + + mp_obj_t previous_obj = MP_STATE_VM(dupterm_objs[idx]); + if (previous_obj == MP_OBJ_NULL) { + previous_obj = mp_const_none; + } + if (args[0] == mp_const_none) { + MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL; + } else { + MP_STATE_VM(dupterm_objs[idx]) = args[0]; + if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) { + MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); + } + } + + return previous_obj; } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 0, 1, mp_uos_dupterm); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 1, 2, mp_uos_dupterm); #endif diff --git a/ports/esp8266/esp_mphal.c b/ports/esp8266/esp_mphal.c index 71d4c50628..9f4f051fdd 100644 --- a/ports/esp8266/esp_mphal.c +++ b/ports/esp8266/esp_mphal.c @@ -155,41 +155,6 @@ void mp_hal_signal_input(void) { #endif } -static int call_dupterm_read(void) { - if (MP_STATE_PORT(term_obj) == NULL) { - return -1; - } - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t readinto_m[3]; - mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_readinto, readinto_m); - readinto_m[2] = MP_STATE_PORT(dupterm_arr_obj); - mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m); - if (res == mp_const_none) { - nlr_pop(); - return -2; - } - if (res == MP_OBJ_NEW_SMALL_INT(0)) { - mp_uos_deactivate("dupterm: EOF received, deactivating\n", MP_OBJ_NULL); - nlr_pop(); - return -1; - } - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(MP_STATE_PORT(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ); - nlr_pop(); - if (*(byte*)bufinfo.buf == mp_interrupt_char) { - mp_keyboard_interrupt(); - return -2; - } - return *(byte*)bufinfo.buf; - } else { - mp_uos_deactivate("dupterm: Exception in read() method, deactivating: ", nlr.ret_val); - } - - return -1; -} - STATIC void dupterm_task_handler(os_event_t *evt) { static byte lock; if (lock) { @@ -197,7 +162,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) { } lock = 1; while (1) { - int c = call_dupterm_read(); + int c = mp_uos_dupterm_rx_chr(); if (c < 0) { break; } diff --git a/ports/esp8266/main.c b/ports/esp8266/main.c index 7f5dca84e2..d1b88a8cec 100644 --- a/ports/esp8266/main.c +++ b/ports/esp8266/main.c @@ -51,8 +51,6 @@ STATIC void mp_reset(void) { mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_lib)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_)); mp_obj_list_init(mp_sys_argv, 0); - MP_STATE_PORT(term_obj) = MP_OBJ_NULL; - MP_STATE_PORT(dupterm_arr_obj) = MP_OBJ_NULL; #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA extern void esp_native_code_init(void); esp_native_code_init(); diff --git a/ports/esp8266/modules/webrepl.py b/ports/esp8266/modules/webrepl.py index 5a76e9b26d..aa156d1487 100644 --- a/ports/esp8266/modules/webrepl.py +++ b/ports/esp8266/modules/webrepl.py @@ -31,7 +31,9 @@ def setup_conn(port, accept_handler): def accept_conn(listen_sock): global client_s cl, remote_addr = listen_sock.accept() - if uos.dupterm(): + prev = uos.dupterm(None) + uos.dupterm(prev) + if prev: print("\nConcurrent WebREPL connection from", remote_addr, "rejected") cl.close() return diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 2b273d8341..f27c62fd1d 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -108,11 +108,11 @@ void mp_hal_stdio_mode_orig(void) { #endif #if MICROPY_PY_OS_DUPTERM -static int call_dupterm_read(void) { +static int call_dupterm_read(size_t idx) { nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t read_m[3]; - mp_load_method(MP_STATE_PORT(term_obj), MP_QSTR_read, read_m); + mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_read, read_m); read_m[2] = MP_OBJ_NEW_SMALL_INT(1); mp_obj_t res = mp_call_method_n_kw(1, 0, read_m); if (res == mp_const_none) { @@ -122,18 +122,18 @@ static int call_dupterm_read(void) { mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ); if (bufinfo.len == 0) { mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n"); - MP_STATE_PORT(term_obj) = NULL; + MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL; return -1; } nlr_pop(); return *(byte*)bufinfo.buf; } else { // Temporarily disable dupterm to avoid infinite recursion - mp_obj_t save_term = MP_STATE_PORT(term_obj); - MP_STATE_PORT(term_obj) = NULL; + mp_obj_t save_term = MP_STATE_VM(dupterm_objs[idx]); + MP_STATE_VM(dupterm_objs[idx]) = NULL; mp_printf(&mp_plat_print, "dupterm: "); mp_obj_print_exception(&mp_plat_print, nlr.ret_val); - MP_STATE_PORT(term_obj) = save_term; + MP_STATE_VM(dupterm_objs[idx]) = save_term; } return -1; @@ -143,10 +143,11 @@ static int call_dupterm_read(void) { int mp_hal_stdin_rx_chr(void) { unsigned char c; #if MICROPY_PY_OS_DUPTERM - if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) { + // TODO only support dupterm one slot at the moment + if (MP_STATE_VM(dupterm_objs[0]) != MP_OBJ_NULL) { int c; do { - c = call_dupterm_read(); + c = call_dupterm_read(0); } while (c == -2); if (c == -1) { goto main_term; diff --git a/py/mpstate.h b/py/mpstate.h index eca14a9e44..6a39ebdea9 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -168,7 +168,7 @@ typedef struct _mp_state_vm_t { // root pointers for extmod #if MICROPY_PY_OS_DUPTERM - mp_obj_t term_obj; + mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM]; mp_obj_t dupterm_arr_obj; #endif diff --git a/py/runtime.c b/py/runtime.c index 069548debb..17e5d235c9 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -102,6 +102,13 @@ void mp_init(void) { MP_STATE_VM(mp_module_builtins_override_dict) = NULL; #endif + #if MICROPY_PY_OS_DUPTERM + for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) { + MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL; + } + MP_STATE_VM(dupterm_arr_obj) = MP_OBJ_NULL; + #endif + #if MICROPY_FSUSERMOUNT // zero out the pointers to the user-mounted devices memset(MP_STATE_VM(fs_user_mount), 0, sizeof(MP_STATE_VM(fs_user_mount)));