| /* |
| * This file is part of the Micro Python project, http://micropython.org/ |
| * |
| * The MIT License (MIT) |
| * |
| * Copyright (c) 2015 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 |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| * THE SOFTWARE. |
| */ |
| |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/time.h> |
| |
| #include "py/mpstate.h" |
| #include "py/mphal.h" |
| #include "py/runtime.h" |
| #include "extmod/misc.h" |
| |
| #ifndef _WIN32 |
| #include <signal.h> |
| |
| STATIC void sighandler(int signum) { |
| if (signum == SIGINT) { |
| #if MICROPY_ASYNC_KBD_INTR |
| mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj)); |
| sigset_t mask; |
| sigemptyset(&mask); |
| // On entry to handler, its signal is blocked, and unblocked on |
| // normal exit. As we instead perform longjmp, unblock it manually. |
| sigprocmask(SIG_SETMASK, &mask, NULL); |
| nlr_raise(MP_STATE_VM(keyboard_interrupt_obj)); |
| #else |
| if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) { |
| // this is the second time we are called, so die straight away |
| exit(1); |
| } |
| mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj)); |
| MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj); |
| #endif |
| } |
| } |
| #endif |
| |
| void mp_hal_set_interrupt_char(char c) { |
| // configure terminal settings to (not) let ctrl-C through |
| if (c == CHAR_CTRL_C) { |
| #ifndef _WIN32 |
| // enable signal handler |
| struct sigaction sa; |
| sa.sa_flags = 0; |
| sa.sa_handler = sighandler; |
| sigemptyset(&sa.sa_mask); |
| sigaction(SIGINT, &sa, NULL); |
| #endif |
| } else { |
| #ifndef _WIN32 |
| // disable signal handler |
| struct sigaction sa; |
| sa.sa_flags = 0; |
| sa.sa_handler = SIG_DFL; |
| sigemptyset(&sa.sa_mask); |
| sigaction(SIGINT, &sa, NULL); |
| #endif |
| } |
| } |
| |
| #if MICROPY_USE_READLINE == 1 |
| |
| #include <termios.h> |
| |
| static struct termios orig_termios; |
| |
| void mp_hal_stdio_mode_raw(void) { |
| // save and set terminal settings |
| tcgetattr(0, &orig_termios); |
| static struct termios termios; |
| termios = orig_termios; |
| termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); |
| termios.c_cflag = (termios.c_cflag & ~(CSIZE | PARENB)) | CS8; |
| termios.c_lflag = 0; |
| termios.c_cc[VMIN] = 1; |
| termios.c_cc[VTIME] = 0; |
| tcsetattr(0, TCSAFLUSH, &termios); |
| } |
| |
| void mp_hal_stdio_mode_orig(void) { |
| // restore terminal settings |
| tcsetattr(0, TCSAFLUSH, &orig_termios); |
| } |
| |
| #endif |
| |
| #if MICROPY_PY_OS_DUPTERM |
| static int call_dupterm_read(void) { |
| 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); |
| 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_PORT(term_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_printf(&mp_plat_print, "dupterm: "); |
| mp_obj_print_exception(&mp_plat_print, nlr.ret_val); |
| MP_STATE_PORT(term_obj) = save_term; |
| } |
| |
| return -1; |
| } |
| #endif |
| |
| int mp_hal_stdin_rx_chr(void) { |
| unsigned char c; |
| #if MICROPY_PY_OS_DUPTERM |
| if (MP_STATE_PORT(term_obj) != MP_OBJ_NULL) { |
| int c; |
| do { |
| c = call_dupterm_read(); |
| } while (c == -2); |
| if (c == -1) { |
| goto main_term; |
| } |
| if (c == '\n') { |
| c = '\r'; |
| } |
| return c; |
| } else { |
| main_term:; |
| #endif |
| int ret = read(0, &c, 1); |
| if (ret == 0) { |
| c = 4; // EOF, ctrl-D |
| } else if (c == '\n') { |
| c = '\r'; |
| } |
| return c; |
| #if MICROPY_PY_OS_DUPTERM |
| } |
| #endif |
| } |
| |
| void mp_hal_stdout_tx_strn(const char *str, size_t len) { |
| int ret = write(1, str, len); |
| mp_uos_dupterm_tx_strn(str, len); |
| (void)ret; // to suppress compiler warning |
| } |
| |
| // cooked is same as uncooked because the terminal does some postprocessing |
| void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { |
| mp_hal_stdout_tx_strn(str, len); |
| } |
| |
| void mp_hal_stdout_tx_str(const char *str) { |
| mp_hal_stdout_tx_strn(str, strlen(str)); |
| } |
| |
| mp_uint_t mp_hal_ticks_ms(void) { |
| struct timeval tv; |
| gettimeofday(&tv, NULL); |
| return tv.tv_sec * 1000 + tv.tv_usec / 1000; |
| } |
| |
| mp_uint_t mp_hal_ticks_us(void) { |
| struct timeval tv; |
| gettimeofday(&tv, NULL); |
| return tv.tv_sec * 1000000 + tv.tv_usec; |
| } |