diff --git a/README.md b/README.md index 7f6ad1c45..647577ddd 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Most of the code is in `ports/sh` and is shared between the platforms. Bugs to fix: - Fix not world switching during filesystem accesses (very unstable) +- Fix console line spacing being hardcoded instead of using font data +- Fix the console not garbage collecting its lines (enable and test the feature) Python features: - Compare features with existing implementations and other brands diff --git a/ports/sh/Makefile b/ports/sh/Makefile index f5223a9c7..45f7a655b 100644 --- a/ports/sh/Makefile +++ b/ports/sh/Makefile @@ -14,16 +14,19 @@ SRC_C = \ ports/sh/console.c \ ports/sh/keymap.c \ ports/sh/modgint.c \ + ports/sh/modtime.c \ ports/sh/mphalport.c \ ports/sh/shell.c \ shared/readline/readline.c \ shared/runtime/gchelper_generic.c \ shared/runtime/pyexec.c \ shared/runtime/stdout_helpers.c \ + shared/runtime/interrupt_char.c \ SRC_QSTR += \ shared/readline/readline.c \ ports/sh/modgint.c \ + ports/sh/modtime.c \ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) diff --git a/ports/sh/keymap.c b/ports/sh/keymap.c index 942ae5b14..eefbb4749 100644 --- a/ports/sh/keymap.c +++ b/ports/sh/keymap.c @@ -23,7 +23,7 @@ static uint8_t map_alpha[36] = { 'm', 'n', 'o', 0, 0, 0, 'p', 'q', 'r', 's', 't', 0, 'u', 'v', 'w', 'x', 'y', 0, - 'z', ' ', '"', 0, 0, 0, + 'z', ' ', '"', ':', 0, 0, }; uint32_t keymap_translate(int key, bool shift, bool alpha) diff --git a/ports/sh/modtime.c b/ports/sh/modtime.c new file mode 100644 index 000000000..f34a4e72e --- /dev/null +++ b/ports/sh/modtime.c @@ -0,0 +1,167 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Paul Sokolovsky + * Copyright (c) 2014-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 + * 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 "py/mpconfig.h" +#if MICROPY_PY_UTIME + +#include +#include +#include +#include +#include +#include +#include + +#include "py/runtime.h" +#include "py/smallint.h" +#include "py/mphal.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t mod_time_time(void) +{ + mp_float_t seconds = (mp_float_t)rtc_ticks() / 128; + return mp_obj_new_float(seconds); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); + +STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) +{ + uint64_t us = mp_obj_get_float(arg) * 1000000; + sleep_us(us); + mp_handle_pending(true); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); + +STATIC mp_obj_t mod_time_gm_local_time(size_t n_args, const mp_obj_t *args, + struct tm *(*time_func)(const time_t *timep)) { + time_t t; + if (n_args == 0) { + t = time(NULL); + } else { + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + mp_float_t val = mp_obj_get_float(args[0]); + t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val); + #else + t = mp_obj_get_int(args[0]); + #endif + } + struct tm *tm = time_func(&t); + + mp_obj_t ret = mp_obj_new_tuple(9, NULL); + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(ret); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(tm->tm_year + 1900); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(tm->tm_mon + 1); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(tm->tm_mday); + tuple->items[3] = MP_OBJ_NEW_SMALL_INT(tm->tm_hour); + tuple->items[4] = MP_OBJ_NEW_SMALL_INT(tm->tm_min); + tuple->items[5] = MP_OBJ_NEW_SMALL_INT(tm->tm_sec); + int wday = tm->tm_wday - 1; + if (wday < 0) { + wday = 6; + } + tuple->items[6] = MP_OBJ_NEW_SMALL_INT(wday); + tuple->items[7] = MP_OBJ_NEW_SMALL_INT(tm->tm_yday + 1); + tuple->items[8] = MP_OBJ_NEW_SMALL_INT(tm->tm_isdst); + + return ret; +} + +STATIC mp_obj_t mod_time_gmtime(size_t n_args, const mp_obj_t *args) +{ + return mod_time_gm_local_time(n_args, args, gmtime); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_gmtime_obj, 0, 1, + mod_time_gmtime); + +STATIC mp_obj_t mod_time_localtime(size_t n_args, const mp_obj_t *args) +{ + return mod_time_gm_local_time(n_args, args, localtime); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_time_localtime_obj, 0, 1, + mod_time_localtime); + +STATIC mp_obj_t mod_time_mktime(mp_obj_t tuple) +{ + size_t len; + mp_obj_t *elem; + mp_obj_get_array(tuple, &len, &elem); + + // localtime generates a tuple of len 8. CPython uses 9, so we accept both. + if (len < 8 || len > 9) { + mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9")); + } + + struct tm time = { + .tm_year = mp_obj_get_int(elem[0]) - 1900, + .tm_mon = mp_obj_get_int(elem[1]) - 1, + .tm_mday = mp_obj_get_int(elem[2]), + .tm_hour = mp_obj_get_int(elem[3]), + .tm_min = mp_obj_get_int(elem[4]), + .tm_sec = mp_obj_get_int(elem[5]), + }; + if (len == 9) { + time.tm_isdst = mp_obj_get_int(elem[8]); + } else { + time.tm_isdst = -1; // auto-detect + } + time_t ret = mktime(&time); + if (ret == -1) { + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("invalid mktime usage")); + } + return mp_obj_new_int(ret); +} +MP_DEFINE_CONST_FUN_OBJ_1(mod_time_mktime_obj, mod_time_mktime); + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mod_time_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, + { MP_ROM_QSTR(MP_QSTR_time_ns), MP_ROM_PTR(&mp_utime_time_ns_obj) }, + { MP_ROM_QSTR(MP_QSTR_gmtime), MP_ROM_PTR(&mod_time_gmtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&mod_time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&mod_time_mktime_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_time = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mp_module_time_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_utime, mp_module_time); + +#endif // MICROPY_PY_UTIME diff --git a/ports/sh/mpconfigport.h b/ports/sh/mpconfigport.h index bddb2e9a2..e4587a318 100644 --- a/ports/sh/mpconfigport.h +++ b/ports/sh/mpconfigport.h @@ -21,7 +21,8 @@ #define MICROPY_ENABLE_SOURCE_LINE (1) /* in EXTRA_FEATURES */ #define MICROPY_PY_BUILTINS_STR_UNICODE (1) /* in EXTRA_FEATURES */ #define MICROPY_PY_BUILTINS_HELP_MODULES (1) /* in EXTRA_FEATURES */ -// #define MICROPY_PY_SYS_STDFILES (1) /* in EXTRA_FEATURES */ +#define MICROPY_KBD_EXCEPTION (1) /* in EXTRA_FEATURES */ +// #define MICROPY_PY_SYS_STDFILES (1) /* in EXTRA_FEATURES */ #define MICROPY_ALLOC_PATH_MAX (256) #define MICROPY_ALLOC_PARSE_CHUNK_INIT (32) @@ -54,6 +55,12 @@ #define MICROPY_PY_SYS (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URANDOM_EXTRA_FUNCS (1) +#define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) +// TODO: Enable the os module: +// #define MICROPY_PY_UOS (1) +// TODO: Enable other modules +// #define MICROPY_PY_URE (1) // + other flags? /* Enable alias of u-modules, eg. urandom -> random */ #define MICROPY_MODULE_WEAK_LINKS (1) diff --git a/ports/sh/mphalport.h b/ports/sh/mphalport.h index 0db02a8c2..896abde5d 100644 --- a/ports/sh/mphalport.h +++ b/ports/sh/mphalport.h @@ -1 +1,35 @@ -static inline void mp_hal_set_interrupt_char(char c) {} + +#include +#include + +void mp_hal_set_interrupt_char(char c); + +static inline void mp_hal_delay_ms(mp_uint_t ms) +{ + sleep_ms(ms); +} + +static inline void mp_hal_delay_us(mp_uint_t us) +{ + sleep_us(us); +} + +static inline mp_uint_t mp_hal_ticks_ms(void) +{ + return ((uint64_t)clock() * 1000) / CLOCKS_PER_SEC; +} + +static inline mp_uint_t mp_hal_ticks_us(void) +{ + return ((uint64_t)clock() * 1000000) / CLOCKS_PER_SEC; +} + +static inline mp_uint_t mp_hal_ticks_cpu(void) +{ + return clock(); +} + +static inline uint64_t mp_hal_time_ns(void) +{ + return (uint64_t)time(NULL) * 1000000000; +}