From dd803e8e7ab3ff71d384f490692bff2c926c0aa2 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 27 May 2020 16:31:07 +1000 Subject: [PATCH 1/2] ports/unix: Add full uos.dupterm support. --- ports/unix/main.c | 9 ++- ports/unix/mphalport.h | 4 ++ ports/unix/unix_mphal.c | 125 ++++++++++++++++++++++++++-------------- 3 files changed, 93 insertions(+), 45 deletions(-) diff --git a/ports/unix/main.c b/ports/unix/main.c index 6f85cbf8d021d..1cb71bd4458e9 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -64,9 +64,12 @@ long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4); STATIC void stderr_print_strn(void *env, const char *str, size_t len) { (void)env; + #if MICROPY_PY_OS_DUPTERM + mp_uos_dupterm_tx_strn(str, len); + #else ssize_t ret; MP_HAL_RETRY_SYSCALL(ret, write(STDERR_FILENO, str, len), {}); - mp_uos_dupterm_tx_strn(str, len); + #endif } const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; @@ -537,6 +540,10 @@ MP_NOINLINE int main_(int argc, char **argv) { } #endif + #if MICROPY_PY_OS_DUPTERM + init_dupterm_stdio(); + #endif + // Here is some example code to create a class and instance of that class. // First is the Python, then the C code. // diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index 89d23ca5d22e9..c2ebbff7f225d 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -98,3 +98,7 @@ enum { void mp_hal_get_mac(int idx, uint8_t buf[6]); #endif + +#if MICROPY_PY_OS_DUPTERM +void init_dupterm_stdio(); +#endif diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 28a4ca2c4a8e9..157ce2105c0f7 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -33,6 +33,8 @@ #include "py/mphal.h" #include "py/mpthread.h" #include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" #include "extmod/misc.h" #ifndef _WIN32 @@ -64,8 +66,11 @@ STATIC void sighandler(int signum) { } #endif +int mp_interrupt_char = -1; + void mp_hal_set_interrupt_char(char c) { // configure terminal settings to (not) let ctrl-C through + mp_interrupt_char = c; if (c == CHAR_CTRL_C) { #ifndef _WIN32 // enable signal handler @@ -114,57 +119,85 @@ void mp_hal_stdio_mode_orig(void) { #endif #if MICROPY_PY_OS_DUPTERM -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_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) { - return -2; - } - mp_buffer_info_t bufinfo; - 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_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_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_VM(dupterm_objs[idx]) = save_term; +STATIC mp_uint_t unix_stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + ssize_t ret; + MP_HAL_RETRY_SYSCALL(ret, read(STDIN_FILENO, (byte *)buf, size), {}); + if (ret == 0) { + // return EAGAIN error to indicate non-blocking + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; } + return ret; +} + +STATIC mp_uint_t unix_stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + int ret; + MP_HAL_RETRY_SYSCALL(ret, write(STDOUT_FILENO, (const byte *)buf, size), {}); + if (ret == 0) { + // return EAGAIN error to indicate non-blocking + *errcode = MP_EAGAIN; + return MP_STREAM_ERROR; + } + return ret; +} + +STATIC mp_uint_t unix_stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; +} + +STATIC mp_obj_t unix_stdio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); + +STATIC const mp_stream_p_t unix_stdio_stream_p = { + .read = unix_stdio_read, + .write = unix_stdio_write, + .ioctl = unix_stdio_ioctl, +}; + +STATIC const mp_rom_map_elem_t unix_stdio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, + { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)}, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(unix_stdio_locals_dict, unix_stdio_locals_dict_table); + +const mp_obj_type_t unix_stdio_type = { + { &mp_type_type }, + .name = MP_QSTR_UNIX_STDIO, + .make_new = unix_stdio_make_new, + .protocol = &unix_stdio_stream_p, + .locals_dict = (mp_obj_dict_t *)&unix_stdio_locals_dict, +}; - return -1; +typedef struct _unix_stdio_obj_t { + mp_obj_base_t base; +} unix_stdio_obj_t; + +STATIC const unix_stdio_obj_t unix_stdio_obj = {{&unix_stdio_type}}; + +STATIC mp_obj_t unix_stdio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return MP_OBJ_FROM_PTR(&unix_stdio_obj); +} + +void init_dupterm_stdio() { + MP_STATE_VM(dupterm_objs[0]) = MP_OBJ_FROM_PTR(&unix_stdio_obj); } #endif int mp_hal_stdin_rx_chr(void) { #if MICROPY_PY_OS_DUPTERM - // 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(0); - } while (c == -2); - if (c == -1) { - goto main_term; - } - if (c == '\n') { - c = '\r'; - } - return c; + int c; + do { + c = mp_uos_dupterm_rx_chr(); + } while (c == -2); + if (c == '\n') { + c = '\r'; } -main_term:; - #endif - + return c; + #else unsigned char c; ssize_t ret; MP_HAL_RETRY_SYSCALL(ret, read(STDIN_FILENO, &c, 1), {}); @@ -174,12 +207,16 @@ main_term:; c = '\r'; } return c; + #endif } void mp_hal_stdout_tx_strn(const char *str, size_t len) { + #if MICROPY_PY_OS_DUPTERM + mp_uos_dupterm_tx_strn(str, len); + #else ssize_t ret; MP_HAL_RETRY_SYSCALL(ret, write(STDOUT_FILENO, str, len), {}); - mp_uos_dupterm_tx_strn(str, len); + #endif } // cooked is same as uncooked because the terminal does some postprocessing From da3f65564af7fa730ef16ed291d8a9bdff3e9d85 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 28 May 2020 16:29:02 +1000 Subject: [PATCH 2/2] ports/unix: Add full uos.dupterm support. --- extmod/vfs_posix.h | 13 +++++++ extmod/vfs_posix_file.c | 33 ++++++++++------- ports/unix/unix_mphal.c | 80 ++++++----------------------------------- 3 files changed, 44 insertions(+), 82 deletions(-) diff --git a/extmod/vfs_posix.h b/extmod/vfs_posix.h index 00756b4c9d6f7..86bdb9f4a5d4d 100644 --- a/extmod/vfs_posix.h +++ b/extmod/vfs_posix.h @@ -35,4 +35,17 @@ extern const mp_obj_type_t mp_type_vfs_posix_textio; mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in); +#if MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE +typedef struct _mp_obj_vfs_posix_file_t { + mp_obj_base_t base; + int fd; + bool raw_stdio; +} mp_obj_vfs_posix_file_t; + +extern const mp_obj_vfs_posix_file_t mp_sys_stdin_obj; +extern const mp_obj_vfs_posix_file_t mp_sys_stdout_obj; +extern const mp_obj_vfs_posix_file_t mp_sys_stderr_obj; +extern const mp_obj_vfs_posix_file_t mp_sys_raw_stdio_obj; +#endif + #endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index 264764b4ee29d..8a8e2a7224cb0 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -39,11 +39,6 @@ #define fsync _commit #endif -typedef struct _mp_obj_vfs_posix_file_t { - mp_obj_base_t base; - int fd; -} mp_obj_vfs_posix_file_t; - #ifdef MICROPY_CPYTHON_COMPAT STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) { if (o->fd < 0) { @@ -137,7 +132,13 @@ STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, i mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); check_fd_is_open(o); ssize_t r; - MP_HAL_RETRY_SYSCALL(r, read(o->fd, buf, size), { + int fd = o->fd; + #if MICROPY_PY_OS_DUPTERM + if (fd <= STDERR_FILENO && o->raw_stdio) { + fd = STDIN_FILENO; + } + #endif + MP_HAL_RETRY_SYSCALL(r, read(fd, buf, size), { *errcode = err; return MP_STREAM_ERROR; }); @@ -147,14 +148,19 @@ STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, i STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) { mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in); check_fd_is_open(o); + int fd = o->fd; #if MICROPY_PY_OS_DUPTERM - if (o->fd <= STDERR_FILENO) { - mp_hal_stdout_tx_strn(buf, size); - return size; + if (fd <= STDERR_FILENO) { + if (o->raw_stdio) { + fd = STDOUT_FILENO; + } else { + mp_hal_stdout_tx_strn(buf, size); + return size; + } } #endif ssize_t r; - MP_HAL_RETRY_SYSCALL(r, write(o->fd, buf, size), { + MP_HAL_RETRY_SYSCALL(r, write(fd, buf, size), { *errcode = err; return MP_STREAM_ERROR; }); @@ -262,8 +268,9 @@ const mp_obj_type_t mp_type_vfs_posix_textio = { .locals_dict = (mp_obj_dict_t *)&vfs_posix_rawfile_locals_dict, }; -const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO}; -const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO}; -const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, .fd=STDIN_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, .fd=STDOUT_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, .fd=STDERR_FILENO}; +const mp_obj_vfs_posix_file_t mp_sys_raw_stdio_obj = {{&mp_type_textio}, .fd=STDIN_FILENO, .raw_stdio=true}; #endif // MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE diff --git a/ports/unix/unix_mphal.c b/ports/unix/unix_mphal.c index 157ce2105c0f7..2e6f057d1bf94 100644 --- a/ports/unix/unix_mphal.c +++ b/ports/unix/unix_mphal.c @@ -36,6 +36,7 @@ #include "py/stream.h" #include "py/mperrno.h" #include "extmod/misc.h" +#include "extmod/vfs_posix.h" #ifndef _WIN32 #include @@ -66,6 +67,7 @@ STATIC void sighandler(int signum) { } #endif +// Implementation for lib/utils/interupt_char.h int mp_interrupt_char = -1; void mp_hal_set_interrupt_char(char c) { @@ -119,71 +121,8 @@ void mp_hal_stdio_mode_orig(void) { #endif #if MICROPY_PY_OS_DUPTERM -STATIC mp_uint_t unix_stdio_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { - ssize_t ret; - MP_HAL_RETRY_SYSCALL(ret, read(STDIN_FILENO, (byte *)buf, size), {}); - if (ret == 0) { - // return EAGAIN error to indicate non-blocking - *errcode = MP_EAGAIN; - return MP_STREAM_ERROR; - } - return ret; -} - -STATIC mp_uint_t unix_stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { - int ret; - MP_HAL_RETRY_SYSCALL(ret, write(STDOUT_FILENO, (const byte *)buf, size), {}); - if (ret == 0) { - // return EAGAIN error to indicate non-blocking - *errcode = MP_EAGAIN; - return MP_STREAM_ERROR; - } - return ret; -} - -STATIC mp_uint_t unix_stdio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { - *errcode = MP_EINVAL; - return MP_STREAM_ERROR; -} - -STATIC mp_obj_t unix_stdio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); - -STATIC const mp_stream_p_t unix_stdio_stream_p = { - .read = unix_stdio_read, - .write = unix_stdio_write, - .ioctl = unix_stdio_ioctl, -}; - -STATIC const mp_rom_map_elem_t unix_stdio_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, - { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj)}, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(unix_stdio_locals_dict, unix_stdio_locals_dict_table); - -const mp_obj_type_t unix_stdio_type = { - { &mp_type_type }, - .name = MP_QSTR_UNIX_STDIO, - .make_new = unix_stdio_make_new, - .protocol = &unix_stdio_stream_p, - .locals_dict = (mp_obj_dict_t *)&unix_stdio_locals_dict, -}; - -typedef struct _unix_stdio_obj_t { - mp_obj_base_t base; -} unix_stdio_obj_t; - -STATIC const unix_stdio_obj_t unix_stdio_obj = {{&unix_stdio_type}}; - -STATIC mp_obj_t unix_stdio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 0, false); - return MP_OBJ_FROM_PTR(&unix_stdio_obj); -} - void init_dupterm_stdio() { - MP_STATE_VM(dupterm_objs[0]) = MP_OBJ_FROM_PTR(&unix_stdio_obj); + MP_STATE_VM(dupterm_objs[0]) = MP_OBJ_FROM_PTR(&mp_sys_raw_stdio_obj); } #endif @@ -197,10 +136,12 @@ int mp_hal_stdin_rx_chr(void) { c = '\r'; } return c; - #else + + #else // ! MICROPY_PY_OS_DUPTERM unsigned char c; - ssize_t ret; - MP_HAL_RETRY_SYSCALL(ret, read(STDIN_FILENO, &c, 1), {}); + int errcode = 0; + const mp_stream_p_t *stream_p = mp_get_stream(&mp_sys_raw_stdio_obj); + mp_uint_t ret = stream_p->read((mp_obj_t)&mp_sys_raw_stdio_obj, &c, 1, &errcode); if (ret == 0) { c = 4; // EOF, ctrl-D } else if (c == '\n') { @@ -214,8 +155,9 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) { #if MICROPY_PY_OS_DUPTERM mp_uos_dupterm_tx_strn(str, len); #else - ssize_t ret; - MP_HAL_RETRY_SYSCALL(ret, write(STDOUT_FILENO, str, len), {}); + int errcode = 0; + const mp_stream_p_t *stream_p = mp_get_stream(&mp_sys_raw_stdio_obj); + stream_p->write((mp_obj_t)&mp_sys_raw_stdio_obj, str, len, &errcode); #endif }