diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index f2ec249d6..0447fe01f 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -93,3 +93,13 @@ PythonTan = "Tangent" PythonTanh = "Hyperbolic tangent" PythonTrunc = "x truncated to an integer" PythonUniform = "Floating point number in [a,b]" +PythonImportFromTime = "Import time module" +PythonImportTime = "Import time module" +PythonTimeFunction = "time module function prefix" +PythonTimeSleepMs = "Sleep for the given duration" +PythonTimeSleep = "Sleep for the given duration" +PythonTimeSleepUs = "Sleep for the given duration" +PythonTimeTicksAdd = "Offset ticks value" +PythonTimeTicksDiff = "Measure ticks difference" +PythonTimeTicksMs = "Increasing millisecond counter" +PythonTimeTicksUs = "Increasing microsecond counter" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 24597a9e9..2ced55b3c 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -93,3 +93,13 @@ PythonTan = "Tangent" PythonTanh = "Hyperbolic tangent" PythonTrunc = "x truncated to an integer" PythonUniform = "Floating point number in [a,b]" +PythonImportFromTime = "Import time module" +PythonImportTime = "Import time module" +PythonTimeFunction = "time module function prefix" +PythonTimeSleepMs = "Sleep for the given duration" +PythonTimeSleep = "Sleep for the given duration" +PythonTimeSleepUs = "Sleep for the given duration" +PythonTimeTicksAdd = "Offset ticks value" +PythonTimeTicksDiff = "Measure ticks difference" +PythonTimeTicksMs = "Increasing millisecond counter" +PythonTimeTicksUs = "Increasing microsecond counter" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index 24597a9e9..2ced55b3c 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -93,3 +93,13 @@ PythonTan = "Tangent" PythonTanh = "Hyperbolic tangent" PythonTrunc = "x truncated to an integer" PythonUniform = "Floating point number in [a,b]" +PythonImportFromTime = "Import time module" +PythonImportTime = "Import time module" +PythonTimeFunction = "time module function prefix" +PythonTimeSleepMs = "Sleep for the given duration" +PythonTimeSleep = "Sleep for the given duration" +PythonTimeSleepUs = "Sleep for the given duration" +PythonTimeTicksAdd = "Offset ticks value" +PythonTimeTicksDiff = "Measure ticks difference" +PythonTimeTicksMs = "Increasing millisecond counter" +PythonTimeTicksUs = "Increasing microsecond counter" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index 825a1f526..04c3502cf 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -93,3 +93,13 @@ PythonTan = "Tangente" PythonTanh = "Tangente hyperbolique" PythonTrunc = "Troncature entière" PythonUniform = "Nombre décimal dans [a,b]" +PythonImportFromTime = "Importation du module time" +PythonImportTime = "Importation du module time" +PythonTimeFunction = "Prefixe fonction du module time" +PythonTimeSleep = "Effectuer une pause" +PythonTimeSleepMs = "Effectuer une pause" +PythonTimeSleepUs = "Effectuer une pause" +PythonTimeTicksAdd = "Ajouter une valeur à un compteur" +PythonTimeTicksDiff = "Différence entre compteurs" +PythonTimeTicksMs = "Compteur croissant (millisecondes)" +PythonTimeTicksUs = "Compteur croissant (microsecondes)" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index c31c5a44a..3e06afd7e 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -93,3 +93,13 @@ PythonTan = "Tangent" PythonTanh = "Hyperbolic tangent" PythonTrunc = "x truncated to an integer" PythonUniform = "Floating point number in [a,b]" +PythonImportFromTime = "Import time module" +PythonImportTime = "Import time module" +PythonTimeFunction = "time module function prefix" +PythonTimeSleepMs = "Sleep for the given duration" +PythonTimeSleep = "Sleep for the given duration" +PythonTimeSleepUs = "Sleep for the given duration" +PythonTimeTicksAdd = "Offset ticks value" +PythonTimeTicksDiff = "Measure ticks difference" +PythonTimeTicksMs = "Increasing millisecond counter" +PythonTimeTicksUs = "Increasing microsecond counter" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 2ae4a162d..91d8f15d4 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -104,3 +104,15 @@ PythonCommandReal = "z.real" PythonCommandImagWithoutArg = "ø.imag" PythonCommandRealWithoutArg = "ø.real" PythonCommandUniform = "uniform(a,b)" +PythonCommandImportFromTime = "from time import *" +PythonCommandImportTime = "import time" +PythonCommandTimeFunction = "time.function" +PythonCommandTimeFunctionWithoutArg = "time.ø" +PythonCommandTimeSleepMs = "sleep_ms(milliseconds)" +PythonCommandTimeSleep = "sleep(seconds)" +PythonCommandTimeSleepUs = "sleep_us(microseconds)" +PythonCommandTimeTicksAdd = "ticks_add(ticks,delta)" +PythonCommandTimeTicksDiff = "ticks_diff(end,start)" +PythonCommandTimeTicksMs = "ticks_ms()" +PythonCommandTimeTicksUs = "ticks_us()" +TimeModule = "time" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index b0c93eec8..c628c8b12 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -8,7 +8,7 @@ extern "C" { namespace Code { -static constexpr int catalogChildrenCount = 95; +static constexpr int catalogChildrenCount = 96; static constexpr int MathModuleChildrenCount = 43; static constexpr int KandinskyModuleChildrenCount = 7; static constexpr int CMathModuleChildrenCount = 13; @@ -19,8 +19,9 @@ static constexpr int functionsChildrenCount = 2; static constexpr int ifStatementChildrenCount = 5; static constexpr int loopsAndTestsChildrenCount = 4; static constexpr int menuChildrenCount = 4; -static constexpr int modulesChildrenCount = 4; +static constexpr int modulesChildrenCount = 5; static constexpr int whileLoopChildrenCount = 1; +static constexpr int TimeModuleChildrenCount = 10; const ToolboxMessageTree forLoopChildren[forLoopChildrenCount] = { @@ -123,6 +124,19 @@ const ToolboxMessageTree RandomModuleChildren[RandomModuleChildrenCount] = { ToolboxMessageTree(I18n::Message::PythonCommandUniform, I18n::Message::PythonUniform, I18n::Message::PythonCommandUniform) }; +const ToolboxMessageTree TimeModuleChildren[TimeModuleChildrenCount] = { + ToolboxMessageTree(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, I18n::Message::PythonCommandImportTime), + ToolboxMessageTree(I18n::Message::PythonCommandImportFromTime, I18n::Message::PythonImportFromTime, I18n::Message::PythonCommandImportFromTime), + ToolboxMessageTree(I18n::Message::PythonCommandTimeFunction, I18n::Message::PythonTimeFunction, I18n::Message::PythonCommandTimeFunctionWithoutArg), + ToolboxMessageTree(I18n::Message::PythonCommandTimeSleep, I18n::Message::PythonTimeSleep, I18n::Message::PythonCommandTimeSleep), + ToolboxMessageTree(I18n::Message::PythonCommandTimeSleepMs, I18n::Message::PythonTimeSleepMs, I18n::Message::PythonCommandTimeSleepMs), + ToolboxMessageTree(I18n::Message::PythonCommandTimeSleepUs, I18n::Message::PythonTimeSleepUs, I18n::Message::PythonCommandTimeSleepUs), + ToolboxMessageTree(I18n::Message::PythonCommandTimeTicksMs, I18n::Message::PythonTimeTicksMs, I18n::Message::PythonCommandTimeTicksMs), + ToolboxMessageTree(I18n::Message::PythonCommandTimeTicksUs, I18n::Message::PythonTimeTicksUs, I18n::Message::PythonCommandTimeTicksUs), + ToolboxMessageTree(I18n::Message::PythonCommandTimeTicksDiff, I18n::Message::PythonTimeTicksDiff, I18n::Message::PythonCommandTimeTicksDiff), + ToolboxMessageTree(I18n::Message::PythonCommandTimeTicksAdd, I18n::Message::PythonTimeTicksAdd, I18n::Message::PythonCommandTimeTicksAdd), +}; + const ToolboxMessageTree CMathModuleChildren[CMathModuleChildrenCount] = { ToolboxMessageTree(I18n::Message::PythonCommandImportCmath, I18n::Message::PythonImportCmath, I18n::Message::PythonCommandImportCmath), ToolboxMessageTree(I18n::Message::PythonCommandImportFromCmath, I18n::Message::PythonImportFromCmath, I18n::Message::PythonCommandImportFromCmath), @@ -142,6 +156,7 @@ const ToolboxMessageTree modulesChildren[modulesChildrenCount] = { ToolboxMessageTree(I18n::Message::MathModule, I18n::Message::Default, I18n::Message::Default, MathModuleChildren, MathModuleChildrenCount), ToolboxMessageTree(I18n::Message::CmathModule, I18n::Message::Default, I18n::Message::Default, CMathModuleChildren, CMathModuleChildrenCount), ToolboxMessageTree(I18n::Message::RandomModule, I18n::Message::Default, I18n::Message::Default, RandomModuleChildren, RandomModuleChildrenCount), + ToolboxMessageTree(I18n::Message::TimeModule, I18n::Message::Default, I18n::Message::Default, TimeModuleChildren, TimeModuleChildrenCount), ToolboxMessageTree(I18n::Message::KandinskyModule, I18n::Message::Default, I18n::Message::Default, KandinskyModuleChildren, KandinskyModuleChildrenCount)}; const ToolboxMessageTree catalogChildren[catalogChildrenCount] = { @@ -196,6 +211,7 @@ const ToolboxMessageTree catalogChildren[catalogChildrenCount] = { ToolboxMessageTree(I18n::Message::PythonCommandImportKandinsky, I18n::Message::PythonImportKandinsky, I18n::Message::PythonCommandImportKandinsky), ToolboxMessageTree(I18n::Message::PythonCommandImportMath, I18n::Message::PythonImportMath, I18n::Message::PythonCommandImportMath), ToolboxMessageTree(I18n::Message::PythonCommandImportRandom, I18n::Message::PythonImportRandom, I18n::Message::PythonCommandImportRandom), + ToolboxMessageTree(I18n::Message::PythonCommandImportTime, I18n::Message::PythonImportTime, I18n::Message::PythonCommandImportTime), ToolboxMessageTree(I18n::Message::PythonCommandInput, I18n::Message::PythonInput, I18n::Message::PythonCommandInput), ToolboxMessageTree(I18n::Message::PythonCommandInt, I18n::Message::PythonInt, I18n::Message::PythonCommandInt), ToolboxMessageTree(I18n::Message::PythonCommandIsFinite, I18n::Message::PythonIsFinite, I18n::Message::PythonCommandIsFinite), @@ -349,4 +365,3 @@ void PythonToolbox::scrollToAndSelectChild(int i) { } } - diff --git a/liba/src/aeabi-rt/double.c b/liba/src/aeabi-rt/double.c index a796e0988..2a8c0425c 100644 --- a/liba/src/aeabi-rt/double.c +++ b/liba/src/aeabi-rt/double.c @@ -8,6 +8,10 @@ int __aeabi_d2iz(aeabi_double_t x) { return f64_to_i32_r_minMag(f64(x), 0); } +unsigned int __aeabi_d2uiz(aeabi_double_t x) { + return f64_to_i32_r_minMag(f64(x), 0); +} + aeabi_double_t __aeabi_i2d(int i) { return d(i32_to_f64(i)); } diff --git a/python/Makefile b/python/Makefile index ece2546c7..dd43293ba 100644 --- a/python/Makefile +++ b/python/Makefile @@ -123,6 +123,7 @@ py_objs = $(addprefix python/src/py/,\ extmod_objs += $(addprefix python/src/extmod/,\ modurandom.o \ + modutime.o \ ) port_objs += $(addprefix python/port/,\ diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index c6664167f..1d3c835af 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -24,6 +24,16 @@ Q(draw_string) Q(get_pixel) Q(set_pixel) +// utime QSTRs +Q(time) +Q(sleep) +Q(sleep_ms) +Q(sleep_us) +Q(ticks_ms) +Q(ticks_us) +Q(ticks_add) +Q(ticks_diff) + // MicroPython QSTRs Q() Q(*) diff --git a/python/port/helpers.cpp b/python/port/helpers.cpp index cda2b53ca..5da28c6a5 100644 --- a/python/port/helpers.cpp +++ b/python/port/helpers.cpp @@ -4,16 +4,17 @@ extern "C" { #include "mphalport.h" } -void micropython_port_should_interrupt() { +bool micropython_port_should_interrupt() { static int c = 0; c++; if (c%20000 != 0) { - return; + return false; } c = 0; Ion::Keyboard::State scan = Ion::Keyboard::scan(); if (scan.keyDown((Ion::Keyboard::Key)mp_interrupt_char)) { mp_keyboard_interrupt(); + return true; } + return false; } - diff --git a/python/port/helpers.h b/python/port/helpers.h index b07c6de29..76abbde0d 100644 --- a/python/port/helpers.h +++ b/python/port/helpers.h @@ -4,10 +4,11 @@ #ifdef __cplusplus extern "C" { #endif +#include /* should_interrupt effectively does something once every 20000 calls. It checks * if a key is down to raise an interruption flag. */ -void micropython_port_should_interrupt(); +bool micropython_port_should_interrupt(); #ifdef __cplusplus } diff --git a/python/port/mpconfigport.h b/python/port/mpconfigport.h index 17794886b..ff7fff87d 100644 --- a/python/port/mpconfigport.h +++ b/python/port/mpconfigport.h @@ -107,6 +107,8 @@ typedef long mp_off_t; #define MP_STATE_PORT MP_STATE_VM extern const struct _mp_obj_module_t kandinsky_module; +extern const struct _mp_obj_module_t mp_module_utime; #define MICROPY_PORT_BUILTIN_MODULES \ - { MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&kandinsky_module) } + { MP_ROM_QSTR(MP_QSTR_kandinsky), MP_ROM_PTR(&kandinsky_module) }, \ + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_utime) }, diff --git a/python/src/extmod/modutime.c b/python/src/extmod/modutime.c new file mode 100644 index 000000000..a88e06104 --- /dev/null +++ b/python/src/extmod/modutime.c @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 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 +#include + +#include "py/smallint.h" +#include "py/runtime.h" + +long millis(); +long micros(); + +void delay_ms(mp_uint_t delay) { + uint32_t start = millis(); + while (millis() - start < delay && !micropython_port_should_interrupt()) { + } +} + +void delay_us(mp_uint_t delay) { + uint32_t start = micros(); + while (micros() - start < delay && !micropython_port_should_interrupt()) { + } +} + +STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { + #if MICROPY_PY_BUILTINS_FLOAT + delay_ms((mp_uint_t)(1000 * mp_obj_get_float(seconds_o))); + #else + delay_ms(1000 * mp_obj_get_int(seconds_o)); + #endif + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep); + +STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { + mp_int_t ms = mp_obj_get_int(arg); + if (ms > 0) { + delay_ms(ms); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms); + +STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { + mp_int_t us = mp_obj_get_int(arg); + if (us > 0) { + delay_us(us); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us); + +STATIC mp_obj_t time_ticks_ms(void) { + return MP_OBJ_NEW_SMALL_INT(millis() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms); + +STATIC mp_obj_t time_ticks_us(void) { + return MP_OBJ_NEW_SMALL_INT(micros() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us); + +STATIC mp_obj_t time_ticks_diff(mp_obj_t end_in, mp_obj_t start_in) { + // we assume that the arguments come from ticks_xx so are small ints + mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in); + mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in); + // Optimized formula avoiding if conditions. We adjust difference "forward", + // wrap it around and adjust back. + mp_int_t diff = ((end - start + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)) + - MICROPY_PY_UTIME_TICKS_PERIOD / 2; + return MP_OBJ_NEW_SMALL_INT(diff); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff); + +STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) { + // we assume that first argument come from ticks_xx so is small int + mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in); + mp_uint_t delta = mp_obj_get_int(delta_in); + return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add); + +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_time) }, + + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_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_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_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); + +const mp_obj_module_t mp_module_utime = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&time_module_globals, +};