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.
This commit is contained in:
Damien George 2017-10-13 20:01:57 +11:00
parent e39fcda8eb
commit 37282f8fc1
8 changed files with 97 additions and 75 deletions

View File

@ -35,8 +35,9 @@
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj);
#if MICROPY_PY_OS_DUPTERM #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_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 #else
#define mp_uos_dupterm_tx_strn(s, l) #define mp_uos_dupterm_tx_strn(s, l)
#endif #endif

View File

@ -4,6 +4,7 @@
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2016 Paul Sokolovsky * Copyright (c) 2016 Paul Sokolovsky
* Copyright (c) 2017 Damien P. George
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -31,12 +32,13 @@
#include "py/objtuple.h" #include "py/objtuple.h"
#include "py/objarray.h" #include "py/objarray.h"
#include "py/stream.h" #include "py/stream.h"
#include "lib/utils/interrupt_char.h"
#if MICROPY_PY_OS_DUPTERM #if MICROPY_PY_OS_DUPTERM
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) {
mp_obj_t term = MP_STATE_PORT(term_obj); mp_obj_t term = MP_STATE_VM(dupterm_objs[dupterm_idx]);
MP_STATE_PORT(term_obj) = NULL; MP_STATE_VM(dupterm_objs[dupterm_idx]) = MP_OBJ_NULL;
mp_printf(&mp_plat_print, msg); mp_printf(&mp_plat_print, msg);
if (exc != MP_OBJ_NULL) { if (exc != MP_OBJ_NULL) {
mp_obj_print_exception(&mp_plat_print, exc); 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); 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) { 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; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_obj_t write_m[3]; 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; void *org_items = arr->items;
arr->items = (void*)str; arr->items = (void*)str;
arr->len = len; 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); 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->items = org_items;
arr->len = 1; arr->len = 1;
nlr_pop(); nlr_pop();
} else { } 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) { STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) { mp_int_t idx = 0;
if (MP_STATE_PORT(term_obj) == MP_OBJ_NULL) { if (n_args == 2) {
return mp_const_none; idx = mp_obj_get_int(args[1]);
} else { }
return MP_STATE_PORT(term_obj);
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;
} }
} else {
if (args[0] == mp_const_none) { if (args[0] == mp_const_none) {
MP_STATE_PORT(term_obj) = MP_OBJ_NULL; MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
} else { } else {
MP_STATE_PORT(term_obj) = args[0]; MP_STATE_VM(dupterm_objs[idx]) = args[0];
if (MP_STATE_PORT(dupterm_arr_obj) == MP_OBJ_NULL) { if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) {
MP_STATE_PORT(dupterm_arr_obj) = mp_obj_new_bytearray(1, ""); MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, "");
} }
} }
return mp_const_none;
return previous_obj;
} }
} MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 1, 2, mp_uos_dupterm);
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj, 0, 1, mp_uos_dupterm);
#endif #endif

View File

@ -155,41 +155,6 @@ void mp_hal_signal_input(void) {
#endif #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 void dupterm_task_handler(os_event_t *evt) {
static byte lock; static byte lock;
if (lock) { if (lock) {
@ -197,7 +162,7 @@ STATIC void dupterm_task_handler(os_event_t *evt) {
} }
lock = 1; lock = 1;
while (1) { while (1) {
int c = call_dupterm_read(); int c = mp_uos_dupterm_rx_chr();
if (c < 0) { if (c < 0) {
break; break;
} }

View File

@ -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_lib));
mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_));
mp_obj_list_init(mp_sys_argv, 0); 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 #if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
extern void esp_native_code_init(void); extern void esp_native_code_init(void);
esp_native_code_init(); esp_native_code_init();

View File

@ -31,7 +31,9 @@ def setup_conn(port, accept_handler):
def accept_conn(listen_sock): def accept_conn(listen_sock):
global client_s global client_s
cl, remote_addr = listen_sock.accept() 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") print("\nConcurrent WebREPL connection from", remote_addr, "rejected")
cl.close() cl.close()
return return

View File

@ -108,11 +108,11 @@ void mp_hal_stdio_mode_orig(void) {
#endif #endif
#if MICROPY_PY_OS_DUPTERM #if MICROPY_PY_OS_DUPTERM
static int call_dupterm_read(void) { static int call_dupterm_read(size_t idx) {
nlr_buf_t nlr; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_obj_t read_m[3]; 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); read_m[2] = MP_OBJ_NEW_SMALL_INT(1);
mp_obj_t res = mp_call_method_n_kw(1, 0, read_m); mp_obj_t res = mp_call_method_n_kw(1, 0, read_m);
if (res == mp_const_none) { if (res == mp_const_none) {
@ -122,18 +122,18 @@ static int call_dupterm_read(void) {
mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ); mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len == 0) { if (bufinfo.len == 0) {
mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n"); 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; return -1;
} }
nlr_pop(); nlr_pop();
return *(byte*)bufinfo.buf; return *(byte*)bufinfo.buf;
} else { } else {
// Temporarily disable dupterm to avoid infinite recursion // Temporarily disable dupterm to avoid infinite recursion
mp_obj_t save_term = MP_STATE_PORT(term_obj); mp_obj_t save_term = MP_STATE_VM(dupterm_objs[idx]);
MP_STATE_PORT(term_obj) = NULL; MP_STATE_VM(dupterm_objs[idx]) = NULL;
mp_printf(&mp_plat_print, "dupterm: "); mp_printf(&mp_plat_print, "dupterm: ");
mp_obj_print_exception(&mp_plat_print, nlr.ret_val); 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; return -1;
@ -143,10 +143,11 @@ static int call_dupterm_read(void) {
int mp_hal_stdin_rx_chr(void) { int mp_hal_stdin_rx_chr(void) {
unsigned char c; unsigned char c;
#if MICROPY_PY_OS_DUPTERM #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; int c;
do { do {
c = call_dupterm_read(); c = call_dupterm_read(0);
} while (c == -2); } while (c == -2);
if (c == -1) { if (c == -1) {
goto main_term; goto main_term;

View File

@ -168,7 +168,7 @@ typedef struct _mp_state_vm_t {
// root pointers for extmod // root pointers for extmod
#if MICROPY_PY_OS_DUPTERM #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; mp_obj_t dupterm_arr_obj;
#endif #endif

View File

@ -102,6 +102,13 @@ void mp_init(void) {
MP_STATE_VM(mp_module_builtins_override_dict) = NULL; MP_STATE_VM(mp_module_builtins_override_dict) = NULL;
#endif #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 #if MICROPY_FSUSERMOUNT
// zero out the pointers to the user-mounted devices // zero out the pointers to the user-mounted devices
memset(MP_STATE_VM(fs_user_mount), 0, sizeof(MP_STATE_VM(fs_user_mount))); memset(MP_STATE_VM(fs_user_mount), 0, sizeof(MP_STATE_VM(fs_user_mount)));