From ac70119779c9379ffacd919607b2f9fadd064e19 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 10 Oct 2016 21:21:45 +0300 Subject: [PATCH 01/78] zephyr: Add README. --- zephyr/README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 zephyr/README.md diff --git a/zephyr/README.md b/zephyr/README.md new file mode 100644 index 0000000000..63fb0e39f4 --- /dev/null +++ b/zephyr/README.md @@ -0,0 +1,45 @@ +MicroPython port to Zephyr RTOS +=============================== + +This is an initial port of MicroPython to Zephyr RTOS +(http://zephyrproject.org). + +The port integrates well with Zephyr build system, using the latest +features which will be available in 1.6.0, and thus requires Zephyr +master to build against. All boards supported by Zephyr should be +supported (but not all were tested). + +At this time, only basic interactive prompt (REPL) over UART connection +is supported. Over time, bindings for various Zephyr subsystems may +be added. + + +Building +-------- + +Follow to Zephyr web site for Getting Started instruction of installing +Zephyr SDK, getting Zephyr source code, and setting up development +environment. (Direct link: +https://www.zephyrproject.org/doc/getting_started/getting_started.html). +You may want to build Zephyr's own sample applications to make sure your +setup is correct. + +To build MicroPython port, in the port subdirectory (zephyr/), run: + + make BOARD= + +If you don't specify BOARD, the default is `qemu_x86` (x86 target running +in QEMU emulator). Consult Zephyr documentation above for the list of +supported boards. + + +Running +------- + +To run the resulting application in QEMU (for BOARDs like qemu_x86, +qemu_cortex_m3): + + make qemu + +For deploying/flashing the application on a real board, follow Zephyr +documentation for a given board. From b3a65791b16dcc41281649a0a5faac4e8c00c8e3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 24 Aug 2016 23:13:11 +0300 Subject: [PATCH 02/78] zephyr: Enable stack checking and micropython.mem_info(). --- zephyr/main.c | 4 ++++ zephyr/mpconfigport.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/zephyr/main.c b/zephyr/main.c index 65074b157e..445ef98f4d 100644 --- a/zephyr/main.c +++ b/zephyr/main.c @@ -7,6 +7,7 @@ #include "py/runtime.h" #include "py/repl.h" #include "py/gc.h" +#include "py/stackctrl.h" #include "lib/utils/pyexec.h" void do_str(const char *src, mp_parse_input_kind_t input_kind) { @@ -35,6 +36,9 @@ static char heap[16 * 1024]; int real_main(void) { int stack_dummy; stack_top = (char*)&stack_dummy; + mp_stack_set_top(stack_top); + // Should be set to stack size in prj.mdef minus fuzz factor + mp_stack_set_limit(3584); #if MICROPY_ENABLE_GC gc_init(heap, heap + sizeof(heap)); diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index cf5884e0e7..f125ab3993 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -5,6 +5,7 @@ #define MICROPY_COMP_CONST (0) #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +#define MICROPY_STACK_CHECK (1) #define MICROPY_ENABLE_GC (1) #define MICROPY_HELPER_REPL (1) #define MICROPY_REPL_AUTO_INDENT (1) @@ -23,6 +24,7 @@ #define MICROPY_PY_COLLECTIONS (0) #define MICROPY_PY_CMATH (0) #define MICROPY_PY_IO (0) +#define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_STRUCT (0) #define MICROPY_PY_SYS_MODULES (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) From 7e3b21ec54643281ec71ab192724684f2918067b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 17 Sep 2016 21:15:58 +0300 Subject: [PATCH 03/78] zephyr: Enable frozen modules support. --- zephyr/Makefile | 3 +++ zephyr/mpconfigport.h | 1 + 2 files changed, 4 insertions(+) diff --git a/zephyr/Makefile b/zephyr/Makefile index d0dce488db..501fb0a310 100644 --- a/zephyr/Makefile +++ b/zephyr/Makefile @@ -15,6 +15,8 @@ BOARD ?= qemu_x86 # Zephyr 1.6.0 OUTDIR_PREFIX = $(BOARD) +FROZEN_DIR = scripts + # Zephyr (generated) config files - must be defined before include below Z_SYSGEN_H = outdir/$(OUTDIR_PREFIX)/misc/generated/sysgen/sysgen.h Z_EXPORTS = outdir/$(OUTDIR_PREFIX)/Makefile.export @@ -36,6 +38,7 @@ SRC_C = main.c \ lib/utils/printf.c \ lib/utils/pyexec.c \ lib/mp-readline/readline.c \ + $(BUILD)/frozen.c \ $(SRC_MOD) OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index f125ab3993..5d021b6aa2 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -32,6 +32,7 @@ #define MICROPY_PY_BUILTINS_COMPLEX (0) #define MICROPY_HW_BOARD_NAME "zephyr-generic" #define MICROPY_HW_MCU_NAME "unknown-cpu" +#define MICROPY_MODULE_FROZEN_STR (1) typedef int mp_int_t; // must be pointer size typedef unsigned mp_uint_t; // must be pointer size From aa7828f822391f2b44224e81af27d29a26a9ccb6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 22 Sep 2016 04:05:10 +0300 Subject: [PATCH 04/78] zephyr/main: Execute main.py frozen module on boot, if available. --- zephyr/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/zephyr/main.c b/zephyr/main.c index 445ef98f4d..d6ac56943c 100644 --- a/zephyr/main.c +++ b/zephyr/main.c @@ -44,6 +44,7 @@ int real_main(void) { gc_init(heap, heap + sizeof(heap)); #endif mp_init(); + pyexec_frozen_module("main.py"); #if MICROPY_REPL_EVENT_DRIVEN pyexec_event_repl_init(); for (;;) { From 1b76f88e7a04e6accbfd1caab325a7dfd4717ef8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 29 Sep 2016 10:18:06 -0700 Subject: [PATCH 05/78] zephyr/zephyr_getchar: Add support for Ctrl+C handling. Patch on top of upstream Zephyr console helpers. --- zephyr/src/zephyr_getchar.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/zephyr/src/zephyr_getchar.c b/zephyr/src/zephyr_getchar.c index 3a1898a607..89e3e0efbc 100644 --- a/zephyr/src/zephyr_getchar.c +++ b/zephyr/src/zephyr_getchar.c @@ -20,6 +20,9 @@ #include #include "zephyr_getchar.h" +extern int mp_interrupt_char; +void mp_keyboard_interrupt(void); + static struct nano_sem uart_sem; #define UART_BUFSIZE 256 static uint8_t uart_ringbuf[UART_BUFSIZE]; @@ -32,8 +35,13 @@ static int console_irq_input_hook(struct device *dev, uint8_t ch) printk("UART buffer overflow - char dropped\n"); return 1; } - uart_ringbuf[i_put] = ch; - i_put = i_next; + if (ch == mp_interrupt_char) { + mp_keyboard_interrupt(); + return 1; + } else { + uart_ringbuf[i_put] = ch; + i_put = i_next; + } //printk("%x\n", ch); nano_isr_sem_give(&uart_sem); return 1; From 93c76d2b06e0f52395dc2d5fa1d7fae54c9164f7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 29 Sep 2016 10:24:56 -0700 Subject: [PATCH 06/78] zephyr: Add Ctrl+C handling. --- zephyr/Makefile | 1 + zephyr/main.c | 2 ++ zephyr/mpconfigport.h | 1 + zephyr/mphalport.h | 1 - 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/zephyr/Makefile b/zephyr/Makefile index 501fb0a310..2cc314b533 100644 --- a/zephyr/Makefile +++ b/zephyr/Makefile @@ -37,6 +37,7 @@ SRC_C = main.c \ lib/utils/stdout_helpers.c \ lib/utils/printf.c \ lib/utils/pyexec.c \ + lib/utils/interrupt_char.c \ lib/mp-readline/readline.c \ $(BUILD)/frozen.c \ $(SRC_MOD) diff --git a/zephyr/main.c b/zephyr/main.c index d6ac56943c..3bd768f686 100644 --- a/zephyr/main.c +++ b/zephyr/main.c @@ -9,6 +9,7 @@ #include "py/gc.h" #include "py/stackctrl.h" #include "lib/utils/pyexec.h" +#include "lib/mp-readline/readline.h" void do_str(const char *src, mp_parse_input_kind_t input_kind) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); @@ -44,6 +45,7 @@ int real_main(void) { gc_init(heap, heap + sizeof(heap)); #endif mp_init(); + MP_STATE_PORT(mp_kbd_exception) = mp_obj_new_exception(&mp_type_KeyboardInterrupt); pyexec_frozen_module("main.py"); #if MICROPY_REPL_EVENT_DRIVEN pyexec_event_repl_init(); diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index 5d021b6aa2..2c5fad21b7 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -46,6 +46,7 @@ typedef long mp_off_t; #define MP_STATE_PORT MP_STATE_VM #define MICROPY_PORT_ROOT_POINTERS \ + mp_obj_t mp_kbd_exception; \ const char *readline_hist[8]; // Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles diff --git a/zephyr/mphalport.h b/zephyr/mphalport.h index 60d68bd2d6..1bb64e0002 100644 --- a/zephyr/mphalport.h +++ b/zephyr/mphalport.h @@ -1,2 +1 @@ static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; } -static inline void mp_hal_set_interrupt_char(char c) {} From 7dc2345715f6c0619e833661d709f6e4e550d7b5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 7 Oct 2016 15:59:50 +1100 Subject: [PATCH 07/78] py/modmicropython: Add micropython.opt_level([value]) function. This allows to get/set at runtime the optimisation level of the compiler. --- py/modmicropython.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/py/modmicropython.c b/py/modmicropython.c index f7d74db2e0..675d169cc4 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -34,6 +34,16 @@ // Various builtins specific to MicroPython runtime, // living in micropython module +STATIC mp_obj_t mp_micropython_opt_level(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + return MP_OBJ_NEW_SMALL_INT(MP_STATE_VM(mp_optimise_value)); + } else { + MP_STATE_VM(mp_optimise_value) = mp_obj_get_int(args[0]); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_opt_level_obj, 0, 1, mp_micropython_opt_level); + #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS @@ -121,6 +131,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_alloc_emergency_exception_buf_obj, mp_alloc_ STATIC const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_micropython) }, { MP_ROM_QSTR(MP_QSTR_const), MP_ROM_PTR(&mp_identity_obj) }, + { MP_ROM_QSTR(MP_QSTR_opt_level), MP_ROM_PTR(&mp_micropython_opt_level_obj) }, #if MICROPY_PY_MICROPYTHON_MEM_INFO #if MICROPY_MEM_STATS { MP_ROM_QSTR(MP_QSTR_mem_total), MP_ROM_PTR(&mp_micropython_mem_total_obj) }, From 7f0e563de3f02b26aa0ebf5dd62907d67b524a8e Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 11:01:22 +1100 Subject: [PATCH 08/78] tests/micropython: Add test for micropython.opt_level() function. --- tests/micropython/opt_level.py | 14 ++++++++++++++ tests/micropython/opt_level.py.exp | 4 ++++ 2 files changed, 18 insertions(+) create mode 100644 tests/micropython/opt_level.py create mode 100644 tests/micropython/opt_level.py.exp diff --git a/tests/micropython/opt_level.py b/tests/micropython/opt_level.py new file mode 100644 index 0000000000..4e2f2f4ea3 --- /dev/null +++ b/tests/micropython/opt_level.py @@ -0,0 +1,14 @@ +import micropython as micropython + +# check we can get and set the level +micropython.opt_level(0) +print(micropython.opt_level()) +micropython.opt_level(1) +print(micropython.opt_level()) + +# check that the optimisation levels actually differ +micropython.opt_level(0) +exec('print(__debug__)') +micropython.opt_level(1) +exec('print(__debug__)') +exec('assert 0') diff --git a/tests/micropython/opt_level.py.exp b/tests/micropython/opt_level.py.exp new file mode 100644 index 0000000000..74b3dd74e8 --- /dev/null +++ b/tests/micropython/opt_level.py.exp @@ -0,0 +1,4 @@ +0 +1 +True +False From e49153fb98ade48395b80271093bd763e771b3da Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 12:29:54 +1100 Subject: [PATCH 09/78] py/compile: Remove unreachable code. --- py/compile.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/py/compile.c b/py/compile.c index 0ea8a3c150..de75bcdc3c 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2836,12 +2836,10 @@ STATIC void compile_scope_func_annotations(compiler_t *comp, mp_parse_node_t pn) // no annotation return; } - } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star) { + } else { + assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_typedargslist_dbl_star); // double star with possible annotation // fallthrough - } else { - // no annotation - return; } mp_parse_node_t pn_annotation = pns->nodes[1]; From 5e22afce41de8c87071d8fc149a6ba3cd8762819 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 12:30:32 +1100 Subject: [PATCH 10/78] tests: Improve test coverage of py/compile.c. --- tests/basics/async_def.py | 16 ++++++++++++++++ tests/basics/async_def.py.exp | 3 +++ tests/basics/async_with.py | 4 +++- tests/basics/async_with.py.exp | 1 + tests/basics/del_global.py | 5 +++++ tests/basics/for_range.py | 5 +++++ tests/basics/syntaxerror.py | 4 ++++ tests/basics/unpack1.py | 1 + tests/cmdline/repl_basic.py | 1 + tests/cmdline/repl_basic.py.exp | 2 ++ tests/import/import2a.py | 3 +++ tests/micropython/viper_args.py | 8 ++++++++ tests/misc/non_compliant.py | 6 ++++++ tests/misc/non_compliant.py.exp | 1 + tests/run-tests | 2 +- 15 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/basics/async_def.py create mode 100644 tests/basics/async_def.py.exp diff --git a/tests/basics/async_def.py b/tests/basics/async_def.py new file mode 100644 index 0000000000..e345703d74 --- /dev/null +++ b/tests/basics/async_def.py @@ -0,0 +1,16 @@ +# test async def + +def dec(f): + print('decorator') + return f + +# test definition with a decorator +@dec +async def foo(): + print('foo') + +coro = foo() +try: + coro.send(None) +except StopIteration: + print('StopIteration') diff --git a/tests/basics/async_def.py.exp b/tests/basics/async_def.py.exp new file mode 100644 index 0000000000..f555ace99a --- /dev/null +++ b/tests/basics/async_def.py.exp @@ -0,0 +1,3 @@ +decorator +foo +StopIteration diff --git a/tests/basics/async_with.py b/tests/basics/async_with.py index 9eccfd816c..5af0c5d955 100644 --- a/tests/basics/async_with.py +++ b/tests/basics/async_with.py @@ -3,6 +3,7 @@ class AContext: async def __aenter__(self): print('enter') + return 1 async def __aexit__(self, exc_type, exc, tb): print('exit', exc_type, exc) @@ -17,7 +18,8 @@ except StopIteration: print('finished') async def g(): - async with AContext(): + async with AContext() as ac: + print(ac) raise ValueError('error') o = g() diff --git a/tests/basics/async_with.py.exp b/tests/basics/async_with.py.exp index 6072a3e0b3..d00b18c969 100644 --- a/tests/basics/async_with.py.exp +++ b/tests/basics/async_with.py.exp @@ -3,5 +3,6 @@ body exit None None finished enter +1 exit error ValueError diff --git a/tests/basics/del_global.py b/tests/basics/del_global.py index 77d11cb3c4..d740357b03 100644 --- a/tests/basics/del_global.py +++ b/tests/basics/del_global.py @@ -54,3 +54,8 @@ try: print(c) except NameError: print("NameError") + +a = 1 +b = 2 +c = 3 +del (a, (b, c)) diff --git a/tests/basics/for_range.py b/tests/basics/for_range.py index ddff5ebd44..58a8f7caa7 100644 --- a/tests/basics/for_range.py +++ b/tests/basics/for_range.py @@ -34,6 +34,11 @@ try: print(x) except TypeError: print('TypeError') +try: + for x in range(start=0, end=1): + print(x) +except TypeError: + print('TypeError') try: for x in range(0, 1, step=1): print(x) diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index 2ae0183f8b..e5cbbac060 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -49,6 +49,9 @@ test_syntax("f[0]**2 = 1") # can't assign to empty tuple test_syntax("() = 1") +# can't have *x on RHS +test_syntax("x = *x") + # can't have multiple *x on LHS test_syntax("*a, *b = c") @@ -76,6 +79,7 @@ test_syntax("continue") test_syntax("return") test_syntax("yield") test_syntax("nonlocal a") +test_syntax("await 1") # error on uPy, warning on CPy #test_syntax("def f():\n a = 1\n global a") diff --git a/tests/basics/unpack1.py b/tests/basics/unpack1.py index 10e01dea06..0e8ec592c9 100644 --- a/tests/basics/unpack1.py +++ b/tests/basics/unpack1.py @@ -12,6 +12,7 @@ a, b, c = range(3); print(a, b, c) (a,) = range(1); print(a) (a, b) = range(2); print(a, b) (a, b, c) = range(3); print(a, b, c) +(a, (b, c)) = [-1, range(2)]; print(a, b, c) # lists diff --git a/tests/cmdline/repl_basic.py b/tests/cmdline/repl_basic.py index b416493dce..cbd5d3a4ac 100644 --- a/tests/cmdline/repl_basic.py +++ b/tests/cmdline/repl_basic.py @@ -1,3 +1,4 @@ # basic REPL tests print(1)  +2 diff --git a/tests/cmdline/repl_basic.py.exp b/tests/cmdline/repl_basic.py.exp index 96b8c28dce..2b390ea98b 100644 --- a/tests/cmdline/repl_basic.py.exp +++ b/tests/cmdline/repl_basic.py.exp @@ -5,4 +5,6 @@ Use \.\+ 1 >>> print(1) 1 +>>> 2 +2 >>> diff --git a/tests/import/import2a.py b/tests/import/import2a.py index ce32b10b1b..def6aeb6aa 100644 --- a/tests/import/import2a.py +++ b/tests/import/import2a.py @@ -1,2 +1,5 @@ from import1b import var print(var) + +from import1b import var as var2 +print(var2) diff --git a/tests/micropython/viper_args.py b/tests/micropython/viper_args.py index ca2a5e6704..2aebe1b048 100644 --- a/tests/micropython/viper_args.py +++ b/tests/micropython/viper_args.py @@ -26,3 +26,11 @@ def f4(x1:int, x2:int, x3:int, x4:int): f4(1, 2, 3, 4) # only up to 4 arguments currently supported + +# test compiling *x, **x, * args (currently unsupported at runtime) +@micropython.viper +def f(*x, **y): + pass +@micropython.viper +def f(*): + pass diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 1157ff8b29..e0b07c3ad6 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -3,6 +3,12 @@ import array import ustruct +# when super can't find self +try: + exec('def f(): super()') +except SyntaxError: + print('SyntaxError') + # array deletion not implemented try: a = array.array('b', (1, 2, 3)) diff --git a/tests/misc/non_compliant.py.exp b/tests/misc/non_compliant.py.exp index c03580442d..3095441ad0 100644 --- a/tests/misc/non_compliant.py.exp +++ b/tests/misc/non_compliant.py.exp @@ -1,3 +1,4 @@ +SyntaxError TypeError NotImplementedError True diff --git a/tests/run-tests b/tests/run-tests index cb920c0946..422d7463af 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -273,7 +273,7 @@ def run_tests(pyb, tests, args): if args.emit == 'native': skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join'.split()}) # require yield - skip_tests.update({'basics/async_%s.py' % t for t in 'await await2 for for2 with with2'.split()}) # require yield + skip_tests.update({'basics/async_%s.py' % t for t in 'def await await2 for for2 with with2'.split()}) # require yield skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs skip_tests.update({'basics/%s.py' % t for t in 'with_break with_continue with_return'.split()}) # require complete with support skip_tests.add('basics/array_construct2.py') # requires generators From 48874942f0e0c948a9cb351b25d9fb04cdb82d56 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 13:00:01 +1100 Subject: [PATCH 11/78] py/mpz: In divmod, replace check for rhs!=0 with assert. The check for division by zero is made by the caller of this function. --- py/mpz.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index bb76479569..b5ec171dea 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1497,13 +1497,10 @@ mpz_t *mpz_lcm(const mpz_t *z1, const mpz_t *z2) { quo * rhs + rem = lhs 0 <= rem < rhs can have lhs, rhs the same + assumes rhs != 0 (undefined behaviour if it is) */ void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs) { - if (rhs->len == 0) { - mpz_set_from_int(dest_quo, 0); - mpz_set_from_int(dest_rem, 0); - return; - } + assert(!mpz_is_zero(rhs)); mpz_need_dig(dest_quo, lhs->len + 1); // +1 necessary? memset(dest_quo->dig, 0, (lhs->len + 1) * sizeof(mpz_dig_t)); From df3e5d2b2f8610d246fea348bb96e70f636183ea Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 13:00:56 +1100 Subject: [PATCH 12/78] py/mpz: Use assert to verify mpz does not have a fixed digit buffer. --- py/mpz.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index b5ec171dea..6415e1df4a 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -734,11 +734,9 @@ STATIC void mpz_need_dig(mpz_t *z, mp_uint_t need) { } if (z->dig == NULL || z->alloc < need) { - if (z->fixed_dig) { - // cannot reallocate fixed buffers - assert(0); - return; - } + // if z has fixed digit buffer there's not much we can do as the caller will + // be expecting a buffer with at least "need" bytes (but it shouldn't happen) + assert(!z->fixed_dig); z->dig = m_renew(mpz_dig_t, z->dig, z->alloc, need); z->alloc = need; } From 8bb7d958f173eec58892bc00115516c160f93243 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 13:11:32 +1100 Subject: [PATCH 13/78] py: Factor duplicated function to calculate size of formatted int. --- py/mpz.c | 26 +------------------------- py/mpz.h | 1 + py/objint.c | 10 +++++----- py/objint.h | 2 ++ py/objint_mpz.c | 2 +- 5 files changed, 10 insertions(+), 31 deletions(-) diff --git a/py/mpz.c b/py/mpz.c index 6415e1df4a..cceb079cd3 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -645,18 +645,6 @@ STATIC void mpn_div(mpz_dig_t *num_dig, mp_uint_t *num_len, const mpz_dig_t *den #define MIN_ALLOC (2) -STATIC const uint8_t log_base2_floor[] = { - 0, - 0, 1, 1, 2, - 2, 2, 2, 3, - 3, 3, 3, 3, - 3, 3, 3, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 5 -}; - void mpz_init_zero(mpz_t *z) { z->neg = 0; z->fixed_dig = 0; @@ -1652,18 +1640,6 @@ mp_float_t mpz_as_float(const mpz_t *i) { } #endif -mp_uint_t mpz_as_str_size(const mpz_t *i, mp_uint_t base, const char *prefix, char comma) { - if (base < 2 || base > 32) { - return 0; - } - - mp_uint_t num_digits = i->len * DIG_SIZE / log_base2_floor[base] + 1; - mp_uint_t num_commas = comma ? num_digits / 3: 0; - mp_uint_t prefix_len = prefix ? strlen(prefix) : 0; - - return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte -} - #if 0 this function is unused char *mpz_as_str(const mpz_t *i, mp_uint_t base) { @@ -1673,7 +1649,7 @@ char *mpz_as_str(const mpz_t *i, mp_uint_t base) { } #endif -// assumes enough space as calculated by mpz_as_str_size +// assumes enough space as calculated by mp_int_format_size // returns length of string, not including null byte mp_uint_t mpz_as_str_inpl(const mpz_t *i, mp_uint_t base, const char *prefix, char base_char, char comma, char *str) { if (str == NULL || base < 2 || base > 32) { diff --git a/py/mpz.h b/py/mpz.h index 63ac772ffd..55ef3e15ff 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -127,6 +127,7 @@ void mpz_or_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs); void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs); +static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_SIZE; } mp_int_t mpz_hash(const mpz_t *z); bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value); bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value); diff --git a/py/objint.c b/py/objint.c index 9f948a1455..31067aaa52 100644 --- a/py/objint.c +++ b/py/objint.c @@ -162,14 +162,14 @@ STATIC const uint8_t log_base2_floor[] = { 4, 4, 4, 5 }; -STATIC uint int_as_str_size_formatted(uint base, const char *prefix, char comma) { +size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma) { if (base < 2 || base > 32) { return 0; } - uint num_digits = sizeof(fmt_int_t) * 8 / log_base2_floor[base] + 1; - uint num_commas = comma ? num_digits / 3: 0; - uint prefix_len = prefix ? strlen(prefix) : 0; + size_t num_digits = num_bits / log_base2_floor[base] + 1; + size_t num_commas = comma ? num_digits / 3 : 0; + size_t prefix_len = prefix ? strlen(prefix) : 0; return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte } @@ -211,7 +211,7 @@ char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, sign = '-'; } - uint needed_size = int_as_str_size_formatted(base, prefix, comma); + uint needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; diff --git a/py/objint.h b/py/objint.h index c79eb874a9..dc53e0708a 100644 --- a/py/objint.h +++ b/py/objint.h @@ -50,6 +50,8 @@ typedef enum { mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val); #endif // MICROPY_PY_BUILTINS_FLOAT +size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma); + void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 3a30eb9d9b..137d514de2 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -95,7 +95,7 @@ char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_ assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); - mp_uint_t needed_size = mpz_as_str_size(&self->mpz, base, prefix, comma); + mp_uint_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; From 6dff3df501242d106590a48b5ed382b01a97baea Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 13:20:11 +1100 Subject: [PATCH 14/78] py/objint: Use size_t for arguments that measure bytes/sizes. --- py/mpprint.c | 4 ++-- py/objint.c | 8 ++++---- py/objint.h | 6 +++--- py/objint_longlong.c | 2 +- py/objint_mpz.c | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/py/mpprint.c b/py/mpprint.c index 97ea33ad2a..9ad0f3f9a0 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -252,8 +252,8 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char // enough, a dynamic one will be allocated. char stack_buf[sizeof(mp_int_t) * 4]; char *buf = stack_buf; - mp_uint_t buf_size = sizeof(stack_buf); - mp_uint_t fmt_size = 0; + size_t buf_size = sizeof(stack_buf); + size_t fmt_size = 0; char *str; if (prec > 1) { diff --git a/py/objint.c b/py/objint.c index 31067aaa52..49dec0653c 100644 --- a/py/objint.c +++ b/py/objint.c @@ -133,8 +133,8 @@ void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t // enough, a dynamic one will be allocated. char stack_buf[sizeof(mp_int_t) * 4]; char *buf = stack_buf; - mp_uint_t buf_size = sizeof(stack_buf); - mp_uint_t fmt_size; + size_t buf_size = sizeof(stack_buf); + size_t fmt_size; char *str = mp_obj_int_formatted(&buf, &buf_size, &fmt_size, self_in, 10, NULL, '\0', '\0'); mp_print_str(print, str); @@ -180,7 +180,7 @@ size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char co // // The resulting formatted string will be returned from this function and the // formatted size will be in *fmt_size. -char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { fmt_int_t num; if (MP_OBJ_IS_SMALL_INT(self_in)) { @@ -211,7 +211,7 @@ char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, sign = '-'; } - uint needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); + size_t needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; diff --git a/py/objint.h b/py/objint.h index dc53e0708a..6e627f1bd7 100644 --- a/py/objint.h +++ b/py/objint.h @@ -53,12 +53,12 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val); size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma); void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); -char *mp_obj_int_formatted(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); -char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); mp_int_t mp_obj_int_hash(mp_obj_t self_in); -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, mp_uint_t len, byte *buf); +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); int mp_obj_int_sign(mp_obj_t self_in); mp_obj_t mp_obj_int_abs(mp_obj_t self_in); mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index f10e46447b..b051cfbe64 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -53,7 +53,7 @@ const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, mp_uint_t len, byte *buf) { +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; long long val = self->val; diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 137d514de2..6a59133d74 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -90,12 +90,12 @@ STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { // formatted size will be in *fmt_size. // // This particular routine should only be called for the mpz representation of the int. -char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_size, mp_const_obj_t self_in, +char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); - mp_uint_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); + size_t needed_size = mp_int_format_size(mpz_max_num_bits(&self->mpz), base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); *buf_size = needed_size; @@ -107,7 +107,7 @@ char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_ return str; } -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, mp_uint_t len, byte *buf) { +void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); mpz_as_bytes(&self->mpz, big_endian, len, buf); From 39968aaaff575800218b47488f85eed7081cd0cb Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 11 Oct 2016 07:10:48 +0300 Subject: [PATCH 15/78] extmod/uzlib: Update to upstream v2.1. Adds check that LZ offsets fall into the sliding dictionary used. This catches a case when uzlib.DecompIO with a smaller dictionary is used to decompress data which was compressed with a larger dictionary. Previously, this would lead to producing invalid data or crash, now an exception will be thrown. --- extmod/uzlib/tinf.h | 1 + extmod/uzlib/tinflate.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/extmod/uzlib/tinf.h b/extmod/uzlib/tinf.h index 3545bbd883..106203a099 100644 --- a/extmod/uzlib/tinf.h +++ b/extmod/uzlib/tinf.h @@ -32,6 +32,7 @@ extern "C" { #define TINF_DONE 1 #define TINF_DATA_ERROR (-3) #define TINF_CHKSUM_ERROR (-4) +#define TINF_DICT_ERROR (-5) /* checksum types */ #define TINF_CHKSUM_NONE 0 diff --git a/extmod/uzlib/tinflate.c b/extmod/uzlib/tinflate.c index 0e53f7f072..58850eb4a2 100644 --- a/extmod/uzlib/tinflate.c +++ b/extmod/uzlib/tinflate.c @@ -361,6 +361,9 @@ static int tinf_inflate_block_data(TINF_DATA *d, TINF_TREE *lt, TINF_TREE *dt) /* possibly get more bits from distance code */ offs = tinf_read_bits(d, dist_bits[dist], dist_base[dist]); if (d->dict_ring) { + if (offs > d->dict_size) { + return TINF_DICT_ERROR; + } d->lzOff = d->dict_idx - offs; if (d->lzOff < 0) { d->lzOff += d->dict_size; From 9e1dec181806d7cd34b5dfec8cdce4c41b39ab53 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Tue, 6 Sep 2016 07:52:00 +0100 Subject: [PATCH 16/78] docs/reference: Add constrained.rst doc. It contains detailed information about writing scripts to run efficiently on microcontrollers (and other constrained systems). --- docs/reference/constrained.rst | 456 +++++++++++++++++++++++++++++++++ docs/reference/index.rst | 1 + 2 files changed, 457 insertions(+) create mode 100644 docs/reference/constrained.rst diff --git a/docs/reference/constrained.rst b/docs/reference/constrained.rst new file mode 100644 index 0000000000..7c1b6a3eb2 --- /dev/null +++ b/docs/reference/constrained.rst @@ -0,0 +1,456 @@ +.. _constrained: + +MicroPython on Microcontrollers +=============================== + +MicroPython is designed to be capable of running on microcontrollers. These +have hardware limitations which may be unfamiliar to programmers more familiar +with conventional computers. In particular the amount of RAM and nonvolatile +"disk" (flash memory) storage is limited. This tutorial offers ways to make +the most of the limited resources. Because MicroPython runs on controllers +based on a variety of architectures, the methods presented are generic: in some +cases it will be necessary to obtain detailed information from platform specific +documentation. + +Flash Memory +------------ + +On the Pyboard the simple way to address the limited capacity is to fit a micro +SD card. In some cases this is impractical, either because the device does not +have an SD card slot or for reasons of cost or power consumption; hence the +on-chip flash must be used. The firmware including the MicroPython subsystem is +stored in the onboard flash. The remaining capacity is available for use. For +reasons connected with the physical architecture of the flash memory part of +this capacity may be inaccessible as a filesystem. In such cases this space may +be employed by incorporating user modules into a firmware build which is then +flashed to the device. + +There are two ways to achieve this: frozen modules and frozen bytecode. Frozen +modules store the Python source with the firmware. Frozen bytecode uses the +cross compiler to convert the source to bytecode which is then stored with the +firmware. In either case the module may be accessed with an import statement: + +.. code:: + + import mymodule + +The procedure for producing frozen modules and bytecode is platform dependent; +instructions for building the firmware can be found in the README files in the +relevant part of the source tree. + +In general terms the steps are as follows: + +* Clone the MicroPython `repository `_. +* Acquire the (platform specific) toolchain to build the firmware. +* Build the cross compiler. +* Place the modules to be frozen in a specified directory (dependent on whether + the module is to be frozen as source or as bytecode). +* Build the firmware. A specific command may be required to build frozen + code of either type - see the platform documentation. +* Flash the firmware to the device. + +RAM +--- + +When reducing RAM usage there are two phases to consider: compilation and +execution. In addition to memory consumption, there is also an issue known as +heap fragmentation. In general terms it is best to minimise the repeated +creation and destruction of objects. The reason for this is covered in the +section covering the `heap`_. + +Compilation Phase +~~~~~~~~~~~~~~~~~ + +When a module is imported, MicroPython compiles the code to bytecode which is +then executed by the MicroPython virtual machine (VM). The bytecode is stored +in RAM. The compiler itself requires RAM, but this becomes available for use +when the compilation has completed. + +If a number of modules have already been imported the situation can arise where +there is insufficient RAM to run the compiler. In this case the import +statement will produce a memory exception. + +If a module instantiates global objects on import it will consume RAM at the +time of import, which is then unavailable for the compiler to use on subsequent +imports. In general it is best to avoid code which runs on import; a better +approach is to have initialisation code which is run by the application after +all modules have been imported. This maximises the RAM available to the +compiler. + +If RAM is still insufficient to compile all modules one solution is to +precompile modules. MicroPython has a cross compiler capable of compiling Python +modules to bytecode (see the README in the mpy-cross directory). The resulting +bytecode file has a .mpy extension; it may be copied to the filesystem and +imported in the usual way. Alternatively some or all modules may be implemented +as frozen bytecode: on most platforms this saves even more RAM as the bytecode +is run directly from flash rather than being stored in RAM. + +Execution Phase +~~~~~~~~~~~~~~~ + +There are a number of coding techniques for reducing RAM usage. + +**Constants** + +MicroPython provides a ``const`` keyword which may be used as follows: + +.. code:: + + from micropython import const + ROWS = const(33) + _COLS = const(0x10) + a = ROWS + b = _COLS + +In both instances where the constant is assigned to a variable the compiler +will avoid coding a lookup to the name of the constant by substituting its +literal value. This saves bytecode and hence RAM. However the ``ROWS`` value +will occupy at least two machine words, one each for the key and value in the +globals dictionary. The presence in the dictionary is necessary because another +module might import or use it. This RAM can be saved by prepending the name +with an underscore as in ``_COLS``: this symbol is not visible outside the +module so will not occupy RAM. + +The argument to ``const()`` may be anything which, at compile time, evaluates +to an integer e.g. ``0x100`` or ``1 << 8``. It can even include other const +symbols that have already been defined, e.g. ``1 << BIT``. + +**Constant data structures** + +Where there is a substantial volume of constant data and the platform supports +execution from Flash, RAM may be saved as follows. The data should be located in +Python modules and frozen as bytecode. The data must be defined as ``bytes`` +objects. The compiler 'knows' that ``bytes`` objects are immutable and ensures +that the objects remain in flash memory rather than being copied to RAM. The +``ustruct`` module can assist in converting between ``bytes`` types and other +Python built-in types. + +When considering the implications of frozen bytecode, note that in Python +strings, floats, bytes, integers and complex numbers are immutable. Accordingly +these will be frozen into flash. Thus, in the line + +.. code:: + + mystring = "The quick brown fox" + +the actual string "The quick brown fox" will reside in flash. At runtime a +reference to the string is assigned to the *variable* ``mystring``. The reference +occupies a single machine word. In principle a long integer could be used to +store constant data: + +.. code:: + + bar = 0xDEADBEEF0000DEADBEEF + +As in the string example, at runtime a reference to the arbitrarily large +integer is assigned to the variable ``bar``. That reference occupies a +single machine word. + +It might be expected that tuples of integers could be employed for the purpose +of storing constant data with minimal RAM use. With the current compiler this +is ineffective (the code works, but RAM is not saved). + +.. code:: + + foo = (1, 2, 3, 4, 5, 6, 100000) + +At runtime the tuple will be located in RAM. This may be subject to future +improvement. + +**Needless object creation** + +There are a number of situations where objects may unwittingly be created and +destroyed. This can reduce the usability of RAM through fragmentation. The +following sections discuss instances of this. + +**String concatenation** + +Consider the following code fragments which aim to produce constant strings: + +.. code:: + + var = "foo" + "bar" + var1 = "foo" "bar" + var2 = """\ + foo\ + bar""" + +Each produces the same outcome, however the first needlessly creates two string +objects at runtime, allocates more RAM for concatenation before producing the +third. The others perform the concatenation at compile time which is more +efficient, reducing fragmentation. + +Where strings must be dynamically created before being fed to a stream such as +a file it will save RAM if this is done in a piecemeal fashion. Rather than +creating a large string object, create a substring and feed it to the stream +before dealing with the next. + +The best way to create dynamic strings is by means of the string ``format`` +method: + +.. code:: + + var = "Temperature {:5.2f} Pressure {:06d}\n".format(temp, press) + +**Buffers** + +When accessing devices such as instances of UART, I2C and SPI interfaces, using +pre-allocated buffers avoids the creation of needless objects. Consider these +two loops: + +.. code:: + + while True: + var = spi.read(100) + # process data + + buf = bytearray(100) + while True: + spi.readinto(buf) + # process data in buf + +The first creates a buffer on each pass whereas the second re-uses a pre-allocated +buffer; this is both faster and more efficient in terms of memory fragmentation. + +**Bytes are smaller than ints** + +On most platforms an integer consumes four bytes. Consider the two calls to the +function ``foo()``: + +.. code:: + + def foo(bar): + for x in bar: + print(x) + foo((1, 2, 0xff)) + foo(b'\1\2\xff') + +In the first call a tuple of integers is created in RAM. The second efficiently +creates a ``bytes`` object consuming the minimum amount of RAM. If the module +were frozen as bytecode, the ``bytes`` object would reside in flash. + +**Strings Versus Bytes** + +Python3 introduced Unicode support. This introduced a distinction between a +string and an array of bytes. MicroPython ensures that Unicode strings take no +additional space so long as all characters in the string are ASCII (i.e. have +a value < 126). If values in the full 8-bit range are required ``bytes`` and +``bytearray`` objects can be used to ensure that no additional space will be +required. Note that most string methods (e.g. ``strip()``) apply also to ``bytes`` +instances so the process of eliminating Unicode can be painless. + +.. code:: + + s = 'the quick brown fox' # A string instance + b = b'the quick brown fox' # a bytes instance + +Where it is necessary to convert between strings and bytes the string ``encode`` +and the bytes ``decode`` methods can be used. Note that both strings and bytes +are immutable. Any operation which takes as input such an object and produces +another implies at least one RAM allocation to produce the result. In the +second line below a new bytes object is allocated. This would also occur if ``foo`` +were a string. + +.. code:: + + foo = b' empty whitespace' + foo = foo.lstrip() + +**Runtime compiler execution** + +The Python keywords ``eval`` and ``exec`` invoke the compiler at runtime, which +requires significant amounts of RAM. Note that the ``pickle`` library employs +``exec``. It may be more RAM efficient to use the ``json`` library for object +serialisation. + +**Storing strings in flash** + +Python strings are immutable hence have the potential to be stored in read only +memory. The compiler can place in flash strings defined in Python code. As with +frozen modules it is necessary to have a copy of the source tree on the PC and +the toolchain to build the firmware. The procedure will work even if the +modules have not been fully debugged, so long as they can be imported and run. + +After importing the modules, execute: + +.. code:: + + micropython.qstr_info(1) + +Then copy and paste all the Q(xxx) lines into a text editor. Check for and +remove lines which are obviously invalid. Open the file qstrdefsport.h which +will be found in stmhal (or the equivalent directory for the architecture in +use). Copy and paste the corrected lines at the end of the file. Save the file, +rebuild and flash the firmware. The outcome can be checked by importing the +modules and again issuing: + +.. code:: + + micropython.qstr_info(1) + +The Q(xxx) lines should be gone. + +.. _heap: + +The Heap +-------- + +When a running program instantiates an object the necessary RAM is allocated +from a fixed size pool known as the heap. When the object goes out of scope (in +other words becomes inaccessible to code) the redundant object is known as +"garbage". A process known as "garbage collection" (GC) reclaims that memory, +returning it to the free heap. This process runs automatically, however it can +be invoked directly by issuing ``gc.collect()``. + +The discourse on this is somewhat involved. For a 'quick fix' issue the +following periodically: + +.. code:: + + gc.collect() + gc.threshold(gc.mem_free() // 4 + gc.mem_alloc()) + +Fragmentation +~~~~~~~~~~~~~ + +Say a program creates an object ``foo``, then an object ``bar``. Subsequently +``foo`` goes out of scope but ``bar`` remains. The RAM used by ``foo`` will be +reclaimed by GC. However if ``bar`` was allocated to a higher address, the +RAM reclaimed from ``foo`` will only be of use for objects no bigger than +``foo``. In a complex or long running program the heap can become fragmented: +despite there being a substantial amount of RAM available, there is insufficient +contiguous space to allocate a particular object, and the program fails with a +memory error. + +The techniques outlined above aim to minimise this. Where large permanent buffers +or other objects are required it is best to instantiate these early in the +process of program execution before fragmentation can occur. Further improvements +may be made by monitoring the state of the heap and by controlling GC; these are +outlined below. + +Reporting +~~~~~~~~~ + +A number of library functions are available to report on memory allocation and +to control GC. These are to be found in the ``gc`` and ``micropython`` modules. +The following example may be pasted at the REPL (``ctrl e`` to enter paste mode, +``ctrl d`` to run it). + +.. code:: + + import gc + import micropython + gc.collect() + micropython.mem_info() + print('-----------------------------') + print('Initial free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + def func(): + a = bytearray(10000) + gc.collect() + print('Func definition: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + func() + print('Func run free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + gc.collect() + print('Garbage collect free: {} allocated: {}'.format(gc.mem_free(), gc.mem_alloc())) + print('-----------------------------') + micropython.mem_info(1) + +Methods employed above: + +* ``gc.collect()`` Force a garbage collection. See footnote. +* ``micropython.mem_info()`` Print a summary of RAM utilisation. +* ``gc.mem_free()`` Return the free heap size in bytes. +* ``gc.mem_alloc()`` Return the number of bytes currently allocated. +* ``micropython.mem_info(1)`` Print a table of heap utilisation (detailed below). + +The numbers produced are dependent on the platform, but it can be seen that +declaring the function uses a small amount of RAM in the form of bytecode +emitted by the compiler (the RAM used by the compiler has been reclaimed). +Running the function uses over 10KiB, but on return ``a`` is garbage because it +is out of scope and cannot be referenced. The final ``gc.collect()`` recovers +that memory. + +The final output produced by ``micropython.mem_info(1)`` will vary in detail but +may be interpreted as follows: + +====== ================= +Symbol Meaning +====== ================= + . free block + h head block + = tail block + m marked head block + T tuple + L list + D dict + F float + B byte code + M module +====== ================= + +Each letter represents a single block of memory, a block being 16 bytes. So each +line of the heap dump represents 0x400 bytes or 1KiB of RAM. + +Control of Garbage Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A GC can be demanded at any time by issuing ``gc.collect()``. It is advantageous +to do this at intervals, firstly to pre-empt fragmentation and secondly for +performance. A GC can take several milliseconds but is quicker when there is +little work to do (about 1ms on the Pyboard). An explicit call can minimise that +delay while ensuring it occurs at points in the program when it is acceptable. + +Automatic GC is provoked under the following circumstances. When an attempt at +allocation fails, a GC is performed and the allocation re-tried. Only if this +fails is an exception raised. Secondly an automatic GC will be triggered if the +amount of free RAM falls below a threshold. This threshold can be adapted as +execution progresses: + +.. code:: + + gc.collect() + gc.threshold(gc.mem_free() // 4 + gc.mem_alloc()) + +This will provoke a GC when more than 25% of the currently free heap becomes +occupied. + +In general modules should instantiate data objects at runtime using constructors +or other initialisation functions. The reason is that if this occurs on +initialisation the compiler may be starved of RAM when subsequent modules are +imported. If modules do instantiate data on import then ``gc.collect()`` issued +after the import will ameliorate the problem. + +String Operations +----------------- + +MicroPython handles strings in an efficient manner and understanding this can +help in designing applications to run on microcontrollers. When a module +is compiled, strings which occur multiple times are stored once only, a process +known as string interning. In MicroPython an interned string is known as a ``qstr``. +In a module imported normally that single instance will be located in RAM, but +as described above, in modules frozen as bytecode it will be located in flash. + +String comparisons are also performed efficiently using hashing rather than +character by character. The penalty for using strings rather than integers may +hence be small both in terms of performance and RAM usage - a fact which may +come as a surprise to C programmers. + +Postscript +---------- + +MicroPython passes, returns and (by default) copies objects by reference. A +reference occupies a single machine word so these processes are efficient in +RAM usage and speed. + +Where variables are required whose size is neither a byte nor a machine word +there are standard libraries which can assist in storing these efficiently and +in performing conversions. See the ``array``, ``ustruct`` and ``uctypes`` +modules. + +Footnote: gc.collect() return value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On Unix and Windows platforms the ``gc.collect()`` method returns an integer +which signifies the number of distinct memory regions that were reclaimed in the +collection (more precisely, the number of heads that were turned into frees). For +efficiency reasons bare metal ports do not return this value. diff --git a/docs/reference/index.rst b/docs/reference/index.rst index ae8d6530af..7a85fc5cf3 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -15,6 +15,7 @@ MicroPython are described in the sections here. repl.rst isr_rules.rst speed_python.rst + constrained.rst .. only:: port_pyboard From eaef6b5324fa2ff425802d4abeea45aa945bfc14 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sat, 8 Oct 2016 17:34:46 +0200 Subject: [PATCH 17/78] extmod/machine_i2c: Use writes not reads in i2c.scan(). As per discussion in #2449, using write requests instead of read requests for I2C.scan() seems to support a larger number of devices, especially ones that are write-only. Even a read-only I2C device has to implement writes in order to be able to receive the address of the register to read. --- extmod/machine_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/machine_i2c.c b/extmod/machine_i2c.c index d76e5eedd1..e201b23990 100644 --- a/extmod/machine_i2c.c +++ b/extmod/machine_i2c.c @@ -272,7 +272,7 @@ STATIC mp_obj_t machine_i2c_scan(mp_obj_t self_in) { // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved for (int addr = 0x08; addr < 0x78; ++addr) { mp_hal_i2c_start(self); - int ack = mp_hal_i2c_write_byte(self, (addr << 1) | 1); + int ack = mp_hal_i2c_write_byte(self, (addr << 1)); if (ack) { mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); } From d02f3a57f47b44bf31769fb089f1f18060ea3b4d Mon Sep 17 00:00:00 2001 From: Alex March Date: Wed, 28 Sep 2016 14:51:35 +0100 Subject: [PATCH 18/78] extmod/vfs_fat: Add file and directory checks for remove and rmdir. --- extmod/vfs_fat.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 3a17533e43..6e827fc664 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -31,6 +31,7 @@ #include #include "py/nlr.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" #include "extmod/vfs_fat_file.h" @@ -76,24 +77,42 @@ STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_listdir_obj, 1, 2, fat_vfs_listdir_func); -STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { - (void)vfs_in; +STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t path_in, mp_int_t attr) { const char *path = mp_obj_str_get_str(path_in); - // TODO check that path is actually a file before trying to unlink it - FRESULT res = f_unlink(path); - if (res == FR_OK) { - return mp_const_none; - } else { + + FILINFO fno; +#if _USE_LFN + fno.lfname = NULL; + fno.lfsize = 0; +#endif + FRESULT res = f_stat(path, &fno); + + if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } + + // check if path is a file or directory + if ((fno.fattrib & AM_DIR) == attr) { + res = f_unlink(path); + + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return mp_const_none; + } else { + mp_raise_OSError(attr ? MP_ENOTDIR : MP_EISDIR); + } +} + +STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { + (void)vfs_in; + return fat_vfs_remove_internal(path_in, 0); // 0 == file attribute } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove); STATIC mp_obj_t fat_vfs_rmdir(mp_obj_t vfs_in, mp_obj_t path_in) { - // TODO: Currently just redirects to fat_vfs_remove(), which are - // backed by the same underlying FatFs function. Should at least - // check that path is actually a dir. - return fat_vfs_remove(vfs_in, path_in); + (void) vfs_in; + return fat_vfs_remove_internal(path_in, AM_DIR); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_rmdir_obj, fat_vfs_rmdir); From f274561e16dd35242d34c9b8fa7a09905857992c Mon Sep 17 00:00:00 2001 From: Alex March Date: Fri, 7 Oct 2016 10:19:04 +0100 Subject: [PATCH 19/78] tests/extmod/vfs_fat: Test coverage for remove() and rmdir(). --- tests/extmod/vfs_fat_ramdisk.py | 26 +++++++++++++++++++++++++- tests/extmod/vfs_fat_ramdisk.py.exp | 5 +++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index f470dbcfe7..d11ad324fc 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -62,11 +62,22 @@ assert b"hello!" in bdev.data assert vfs.listdir() == ['foo_file.txt'] +try: + vfs.rmdir("foo_file.txt") +except OSError as e: + print(e.args[0] == 20) # uerrno.ENOTDIR + vfs.remove('foo_file.txt') assert vfs.listdir() == [] vfs.mkdir("foo_dir") assert vfs.listdir() == ['foo_dir'] + +try: + vfs.remove("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EISDIR) + f = vfs.open("foo_dir/file-in-dir.txt", "w") f.write("data in file") f.close() @@ -84,9 +95,22 @@ with vfs.open("sub_file.txt", "w") as f: f.write("test2") assert vfs.listdir() == ["sub_file.txt"] +try: + vfs.chdir("sub_file.txt") +except OSError as e: + print(e.args[0] == uerrno.ENOENT) + vfs.chdir("..") print("getcwd:", vfs.getcwd()) +try: + vfs.rmdir("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EACCES) + +vfs.remove("foo_dir/sub_file.txt") +vfs.rmdir("foo_dir") +print(vfs.listdir()) vfs.umount() try: @@ -97,4 +121,4 @@ else: raise AssertionError("expected OSError not thrown") vfs = uos.VfsFat(bdev, "/ramdisk") -assert vfs.listdir() == ['foo_dir', 'moved-to-root.txt'] +assert vfs.listdir() == ['moved-to-root.txt'] diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index fd893b6e4c..ff16e5552d 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -1,5 +1,10 @@ statvfs: (512, 512, 14, 14, 14, 0, 0, 0, 0, 255) getcwd: /ramdisk hello! +True +True getcwd: /ramdisk/foo_dir +True getcwd: /ramdisk +True +['moved-to-root.txt'] From db4e0092170914f2d74b5946f56789f36add2e27 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Tue, 11 Oct 2016 12:22:36 +0200 Subject: [PATCH 20/78] esp8266/mpconfigport: Enable MICROPY_PY_BUILTINS_SLICE_ATTRS --- esp8266/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 19cf9a6792..5f65e920f1 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -33,6 +33,7 @@ #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_SET (1) #define MICROPY_PY_BUILTINS_SLICE (1) +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (1) #define MICROPY_PY_BUILTINS_PROPERTY (1) #define MICROPY_PY___FILE__ (0) #define MICROPY_PY_GC (1) From deaa57acf3db104e2c1a54c6bf4bbd96f95583f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 12 Oct 2016 10:20:48 +1100 Subject: [PATCH 21/78] py/compile: Remove debugging code for compiler dispatch. It was a relic from the days of developing the compiler and is no longer needed, and it's impossible to trigger via a test. --- py/compile.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/py/compile.c b/py/compile.c index de75bcdc3c..f84d5e2145 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2723,15 +2723,8 @@ STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn; EMIT_ARG(set_source_line, pns->source_line); compile_function_t f = compile_function[MP_PARSE_NODE_STRUCT_KIND(pns)]; - if (f == NULL) { -#if MICROPY_DEBUG_PRINTERS - printf("node %u cannot be compiled\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns)); - mp_parse_node_print(pn, 0); -#endif - compile_syntax_error(comp, pn, "internal compiler error"); - } else { - f(comp, pns); - } + assert(f != NULL); + f(comp, pns); } } From 31101d91ceb5758c17d02b7d41bffbd387cad112 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 12 Oct 2016 11:00:17 +1100 Subject: [PATCH 22/78] py/lexer: Remove unnecessary code, and unreachable code. Setting emit_dent=0 is unnecessary because arriving in that part of the if-logic will guarantee that emit_dent is already zero. The block to check indent_top(lex)>0 is unreachable because a newline is always inserted an the end of the input stream, and hence dedents are always processed before EOF. --- py/lexer.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/py/lexer.c b/py/lexer.c index b2c9c5ff78..4a7c8f580a 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -343,7 +343,6 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, bool first_token) { lex->tok_kind = MP_TOKEN_NEWLINE; mp_uint_t num_spaces = lex->column - 1; - lex->emit_dent = 0; if (num_spaces == indent_top(lex)) { } else if (num_spaces > indent_top(lex)) { indent_push(lex, num_spaces); @@ -359,16 +358,7 @@ STATIC void mp_lexer_next_token_into(mp_lexer_t *lex, bool first_token) { } } else if (is_end(lex)) { - if (indent_top(lex) > 0) { - lex->tok_kind = MP_TOKEN_NEWLINE; - lex->emit_dent = 0; - while (indent_top(lex) > 0) { - indent_pop(lex); - lex->emit_dent -= 1; - } - } else { - lex->tok_kind = MP_TOKEN_END; - } + lex->tok_kind = MP_TOKEN_END; } else if (is_char_or(lex, '\'', '\"') || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"')) From 11fc6553e831885d993c8a6c09ae98aa74fdf6b7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 16:22:21 +1100 Subject: [PATCH 23/78] esp8266: Enable sys.{stdin,stdout,stderr}.buffer for raw serial access. --- esp8266/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 5f65e920f1..ee32a848d0 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -50,6 +50,7 @@ #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_STDFILES (1) +#define MICROPY_PY_SYS_STDIO_BUFFER (1) #define MICROPY_PY_UERRNO (1) #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_UCTYPES (1) From af8d791bd09e2d735ec59424ec05f495348d99e7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Oct 2016 16:23:20 +1100 Subject: [PATCH 24/78] esp8266: Enable importing of precompiled .mpy files. --- esp8266/mpconfigport.h | 1 + py/emitglue.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index ee32a848d0..33f319f69a 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -9,6 +9,7 @@ #define MICROPY_ALLOC_PARSE_RULE_INC (8) #define MICROPY_ALLOC_PARSE_RESULT_INC (8) #define MICROPY_ALLOC_PARSE_CHUNK_INIT (64) +#define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_X64 (0) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) diff --git a/py/emitglue.c b/py/emitglue.c index f4b59df3eb..dc5be6e0e0 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -425,7 +425,7 @@ mp_raw_code_t *mp_raw_code_load_file(const char *filename) { return rc; } -#elif defined(__thumb2__) +#elif defined(__thumb2__) || defined(__xtensa__) // fatfs file reader (assume thumb2 arch uses fatfs...) #include "lib/fatfs/ff.h" From 4021b1e1b86a86af9e43c393c447110d36ebb36d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 12 Oct 2016 18:00:32 +0300 Subject: [PATCH 25/78] lib/utils/pyexec: Don't treat SystemExit as "forced exit". "Forced exit" is treated as soft-reboot (Ctrl+D). But expected effect of calling sys.exit() is termination of the current script, not any further and more serious actions like mentioned soft reboot. --- lib/utils/pyexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 2bc7a00cc0..aac211894c 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -99,7 +99,7 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, // check for SystemExit if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) { // at the moment, the value of SystemExit is unused - ret = PYEXEC_FORCED_EXIT; + ret = 0; } else { mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); ret = 0; From cdbeee0c506fd5b465f76d8072b1fe4e954dd782 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 12 Oct 2016 18:55:31 +0300 Subject: [PATCH 26/78] tools: Upgrade upip to 1.1.3. Initial support for running on a baremetal, low-heap systems (like esp8266), using Python module interface. --- tools/micropython-upip-1.0.tar.gz | Bin 4075 -> 0 bytes tools/micropython-upip-1.1.3.tar.gz | Bin 0 -> 4072 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tools/micropython-upip-1.0.tar.gz create mode 100644 tools/micropython-upip-1.1.3.tar.gz diff --git a/tools/micropython-upip-1.0.tar.gz b/tools/micropython-upip-1.0.tar.gz deleted file mode 100644 index f34915070829f706510fcbc2473f3a1fd32a23d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4075 zcmVctuE-)^1VR8WNTYGcc zHWJU@{1iB5a-uF0_3*2ssXFJ0mB!P=_SsH*9mk`gL`Y&y5j=pDqg>n1e!Bojf)s5h zY3s{f#i=6_1Qv_MZ=Yb7!IZOjoh(??PU9eM_uOvh$?to0;W{|j!{6S)Uf2B1t|z@d z^nm7r9q8BF?{@c}ki935aHS&gI3Z8snHNr3bZ5VZ-e(KRe*Z_VW!?T8jbm(d>3rS} zq8aNv&i?mzdcE#;|G&WfKl|?6_VLNf(@)<2{r%lL_y3@`TiO5Je)r%B>2CM`55L~f z#PhwxYkyC<2v{^A008U6ThalkV#6x+xk#5wkFN*hB3Q;DC9yZX@#d5)y$F6dnK4e@ zAcZqY!L?qoC2hy>Za@}E5{p5nGY^tQI&r6LX=1K)9|)0B(b?_pS%)dK@PSE{9MKgG zSqzNn*KNA=f>1NxRz&_jXKWtQIcI4sa5n38Fr|?IPTm|}T1Qk&c@QUZX?it+hO_p9 ziG=zOt&BLF{wobQ6(kjGdP9>I+=vkV{SXEd_?af_7~W3OAWVXYESaB%R5V@kf-Pe& z2_`Thi^4Uz1$kuC3Hij*giHaWYzZtSY3#;pGG#t>t+UWefRp8bygm8uk;(- z;`HtLi_wLfyia~V{om>Ks``JhzrWT0$G9?3S#qEC?>GgS%z}_&!^6(N`Y62I)61tZ zjeHtS*W)mVZo~uK6Bds{)ca3^;r9CN`d_zGzghpg8~T6H+uQ2@qg>Wj1-APC@%sN+ zruRYp@9$Lfe{Uatw)+1V%g4CBP!P)) z!WPT29dL zS%x+z;Yo`+Y@B&%NG{k73)xECtSj%w(&Fmvxy$0_W1w%8z#j#=^@hBr>!(c-D&r3H zk1zAacsPe;(WZ z>)VtG;t9fv2FiKFuub0N%|8iHTWH1Kyb{$Oes_RKO&%Q_mpJbe55a{T7_#rf&k zk7tLMugH+tzjj>HBmu2KClwrTOj~7JmQN??9EQB~LP4!*NWCbH$4Fg3>(#XdZJrS1 zge5Oo8u=s68FxnSr&QYW=0KW-7`h;>8Da5Q#9@#)=$rK0U`FtX41qIypzR1D9PBLz z>u%dEXm84P4wFi+#uXL21222cj7&%)hc}T>ubz&aRlZrEzZ?>N)xFL}M=X)e#ZcV| zX0c34*xZ7lJ+NfiswSSG=swMb>Hg(4!zeXqy!37;_N1g`{giu?gDCfwx>@Z*SPsa>&g z$y1s)Q@Ow7^g?d8glw4>NRzrAp9>H#`O8ot+8vGld3oYcMLK|&qq*~}Snry(J;a=&I`ja=&v&auyQ&J z-fOm(kU#<(|NbT4e=HOt1dNHF#vEL^gKr8Bjsfe-%CIN zfO>=LDhR&!!jwuJ)YAgQ7C?l3sbUG265~1?TSZu??pb97@6ShvM{h6?rMWFLZ1O{|Y+$1ogo!44zDMReFIYEgAjeJGH?qmTcR%h!N%P!osE8C~Bu&+_9 zE`6VHZ<_WMA9_aU4W*5T{&A{d@|tCbE%(ije@& z>Wx+K1W?RMpwdGn+A!`$Yn&Z(f_`8Acs3f;ZB$_nvpMb%tX|U#;1;t38#u^Elm<|c zTkTZ$2u%|oseJ;G-9umQ5txPgowe$=QyHaU?>+1T#C?=SfJe! z?wlqxS~>QsQ&fxGH3+~`9C}mgfPaUbUMPcKA`f0T3mPCpD(+?4WZil^8sm#hN0AT6 zZ^qJC!j0x*97Q zk_wQQgyB|;74jYV+EHzJxPohy@rp|PY}3~crEJ04d*Jug)S~1sa=Dcus2TbJ-U99h z&gmgA5FARJHzfGP=X_vufZlf|DYQ?3bnR~a2xvYjD(ip)Y zh>RkE70PD-Cag|?0K&Bvh;m}~x1&qa0S;eXUY>OzmwCtEMX!JpWE=1C54m$R3=}Gw ziqTM`)$>EhI<@taGF?#)N|AU;Dj*;d7P6WcFfh%s*#Q+uklS&16AICTI@luzC9mC$ul*%Zjv$M)V zyp97`h2<{ebNLJ#(7~(#1zngYA?=ajSBfaZ-~`9HA@h8J=u}+IfRoSxv1ehsL?k{d z!fOF$4z{9KiC17H4z5PTblNIfi$EBc2wZKfIvb=lD+El7WDFpH&e-9~mLB^0%GRYP z`&#D{xbsa z9Y0ijwB8DN(qd%Iq`j0Wc_uw_)sD&6D8g^9@mJFO#&uotGih`3wGJkiG)iPZ`Hf{A z&j^gs)_xwWXw)*xl0b7pGx87ufiIdt;FPE|8i4?|GD--WSw`aD!nhZ@ZYKX7GFgM9 zW?mX5t_7()EJ)TvO^1=s@1!DydDpGd!PVcI#N)Xa0j5AumS)kzQb0=y#b;D4OZS9P zlK?^|uIj3YldRC{+F9DaVR^7*>6D`p8PqA~V4xO2jgG@ID+EXlvd>kMd`j&mlpu+WH{7ldZvkFl2F44E8c2s1Q)%MDzosFbPgZ6E76S3QSeX-874nMb~;8^b}1eI0%-8K6;24LU_z=7L-Hi zJW0VFvZ#Sh5n%%+o+JypG=)QbWob72vO;|w1NZ0DS``0CDd-FAM?s;i7+Ls)u}UEj zeRf%yD(?%vBIkQ^YDnE6flteoiAtbzPvlx>s;Hl-ToJi`iX3qEW<>{MjAHQxDuJVl zMY7od2mnXF8id&i7y4gPrR4U;F*-`QM{lS9CrfV={YfCEk3D zpCX{Cl@D0Tf%~p}5UXg+=_Oe{eX?ACkEW>dG-n?^> zK)mX4-^C{D^6-58YIJxsI>%E%>F#VSaM%M#(A6yN;raRDkK||4&A)+i-yWY_eg#dv zZnvpE*|A0Np>|ZSzgsh|55s=3EPaxL=X-v@ZR>pWZT5^{wpE(WF=_zkyYj*o@xovp zl~2a;1w_U24QWHLPX0=Mb&5xQntKCL(5yv}Q9WK4^{@pZgS}oK)10nV9M?|P3H3Pl z)(*ThOTak9sMaHac9yU~IK$NWtp2J2Yh@P@L1U7mf(&_Z4~9HQ#$yLRQiEuuB|}Xb zCF2kaHIjYmp?jv6fWtK@%1X8w{q0gpgQQ<+7w(Bi=QS2 zXvu{j6$giH;Ly!MQlj|W09&pEmmWWcz@?-BkeO)wH#a`CvGoAw8E=ti0{;A_ERjpv z`rH$5(X!}UsoKVbsCaj4ocv5xod;!wYkc#G@#!L1 zZG1Gaknqq2%kC$v0%Pe6c9jI%)dwxGIA@{ZmnX)xDYh@+D60gCgN{VNK#9=2e~Wxo z9izT=AXnNGwup9-*H?-KSwb4hD$%u7yX~00XE%oDQF;TgSA4Z{ubMq05Sn$S%P(nA zLhsgDY&AP0fHym@G6YI|mkvQ!n^nHz*z_V{@i9y<&jG4auZnriZzzdu^}nwY|R7>p!<0h< diff --git a/tools/micropython-upip-1.1.3.tar.gz b/tools/micropython-upip-1.1.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..90f726d86248e023fe0059c9de67f3ced7d6517a GIT binary patch literal 4072 zcmVI31qujSfyv zPmhjACr1Z+!-J#4 z##uUMqhRP)n4?X4x{~OOchiq+^^P;yF(xM0kI326DtFtmria2GfEGiQ&{eZpBR(V*&GaQ(u$(lXF z5Y=%~ePw0A=5Wt!1(Av}5ArpeXAuvat0XKS$!g3#UH+AT48J8_mzQ9LiE@(G`#6ZSP59Xk%KPiN%&C5s8iL-9Se-S7h3+7;ROormOItN3oC| zP4y_n@v~uuaBi5^S4!V>ZLXG&(&?NbFVa?+s6Z|z6Zt`HE&q1hA59t!p|)(kG{3JK zjq8bd{aK(ywKiljSlvTnPx`HSE$EFXc|FaQU$76?%1xB#w|PMv9)w~kaV_jW&U9b| z=jZ=(aec$WH0oTvxPEi-vCT)FAI6e*NYt3l+z%d(zDF58a1{&QLR(*!vxTwyGRbCP z!m3D6bE?XqW~LRr`#5ub73F2IXheFvqd+B7Y}lHDjLrxITq;hB%&YkOn|2}Zluz4g z&am~qeIYnIcocELYi`iw$@prO29Ps6%;$nH;?G9M72pdb`s?3ncOsBV9%U)>A{UU< zqm@QTr9ZaPY@nR^S%0ZW)$>;U25}nk&&oe3;fyDn9`mO#DYf%p1rNZ9y{_*_PoA>9gzinTmuDRgc-y*=>XeFrh6_R|y%YB9u-5Te+%7#R> zeL#x`Pb1C29aLB-C_Wcmf>nbq?beNWF5L;4HQ=8M5zY(c$Lf}pcX@s%2V<=!C^|$_ zb>w*gw1M2~`#8_zbP01RUAoWH?%K*fkYK#!z~*ALd%`IeEvGVDmA4Tjq-FFl z9y`<$g)uGZlS!>GiUgU|)7y`Z44sKv_Z8MT5DL-AG4u;#!w3st6~?G0w?`AFuBH`p z{qQuwaMEV`I!jX&aK#1e6=S?=B5IA)vZv>2m_xcMoTD2y3+?EGWrD;V0x#&Jt%{1> zwcXkdYy|omS&hiy~gc^RVD7ma2R_gh`CBOh7BO$yPKPij>0-&G3j)1XKq=5+l`Btk)C3v^SkSanA*; z2KhRV1KsfknOLfCT=0OJ7rMwMF-nyQtx~iI=1C?iwT&dSFG#X5lH~nbss$uTJX~wl zPN;jJZ_RiukzjGvqYa1yO+3;@!bCl0_dkXasR*gIw5~Rp$W0J4vY5ijKuiR;t}5!2 zTNiT@eU3XZeU9=BS(6El21{~O=G%serj2-_h;(MO8#k4lq(uCxhNfbw`x^V4DXv2` zM4Euol#8iK811bWT5T$5h&%i(M7F|HMOkB=M!cTQ-b7wCQc0yL~O=cj$%bs{EiD0iCI~&C`X;zR$#zx_{VjH&)7v|!v4K3aKyc5~oeo+y7k!N^M4WpaN91z*1jC6Q zL4?c`0gnJ{_rC!rjTKygk8NmfnHxBsbR!m;&h)33S@D*Tz($K&^%QEB&BIhd1~j{D z|E1iovMTe?DFBrwO0lIa6-%TQV5<_*l=I6npa0!srQa1PRFv<;%vK}$;>U0m5y^1 z+_cOq)fOcC%RgFStolzGlqoXFy|>ZVncMzwy>ZW7F#NT?ZIleRhoo3(4eaeRWYg$tq0o5K1EpkUO6wrpIhWQyPb{{)#C^ zRnole=j>ZD(RUMiDt_MuLBRf(^#%J@@V}G*>nmKG42sXicXfXUCjX^=gR1aV)jShZ zO42=cYZybXi-kF*>Nl4015YhqevBc^j9aM`if1i9@DLEh z7vvz)VeKqMB-(9Jt)o}UlH#kwO(kj<}ImX*TNAX>Q1VW!=j8H5eeD*CnV3erL z1gxVv+5Vl|Io&50w~&DL_@+@(0bCztZzl|4#IpA5Ccynbmftta`>@9ffe|$}bq!{3 zV}^-22=510D;7hkwvvihB}+V^w5GJN1j&#A&TOJ4zY)S2**%z|ZH!cZZW^bbrF>#<#w^+nu>l5ejm3F@v9 z37LC-Cy_yuNjHn8@%Gjo9I;J?ESk9JKIw#?~j5}a5$jXX<0S1`TGBL#t`G=?bDZr)v2dM_=igV~)D9O-3~Nbarxle0XBXLC|LF+%q;Dchq?{ zbKTa)C-&Xe?)FBIoNbZR6cI{IwXSQZC!d;9pf(fyAv*tgJN3chX`_HB-fbfgmN$l& zm5YDW219!r2}its(GDPjE-Svu#QGuTk80QLcyrUl**2Uuj1rzU{YEojrZ$4S2WFsc zwjXv~5MrV6vi6O4sWn>{JQN~ad!v&!{?XuRbC)`o%z+v#pL%R_R}&vC)#1M#bWcj} zDnf5Uagi>vR&)X@nc%eaHs*272JfZlv6mA6k?*pXOpyna$a-27NK8CuO{y@h7TXmwcf(s`Ia{=PD3Uh?Xxp@o z9Tl``+tiHrrvnj#a+|lgn?}qUDuQcO32>`;t*b>CMS@FIE)^s_ z*3_k@c>Hj2bMwRb^!)P8#j8ud&H4p9U**M`&5~?>k3bDm$pB?pwm@?`zl$IErucWt zJxl{O{0&+}gu#v5wT%)fmSnm@cz4GA+_G5ozj6H<^lxk-cf=M%iARAbu~B(wP2XeR zZ0;d@P}^zBWsjLUI=R&%-1bMhuN=4&r}NseJE~r+vZ&(*Zm;F))up%kCP(P%Az9Rl zpn^XivovcHlLK!PKU5y5{M)yq?SaKo-OEOT4`a#Mb&=&4I6fqGHjjR2&IMNy&I^i7 z6X`%pG46C*V6&ji_3zhm?8a{F#%}D!ZtTWx?8a{F#%}D!ZtTWx?8a{F#%}D!ZtTWx a?8a{F#%}D!ZtTWCdHf$;ga=drPyhhT#s2pI literal 0 HcmV?d00001 From 998578a2b867af7353330320db25e702ad972ba8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 12 Oct 2016 19:11:04 +0300 Subject: [PATCH 27/78] README: Mention _thread module availability in select ports. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 60123ca6bd..aeec167cca 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ MicroPython implements the entire Python 3.4 syntax (including exceptions, The following core datatypes are provided: str (including basic Unicode support), bytes, bytearray, tuple, list, dict, set, frozenset, array.array, collections.namedtuple, classes and instances. Builtin modules include sys, -time, and struct. Note that only subset of Python 3.4 functionality +time, and struct, etc. Select ports have support for _thread module +(multithreading). Note that only subset of Python 3.4 functionality implemented for the data types and modules. See the repository www.github.com/micropython/pyboard for the Micro From 06ee5e947f1584fec752a87b9f1fb0948b494b75 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 12 Oct 2016 19:15:32 +0300 Subject: [PATCH 28/78] zephyr/Makefile: Be sure to extra qstr's from port sources. --- zephyr/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zephyr/Makefile b/zephyr/Makefile index 2cc314b533..d07a0de5bb 100644 --- a/zephyr/Makefile +++ b/zephyr/Makefile @@ -42,6 +42,9 @@ SRC_C = main.c \ $(BUILD)/frozen.c \ $(SRC_MOD) +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) + OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) CFLAGS = $(KBUILD_CFLAGS) $(NOSTDINC_FLAGS) $(ZEPHYRINCLUDE) \ From b6a544b9175448cb533d43781bb62c424a51ea3d Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Sat, 24 Sep 2016 21:20:59 +0100 Subject: [PATCH 29/78] zephyr: Implement the help() function. The boot issue text mentions a help() function and encourages the user to run it. It is very disconcerting to find that the function does not exist... Signed-off-by: Daniel Thompson --- zephyr/Makefile | 2 ++ zephyr/help.c | 56 +++++++++++++++++++++++++++++++++++++++++++ zephyr/mpconfigport.h | 5 ++++ 3 files changed, 63 insertions(+) create mode 100644 zephyr/help.c diff --git a/zephyr/Makefile b/zephyr/Makefile index d07a0de5bb..1db84cb320 100644 --- a/zephyr/Makefile +++ b/zephyr/Makefile @@ -33,11 +33,13 @@ INC += -I$(ZEPHYR_BASE)/net/ip/contiki INC += -I$(ZEPHYR_BASE)/net/ip/contiki/os SRC_C = main.c \ + help.c \ uart_core.c \ lib/utils/stdout_helpers.c \ lib/utils/printf.c \ lib/utils/pyexec.c \ lib/utils/interrupt_char.c \ + lib/utils/pyhelp.c \ lib/mp-readline/readline.c \ $(BUILD)/frozen.c \ $(SRC_MOD) diff --git a/zephyr/help.c b/zephyr/help.c new file mode 100644 index 0000000000..e574adf473 --- /dev/null +++ b/zephyr/help.c @@ -0,0 +1,56 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 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 "lib/utils/pyhelp.h" + +STATIC const char *help_text = +"Welcome to MicroPython!\n" +"\n" +"Control commands:\n" +" CTRL-A -- on a blank line, enter raw REPL mode\n" +" CTRL-B -- on a blank line, enter normal REPL mode\n" +" CTRL-C -- interrupt a running program\n" +" CTRL-D -- on a blank line, do a soft reset of the board\n" +" CTRL-E -- on a blank line, enter paste mode\n" +"\n" +"For further help on a specific object, type help(obj)\n" +; + +STATIC mp_obj_t builtin_help(uint n_args, const mp_obj_t *args) { + if (n_args == 0) { + // print a general help message + printf("%s", help_text); + + } else { + // try to print something sensible about the given object + pyhelp_print_obj(args[0]); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj, 0, 1, builtin_help); diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index 2c5fad21b7..32dc9f1ff9 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -51,3 +51,8 @@ typedef long mp_off_t; // Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles #include "autoconf.h" + +// extra built in names to add to the global namespace +#define MICROPY_PORT_BUILTINS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \ + From 1a01ed0d2a76c46f5cc3d9f9211b550c7d4deb7c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 12 Oct 2016 19:42:55 +0300 Subject: [PATCH 30/78] zephyr/mpconfigport.h: Fix rebasing artifacts. --- zephyr/mpconfigport.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index 32dc9f1ff9..0208dc737e 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -1,5 +1,8 @@ #include +// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles +#include "autoconf.h" + // Saving extra crumbs to make sure binary fits in 128K #define MICROPY_COMP_CONST_FOLDING (0) #define MICROPY_COMP_CONST (0) @@ -49,9 +52,6 @@ typedef long mp_off_t; mp_obj_t mp_kbd_exception; \ const char *readline_hist[8]; -// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles -#include "autoconf.h" - // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \ From f17f3314d0a857fdf06132f3e8ef84a56345622b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 12 Oct 2016 22:51:17 +0300 Subject: [PATCH 31/78] zephyr: Add copyright blurbs. --- zephyr/main.c | 26 ++++++++++++++++++++++++++ zephyr/mpconfigport.h | 25 +++++++++++++++++++++++++ zephyr/src/zephyr_start.c | 25 +++++++++++++++++++++++++ zephyr/uart_core.c | 25 +++++++++++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/zephyr/main.c b/zephyr/main.c index 3bd768f686..8d319098b2 100644 --- a/zephyr/main.c +++ b/zephyr/main.c @@ -1,3 +1,29 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * 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 diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index 0208dc737e..1654e79b8c 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -1,3 +1,28 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * 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 Zephyr's autoconf.h, which should be made first by Zephyr makefiles diff --git a/zephyr/src/zephyr_start.c b/zephyr/src/zephyr_start.c index b490cc7709..9e8a90bebd 100644 --- a/zephyr/src/zephyr_start.c +++ b/zephyr/src/zephyr_start.c @@ -1,3 +1,28 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * 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 "zephyr_getchar.h" diff --git a/zephyr/uart_core.c b/zephyr/uart_core.c index 5f48f973f6..702c97d20a 100644 --- a/zephyr/uart_core.c +++ b/zephyr/uart_core.c @@ -1,3 +1,28 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * 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 "py/mpconfig.h" #include "src/zephyr_getchar.h" From e93c1ca5da58df336305c9a5e50214849342f298 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 13 Oct 2016 11:43:28 +1100 Subject: [PATCH 32/78] extmod/modujson: Implement ujson.load() to load JSON from a stream. This refactors ujson.loads(s) to behave as ujson.load(StringIO(s)). Increase in code size is: 366 bytes for unix x86-64, 180 bytes for stmhal, 84 bytes for esp8266. --- extmod/modujson.c | 107 ++++++++++++++++++++++++++++++---------------- py/objstringio.c | 8 +--- py/objstringio.h | 38 ++++++++++++++++ 3 files changed, 109 insertions(+), 44 deletions(-) create mode 100644 py/objstringio.h diff --git a/extmod/modujson.c b/extmod/modujson.c index 0d0781e063..193292b9e5 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -1,9 +1,9 @@ /* - * This file is part of the Micro Python project, http://micropython.org/ + * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * - * Copyright (c) 2014 Damien P. George + * Copyright (c) 2014-2016 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 @@ -28,8 +28,10 @@ #include "py/nlr.h" #include "py/objlist.h" +#include "py/objstringio.h" #include "py/parsenum.h" #include "py/runtime.h" +#include "py/stream.h" #if MICROPY_PY_UJSON @@ -42,7 +44,7 @@ STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps); -// This function implements a simple non-recursive JSON parser. +// The function below implements a simple non-recursive JSON parser. // // The JSON specification is at http://www.ietf.org/rfc/rfc4627.txt // The parser here will parse any valid JSON and return the correct @@ -52,13 +54,35 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_dumps_obj, mod_ujson_dumps); // input is outside it's specs. // // Most of the work is parsing the primitives (null, false, true, numbers, -// strings). It does 1 pass over the input string and so is easily extended to -// being able to parse from a non-seekable stream. It tries to be fast and +// strings). It does 1 pass over the input stream. It tries to be fast and // small in code size, while not using more RAM than necessary. -STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { - mp_uint_t len; - const char *s = mp_obj_str_get_data(obj, &len); - const char *top = s + len; + +typedef struct _ujson_stream_t { + mp_obj_t stream_obj; + mp_uint_t (*read)(mp_obj_t obj, void *buf, mp_uint_t size, int *errcode); + int errcode; + byte cur; +} ujson_stream_t; + +#define S_EOF (0) // null is not allowed in json stream so is ok as EOF marker +#define S_END(s) ((s).cur == S_EOF) +#define S_CUR(s) ((s).cur) +#define S_NEXT(s) (ujson_stream_next(&(s))) + +STATIC byte ujson_stream_next(ujson_stream_t *s) { + mp_uint_t ret = s->read(s->stream_obj, &s->cur, 1, &s->errcode); + if (s->errcode != 0) { + mp_raise_OSError(s->errcode); + } + if (ret == 0) { + s->cur = S_EOF; + } + return s->cur; +} + +STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) { + const mp_stream_p_t *stream_p = mp_get_stream_raise(stream_obj, MP_STREAM_OP_READ); + ujson_stream_t s = {stream_obj, stream_p->read, 0, 0}; vstr_t vstr; vstr_init(&vstr, 8); mp_obj_list_t stack; // we use a list as a simple stack for nested JSON @@ -67,41 +91,43 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { mp_obj_t stack_top = MP_OBJ_NULL; mp_obj_type_t *stack_top_type = NULL; mp_obj_t stack_key = MP_OBJ_NULL; + S_NEXT(s); for (;;) { cont: - if (s == top) { + if (S_END(s)) { break; } mp_obj_t next = MP_OBJ_NULL; bool enter = false; - switch (*s) { + byte cur = S_CUR(s); + S_NEXT(s); + switch (cur) { case ',': case ':': case ' ': case '\t': case '\n': case '\r': - s += 1; goto cont; case 'n': - if (s + 3 < top && s[1] == 'u' && s[2] == 'l' && s[3] == 'l') { - s += 4; + if (S_CUR(s) == 'u' && S_NEXT(s) == 'l' && S_NEXT(s) == 'l') { + S_NEXT(s); next = mp_const_none; } else { goto fail; } break; case 'f': - if (s + 4 < top && s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e') { - s += 5; + if (S_CUR(s) == 'a' && S_NEXT(s) == 'l' && S_NEXT(s) == 's' && S_NEXT(s) == 'e') { + S_NEXT(s); next = mp_const_false; } else { goto fail; } break; case 't': - if (s + 3 < top && s[1] == 'r' && s[2] == 'u' && s[3] == 'e') { - s += 4; + if (S_CUR(s) == 'r' && S_NEXT(s) == 'u' && S_NEXT(s) == 'e') { + S_NEXT(s); next = mp_const_true; } else { goto fail; @@ -109,11 +135,10 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { break; case '"': vstr_reset(&vstr); - for (s++; s < top && *s != '"';) { - byte c = *s; + for (; !S_END(s) && S_CUR(s) != '"';) { + byte c = S_CUR(s); if (c == '\\') { - s++; - c = *s; + c = S_NEXT(s); switch (c) { case 'b': c = 0x08; break; case 'f': c = 0x0c; break; @@ -121,10 +146,9 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { case 'r': c = 0x0d; break; case 't': c = 0x09; break; case 'u': { - if (s + 4 >= top) { goto fail; } mp_uint_t num = 0; for (int i = 0; i < 4; i++) { - c = (*++s | 0x20) - '0'; + c = (S_NEXT(s) | 0x20) - '0'; if (c > 9) { c -= ('a' - ('9' + 1)); } @@ -137,27 +161,29 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { } vstr_add_byte(&vstr, c); str_cont: - s++; + S_NEXT(s); } - if (s == top) { + if (S_END(s)) { goto fail; } - s++; + S_NEXT(s); next = mp_obj_new_str(vstr.buf, vstr.len, false); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { bool flt = false; vstr_reset(&vstr); - for (; s < top; s++) { - if (*s == '.' || *s == 'E' || *s == 'e') { + for (;;) { + vstr_add_byte(&vstr, cur); + cur = S_CUR(s); + if (cur == '.' || cur == 'E' || cur == 'e') { flt = true; - } else if (*s == '-' || unichar_isdigit(*s)) { + } else if (cur == '-' || unichar_isdigit(cur)) { // pass } else { break; } - vstr_add_byte(&vstr, *s); + S_NEXT(s); } if (flt) { next = mp_parse_num_decimal(vstr.buf, vstr.len, false, false, NULL); @@ -169,16 +195,13 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { case '[': next = mp_obj_new_list(0, NULL); enter = true; - s += 1; break; case '{': next = mp_obj_new_dict(0); enter = true; - s += 1; break; case '}': case ']': { - s += 1; if (stack_top == MP_OBJ_NULL) { // no object at all goto fail; @@ -231,10 +254,10 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { } success: // eat trailing whitespace - while (s < top && unichar_isspace(*s)) { - s++; + while (unichar_isspace(S_CUR(s))) { + S_NEXT(s); } - if (s < top) { + if (!S_END(s)) { // unexpected chars goto fail; } @@ -248,11 +271,21 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { fail: nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "syntax error in JSON")); } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_load_obj, mod_ujson_load); + +STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { + mp_uint_t len; + const char *buf = mp_obj_str_get_data(obj, &len); + vstr_t vstr = {len, len, (char*)buf, true}; + mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0}; + return mod_ujson_load(&sio); +} STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads); STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) }, { MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) }, + { MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) }, { MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) }, }; diff --git a/py/objstringio.c b/py/objstringio.c index eb0cc4eb36..be1a7d89cb 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -30,18 +30,12 @@ #include "py/nlr.h" #include "py/objstr.h" +#include "py/objstringio.h" #include "py/runtime.h" #include "py/stream.h" #if MICROPY_PY_IO -typedef struct _mp_obj_stringio_t { - mp_obj_base_t base; - vstr_t *vstr; - // StringIO has single pointer used for both reading and writing - mp_uint_t pos; -} mp_obj_stringio_t; - #if MICROPY_CPYTHON_COMPAT STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { if (o->vstr == NULL) { diff --git a/py/objstringio.h b/py/objstringio.h new file mode 100644 index 0000000000..853bfb11b7 --- /dev/null +++ b/py/objstringio.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 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. + */ +#ifndef MICROPY_INCLUDED_PY_OBJSTRINGIO_H +#define MICROPY_INCLUDED_PY_OBJSTRINGIO_H + +#include "py/obj.h" + +typedef struct _mp_obj_stringio_t { + mp_obj_base_t base; + vstr_t *vstr; + // StringIO has single pointer used for both reading and writing + mp_uint_t pos; +} mp_obj_stringio_t; + +#endif // MICROPY_INCLUDED_PY_OBJSTRINGIO_H From 11ab807d76365bef451df0168b021f06bf14534c Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 13 Oct 2016 11:44:40 +1100 Subject: [PATCH 33/78] tests/extmod: Add test for ujson.load(). --- tests/extmod/ujson_load.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/extmod/ujson_load.py diff --git a/tests/extmod/ujson_load.py b/tests/extmod/ujson_load.py new file mode 100644 index 0000000000..bf484a2074 --- /dev/null +++ b/tests/extmod/ujson_load.py @@ -0,0 +1,11 @@ +try: + from uio import StringIO + import ujson as json +except: + from io import StringIO + import json + +print(json.load(StringIO('null'))) +print(json.load(StringIO('"abc\\u0064e"'))) +print(json.load(StringIO('[false, true, 1, -2]'))) +print(json.load(StringIO('{"a":true}'))) From f2f8ae110bfa1a17a34b81a9ac9de1378d2b3c50 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 13 Oct 2016 12:09:18 +1100 Subject: [PATCH 34/78] extmod/modujson: Fix nanbox build. --- extmod/modujson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extmod/modujson.c b/extmod/modujson.c index 193292b9e5..ca4e6df104 100644 --- a/extmod/modujson.c +++ b/extmod/modujson.c @@ -278,7 +278,7 @@ STATIC mp_obj_t mod_ujson_loads(mp_obj_t obj) { const char *buf = mp_obj_str_get_data(obj, &len); vstr_t vstr = {len, len, (char*)buf, true}; mp_obj_stringio_t sio = {{&mp_type_stringio}, &vstr, 0}; - return mod_ujson_load(&sio); + return mod_ujson_load(MP_OBJ_FROM_PTR(&sio)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads); From e42186d3561921bd237dd10a73a60c76d238dd0c Mon Sep 17 00:00:00 2001 From: Alex March Date: Wed, 12 Oct 2016 14:44:32 +0100 Subject: [PATCH 35/78] tests/extmod/vfs_fat: Replace asserts with prints and expected outputs. --- tests/extmod/vfs_fat_ramdisk.py | 28 +++++++++++++--------------- tests/extmod/vfs_fat_ramdisk.py.exp | 13 +++++++++++++ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index d11ad324fc..6380761c6d 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -41,8 +41,8 @@ except MemoryError: uos.VfsFat.mkfs(bdev) -assert b"FOO_FILETXT" not in bdev.data -assert b"hello!" not in bdev.data +print(b"FOO_FILETXT" not in bdev.data) +print(b"hello!" not in bdev.data) vfs = uos.VfsFat(bdev, "/ramdisk") print("statvfs:", vfs.statvfs("/ramdisk")) @@ -57,10 +57,10 @@ f2 = vfs.open("foo_file.txt") print(f2.read()) f2.close() -assert b"FOO_FILETXT" in bdev.data -assert b"hello!" in bdev.data +print(b"FOO_FILETXT" in bdev.data) +print(b"hello!" in bdev.data) -assert vfs.listdir() == ['foo_file.txt'] +print(vfs.listdir()) try: vfs.rmdir("foo_file.txt") @@ -68,10 +68,10 @@ except OSError as e: print(e.args[0] == 20) # uerrno.ENOTDIR vfs.remove('foo_file.txt') -assert vfs.listdir() == [] +print(vfs.listdir()) vfs.mkdir("foo_dir") -assert vfs.listdir() == ['foo_dir'] +print(vfs.listdir()) try: vfs.remove("foo_dir") @@ -82,18 +82,18 @@ f = vfs.open("foo_dir/file-in-dir.txt", "w") f.write("data in file") f.close() -assert vfs.listdir("foo_dir") == ['file-in-dir.txt'] +print(vfs.listdir("foo_dir")) vfs.rename("foo_dir/file-in-dir.txt", "moved-to-root.txt") -assert vfs.listdir() == ['foo_dir', 'moved-to-root.txt'] +print(vfs.listdir()) vfs.chdir("foo_dir") print("getcwd:", vfs.getcwd()) -assert vfs.listdir() == [] +print(vfs.listdir()) with vfs.open("sub_file.txt", "w") as f: f.write("test2") -assert vfs.listdir() == ["sub_file.txt"] +print(vfs.listdir()) try: vfs.chdir("sub_file.txt") @@ -116,9 +116,7 @@ vfs.umount() try: vfs.listdir() except OSError as e: - assert e.args[0] == uerrno.ENODEV -else: - raise AssertionError("expected OSError not thrown") + print(e.args[0] == uerrno.ENODEV) vfs = uos.VfsFat(bdev, "/ramdisk") -assert vfs.listdir() == ['moved-to-root.txt'] +print(vfs.listdir()) diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index ff16e5552d..8a498b2fc4 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -1,10 +1,23 @@ +True +True statvfs: (512, 512, 14, 14, 14, 0, 0, 0, 0, 255) getcwd: /ramdisk hello! True True +['foo_file.txt'] +True +[] +['foo_dir'] +True +['file-in-dir.txt'] +['foo_dir', 'moved-to-root.txt'] getcwd: /ramdisk/foo_dir +[] +['sub_file.txt'] True getcwd: /ramdisk True ['moved-to-root.txt'] +True +['moved-to-root.txt'] From 8298251215a1606b50d8110665dc6bff9e31ab0e Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 14 Oct 2016 00:07:32 +1100 Subject: [PATCH 36/78] stmhal/pybstdio: Use size_t instead of mp_uint_t. --- stmhal/pybstdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stmhal/pybstdio.c b/stmhal/pybstdio.c index cf31f53acf..9cc787ce2d 100644 --- a/stmhal/pybstdio.c +++ b/stmhal/pybstdio.c @@ -85,7 +85,7 @@ STATIC mp_uint_t stdio_write(mp_obj_t self_in, const void *buf, mp_uint_t size, } } -STATIC mp_obj_t stdio_obj___exit__(mp_uint_t n_args, const mp_obj_t *args) { +STATIC mp_obj_t stdio_obj___exit__(size_t n_args, const mp_obj_t *args) { return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stdio_obj___exit___obj, 4, 4, stdio_obj___exit__); From b0a15aa73540f82ef47c9492af7ce196d1b1a6e9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 14 Oct 2016 00:08:19 +1100 Subject: [PATCH 37/78] qemu-arm: Enable lots of extmods and enable tests for them. The qemu-arm port is used for testing of ARM Thumb architecture on a desktop so should have many features enabled. --- qemu-arm/Makefile | 9 +++++++++ qemu-arm/memory.h | 2 ++ qemu-arm/mpconfigport.h | 11 ++++++++++- qemu-arm/mphalport.h | 3 ++- tools/tinytest-codegen.py | 11 +++++++++-- 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 qemu-arm/memory.h diff --git a/qemu-arm/Makefile b/qemu-arm/Makefile index 31ba6baa26..6a25eb9311 100644 --- a/qemu-arm/Makefile +++ b/qemu-arm/Makefile @@ -40,19 +40,28 @@ SRC_C = \ SRC_TEST_C = \ test_main.c \ +STM_SRC_C = $(addprefix stmhal/,\ + pybstdio.c \ + ) + SRC_S = \ OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ_TEST = OBJ_TEST += $(PY_O) OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o)) OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ_TEST += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ_TEST += $(BUILD)/tinytest.o +# List of sources for qstr extraction +SRC_QSTR += $(SRC_C) $(SRC_TEST_C) $(STM_SRC_C) + all: run run: $(BUILD)/firmware.elf diff --git a/qemu-arm/memory.h b/qemu-arm/memory.h new file mode 100644 index 0000000000..f3777b0e39 --- /dev/null +++ b/qemu-arm/memory.h @@ -0,0 +1,2 @@ +// this is needed for extmod/crypto-algorithms/sha256.c +#include diff --git a/qemu-arm/mpconfigport.h b/qemu-arm/mpconfigport.h index 1f23148c2a..b8806405bc 100644 --- a/qemu-arm/mpconfigport.h +++ b/qemu-arm/mpconfigport.h @@ -20,9 +20,18 @@ #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) -#define MICROPY_PY_IO (0) +#define MICROPY_PY_IO (1) #define MICROPY_PY_SYS_EXIT (1) #define MICROPY_PY_SYS_MAXSIZE (1) +#define MICROPY_PY_UERRNO (1) +#define MICROPY_PY_UBINASCII (1) +#define MICROPY_PY_URANDOM (1) +#define MICROPY_PY_UCTYPES (1) +#define MICROPY_PY_UZLIB (1) +#define MICROPY_PY_UJSON (1) +#define MICROPY_PY_URE (1) +#define MICROPY_PY_UHEAPQ (1) +#define MICROPY_PY_UHASHLIB (1) #define MICROPY_USE_INTERNAL_PRINTF (0) // type definitions for the specific machine diff --git a/qemu-arm/mphalport.h b/qemu-arm/mphalport.h index 4bd8276f34..d996402ae4 100644 --- a/qemu-arm/mphalport.h +++ b/qemu-arm/mphalport.h @@ -1 +1,2 @@ -// empty file +#define mp_hal_stdin_rx_chr() (0) +#define mp_hal_stdout_tx_strn_cooked(s, l) write(1, (s), (l)) diff --git a/tools/tinytest-codegen.py b/tools/tinytest-codegen.py index 091c1b065f..bab937135f 100755 --- a/tools/tinytest-codegen.py +++ b/tools/tinytest-codegen.py @@ -46,8 +46,15 @@ testgroup_member = ( ## XXX: may be we could have `--without ` argument... # currently these tests are selected because they pass on qemu-arm -test_dirs = ('basics', 'micropython', 'inlineasm') # 'float', 'import', 'io', 'misc') -exclude_tests = ('inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', 'inlineasm/asmfpmuldiv.py', 'inlineasm/asmfpsqrt.py',) +test_dirs = ('basics', 'micropython', 'extmod', 'inlineasm') # 'float', 'import', 'io', 'misc') +exclude_tests = ( + 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', 'inlineasm/asmfpmuldiv.py', 'inlineasm/asmfpsqrt.py', + 'extmod/time_ms_us.py', + 'extmod/ujson_dumps_float.py', 'extmod/ujson_loads_float.py', + 'extmod/uctypes_native_float.py', 'extmod/uctypes_le_float.py', + 'extmod/machine_pinbase.py', 'extmod/machine_pulse.py', + 'extmod/vfs_fat_ramdisk.py', +) output = [] From 6a4c6fc023292b42502b67b4ec3ece62d188ac14 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 14 Oct 2016 00:30:38 +1100 Subject: [PATCH 38/78] qemu-arm: Remove SRC_TEST_C from SRC_QSTR list, it's not needed. And it gives problems with header dependencies for auto-qstr generation. --- qemu-arm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-arm/Makefile b/qemu-arm/Makefile index 6a25eb9311..9159f97e54 100644 --- a/qemu-arm/Makefile +++ b/qemu-arm/Makefile @@ -60,7 +60,7 @@ OBJ_TEST += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ_TEST += $(BUILD)/tinytest.o # List of sources for qstr extraction -SRC_QSTR += $(SRC_C) $(SRC_TEST_C) $(STM_SRC_C) +SRC_QSTR += $(SRC_C) $(STM_SRC_C) all: run From 34d0b3f85c9926d854acd7723b9e057744916ee0 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 14 Oct 2016 00:32:34 +1100 Subject: [PATCH 39/78] tests/micropython: Add tests for heap_lock, and emergency exceptions. --- tests/micropython/emg_exc.py | 20 ++++++++++++++++++++ tests/micropython/emg_exc.py.exp | 1 + tests/micropython/heap_lock.py | 14 ++++++++++++++ tests/micropython/heap_lock.py.exp | 2 ++ tests/micropython/heapalloc.py | 13 ++++--------- 5 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 tests/micropython/emg_exc.py create mode 100644 tests/micropython/emg_exc.py.exp create mode 100644 tests/micropython/heap_lock.py create mode 100644 tests/micropython/heap_lock.py.exp diff --git a/tests/micropython/emg_exc.py b/tests/micropython/emg_exc.py new file mode 100644 index 0000000000..d228e6faab --- /dev/null +++ b/tests/micropython/emg_exc.py @@ -0,0 +1,20 @@ +# test that emergency exceptions work + +import micropython +import sys + +# some ports need to allocate heap for the emg exc +try: + micropython.alloc_emergency_exception_buf(256) +except AttributeError: + pass + +def f(): + micropython.heap_lock() + try: + raise ValueError(1) + except ValueError as er: + sys.print_exception(er) + micropython.heap_unlock() + +f() diff --git a/tests/micropython/emg_exc.py.exp b/tests/micropython/emg_exc.py.exp new file mode 100644 index 0000000000..82b10b5f54 --- /dev/null +++ b/tests/micropython/emg_exc.py.exp @@ -0,0 +1 @@ +ValueError: diff --git a/tests/micropython/heap_lock.py b/tests/micropython/heap_lock.py new file mode 100644 index 0000000000..0f0a70eff1 --- /dev/null +++ b/tests/micropython/heap_lock.py @@ -0,0 +1,14 @@ +# check that heap_lock/heap_unlock work as expected + +import micropython + +micropython.heap_lock() + +try: + print([]) +except MemoryError: + print('MemoryError') + +micropython.heap_unlock() + +print([]) diff --git a/tests/micropython/heap_lock.py.exp b/tests/micropython/heap_lock.py.exp new file mode 100644 index 0000000000..67b208cfc5 --- /dev/null +++ b/tests/micropython/heap_lock.py.exp @@ -0,0 +1,2 @@ +MemoryError +[] diff --git a/tests/micropython/heapalloc.py b/tests/micropython/heapalloc.py index 2dc7fa5e7e..a651158ca5 100644 --- a/tests/micropython/heapalloc.py +++ b/tests/micropython/heapalloc.py @@ -1,6 +1,6 @@ # check that we can do certain things without allocating heap memory -import gc +import micropython def f1(a): print(a) @@ -28,12 +28,7 @@ def test(): f2(i, i) # 2 args f3(1, 2, 3, 4) # function with lots of local state -# call h with heap allocation disabled and all memory used up -gc.disable() -try: - while True: - 'a'.lower # allocates 1 cell for boundmeth -except MemoryError: - pass +# call test() with heap allocation disabled +micropython.heap_lock() test() -gc.enable() +micropython.heap_unlock() From ed878275b020c006ec197bb5f5bdd8179fb36a4c Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 14 Oct 2016 01:27:53 +1100 Subject: [PATCH 40/78] esp8266: Enable micropython.alloc_emergency_exception_buf(). --- esp8266/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 33f319f69a..6d0deba8da 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -18,6 +18,7 @@ #define MICROPY_DEBUG_PRINTER_DEST mp_debug_print #define MICROPY_ENABLE_GC (1) #define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_REPL_EVENT_DRIVEN (0) #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_HELPER_REPL (1) From 824f5c5a32d740acad50d23b7ab1d69660dcf3ad Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 14 Oct 2016 16:46:34 +1100 Subject: [PATCH 41/78] py/vstr: Combine vstr_new_size with vstr_new since they are rarely used. Now there is just one function to allocate a new vstr, namely vstr_new (in addition to vstr_init etc). The caller of this function should know what initial size to allocate for the buffer, or at least have some policy or config option, instead of leaving it to a default (as it was before). --- lib/utils/pyexec.c | 2 +- py/misc.h | 3 +-- py/objstringio.c | 2 +- py/vstr.c | 14 +------------- teensy/main.c | 2 +- unix/coverage.c | 2 +- 6 files changed, 6 insertions(+), 19 deletions(-) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index aac211894c..5824e14035 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -148,7 +148,7 @@ STATIC int pyexec_raw_repl_process_char(int c); STATIC int pyexec_friendly_repl_process_char(int c); void pyexec_event_repl_init(void) { - MP_STATE_VM(repl_line) = vstr_new_size(32); + MP_STATE_VM(repl_line) = vstr_new(32); repl.cont_line = false; readline_init(MP_STATE_VM(repl_line), ">>> "); if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { diff --git a/py/misc.h b/py/misc.h index 3ed227a352..e60665e591 100644 --- a/py/misc.h +++ b/py/misc.h @@ -151,8 +151,7 @@ void vstr_init_fixed_buf(vstr_t *vstr, size_t alloc, char *buf); struct _mp_print_t; void vstr_init_print(vstr_t *vstr, size_t alloc, struct _mp_print_t *print); void vstr_clear(vstr_t *vstr); -vstr_t *vstr_new(void); -vstr_t *vstr_new_size(size_t alloc); +vstr_t *vstr_new(size_t alloc); void vstr_free(vstr_t *vstr); static inline void vstr_reset(vstr_t *vstr) { vstr->len = 0; } static inline char *vstr_str(vstr_t *vstr) { return vstr->buf; } diff --git a/py/objstringio.c b/py/objstringio.c index be1a7d89cb..212d8e314f 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -150,7 +150,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(stringio___exit___obj, 4, 4, stringio STATIC mp_obj_stringio_t *stringio_new(const mp_obj_type_t *type) { mp_obj_stringio_t *o = m_new_obj(mp_obj_stringio_t); o->base.type = type; - o->vstr = vstr_new(); + o->vstr = vstr_new(16); o->pos = 0; return o; } diff --git a/py/vstr.c b/py/vstr.c index 5096475f10..6a91552b5a 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -74,20 +74,8 @@ void vstr_clear(vstr_t *vstr) { vstr->buf = NULL; } -vstr_t *vstr_new(void) { +vstr_t *vstr_new(size_t alloc) { vstr_t *vstr = m_new_obj(vstr_t); - if (vstr == NULL) { - return NULL; - } - vstr_init(vstr, 16); - return vstr; -} - -vstr_t *vstr_new_size(size_t alloc) { - vstr_t *vstr = m_new_obj(vstr_t); - if (vstr == NULL) { - return NULL; - } vstr_init(vstr, alloc); return vstr; } diff --git a/teensy/main.c b/teensy/main.c index 890ee81493..ba7207fe83 100644 --- a/teensy/main.c +++ b/teensy/main.c @@ -317,7 +317,7 @@ soft_reset: pyexec_frozen_module("main.py"); #else { - vstr_t *vstr = vstr_new(); + vstr_t *vstr = vstr_new(16); vstr_add_str(vstr, "/"); if (pyb_config_main == MP_OBJ_NULL) { vstr_add_str(vstr, "main.py"); diff --git a/unix/coverage.c b/unix/coverage.c index c84a653f75..6a1b43fdce 100644 --- a/unix/coverage.c +++ b/unix/coverage.c @@ -34,7 +34,7 @@ STATIC mp_obj_t extra_coverage(void) { // vstr { mp_printf(&mp_plat_print, "# vstr\n"); - vstr_t *vstr = vstr_new_size(16); + vstr_t *vstr = vstr_new(16); vstr_hint_size(vstr, 32); vstr_add_str(vstr, "ts"); vstr_ins_byte(vstr, 1, 'e'); From a97284423eba9470c16c5f02fadea14bd8263751 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 14 Oct 2016 20:13:02 +0300 Subject: [PATCH 42/78] extmod/utime_mphal: Factor out implementations in terms of mp_hal_* for reuse. As long as a port implement mp_hal_sleep_ms(), mp_hal_ticks_ms(), etc. functions, it can just use standard implementations of utime.sleel_ms(), utime.ticks_ms(), etc. Python-level functions. --- esp8266/modutime.c | 62 ++++--------------------------- esp8266/mpconfigport.h | 1 + extmod/utime_mphal.c | 83 ++++++++++++++++++++++++++++++++++++++++++ extmod/utime_mphal.h | 36 ++++++++++++++++++ py/mpconfig.h | 6 +++ py/mphal.h | 4 ++ py/py.mk | 1 + 7 files changed, 139 insertions(+), 54 deletions(-) create mode 100644 extmod/utime_mphal.c create mode 100644 extmod/utime_mphal.h diff --git a/esp8266/modutime.c b/esp8266/modutime.c index 4b94ace74c..abfe069cc3 100644 --- a/esp8266/modutime.c +++ b/esp8266/modutime.c @@ -38,6 +38,7 @@ #include "modpybrtc.h" #include "timeutils.h" #include "user_interface.h" +#include "extmod/utime_mphal.h" /// \module time - time related functions /// @@ -99,53 +100,6 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) { } MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); -/// \function sleep(seconds) -/// Sleep for the given number of seconds. -STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { - #if MICROPY_PY_BUILTINS_FLOAT - mp_hal_delay_ms(1000 * mp_obj_get_float(seconds_o)); - #else - mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o)); - #endif - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep); - -STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { - mp_hal_delay_ms(mp_obj_get_int(arg)); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_ms_obj, time_sleep_ms); - -STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { - mp_hal_delay_us(mp_obj_get_int(arg)); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us); - -STATIC mp_obj_t time_ticks_ms(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms); - -STATIC mp_obj_t time_ticks_us(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us); - -STATIC mp_obj_t time_ticks_cpu(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu); - -STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) { - // we assume that the arguments come from ticks_xx so are small ints - uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in); - uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in); - return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff); - /// \function time() /// Returns the number of seconds, as an integer, since 1/1/2000. STATIC mp_obj_t time_time(void) { @@ -159,13 +113,13 @@ STATIC const mp_map_elem_t time_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&time_ticks_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&time_ticks_diff_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&mp_utime_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&mp_utime_sleep_ms_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&mp_utime_sleep_us_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&mp_utime_ticks_ms_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&mp_utime_ticks_us_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&mp_utime_ticks_cpu_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&mp_utime_ticks_diff_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj }, }; diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 6d0deba8da..201057f128 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -62,6 +62,7 @@ #define MICROPY_PY_UJSON (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_URE (1) +#define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_UZLIB (1) #define MICROPY_PY_LWIP (1) #define MICROPY_PY_MACHINE (1) diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c new file mode 100644 index 0000000000..9471ad5252 --- /dev/null +++ b/extmod/utime_mphal.c @@ -0,0 +1,83 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * 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_MP_HAL + +#include + +#include "py/obj.h" +#include "py/mphal.h" +#include "py/smallint.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { + #if MICROPY_PY_BUILTINS_FLOAT + mp_hal_delay_ms(1000 * mp_obj_get_float(seconds_o)); + #else + mp_hal_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_hal_delay_ms(mp_obj_get_int(arg)); + 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_hal_delay_us(mp_obj_get_int(arg)); + 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(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK); +} +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(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us); + +STATIC mp_obj_t time_ticks_cpu(void) { + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & MP_SMALL_INT_POSITIVE_MASK); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu); + +STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) { + // we assume that the arguments come from ticks_xx so are small ints + uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in); + uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in); + return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff); + +#endif // MICROPY_PY_UTIME_MP_HAL diff --git a/extmod/utime_mphal.h b/extmod/utime_mphal.h new file mode 100644 index 0000000000..4f2395a090 --- /dev/null +++ b/extmod/utime_mphal.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * + * 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/obj.h" + +MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_ms_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_us_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_ms_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_us_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_cpu_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_diff_obj); diff --git a/py/mpconfig.h b/py/mpconfig.h index e33a41f7a0..dcdaffe0f4 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -860,6 +860,12 @@ typedef double mp_float_t; #define MICROPY_PY_UERRNO (0) #endif +// Whether to provide "utime" module functions implementation +// in terms of mp_hal_* functions. +#ifndef MICROPY_PY_UTIME_MP_HAL +#define MICROPY_PY_UTIME_MP_HAL (0) +#endif + // Whether to provide "_thread" module #ifndef MICROPY_PY_THREAD #define MICROPY_PY_THREAD (0) diff --git a/py/mphal.h b/py/mphal.h index 54a45b0240..8d5654f9e3 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -66,6 +66,10 @@ mp_uint_t mp_hal_ticks_ms(void); mp_uint_t mp_hal_ticks_us(void); #endif +#ifndef mp_hal_ticks_cpu +mp_uint_t mp_hal_ticks_cpu(void); +#endif + // If port HAL didn't define its own pin API, use generic // "virtual pin" API from the core. #ifndef mp_hal_pin_obj_t diff --git a/py/py.mk b/py/py.mk index 741ad52f98..8caa37f8aa 100644 --- a/py/py.mk +++ b/py/py.mk @@ -229,6 +229,7 @@ PY_O_BASENAME = \ ../extmod/vfs_fat_file.o \ ../extmod/vfs_fat_lexer.o \ ../extmod/vfs_fat_misc.o \ + ../extmod/utime_mphal.o \ ../extmod/moduos_dupterm.o \ ../lib/embed/abort_.o \ ../lib/utils/printf.o \ From f059563507502d996c1d7dae3db6dc5a6b83d97b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 14 Oct 2016 20:42:42 +0300 Subject: [PATCH 43/78] stmhal/modutime: Refactor to use extmod/utime_mphal.c. This includes making sure that utime_mphal's sleep_ms() and sleep_us() don't sleep on negative arguments. --- stmhal/modpyb.c | 5 ++-- stmhal/modutime.c | 66 +++++-------------------------------------- stmhal/mpconfigport.h | 1 + stmhal/mphalport.h | 1 + 4 files changed, 12 insertions(+), 61 deletions(-) diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 17c3411ebb..5b2bf7aa99 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -62,6 +62,7 @@ #include "portmodules.h" #include "modmachine.h" #include "extmod/fsusermount.h" +#include "extmod/utime_mphal.h" /// \function millis() /// Returns the number of milliseconds since the board was last reset. @@ -162,8 +163,8 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_millis), (mp_obj_t)&pyb_elapsed_millis_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_micros), (mp_obj_t)&pyb_micros_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_elapsed_micros), (mp_obj_t)&pyb_elapsed_micros_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&time_sleep_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&time_sleep_us_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&mp_utime_sleep_ms_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&mp_utime_sleep_us_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&mod_os_sync_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mount), (mp_obj_t)&fsuser_mount_obj }, diff --git a/stmhal/modutime.c b/stmhal/modutime.c index 60c92d60c1..63597edde8 100644 --- a/stmhal/modutime.c +++ b/stmhal/modutime.c @@ -31,6 +31,7 @@ #include "py/nlr.h" #include "py/smallint.h" #include "py/obj.h" +#include "extmod/utime_mphal.h" #include "systick.h" #include "timeutils.h" #include "portmodules.h" @@ -129,51 +130,6 @@ STATIC mp_obj_t time_time(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); -/// \function sleep(seconds) -/// Sleep for the given number of seconds. Seconds can be a floating-point number to -/// sleep for a fractional number of seconds. -STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { -#if MICROPY_PY_BUILTINS_FLOAT - if (MP_OBJ_IS_INT(seconds_o)) { -#endif - HAL_Delay(1000 * mp_obj_get_int(seconds_o)); -#if MICROPY_PY_BUILTINS_FLOAT - } else { - HAL_Delay((uint32_t)(1000 * mp_obj_get_float(seconds_o))); - } -#endif - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_obj, time_sleep); - -STATIC mp_obj_t time_sleep_ms(mp_obj_t ms_in) { - mp_int_t ms = mp_obj_get_int(ms_in); - if (ms > 0) { - HAL_Delay(ms); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_ms_obj, time_sleep_ms); - -STATIC mp_obj_t time_sleep_us(mp_obj_t usec_in) { - mp_int_t usec = mp_obj_get_int(usec_in); - if (usec > 0) { - sys_tick_udelay(usec); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(time_sleep_us_obj, time_sleep_us); - -STATIC mp_obj_t time_ticks_ms(void) { - return MP_OBJ_NEW_SMALL_INT(HAL_GetTick() & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_ms_obj, time_ticks_ms); - -STATIC mp_obj_t time_ticks_us(void) { - return MP_OBJ_NEW_SMALL_INT(sys_tick_get_microseconds() & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_us_obj, time_ticks_us); - STATIC mp_obj_t time_ticks_cpu(void) { static bool enabled = false; if (!enabled) { @@ -186,27 +142,19 @@ STATIC mp_obj_t time_ticks_cpu(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu); -STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) { - // we assume that the arguments come from ticks_xx so are small ints - uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in); - uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in); - return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(time_ticks_diff_obj, time_ticks_diff); - STATIC const mp_map_elem_t time_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) }, { MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&time_sleep_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&time_sleep_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&time_sleep_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&time_ticks_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&time_ticks_us_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&mp_utime_sleep_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&mp_utime_sleep_ms_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&mp_utime_sleep_us_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&mp_utime_ticks_ms_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&mp_utime_ticks_us_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&time_ticks_diff_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&mp_utime_ticks_diff_obj }, }; STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 52fbcad681..8979ad8dca 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -94,6 +94,7 @@ #define MICROPY_PY_URE (1) #define MICROPY_PY_UHEAPQ (1) #define MICROPY_PY_UHASHLIB (1) +#define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_PY_MACHINE_PULSE (1) #define MICROPY_PY_MACHINE_I2C (1) diff --git a/stmhal/mphalport.h b/stmhal/mphalport.h index 29a9fd6c39..02b408777c 100644 --- a/stmhal/mphalport.h +++ b/stmhal/mphalport.h @@ -37,6 +37,7 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable // timing functions #include "stmhal/systick.h" #define mp_hal_delay_ms HAL_Delay +#define mp_hal_delay_us(us) sys_tick_udelay(us) #define mp_hal_delay_us_fast(us) sys_tick_udelay(us) #define mp_hal_ticks_ms HAL_GetTick #define mp_hal_ticks_us() sys_tick_get_microseconds() From 36f97f19b44471f2ed1a3bd37e096ce32a852a1f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 14 Oct 2016 22:19:45 +0300 Subject: [PATCH 44/78] extmod/utime_mphal: sleep_us/ms(): Don't wait on negative argument. --- extmod/utime_mphal.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c index 9471ad5252..3ecdc94469 100644 --- a/extmod/utime_mphal.c +++ b/extmod/utime_mphal.c @@ -46,13 +46,19 @@ STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep); STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { - mp_hal_delay_ms(mp_obj_get_int(arg)); + mp_int_t ms = mp_obj_get_int(arg); + if (ms > 0) { + mp_hal_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_hal_delay_us(mp_obj_get_int(arg)); + mp_int_t us = mp_obj_get_int(arg); + if (us > 0) { + mp_hal_delay_us(us); + } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us); From 06234a6115096a80f1a20d97a56c53766a9b8239 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 15 Oct 2016 23:46:13 +0300 Subject: [PATCH 45/78] extmod/modussl_mbedtls: Add dummy setblocking() method. Accepts only value of True. --- extmod/modussl_mbedtls.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c index ddb7ba0fe7..5a7a745d82 100644 --- a/extmod/modussl_mbedtls.c +++ b/extmod/modussl_mbedtls.c @@ -215,6 +215,16 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in return MP_STREAM_ERROR; } +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + // Currently supports only blocking mode + (void)self_in; + if (!mp_obj_is_true(flag_in)) { + mp_not_implemented(""); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + STATIC mp_obj_t socket_close(mp_obj_t self_in) { mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in); @@ -236,6 +246,7 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = { { 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_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) }, }; From 799ccdc7892a036bf7d1e3c378f3abaa3ef9fee3 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 16 Oct 2016 10:48:42 +0300 Subject: [PATCH 46/78] esp8266, stmhal, unix: MAKE_FROZEN is consistently defined in mkenv.mk. --- esp8266/Makefile | 1 - stmhal/Makefile | 1 - unix/Makefile | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/esp8266/Makefile b/esp8266/Makefile index d86fec1808..65a513afd6 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -12,7 +12,6 @@ include ../py/py.mk MPY_CROSS = ../mpy-cross/mpy-cross MPY_TOOL = ../tools/mpy-tool.py -MAKE_FROZEN = ../tools/make-frozen.py FROZEN_DIR = scripts FROZEN_MPY_DIR = modules diff --git a/stmhal/Makefile b/stmhal/Makefile index 7be0f28fe1..06be7acc89 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -276,7 +276,6 @@ all: $(BUILD)/firmware.dfu $(BUILD)/firmware.hex ifneq ($(FROZEN_DIR),) CFLAGS += -DMICROPY_MODULE_FROZEN_STR OBJ += $(BUILD)/frozen-files.o -MAKE_FROZEN = ../tools/make-frozen.py $(BUILD)/frozen-files.o: $(BUILD)/frozen-files.c $(call compile_c) diff --git a/unix/Makefile b/unix/Makefile index 4a313b3a80..53ff4cb487 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -273,7 +273,7 @@ coverage_test: coverage gcov -o build-coverage/extmod ../extmod/*.c $(BUILD)/_frozen_upip.c: $(BUILD)/frozen_upip/upip.py - ../tools/make-frozen.py $(dir $^) > $@ + $(MAKE_FROZEN) $(dir $^) > $@ # Select latest upip version available UPIP_TARBALL := $(shell ls -1 -v ../tools/micropython-upip-*.tar.gz | tail -n1) From 453c2e8f55132d92933f2de0308166730576ecc4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 11:23:37 +1100 Subject: [PATCH 47/78] tests/cmdline: Improve coverage test for printing bytecode. --- tests/cmdline/cmd_showbc.py | 17 ++++++ tests/cmdline/cmd_showbc.py.exp | 103 +++++++++++++++++++++++++++++--- 2 files changed, 111 insertions(+), 9 deletions(-) diff --git a/tests/cmdline/cmd_showbc.py b/tests/cmdline/cmd_showbc.py index 9989a7229a..2f4e953bb2 100644 --- a/tests/cmdline/cmd_showbc.py +++ b/tests/cmdline/cmd_showbc.py @@ -34,12 +34,14 @@ def f(): # subscript p = b[0] b[0] = p + b[0] += p # slice a = b[::] # sequenc unpacking a, b = c + a, *a = a # tuple swapping a, b = b, a @@ -79,6 +81,7 @@ def f(): b while not a: b + a = a or a # for loop for a in b: @@ -92,6 +95,11 @@ def f(): b finally: c + while a: + try: + break + except: + pass # with with a: @@ -117,6 +125,12 @@ def f(): return return 1 +# function with lots of locals +def f(): + l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = l10 = 1 + m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m9 = m10 = 2 + l10 + m10 + # functions with default args def f(a=1): pass @@ -133,3 +147,6 @@ def f(): # class class Class: pass + +# delete name +del Class diff --git a/tests/cmdline/cmd_showbc.py.exp b/tests/cmdline/cmd_showbc.py.exp index 0e5c559424..1f0c054cf9 100644 --- a/tests/cmdline/cmd_showbc.py.exp +++ b/tests/cmdline/cmd_showbc.py.exp @@ -7,9 +7,11 @@ arg names: (N_EXC_STACK 0) bc=-1 line=1 ######## - bc=\\d\+ line=134 + bc=\\d\+ line=152 00 MAKE_FUNCTION \.\+ \\d\+ STORE_NAME f +\\d\+ MAKE_FUNCTION \.\+ +\\d\+ STORE_NAME f \\d\+ LOAD_CONST_SMALL_INT 1 \\d\+ BUILD_TUPLE 1 \\d\+ LOAD_NULL @@ -22,6 +24,7 @@ arg names: \\d\+ LOAD_CONST_STRING 'Class' \\d\+ CALL_FUNCTION n=2 nkw=0 \\d\+ STORE_NAME Class +\\d\+ DELETE_NAME Class \\d\+ LOAD_CONST_NONE \\d\+ RETURN_VALUE File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) @@ -35,7 +38,7 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): (INIT_CELL 16) bc=-4 line=1 ######## - bc=\\d\+ line=118 + bc=\\d\+ line=126 00 LOAD_CONST_NONE 01 LOAD_CONST_FALSE 02 BINARY_OP 5 __add__ @@ -123,6 +126,14 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ LOAD_CONST_SMALL_INT 0 \\d\+ STORE_SUBSCR \\d\+ LOAD_DEREF 14 +\\d\+ LOAD_CONST_SMALL_INT 0 +\\d\+ DUP_TOP_TWO +\\d\+ LOAD_SUBSCR +\\d\+ LOAD_FAST 12 +\\d\+ BINARY_OP 18 __iadd__ +\\d\+ ROT_THREE +\\d\+ STORE_SUBSCR +\\d\+ LOAD_DEREF 14 \\d\+ LOAD_CONST_NONE \\d\+ LOAD_CONST_NONE \\d\+ BUILD_SLICE 2 @@ -132,6 +143,10 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ UNPACK_SEQUENCE 2 \\d\+ STORE_FAST 0 \\d\+ STORE_DEREF 14 +\\d\+ LOAD_FAST 0 +\\d\+ UNPACK_EX 1 +\\d\+ STORE_FAST 0 +\\d\+ STORE_FAST 0 \\d\+ LOAD_DEREF 14 \\d\+ LOAD_FAST 0 \\d\+ ROT_TWO @@ -225,6 +240,10 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ POP_TOP \\d\+ LOAD_FAST 0 \\d\+ POP_JUMP_IF_FALSE \\d\+ +\\d\+ LOAD_FAST 0 +\\d\+ JUMP_IF_TRUE_OR_POP \\d\+ +\\d\+ LOAD_FAST 0 +\\d\+ STORE_FAST 0 \\d\+ LOAD_DEREF 14 \\d\+ GET_ITER \\d\+ FOR_ITER \\d\+ @@ -251,6 +270,17 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): \\d\+ LOAD_FAST 1 \\d\+ POP_TOP \\d\+ END_FINALLY +\\d\+ JUMP \\d\+ +\\d\+ SETUP_EXCEPT \\d\+ +\\d\+ UNWIND_JUMP \\d\+ 1 +\\d\+ POP_BLOCK +\\d\+ JUMP \\d\+ +\\d\+ POP_TOP +\\d\+ POP_EXCEPT +\\d\+ JUMP \\d\+ +\\d\+ END_FINALLY +\\d\+ LOAD_FAST 0 +\\d\+ POP_JUMP_IF_TRUE \\d\+ \\d\+ LOAD_FAST 0 \\d\+ SETUP_WITH \\d\+ \\d\+ POP_TOP @@ -291,13 +321,68 @@ Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): ######## +\.\+rg names: +(N_STATE 22) +(N_EXC_STACK 0) + bc=-1 line=1 +######## + bc=\\d\+ line=132 +00 LOAD_CONST_SMALL_INT 1 +01 DUP_TOP +02 STORE_FAST 0 +03 DUP_TOP +04 STORE_FAST 1 +05 DUP_TOP +06 STORE_FAST 2 +07 DUP_TOP +08 STORE_FAST 3 +09 DUP_TOP +10 STORE_FAST 4 +11 DUP_TOP +12 STORE_FAST 5 +13 DUP_TOP +14 STORE_FAST 6 +15 DUP_TOP +16 STORE_FAST 7 +17 DUP_TOP +18 STORE_FAST 8 +19 STORE_FAST 9 +20 LOAD_CONST_SMALL_INT 2 +21 DUP_TOP +22 STORE_FAST 10 +23 DUP_TOP +24 STORE_FAST 11 +25 DUP_TOP +26 STORE_FAST 12 +27 DUP_TOP +28 STORE_FAST 13 +29 DUP_TOP +30 STORE_FAST 14 +31 DUP_TOP +32 STORE_FAST 15 +33 DUP_TOP +34 STORE_FAST_N 16 +36 DUP_TOP +37 STORE_FAST_N 17 +39 DUP_TOP +40 STORE_FAST_N 18 +42 STORE_FAST_N 19 +44 LOAD_FAST 9 +45 LOAD_FAST_N 19 +47 BINARY_OP 5 __add__ +48 POP_TOP +49 LOAD_CONST_NONE +50 RETURN_VALUE +File cmdline/cmd_showbc.py, code block 'f' (descriptor: \.\+, bytecode @\.\+ bytes) +Raw bytecode (code_info_size=\\d\+, bytecode_size=\\d\+): +######## \.\+5b arg names: a (N_STATE 5) (N_EXC_STACK 0) (INIT_CELL 0) ######## - bc=\\d\+ line=124 + bc=\\d\+ line=138 00 LOAD_CONST_SMALL_INT 2 01 BUILD_TUPLE 1 03 LOAD_NULL @@ -314,9 +399,9 @@ arg names: (N_STATE 2) (N_EXC_STACK 0) bc=-1 line=1 - bc=0 line=129 - bc=3 line=130 - bc=6 line=131 + bc=0 line=143 + bc=3 line=144 + bc=6 line=145 00 LOAD_CONST_NONE 01 YIELD_VALUE 02 POP_TOP @@ -338,7 +423,7 @@ arg names: (N_STATE 1) (N_EXC_STACK 0) bc=-1 line=1 - bc=13 line=135 + bc=13 line=149 00 LOAD_NAME __name__ (cache=0) 04 STORE_NAME __module__ 07 LOAD_CONST_STRING 'Class' @@ -411,7 +496,7 @@ arg names: * (N_EXC_STACK 0) bc=-\\d\+ line=1 ######## - bc=\\d\+ line=105 + bc=\\d\+ line=113 00 LOAD_DEREF 0 02 LOAD_CONST_SMALL_INT 1 03 BINARY_OP 5 __add__ @@ -430,7 +515,7 @@ arg names: * b (N_EXC_STACK 0) bc=-\\d\+ line=1 ######## - bc=\\d\+ line=125 + bc=\\d\+ line=139 00 LOAD_FAST 1 01 LOAD_DEREF 0 03 BINARY_OP 5 __add__ From e9404e5f5f058db954ac0a92cb5acfcef6f6724a Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 11:43:47 +1100 Subject: [PATCH 48/78] tests: Improve coverage of array, range, dict, slice, exc, unicode. --- tests/basics/array1.py | 4 ++++ tests/basics/builtin_range.py | 6 ++++++ tests/basics/dict1.py | 24 ++++++++++++++++++++++++ tests/basics/dict_views.py | 15 +++++++++++++++ tests/basics/int_constfolding.py | 5 +++++ tests/basics/slice_attrs.py | 9 +++++++++ tests/misc/non_compliant.py | 18 ++++++++++++++++++ tests/misc/non_compliant.py.exp | 3 +++ tests/unicode/unicode.py | 5 +++-- 9 files changed, 87 insertions(+), 2 deletions(-) diff --git a/tests/basics/array1.py b/tests/basics/array1.py index e5ea6683c3..c45b883c94 100644 --- a/tests/basics/array1.py +++ b/tests/basics/array1.py @@ -21,6 +21,10 @@ print(array.array('i')) print(bool(array.array('i'))) print(bool(array.array('i', [1]))) +# containment, with incorrect type +print('12' in array.array('B', b'12')) +print([] in array.array('B', b'12')) + # bad typecode try: array.array('X') diff --git a/tests/basics/builtin_range.py b/tests/basics/builtin_range.py index 9110cf12cd..59fc0344a4 100644 --- a/tests/basics/builtin_range.py +++ b/tests/basics/builtin_range.py @@ -50,3 +50,9 @@ try: range(1)[0] = 1 except TypeError: print("TypeError") + +# bad attr (can't store) +try: + range(4).start = 0 +except AttributeError: + print('AttributeError') diff --git a/tests/basics/dict1.py b/tests/basics/dict1.py index c70ca588a7..21d5af2726 100644 --- a/tests/basics/dict1.py +++ b/tests/basics/dict1.py @@ -16,3 +16,27 @@ while x < 100: d[x] = x x += 1 print(d[50]) + +# equality operator on dicts of different size +print({} == {1:1}) + +# equality operator on dicts of same size but with different keys +print({1:1} == {2:1}) + +# value not found +try: + {}[0] +except KeyError: + print('KeyError') + +# unsupported unary op +try: + +{} +except TypeError: + print('TypeError') + +# unsupported binary op +try: + {} + {} +except TypeError: + print('TypeError') diff --git a/tests/basics/dict_views.py b/tests/basics/dict_views.py index fbf63fa0ac..7ebcc1f56d 100644 --- a/tests/basics/dict_views.py +++ b/tests/basics/dict_views.py @@ -3,4 +3,19 @@ for m in d.items, d.values, d.keys: print(m()) print(list(m())) +# print a view with more than one item +print({1:1, 2:1}.values()) + +# unsupported binary op on a dict values view +try: + {1:1}.values() + 1 +except TypeError: + print('TypeError') + +# unsupported binary op on a dict keys view +try: + {1:1}.keys() + 1 +except TypeError: + print('TypeError') + # set operations still to come diff --git a/tests/basics/int_constfolding.py b/tests/basics/int_constfolding.py index c01f964daa..aa38fa6b80 100644 --- a/tests/basics/int_constfolding.py +++ b/tests/basics/int_constfolding.py @@ -38,3 +38,8 @@ print(-123 // 7, -123 % 7) print(123 // -7, 123 % -7) print(-123 // -7, -123 % -7) +# zero big-num on rhs +print(1 + ((1 << 65) - (1 << 65))) + +# negative big-num on rhs +print(1 + (-(1 << 65))) diff --git a/tests/basics/slice_attrs.py b/tests/basics/slice_attrs.py index 76368a78c6..67456ff8e6 100644 --- a/tests/basics/slice_attrs.py +++ b/tests/basics/slice_attrs.py @@ -14,3 +14,12 @@ except: A()[1:2:3] + +# test storing to attr (shouldn't be allowed) +class B: + def __getitem__(self, idx): + try: + idx.start = 0 + except AttributeError: + print('AttributeError') +B()[:] diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index e0b07c3ad6..677438b832 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -9,6 +9,12 @@ try: except SyntaxError: print('SyntaxError') +# store to exception attribute is not allowed +try: + ValueError().x = 0 +except AttributeError: + print('AttributeError') + # array deletion not implemented try: a = array.array('b', (1, 2, 3)) @@ -23,6 +29,12 @@ try: except NotImplementedError: print('NotImplementedError') +# containment, looking for integer not implemented +try: + print(1 in array.array('B', b'12')) +except NotImplementedError: + print('NotImplementedError') + # should raise type error try: print(set('12') >= '1') @@ -65,6 +77,12 @@ try: except NotImplementedError: print('NotImplementedError') +# str subscr with step!=1 not implemented +try: + print('abc'[1:2:3]) +except NotImplementedError: + print('NotImplementedError') + # bytes(...) with keywords not implemented try: bytes('abc', encoding='utf8') diff --git a/tests/misc/non_compliant.py.exp b/tests/misc/non_compliant.py.exp index 3095441ad0..737650e9e9 100644 --- a/tests/misc/non_compliant.py.exp +++ b/tests/misc/non_compliant.py.exp @@ -1,6 +1,8 @@ SyntaxError +AttributeError TypeError NotImplementedError +NotImplementedError True True TypeError, ValueError @@ -13,5 +15,6 @@ NotImplementedError NotImplementedError NotImplementedError NotImplementedError +NotImplementedError b'\x01\x02' b'\x01\x00' diff --git a/tests/unicode/unicode.py b/tests/unicode/unicode.py index b31f064e9c..5f29bc1c95 100644 --- a/tests/unicode/unicode.py +++ b/tests/unicode/unicode.py @@ -18,8 +18,9 @@ enc = s.encode() print(enc, enc.decode() == s) # printing of unicode chars using repr -# TODO we don't do this correctly -#print(repr(s)) +# NOTE: for some characters (eg \u10ff) we differ to CPython +print(repr('a\uffff')) +print(repr('a\U0001ffff')) # test invalid escape code try: From a3edeb9ea5ebd05170af7c1e488724debce41a6f Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 11:58:57 +1100 Subject: [PATCH 49/78] py/objdict: Fix optimisation for allocating result in fromkeys. Iterables don't respond to __len__, so call __len__ on the original argument. --- py/objdict.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/py/objdict.c b/py/objdict.c index 7a74557dc1..197a1916fe 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -250,15 +250,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy); // this is a classmethod STATIC mp_obj_t dict_fromkeys(size_t n_args, const mp_obj_t *args) { mp_obj_t iter = mp_getiter(args[1]); - mp_obj_t len = mp_obj_len_maybe(iter); mp_obj_t value = mp_const_none; mp_obj_t next = MP_OBJ_NULL; - mp_obj_t self_out; if (n_args > 2) { value = args[2]; } + // optimisation to allocate result based on len of argument + mp_obj_t self_out; + mp_obj_t len = mp_obj_len_maybe(args[1]); if (len == MP_OBJ_NULL) { /* object's type doesn't have a __len__ slot */ self_out = mp_obj_new_dict(0); From 2750a7b38e0e5f5d2fbcfc28e89de96cd8da978c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 12:00:19 +1100 Subject: [PATCH 50/78] py/objdict: Actually provide the key that failed in KeyError exception. The failed key is available as exc.args[0], as per CPython. --- py/objdict.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/py/objdict.c b/py/objdict.c index 197a1916fe..624fc12d4d 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -162,7 +162,7 @@ mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "")); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } @@ -178,7 +178,7 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_map_elem_t *elem = mp_map_lookup(&self->map, index, MP_MAP_LOOKUP); if (elem == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "")); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, index)); } else { return elem->value; } @@ -283,7 +283,7 @@ STATIC mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp if (elem == NULL || elem->value == MP_OBJ_NULL) { if (deflt == MP_OBJ_NULL) { if (lookup_kind == MP_MAP_LOOKUP_REMOVE_IF_FOUND) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "")); + nlr_raise(mp_obj_new_exception_arg1(&mp_type_KeyError, key)); } else { value = mp_const_none; } From 6caca3259f4ec8f298b1d35f15e4492efbcff6b1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 12:01:18 +1100 Subject: [PATCH 51/78] tests: Add test to print full KeyError exc from failed dict lookup. --- tests/basics/dict1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/basics/dict1.py b/tests/basics/dict1.py index 21d5af2726..20fa9def31 100644 --- a/tests/basics/dict1.py +++ b/tests/basics/dict1.py @@ -26,8 +26,8 @@ print({1:1} == {2:1}) # value not found try: {}[0] -except KeyError: - print('KeyError') +except KeyError as er: + print('KeyError', er, repr(er), er.args) # unsupported unary op try: From 7d0d7215d2575a2d36d34c9a13b58cade0610a28 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 12:17:37 +1100 Subject: [PATCH 52/78] py: Use mp_raise_msg helper function where appropriate. Saves the following number of bytes of code space: 176 for bare-arm, 352 for minimal, 272 for unix x86-64, 140 for stmhal, 120 for esp8266. --- py/argcheck.c | 11 ++++------ py/bc.c | 5 ++--- py/builtinevex.c | 2 +- py/builtinimport.c | 8 +++---- py/modbuiltins.c | 9 ++++---- py/modthread.c | 2 +- py/obj.c | 31 ++++++++++----------------- py/objarray.c | 4 ++-- py/objcomplex.c | 4 ++-- py/objdict.c | 6 ++---- py/objfloat.c | 2 +- py/objgenerator.c | 6 +++--- py/objint.c | 10 ++++----- py/objint_mpz.c | 7 +++--- py/objlist.c | 2 +- py/objnamedtuple.c | 2 +- py/objobject.c | 3 +-- py/objset.c | 4 ++-- py/objstringio.c | 2 +- py/objtype.c | 21 ++++++++---------- py/parsenum.c | 4 ++-- py/runtime.c | 53 +++++++++++++++++----------------------------- py/sequence.c | 2 +- py/stream.c | 2 +- 24 files changed, 83 insertions(+), 119 deletions(-) diff --git a/py/argcheck.c b/py/argcheck.c index a6c769ee82..8cef10b165 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -37,8 +37,7 @@ void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_ar if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { mp_arg_error_terse_mismatch(); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "function does not take keyword arguments")); + mp_raise_msg(&mp_type_TypeError, "function does not take keyword arguments"); } } @@ -116,8 +115,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "extra positional arguments given")); + mp_raise_msg(&mp_type_TypeError, "extra positional arguments given"); } } if (kws_found < kws->used) { @@ -125,8 +123,7 @@ void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n mp_arg_error_terse_mismatch(); } else { // TODO better error message - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "extra keyword arguments given")); + mp_raise_msg(&mp_type_TypeError, "extra keyword arguments given"); } } } @@ -139,7 +136,7 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || _MSC_VER NORETURN void mp_arg_error_terse_mismatch(void) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "argument num/types mismatch")); + mp_raise_msg(&mp_type_TypeError, "argument num/types mismatch"); } #endif diff --git a/py/bc.c b/py/bc.c index e5abea2440..07de08fc36 100644 --- a/py/bc.c +++ b/py/bc.c @@ -185,7 +185,7 @@ void mp_setup_code_state(mp_code_state_t *code_state, mp_obj_fun_bc_t *self, siz } // Didn't find name match with positional args if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "function does not take keyword arguments")); + mp_raise_msg(&mp_type_TypeError, "function does not take keyword arguments"); } mp_obj_dict_store(dict, kwargs[2 * i], kwargs[2 * i + 1]); continue2:; @@ -234,8 +234,7 @@ continue2:; } else { // no keyword arguments given if (n_kwonly_args != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "function missing keyword-only argument")); + mp_raise_msg(&mp_type_TypeError, "function missing keyword-only argument"); } if ((scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) != 0) { *var_pos_kw_args = mp_obj_new_dict(0); diff --git a/py/builtinevex.c b/py/builtinevex.c index 74c43b1768..636f869300 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -95,7 +95,7 @@ STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { case MP_QSTR_exec: parse_input_kind = MP_PARSE_FILE_INPUT; break; case MP_QSTR_eval: parse_input_kind = MP_PARSE_EVAL_INPUT; break; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad compile mode")); + mp_raise_msg(&mp_type_ValueError, "bad compile mode"); } mp_obj_code_t *code = m_new_obj(mp_obj_code_t); diff --git a/py/builtinimport.c b/py/builtinimport.c index e4199f25d7..e72eaf4724 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -138,7 +138,7 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char if (lex == NULL) { // we verified the file exists using stat, but lexer could still fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found")); + mp_raise_msg(&mp_type_ImportError, "module not found"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%s'", fname)); @@ -340,7 +340,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("Warning: no dots in current module name and level>0\n"); p = this_name + this_name_l; } else if (level != -1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "Invalid relative import")); + mp_raise_msg(&mp_type_ImportError, "invalid relative import"); } uint new_mod_l = (mod_len == 0 ? (size_t)(p - this_name) : (size_t)(p - this_name) + 1 + mod_len); @@ -355,7 +355,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("Resolved base name for relative import: '%s'\n", qstr_str(new_mod_q)); if (new_mod_q == MP_QSTR_) { // CPython raises SystemError - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "cannot perform relative import")); + mp_raise_msg(&mp_type_ImportError, "cannot perform relative import"); } module_name = MP_OBJ_NEW_QSTR(new_mod_q); mod_str = new_mod; @@ -425,7 +425,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { #endif // couldn't find the file, so fail if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ImportError, "module not found")); + mp_raise_msg(&mp_type_ImportError, "module not found"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, "no module named '%q'", mod_name)); diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 29f84d6c25..57e52efa52 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -178,7 +178,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { str[3] = (c & 0x3F) | 0x80; len = 4; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)")); + mp_raise_msg(&mp_type_ValueError, "chr() arg not in range(0x110000)"); } return mp_obj_new_str(str, len, true); #else @@ -187,7 +187,7 @@ STATIC mp_obj_t mp_builtin_chr(mp_obj_t o_in) { char str[1] = {ord}; return mp_obj_new_str(str, 1, true); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "chr() arg not in range(256)")); + mp_raise_msg(&mp_type_ValueError, "chr() arg not in range(256)"); } #endif } @@ -286,7 +286,7 @@ STATIC mp_obj_t mp_builtin_min_max(size_t n_args, const mp_obj_t *args, mp_map_t if (default_elem != NULL) { best_obj = default_elem->value; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "arg is an empty sequence")); + mp_raise_msg(&mp_type_ValueError, "arg is an empty sequence"); } } return best_obj; @@ -507,8 +507,7 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj, 1, 2, mp_builtin_sum); STATIC mp_obj_t mp_builtin_sorted(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { if (n_args > 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "must use keyword argument for key function")); + mp_raise_msg(&mp_type_TypeError, "must use keyword argument for key function"); } mp_obj_t self = mp_type_list.make_new(&mp_type_list, 1, 0, args); mp_obj_list_sort(1, &self, kwargs); diff --git a/py/modthread.c b/py/modthread.c index c358cdf9ed..6f55281adc 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -239,7 +239,7 @@ STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) } else { // positional and keyword arguments if (mp_obj_get_type(args[2]) != &mp_type_dict) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "expecting a dict for keyword args")); + mp_raise_msg(&mp_type_TypeError, "expecting a dict for keyword args"); } mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map; th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used); diff --git a/py/obj.c b/py/obj.c index d6ce3dae6a..72b7a216bc 100644 --- a/py/obj.c +++ b/py/obj.c @@ -233,8 +233,7 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return mp_obj_int_get_checked(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "can't convert to int")); + mp_raise_msg(&mp_type_TypeError, "can't convert to int"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to int", mp_obj_get_type_str(arg))); @@ -282,8 +281,7 @@ mp_float_t mp_obj_get_float(mp_obj_t arg) { return mp_obj_float_get(arg); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "can't convert to float")); + mp_raise_msg(&mp_type_TypeError, "can't convert to float"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to float", mp_obj_get_type_str(arg))); @@ -312,8 +310,7 @@ void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) { mp_obj_complex_get(arg, real, imag); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "can't convert to complex")); + mp_raise_msg(&mp_type_TypeError, "can't convert to complex"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "can't convert %s to complex", mp_obj_get_type_str(arg))); @@ -331,8 +328,7 @@ void mp_obj_get_array(mp_obj_t o, mp_uint_t *len, mp_obj_t **items) { mp_obj_list_get(o, len, items); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "expected tuple/list")); + mp_raise_msg(&mp_type_TypeError, "expected tuple/list"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object '%s' is not a tuple or list", mp_obj_get_type_str(o))); @@ -346,8 +342,7 @@ void mp_obj_get_array_fixed_n(mp_obj_t o, mp_uint_t len, mp_obj_t **items) { mp_obj_get_array(o, &seq_len, items); if (seq_len != len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "tuple/list has wrong length")); + mp_raise_msg(&mp_type_ValueError, "tuple/list has wrong length"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "requested length %d but object has length %d", (int)len, (int)seq_len)); @@ -362,8 +357,7 @@ mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, i = MP_OBJ_SMALL_INT_VALUE(index); } else if (!mp_obj_get_int_maybe(index, &i)) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "indices must be integers")); + mp_raise_msg(&mp_type_TypeError, "indices must be integers"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "%q indices must be integers, not %s", @@ -383,7 +377,7 @@ mp_uint_t mp_get_index(const mp_obj_type_t *type, mp_uint_t len, mp_obj_t index, } else { if (i < 0 || (mp_uint_t)i >= len) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "index out of range")); + mp_raise_msg(&mp_type_IndexError, "index out of range"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_IndexError, "%q index out of range", type->name)); @@ -416,8 +410,7 @@ mp_obj_t mp_obj_len(mp_obj_t o_in) { mp_obj_t len = mp_obj_len_maybe(o_in); if (len == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object has no len")); + mp_raise_msg(&mp_type_TypeError, "object has no len"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object of type '%s' has no len()", mp_obj_get_type_str(o_in))); @@ -458,8 +451,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { } if (value == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object does not support item deletion")); + mp_raise_msg(&mp_type_TypeError, "object does not support item deletion"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base))); @@ -474,8 +466,7 @@ mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) { } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object does not support item assignment")); + mp_raise_msg(&mp_type_TypeError, "object does not support item assignment"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base))); @@ -504,7 +495,7 @@ bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) { if (!mp_get_buffer(obj, bufinfo, flags)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "object with buffer protocol required")); + mp_raise_msg(&mp_type_TypeError, "object with buffer protocol required"); } } diff --git a/py/objarray.c b/py/objarray.c index 2cd0fef6b6..8e1d32f0f4 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -95,7 +95,7 @@ STATIC void array_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t STATIC mp_obj_array_t *array_new(char typecode, mp_uint_t n) { int typecode_size = mp_binary_get_size('@', typecode, NULL); if (typecode_size == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "bad typecode")); + mp_raise_msg(&mp_type_ValueError, "bad typecode"); } mp_obj_array_t *o = m_new_obj(mp_obj_array_t); #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY @@ -395,7 +395,7 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_obj_array_t *src_slice = MP_OBJ_TO_PTR(value); if (item_sz != mp_binary_get_size('@', src_slice->typecode & TYPECODE_MASK, NULL)) { compat_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "lhs and rhs should be compatible")); + mp_raise_msg(&mp_type_ValueError, "lhs and rhs should be compatible"); } src_len = src_slice->len; src_items = src_slice->items; diff --git a/py/objcomplex.c b/py/objcomplex.c index 5da655eb3c..96be25255c 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -197,7 +197,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: if (rhs_imag == 0) { if (rhs_real == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "complex division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "complex division by zero"); } lhs_real /= rhs_real; lhs_imag /= rhs_real; @@ -226,7 +226,7 @@ mp_obj_t mp_obj_complex_binary_op(mp_uint_t op, mp_float_t lhs_real, mp_float_t lhs_real = 1; rhs_real = 0; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power")); + mp_raise_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power"); } } else { mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1); diff --git a/py/objdict.c b/py/objdict.c index 624fc12d4d..4942d37791 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -343,7 +343,7 @@ STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { mp_uint_t cur = 0; mp_map_elem_t *next = dict_iter_next(self, &cur); if (next == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "popitem(): dictionary is empty")); + mp_raise_msg(&mp_type_KeyError, "popitem(): dictionary is empty"); } self->map.used--; mp_obj_t items[] = {next->key, next->value}; @@ -385,9 +385,7 @@ STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwarg if (key == MP_OBJ_STOP_ITERATION || value == MP_OBJ_STOP_ITERATION || stop != MP_OBJ_STOP_ITERATION) { - nlr_raise(mp_obj_new_exception_msg( - &mp_type_ValueError, - "dictionary update sequence has the wrong length")); + mp_raise_msg(&mp_type_ValueError, "dictionary update sequence has the wrong length"); } else { mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; } diff --git a/py/objfloat.c b/py/objfloat.c index 85b8b13861..73d07feac8 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -198,7 +198,7 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { zero_division_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } // Python specs require that x == (x//y)*y + (x%y) so we must // call divmod to compute the correct floor division, which diff --git a/py/objgenerator.c b/py/objgenerator.c index 8c32a36496..cbef9fea3d 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -105,7 +105,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_ } if (self->code_state.sp == self->code_state.state - 1) { if (send_value != mp_const_none) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator")); + mp_raise_msg(&mp_type_TypeError, "can't send non-None value to a just-started generator"); } } else { *self->code_state.sp = send_value; @@ -157,7 +157,7 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o case MP_VM_RETURN_YIELD: if (throw_value != MP_OBJ_NULL && mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(throw_value)), MP_OBJ_FROM_PTR(&mp_type_GeneratorExit))) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); + mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"); } return ret; @@ -209,7 +209,7 @@ STATIC mp_obj_t gen_instance_close(mp_obj_t self_in) { mp_obj_t ret; switch (mp_obj_gen_resume(self_in, mp_const_none, MP_OBJ_FROM_PTR(&mp_const_GeneratorExit_obj), &ret)) { case MP_VM_RETURN_YIELD: - nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit")); + mp_raise_msg(&mp_type_RuntimeError, "generator ignored GeneratorExit"); // Swallow StopIteration & GeneratorExit (== successful close), and re-raise any other case MP_VM_RETURN_EXCEPTION: diff --git a/py/objint.c b/py/objint.c index 49dec0653c..f8988d6c94 100644 --- a/py/objint.c +++ b/py/objint.c @@ -294,19 +294,19 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // This is called only with strings whose value doesn't fit in SMALL_INT mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "long int not supported in this build")); + mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build"); return mp_const_none; } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ll(long long val) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } // This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } @@ -316,7 +316,7 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { return MP_OBJ_NEW_SMALL_INT(value); } - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } @@ -342,7 +342,7 @@ mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); } - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "small int overflow")); + mp_raise_msg(&mp_type_OverflowError, "small int overflow"); return mp_const_none; } diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 6a59133d74..0a1d68598d 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -234,8 +234,7 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: { if (mpz_is_zero(zrhs)) { zero_division_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, - "division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mpz_t rem; mpz_init_zero(&rem); mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs); @@ -272,7 +271,7 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case MP_BINARY_OP_INPLACE_RSHIFT: { mp_int_t irhs = mp_obj_int_get_checked(rhs_in); if (irhs < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + mp_raise_msg(&mp_type_ValueError, "negative shift count"); } if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) { mpz_shl_inpl(&res->mpz, zlhs, irhs); @@ -398,7 +397,7 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { return value; } else { // overflow - nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "overflow converting long int to machine word")); + mp_raise_msg(&mp_type_OverflowError, "overflow converting long int to machine word"); } } } diff --git a/py/objlist.c b/py/objlist.c index b5e8b99651..6d4a20a507 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -266,7 +266,7 @@ STATIC mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { mp_check_self(MP_OBJ_IS_TYPE(args[0], &mp_type_list)); mp_obj_list_t *self = MP_OBJ_TO_PTR(args[0]); if (self->len == 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_IndexError, "pop from empty list")); + mp_raise_msg(&mp_type_IndexError, "pop from empty list"); } mp_uint_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); mp_obj_t ret = self->items[index]; diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 38cda1ad75..18931a16c2 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -73,7 +73,7 @@ STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } else { // delete/store attribute // provide more detailed error message than we'd get by just returning - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute")); + mp_raise_msg(&mp_type_AttributeError, "can't set attribute"); } } diff --git a/py/objobject.c b/py/objobject.c index bba6f053e6..b33dc491c4 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -50,8 +50,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(object___init___obj, object___init__); STATIC mp_obj_t object___new__(mp_obj_t cls) { if (!MP_OBJ_IS_TYPE(cls, &mp_type_type) || !mp_obj_is_instance_type((mp_obj_type_t*)MP_OBJ_TO_PTR(cls))) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "__new__ arg must be a user-type")); + mp_raise_msg(&mp_type_TypeError, "__new__ arg must be a user-type"); } mp_obj_t o = MP_OBJ_SENTINEL; mp_obj_t res = mp_obj_instance_make_new(MP_OBJ_TO_PTR(cls), 1, 0, &o); diff --git a/py/objset.c b/py/objset.c index 6b6f95f9b2..fc124fcd8c 100644 --- a/py/objset.c +++ b/py/objset.c @@ -68,7 +68,7 @@ STATIC void check_set(mp_obj_t o) { if (MP_OBJ_IS_TYPE(o, &mp_type_frozenset)) { // Mutable method called on frozenset; emulate CPython behavior, eg: // AttributeError: 'frozenset' object has no attribute 'add' - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "'frozenset' has no such attribute")); + mp_raise_msg(&mp_type_AttributeError, "'frozenset' has no such attribute"); } #endif mp_check_self(MP_OBJ_IS_TYPE(o, &mp_type_set)); @@ -389,7 +389,7 @@ STATIC mp_obj_t set_pop(mp_obj_t self_in) { mp_obj_set_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t obj = mp_set_remove_first(&self->set); if (obj == MP_OBJ_NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_KeyError, "pop from an empty set")); + mp_raise_msg(&mp_type_KeyError, "pop from an empty set"); } return obj; } diff --git a/py/objstringio.c b/py/objstringio.c index 212d8e314f..a430fca3b7 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -39,7 +39,7 @@ #if MICROPY_CPYTHON_COMPAT STATIC void check_stringio_is_open(const mp_obj_stringio_t *o) { if (o->vstr == NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + mp_raise_msg(&mp_type_ValueError, "I/O operation on closed file"); } } #else diff --git a/py/objtype.c b/py/objtype.c index 907308a757..8b46c54001 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -311,8 +311,7 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size } if (init_ret != mp_const_none) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "__init__() should return None")); + mp_raise_msg(&mp_type_TypeError, "__init__() should return None"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret))); @@ -508,7 +507,7 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des // the code. const mp_obj_t *proxy = mp_obj_property_get(member); if (proxy[0] == mp_const_none) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "unreadable attribute")); + mp_raise_msg(&mp_type_AttributeError, "unreadable attribute"); } else { dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); } @@ -710,8 +709,7 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons mp_obj_t call = mp_obj_instance_get_call(self_in); if (call == MP_OBJ_NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not callable")); + mp_raise_msg(&mp_type_TypeError, "object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(self_in))); @@ -793,7 +791,7 @@ STATIC mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_ return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]); default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "type takes 1 or 3 arguments")); + mp_raise_msg(&mp_type_TypeError, "type takes 1 or 3 arguments"); } } @@ -804,7 +802,7 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp if (self->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "cannot create instance")); + mp_raise_msg(&mp_type_TypeError, "cannot create instance"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%q' instances", self->name)); @@ -892,8 +890,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) // TODO: Verify with CPy, tested on function type if (t->make_new == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "type is not an acceptable base type")); + mp_raise_msg(&mp_type_TypeError, "type is not an acceptable base type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "type '%q' is not an acceptable base type", t->name)); @@ -927,7 +924,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) const mp_obj_type_t *native_base; uint num_native_bases = instance_count_native_bases(o, &native_base); if (num_native_bases > 1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict")); + mp_raise_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict"); } mp_map_t *locals_map = &o->locals_dict->map; @@ -1074,7 +1071,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) { mp_obj_tuple_get(classinfo, &len, &items); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes")); + mp_raise_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes"); } for (uint i = 0; i < len; i++) { @@ -1088,7 +1085,7 @@ STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) { STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) { if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class")); + mp_raise_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class"); } return mp_obj_is_subclass(object, classinfo); } diff --git a/py/parsenum.c b/py/parsenum.c index 83a6abd202..1010ad3055 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -27,7 +27,7 @@ #include #include -#include "py/nlr.h" +#include "py/runtime.h" #include "py/parsenumbase.h" #include "py/parsenum.h" #include "py/smallint.h" @@ -55,7 +55,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m // check radix base if ((base != 0 && base < 2) || base > 36) { // this won't be reached if lex!=NULL - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "int() arg 2 must be >= 2 and <= 36")); + mp_raise_msg(&mp_type_ValueError, "int() arg 2 must be >= 2 and <= 36"); } // skip leading space diff --git a/py/runtime.c b/py/runtime.c index 003c9f8b44..6eda77ee9c 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -138,8 +138,7 @@ mp_obj_t mp_load_global(qstr qst) { elem = mp_map_lookup((mp_map_t*)&mp_module_builtins_globals.map, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP); if (elem == NULL) { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_NameError, - "name not defined")); + mp_raise_msg(&mp_type_NameError, "name not defined"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%q' is not defined", qst)); @@ -230,8 +229,7 @@ mp_obj_t mp_unary_op(mp_uint_t op, mp_obj_t arg) { } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "unsupported type for operator")); + mp_raise_msg(&mp_type_TypeError, "unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported type for %q: '%s'", @@ -323,7 +321,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_LSHIFT: { if (rhs_val < 0) { // negative shift not allowed - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + mp_raise_msg(&mp_type_ValueError, "negative shift count"); } else if (rhs_val >= (mp_int_t)BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { // left-shift will overflow, so use higher precision integer lhs = mp_obj_new_int_from_ll(lhs_val); @@ -338,7 +336,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { case MP_BINARY_OP_INPLACE_RSHIFT: if (rhs_val < 0) { // negative shift not allowed - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count")); + mp_raise_msg(&mp_type_ValueError, "negative shift count"); } else { // standard precision is enough for right-shift if (rhs_val >= (mp_int_t)BITS_PER_WORD) { @@ -414,7 +412,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { lhs = mp_obj_new_float(lhs_val); goto generic_binary_op; #else - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support")); + mp_raise_msg(&mp_type_ValueError, "negative power with no float support"); #endif } else { mp_int_t ans = 1; @@ -515,8 +513,7 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) { } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not iterable")); + mp_raise_msg(&mp_type_TypeError, "object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(rhs))); @@ -538,8 +535,7 @@ generic_binary_op: unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "unsupported type for operator")); + mp_raise_msg(&mp_type_TypeError, "unsupported type for operator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "unsupported types for %q: '%s', '%s'", @@ -547,7 +543,7 @@ unsupported_op: } zero_division: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero")); + mp_raise_msg(&mp_type_ZeroDivisionError, "division by zero"); } mp_obj_t mp_call_function_0(mp_obj_t fun) { @@ -581,8 +577,7 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, mp_uint_t n_args, mp_uint_t n_kw } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not callable")); + mp_raise_msg(&mp_type_TypeError, "object not callable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in))); @@ -813,16 +808,14 @@ void mp_unpack_sequence(mp_obj_t seq_in, mp_uint_t num, mp_obj_t *items) { too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "wrong number of values to unpack")); + mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); } too_long: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "wrong number of values to unpack")); + mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", (int)num)); @@ -888,8 +881,7 @@ void mp_unpack_ex(mp_obj_t seq_in, mp_uint_t num_in, mp_obj_t *items) { too_short: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, - "wrong number of values to unpack")); + mp_raise_msg(&mp_type_ValueError, "wrong number of values to unpack"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", (int)seq_len)); @@ -928,8 +920,7 @@ STATIC mp_obj_t checked_fun_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c const mp_obj_type_t *arg0_type = mp_obj_get_type(args[0]); if (arg0_type != self->type) { if (MICROPY_ERROR_REPORTING != MICROPY_ERROR_REPORTING_DETAILED) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "argument has wrong type")); + mp_raise_msg(&mp_type_TypeError, "argument has wrong type"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "argument should be a '%q' not a '%q'", self->type->name, arg0_type->name)); @@ -1045,8 +1036,7 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { if (dest[0] == MP_OBJ_NULL) { // no attribute/method called attr if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, - "no such attribute")); + mp_raise_msg(&mp_type_AttributeError, "no such attribute"); } else { // following CPython, we give a more detailed error message for type objects if (MP_OBJ_IS_TYPE(base, &mp_type_type)) { @@ -1074,8 +1064,7 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { } } if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, - "no such attribute")); + mp_raise_msg(&mp_type_AttributeError, "no such attribute"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%q'", @@ -1105,8 +1094,7 @@ mp_obj_t mp_getiter(mp_obj_t o_in) { // object not iterable if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not iterable")); + mp_raise_msg(&mp_type_TypeError, "object not iterable"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in))); @@ -1128,8 +1116,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { return mp_call_method_n_kw(0, 0, dest); } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not an iterator")); + mp_raise_msg(&mp_type_TypeError, "object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); @@ -1165,8 +1152,7 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { } } else { if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, - "object not an iterator")); + mp_raise_msg(&mp_type_TypeError, "object not an iterator"); } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in))); @@ -1384,8 +1370,7 @@ void *m_malloc_fail(size_t num_bytes) { // dummy #if MICROPY_ENABLE_GC } else if (gc_is_locked()) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_MemoryError, - "memory allocation failed, heap is locked")); + mp_raise_msg(&mp_type_MemoryError, "memory allocation failed, heap is locked"); #endif } else { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, diff --git a/py/sequence.c b/py/sequence.c index 239f1b2cc5..0acdd25be0 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -235,7 +235,7 @@ mp_obj_t mp_seq_index_obj(const mp_obj_t *items, mp_uint_t len, mp_uint_t n_args } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "object not in sequence")); + mp_raise_msg(&mp_type_ValueError, "object not in sequence"); } mp_obj_t mp_seq_count_obj(const mp_obj_t *items, mp_uint_t len, mp_obj_t value) { diff --git a/py/stream.c b/py/stream.c index 5610faf748..cc8a63ac2e 100644 --- a/py/stream.c +++ b/py/stream.c @@ -101,7 +101,7 @@ const mp_stream_p_t *mp_get_stream_raise(mp_obj_t self_in, int flags) { || ((flags & MP_STREAM_OP_WRITE) && stream_p->write == NULL) || ((flags & MP_STREAM_OP_IOCTL) && stream_p->ioctl == NULL)) { // CPython: io.UnsupportedOperation, OSError subclass - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "stream operation not supported")); + mp_raise_msg(&mp_type_OSError, "stream operation not supported"); } return stream_p; } From ad3724e0bc87305f9280f65226066a199042d736 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 13:14:59 +1100 Subject: [PATCH 53/78] lib/utils/pyexec: Allow behaviour of SystemExit to be configurable. Setting the pyexec_system_exit variable to PYEXEC_FORCED_EXT allows SystemExit exceptions to terminate the pyexec functions. --- lib/utils/pyexec.c | 6 +++++- lib/utils/pyexec.h | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 5824e14035..d7c2570240 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -45,6 +45,7 @@ #include "genhdr/mpversion.h" pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; +int pyexec_system_exit = 0; STATIC bool repl_display_debugging_info = 0; #define EXEC_FLAG_PRINT_EOF (1) @@ -61,6 +62,9 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, int ret = 0; uint32_t start = 0; + // by default a SystemExit exception returns 0 + pyexec_system_exit = 0; + nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t module_fun; @@ -99,7 +103,7 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, // check for SystemExit if (mp_obj_is_subclass_fast(mp_obj_get_type((mp_obj_t)nlr.ret_val), &mp_type_SystemExit)) { // at the moment, the value of SystemExit is unused - ret = 0; + ret = pyexec_system_exit; } else { mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); ret = 0; diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index e0f62440e0..ae69a195e7 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -33,6 +33,11 @@ typedef enum { extern pyexec_mode_kind_t pyexec_mode_kind; +// Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through +// the pyexec functions if a SystemExit exception is raised by the running code. +// It will reset to 0 at the start of each execution (eg each REPL entry). +extern int pyexec_system_exit; + #define PYEXEC_FORCED_EXIT (0x100) #define PYEXEC_SWITCH_MODE (0x200) From 57226a2b7f91bd53f0bf392de713be937ede3f5f Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 13:16:47 +1100 Subject: [PATCH 54/78] stmhal: Implement machine.soft_reset(). --- stmhal/modmachine.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stmhal/modmachine.c b/stmhal/modmachine.c index 8bd04f3ec9..7a337adb69 100644 --- a/stmhal/modmachine.c +++ b/stmhal/modmachine.c @@ -33,6 +33,7 @@ #include "extmod/machine_mem.h" #include "extmod/machine_pulse.h" #include "extmod/machine_i2c.h" +#include "lib/utils/pyexec.h" #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" #include "gccollect.h" @@ -172,6 +173,12 @@ STATIC mp_obj_t machine_reset(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); +STATIC mp_obj_t machine_soft_reset(void) { + pyexec_system_exit = PYEXEC_FORCED_EXIT; + nlr_raise(mp_obj_new_exception(&mp_type_SystemExit)); +} +MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); + // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(void) { pyb_usb_dev_deinit(); @@ -502,6 +509,7 @@ STATIC const mp_map_elem_t machine_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&machine_info_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_unique_id), (mp_obj_t)&machine_unique_id_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&machine_reset_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_soft_reset), (mp_obj_t)&machine_soft_reset_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_bootloader), (mp_obj_t)&machine_bootloader_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_freq), (mp_obj_t)&machine_freq_obj }, #if MICROPY_HW_ENABLE_RNG From 48feb8ac6e80ef4d0489bedee4c9f68f96015967 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 13:17:19 +1100 Subject: [PATCH 55/78] stmhal: Enable str.center(), str.[r]partition() and builtin compile(). Also adds "machine" to the list of modules that the parser can search for constants. --- stmhal/mpconfigport.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 8979ad8dca..264db3029d 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -67,10 +67,13 @@ #define MICROPY_USE_INTERNAL_ERRNO (1) #define MICROPY_PY_FUNCTION_ATTRS (1) #define MICROPY_PY_BUILTINS_STR_UNICODE (1) +#define MICROPY_PY_BUILTINS_STR_CENTER (1) +#define MICROPY_PY_BUILTINS_STR_PARTITION (1) #define MICROPY_PY_BUILTINS_STR_SPLITLINES (1) #define MICROPY_PY_BUILTINS_MEMORYVIEW (1) #define MICROPY_PY_BUILTINS_FROZENSET (1) #define MICROPY_PY_BUILTINS_EXECFILE (1) +#define MICROPY_PY_BUILTINS_COMPILE (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) @@ -177,6 +180,7 @@ extern const struct _mp_obj_module_t mp_module_network; // extra constants #define MICROPY_PORT_CONSTANTS \ { MP_OBJ_NEW_QSTR(MP_QSTR_umachine), (mp_obj_t)&machine_module }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&machine_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \ From 1e3a7c4ac57c7102bf7fe24a5432b29ec0718c0c Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 13:18:27 +1100 Subject: [PATCH 56/78] tests/run-tests: Enable extmod/machine1.py on pyboard. It now works. --- tests/run-tests | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run-tests b/tests/run-tests index 422d7463af..4ac7d8e28f 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -237,7 +237,6 @@ def run_tests(pyb, tests, args): skip_tests.add('float/float_divmod.py') # tested by float/float_divmod_relaxed.py instead skip_tests.add('float/float2int_doubleprec.py') # requires double precision floating point to work skip_tests.add('micropython/meminfo.py') # output is very different to PC output - skip_tests.add('extmod/machine1.py') # raw memory access not supported skip_tests.add('extmod/machine_mem.py') # raw memory access not supported if args.target == 'wipy': From c8d31585a00616b39839d112b7c696dafed6b08d Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 17 Oct 2016 15:32:43 +1100 Subject: [PATCH 57/78] docs: Bump version to 1.8.5. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index a737e43ef1..32d9e971d9 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -99,7 +99,7 @@ copyright = '2014-2016, Damien P. George and contributors' # The short X.Y version. version = '1.8' # The full version, including alpha/beta/rc tags. -release = '1.8.4' +release = '1.8.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From a0b2f48c2f501fb60ec312756fe4b17e81f94cc5 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 17 Oct 2016 18:05:16 +0300 Subject: [PATCH 58/78] docs/machine.SPI: Bring up to date with Hardware API, make vendor-neutral. --- docs/library/machine.SPI.rst | 47 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst index 73b3a3996d..7c6627614a 100644 --- a/docs/library/machine.SPI.rst +++ b/docs/library/machine.SPI.rst @@ -1,10 +1,13 @@ .. currentmodule:: machine -class SPI -- a master-driven serial protocol -============================================ +class SPI -- a Serial Peripheral Interface bus protocol +======================================================= -SPI is a serial protocol that is driven by a master. At the physical level -there are 3 lines: SCK, MOSI, MISO. +SPI is a serial protocol that is driven by a master. At the physical level, +bus consistens of 3 lines: SCK, MOSI, MISO. Multiple devices can share the +same bus. Each device should have a separate, 4th signal, SS (Slave Select), +to select a particualr device on a bus with which communication takes place. +Management of an SS signal should happen in user code (via machine.Pin class). .. only:: port_wipy @@ -21,31 +24,37 @@ there are 3 lines: SCK, MOSI, MISO. Constructors ------------ -.. only:: port_wipy +.. class:: SPI(id, ...) - .. class:: SPI(id, ...) + Construct an SPI object on the given bus, ``id``. Values of ``id`` depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. Value -1 can be used for + bitbanging (software) implementation of SPI (if supported by a port). - Construct an SPI object on the given bus. ``id`` can be only 0. - With no additional parameters, the SPI object is created but not - initialised (it has the settings from the last initialisation of - the bus, if any). If extra arguments are given, the bus is initialised. - See ``init`` for parameters of initialisation. + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. Methods ------- -.. method:: SPI.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO)) +.. method:: SPI.init(baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO), sck=None, mosi=None, miso=None) Initialise the SPI bus with the given parameters: - - ``mode`` must be ``SPI.MASTER``. - ``baudrate`` is the SCK clock rate. - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. - ``phase`` can be 0 or 1 to sample data on the first or second clock edge respectively. - - ``bits`` is the width of each transfer, accepted values are 8, 16 and 32. - - ``firstbit`` can be ``SPI.MSB`` only. - - ``pins`` is an optional tuple with the pins to assign to the SPI bus. + - ``bits`` is the width in bits of each transfer. Only 8 of is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``pins`` is an optional tuple with the pins to assign to the SPI bus (deprecated, only for WiPy). + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructore), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alterbative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id``=-1). .. method:: SPI.deinit() @@ -71,7 +80,7 @@ Methods Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the same length. - Returns the number of bytes written + Returns the number of bytes written. Constants --------- @@ -83,3 +92,7 @@ Constants .. data:: SPI.MSB set the first bit to be the most significant bit + +.. data:: SPI.LSB + + set the first bit to be the least significant bit From 4d45f286ebab62fd7c7b524bdfcdf58522b911c8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 18 Oct 2016 00:06:59 +0300 Subject: [PATCH 59/78] esp8266/Makefile: Use latest esptool.py flash size auto-detection. --- esp8266/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp8266/Makefile b/esp8266/Makefile index 65a513afd6..1586c576ca 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -18,7 +18,7 @@ FROZEN_MPY_DIR = modules PORT ?= /dev/ttyACM0 BAUD ?= 115200 FLASH_MODE ?= qio -FLASH_SIZE ?= 8m +FLASH_SIZE ?= detect CROSS_COMPILE = xtensa-lx106-elf- ESP_SDK = $(shell $(CC) -print-sysroot)/usr From 50ddaafa6acf5fbbe6f98e64fd5744a9a8347aff Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 09:53:43 +1100 Subject: [PATCH 60/78] cc3200: Use mp_raise_XXX helper functions to reduce code size. Reduces code size by 632 bytes. --- cc3200/hal/cc3200_hal.c | 4 ---- cc3200/hal/cc3200_hal.h | 1 - cc3200/misc/mpirq.c | 2 +- cc3200/mods/modmachine.c | 2 +- cc3200/mods/modnetwork.c | 2 +- cc3200/mods/moduhashlib.c | 4 ++-- cc3200/mods/moduos.c | 30 +++++++++++++++--------------- cc3200/mods/modusocket.c | 30 +++++++++++++++--------------- cc3200/mods/modussl.c | 4 ++-- cc3200/mods/modutime.c | 4 ++-- cc3200/mods/modwlan.c | 34 +++++++++++++++++----------------- cc3200/mods/pybadc.c | 14 +++++++------- cc3200/mods/pybi2c.c | 14 +++++++------- cc3200/mods/pybpin.c | 20 ++++++++++---------- cc3200/mods/pybrtc.c | 14 +++++++------- cc3200/mods/pybsd.c | 4 ++-- cc3200/mods/pybspi.c | 8 ++++---- cc3200/mods/pybtimer.c | 16 ++++++++-------- cc3200/mods/pybuart.c | 10 +++++----- cc3200/mods/pybwdt.c | 6 +++--- cc3200/mpthreadport.c | 3 ++- cc3200/serverstask.c | 6 +++--- 22 files changed, 114 insertions(+), 118 deletions(-) diff --git a/cc3200/hal/cc3200_hal.c b/cc3200/hal/cc3200_hal.c index f4d38d120e..37026db14e 100644 --- a/cc3200/hal/cc3200_hal.c +++ b/cc3200/hal/cc3200_hal.c @@ -130,10 +130,6 @@ void mp_hal_delay_ms(mp_uint_t delay) { } } -NORETURN void mp_hal_raise(int errno) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, mp_obj_new_int(errno))); -} - void mp_hal_set_interrupt_char (int c) { mpexception_set_interrupt_char (c); } diff --git a/cc3200/hal/cc3200_hal.h b/cc3200/hal/cc3200_hal.h index 054d5035a2..9715096b61 100644 --- a/cc3200/hal/cc3200_hal.h +++ b/cc3200/hal/cc3200_hal.h @@ -62,7 +62,6 @@ extern void HAL_SystemInit (void); extern void HAL_SystemDeInit (void); extern void HAL_IncrementTick(void); -extern NORETURN void mp_hal_raise(int errno); extern void mp_hal_set_interrupt_char (int c); #endif /* CC3200_LAUNCHXL_HAL_CC3200_HAL_H_ */ diff --git a/cc3200/misc/mpirq.c b/cc3200/misc/mpirq.c index 29cc4a7bdb..4389ab0c3c 100644 --- a/cc3200/misc/mpirq.c +++ b/cc3200/misc/mpirq.c @@ -112,7 +112,7 @@ void mp_irq_remove (const mp_obj_t parent) { uint mp_irq_translate_priority (uint priority) { if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return mp_irq_priorities[priority - 1]; } diff --git a/cc3200/mods/modmachine.c b/cc3200/mods/modmachine.c index f82decda2c..8a57c2eb45 100644 --- a/cc3200/mods/modmachine.c +++ b/cc3200/mods/modmachine.c @@ -130,7 +130,7 @@ STATIC mp_obj_t machine_main(mp_obj_t main) { if (MP_OBJ_IS_STR(main)) { MP_STATE_PORT(machine_config_main) = main; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return mp_const_none; } diff --git a/cc3200/mods/modnetwork.c b/cc3200/mods/modnetwork.c index 8e086b1d29..f98d9a88ad 100644 --- a/cc3200/mods/modnetwork.c +++ b/cc3200/mods/modnetwork.c @@ -101,7 +101,7 @@ STATIC mp_obj_t network_server_make_new(const mp_obj_type_t *type, mp_uint_t n_a // check the server id if (args[0].u_obj != MP_OBJ_NULL) { if (mp_obj_get_int(args[0].u_obj) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } } diff --git a/cc3200/mods/moduhashlib.c b/cc3200/mods/moduhashlib.c index 93f15540c9..46f30be21d 100644 --- a/cc3200/mods/moduhashlib.c +++ b/cc3200/mods/moduhashlib.c @@ -93,7 +93,7 @@ STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest) { self->digested = false; } } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -106,7 +106,7 @@ STATIC mp_obj_t hash_read (mp_obj_t self_in) { } } else if (self->c_size < self->b_size) { // it's a fixed len block which is still incomplete - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } if (!self->digested) { diff --git a/cc3200/mods/moduos.c b/cc3200/mods/moduos.c index 8e3e0135ec..d5b29336af 100644 --- a/cc3200/mods/moduos.c +++ b/cc3200/mods/moduos.c @@ -158,7 +158,7 @@ STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonl #endif // cannot mount twice or on existing paths if (f_stat(path, &fno) == FR_OK || osmount_find_by_device(device)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // create a new object @@ -196,7 +196,7 @@ STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonl if (f_mount(&self->fatfs, self->path, 1) != FR_OK) { // remove it and raise mp_obj_list_remove(&MP_STATE_PORT(mount_obj_list), self); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } // mount succeeded, increment the count @@ -252,7 +252,7 @@ STATIC mp_obj_t os_chdir(mp_obj_t path_in) { } if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } return mp_const_none; @@ -263,7 +263,7 @@ STATIC mp_obj_t os_getcwd(void) { char buf[MICROPY_ALLOC_PATH_MAX + 1]; FRESULT res = f_getcwd(buf, sizeof buf); if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } return mp_obj_new_str(buf, strlen(buf), false); } @@ -303,7 +303,7 @@ STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) { res = f_opendir(&dir, path); /* Open the directory */ if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } for ( ; ; ) { @@ -335,10 +335,10 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_o) { case FR_OK: return mp_const_none; case FR_EXIST: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); break; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir); @@ -351,7 +351,7 @@ STATIC mp_obj_t os_rename(mp_obj_t path_in, mp_obj_t path_out) { case FR_OK: return mp_const_none; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename); @@ -363,7 +363,7 @@ STATIC mp_obj_t os_remove(mp_obj_t path_o) { case FR_OK: return mp_const_none; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove); @@ -394,7 +394,7 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) { fno.ftime = 0; fno.fattrib = AM_DIR; } else if ((res = f_stat(path, &fno)) != FR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL); @@ -481,7 +481,7 @@ STATIC mp_obj_t os_mount(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *k return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_value_invalid_arguments)); + mp_raise_msg(&mp_type_OSError, mpexception_value_invalid_arguments); } MP_DEFINE_CONST_FUN_OBJ_KW(os_mount_obj, 2, os_mount); @@ -490,7 +490,7 @@ STATIC mp_obj_t os_unmount(mp_obj_t path_o) { // '/flash' cannot be unmounted, also not the current working directory if (path_equal(path, "/flash")) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // now unmount it @@ -498,7 +498,7 @@ STATIC mp_obj_t os_unmount(mp_obj_t path_o) { if ((mount_obj = osmount_find_by_path(path))) { unmount (mount_obj); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_msg(&mp_type_ValueError, mpexception_value_invalid_arguments); } return mp_const_none; @@ -515,7 +515,7 @@ STATIC mp_obj_t os_mkfs(mp_obj_t device) { path = mp_obj_str_get_str(device); // otherwise the relative path check will pass... if (path[0] != '/') { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_value_invalid_arguments)); + mp_raise_msg(&mp_type_OSError, mpexception_value_invalid_arguments); } } else { // mount it briefly @@ -541,7 +541,7 @@ STATIC mp_obj_t os_mkfs(mp_obj_t device) { } if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } return mp_const_none; } diff --git a/cc3200/mods/modusocket.c b/cc3200/mods/modusocket.c index c7b3fb2035..81a4c2e198 100644 --- a/cc3200/mods/modusocket.c +++ b/cc3200/mods/modusocket.c @@ -156,7 +156,7 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_ // create the socket int _errno; if (wlan_socket_socket(s, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } // add the socket to the list modusocket_socket_add(s->sock_base.sd, true); @@ -182,7 +182,7 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { // call the NIC to bind the socket int _errno; if (wlan_socket_bind(self, ip, port, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -200,7 +200,7 @@ STATIC mp_obj_t socket_listen(mp_uint_t n_args, const mp_obj_t *args) { int _errno; if (wlan_socket_listen(self, backlog, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -220,7 +220,7 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) { mp_uint_t port; int _errno; if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } // add the socket to the list @@ -248,7 +248,7 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { if (!self->sock_base.cert_req && _errno == SL_ESECSNOVERIFY) { return mp_const_none; } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -262,7 +262,7 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { int _errno; mp_int_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno); if (ret < 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_obj_new_int_from_uint(ret); } @@ -278,9 +278,9 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno); if (ret < 0) { if (_errno == EAGAIN && self->sock_base.has_timeout) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out")); + mp_raise_msg(&mp_type_TimeoutError, "timed out"); } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } if (ret == 0) { return mp_const_empty_bytes; @@ -307,7 +307,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_ int _errno; mp_int_t ret = wlan_socket_sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno); if (ret < 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_obj_new_int(ret); } @@ -324,9 +324,9 @@ STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); if (ret < 0) { if (_errno == EAGAIN && self->sock_base.has_timeout) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out")); + mp_raise_msg(&mp_type_TimeoutError, "timed out"); } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } mp_obj_t tuple[2]; if (ret == 0) { @@ -364,7 +364,7 @@ STATIC mp_obj_t socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) { int _errno; if (wlan_socket_setsockopt(self, level, opt, optval, optlen, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -384,7 +384,7 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { } int _errno; if (wlan_socket_settimeout(self, timeout, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -408,7 +408,7 @@ STATIC mp_obj_t socket_makefile(mp_uint_t n_args, const mp_obj_t *args) { if (n_args > 1) { const char *mode = mp_obj_str_get_str(args[1]); if (strcmp(mode, "rb") && strcmp(mode, "wb")) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } return self; @@ -504,7 +504,7 @@ STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; int32_t result = wlan_gethostbyname(host, hlen, out_ip, AF_INET); if (result < 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-result))); + mp_raise_OSError(-result); } mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); tuple->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET); diff --git a/cc3200/mods/modussl.c b/cc3200/mods/modussl.c index 1f27bdd21f..7a4787b6b3 100644 --- a/cc3200/mods/modussl.c +++ b/cc3200/mods/modussl.c @@ -131,10 +131,10 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args, return ssl_sock; socket_error: - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); arg_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket); diff --git a/cc3200/mods/modutime.c b/cc3200/mods/modutime.c index bef8b667f3..7ea8df1eff 100644 --- a/cc3200/mods/modutime.c +++ b/cc3200/mods/modutime.c @@ -29,7 +29,7 @@ #include #include "py/mpconfig.h" -#include "py/nlr.h" +#include "py/runtime.h" #include "py/obj.h" #include "py/smallint.h" #include "py/mphal.h" @@ -109,7 +109,7 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) { // localtime generates a tuple of len 8. CPython uses 9, so we accept both. if (len < 8 || len > 9) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments)); + mp_raise_TypeError(mpexception_num_type_invalid_arguments); } return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), diff --git a/cc3200/mods/modwlan.c b/cc3200/mods/modwlan.c index 2fb7ed377d..4b3dd4ec38 100644 --- a/cc3200/mods/modwlan.c +++ b/cc3200/mods/modwlan.c @@ -603,7 +603,7 @@ STATIC void wlan_reset (void) { STATIC void wlan_validate_mode (uint mode) { if (mode != ROLE_STA && mode != ROLE_AP) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -614,7 +614,7 @@ STATIC void wlan_set_mode (uint mode) { STATIC void wlan_validate_ssid_len (uint32_t len) { if (len > MODWLAN_SSID_LEN_MAX) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -647,7 +647,7 @@ STATIC void wlan_validate_security (uint8_t auth, const char *key, uint8_t len) return; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len) { @@ -670,7 +670,7 @@ STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len) { STATIC void wlan_validate_channel (uint8_t channel) { if (channel < 1 || channel > 11) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -682,7 +682,7 @@ STATIC void wlan_set_channel (uint8_t channel) { #if MICROPY_HW_ANTENNA_DIVERSITY STATIC void wlan_validate_antenna (uint8_t antenna) { if (antenna != ANTENNA_TYPE_INTERNAL && antenna != ANTENNA_TYPE_EXTERNAL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -847,7 +847,7 @@ STATIC mp_obj_t wlan_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_ui if (n_args > 1 || n_kw > 0) { // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // start the peripheral wlan_init_helper(self, &args[1]); @@ -871,7 +871,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { // check for correct wlan mode if (wlan_obj.mode == ROLE_AP) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } Sl_WlanNetworkEntry_t wlanEntry; @@ -925,7 +925,7 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ // check for the correct wlan mode if (wlan_obj.mode == ROLE_AP) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // parse args @@ -973,9 +973,9 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ modwlan_Status_t status; status = wlan_do_connect (ssid, ssid_len, bssid, auth, key, key_len, timeout); if (status == MODWLAN_ERROR_TIMEOUT) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } else if (status == MODWLAN_ERROR_INVALID_PARAMS) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return mp_const_none; } @@ -1004,7 +1004,7 @@ STATIC mp_obj_t wlan_ifconfig (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma // check the interface id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // get the configuration @@ -1051,7 +1051,7 @@ STATIC mp_obj_t wlan_ifconfig (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma // check for the correct string const char *mode = mp_obj_str_get_str(args[1].u_obj); if (strcmp("dhcp", mode)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } // only if we are not in AP mode @@ -1165,7 +1165,7 @@ STATIC mp_obj_t wlan_mac (mp_uint_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); if (bufinfo.len != 6) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } memcpy(self->mac, bufinfo.buf, SL_MAC_ADDR_LEN); sl_NetCfgSet(SL_MAC_ADDRESS_SET, 1, SL_MAC_ADDR_LEN, (_u8 *)self->mac); @@ -1201,7 +1201,7 @@ STATIC mp_obj_t wlan_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t * return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); @@ -1230,18 +1230,18 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // // // the call to sl_NetAppSet corrupts the input string URN=args[1], so we copy into a local buffer // if (len > MAX_DEVICE_URN_LEN) { -// nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); +// mp_raise_ValueError(mpexception_value_invalid_arguments); // } // strcpy(urn, p); // // if (sl_NetAppSet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, len, (unsigned char *)urn) < 0) { -// nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); +// mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); // } // } // else { // // get the URN // if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) { -// nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); +// mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); // } // return mp_obj_new_str(urn, (len - 1), false); // } diff --git a/cc3200/mods/pybadc.c b/cc3200/mods/pybadc.c index 22a90edb0a..f8c9b3da54 100644 --- a/cc3200/mods/pybadc.c +++ b/cc3200/mods/pybadc.c @@ -104,7 +104,7 @@ STATIC void pyb_adc_init (pyb_adc_obj_t *self) { STATIC void pyb_adc_check_init(void) { // not initialized if (!pyb_adc_obj.enabled) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -149,12 +149,12 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // check the number of bits if (args[1].u_int != 12) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } // setup the object @@ -173,7 +173,7 @@ STATIC mp_obj_t adc_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *k mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_adc_init_args[1], args); // check the number of bits if (args[0].u_int != 12) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } pyb_adc_init(pos_args[0]); return mp_const_none; @@ -206,11 +206,11 @@ STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t if (args[0].u_obj != MP_OBJ_NULL) { ch_id = mp_obj_get_int(args[0].u_obj); if (ch_id >= PYB_ADC_NUM_CHANNELS) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_os_resource_not_avaliable)); + mp_raise_ValueError(mpexception_os_resource_not_avaliable); } else if (args[1].u_obj != mp_const_none) { uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0); if (ch_id != pin_ch_id) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } } else { @@ -277,7 +277,7 @@ STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) { // the channel must be enabled if (!self->enabled) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // wait until a new value is available diff --git a/cc3200/mods/pybi2c.c b/cc3200/mods/pybi2c.c index 5022e614f6..d92782d8ae 100644 --- a/cc3200/mods/pybi2c.c +++ b/cc3200/mods/pybi2c.c @@ -144,7 +144,7 @@ STATIC bool pyb_i2c_transaction(uint cmd) { STATIC void pyb_i2c_check_init(pyb_i2c_obj_t *self) { // not initialized if (!self->baudrate) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -256,7 +256,7 @@ STATIC void pyb_i2c_read_into (mp_arg_val_t *args, vstr_t *vstr) { // receive the data if (!pyb_i2c_read(args[0].u_int, (byte *)vstr->buf, vstr->len)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } @@ -275,7 +275,7 @@ STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) { if (pyb_i2c_mem_addr_write (i2c_addr, (byte *)&mem_addr, mem_addr_size)) { // Read the specified length of data if (!pyb_i2c_read (i2c_addr, (byte *)vstr->buf, vstr->len)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } } @@ -323,7 +323,7 @@ STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *arg return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC const mp_arg_t pyb_i2c_init_args[] = { @@ -341,7 +341,7 @@ STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup the object @@ -445,7 +445,7 @@ STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m // send the data if (!pyb_i2c_write(args[0].u_int, bufinfo.buf, bufinfo.len, args[2].u_bool)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } // return the number of bytes written @@ -514,7 +514,7 @@ STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args, return mp_obj_new_int(bufinfo.len); } - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem); diff --git a/cc3200/mods/pybpin.c b/cc3200/mods/pybpin.c index ce304404b5..f59e65fc26 100644 --- a/cc3200/mods/pybpin.c +++ b/cc3200/mods/pybpin.c @@ -145,7 +145,7 @@ pin_obj_t *pin_find(mp_obj_t user_obj) { return pin_obj; } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } void pin_config (pin_obj_t *self, int af, uint mode, uint pull, int value, uint strength) { @@ -185,7 +185,7 @@ uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type) return pin_o->af_list[i].unit; } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit) { @@ -195,13 +195,13 @@ uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit) return pin_o->af_list[i].type; } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) { int8_t af = pin_obj_find_af(pin, fn, unit, type); if (af < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return af; } @@ -426,18 +426,18 @@ STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t prio STATIC void pin_validate_mode (uint mode) { if (mode != GPIO_DIR_MODE_IN && mode != GPIO_DIR_MODE_OUT && mode != PIN_TYPE_OD && mode != GPIO_DIR_MODE_ALT && mode != GPIO_DIR_MODE_ALT_OD) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void pin_validate_pull (uint pull) { if (pull != PIN_TYPE_STD && pull != PIN_TYPE_STD_PU && pull != PIN_TYPE_STD_PD) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void pin_validate_drive(uint strength) { if (strength != PIN_STRENGTH_2MA && strength != PIN_STRENGTH_4MA && strength != PIN_STRENGTH_6MA) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -450,7 +450,7 @@ STATIC void pin_validate_af(const pin_obj_t* pin, int8_t idx, uint8_t *fn, uint8 return; } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC uint8_t pin_get_value (const pin_obj_t* self) { @@ -591,7 +591,7 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_ return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -905,7 +905,7 @@ STATIC mp_obj_t pin_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *k return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq); diff --git a/cc3200/mods/pybrtc.c b/cc3200/mods/pybrtc.c index ea99411052..4662edbe7e 100644 --- a/cc3200/mods/pybrtc.c +++ b/cc3200/mods/pybrtc.c @@ -202,7 +202,7 @@ STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) { // verify the tuple if (len < 3 || len > 8) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } tm.tm_year = mp_obj_get_int(items[0]); @@ -294,7 +294,7 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup the object @@ -362,7 +362,7 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma // check the alarm id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } uint32_t f_seconds; @@ -371,7 +371,7 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given // repeat cannot be used with a datetime tuple if (repeat) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000; } else { // then it must be an integer @@ -397,7 +397,7 @@ STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) { // only alarm id 0 is available if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // get the current time @@ -415,7 +415,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_t n_args, const mp_obj_t *args) { // only alarm id 0 is available if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // disable the alarm pyb_rtc_disable_alarm(); @@ -453,7 +453,7 @@ STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq); diff --git a/cc3200/mods/pybsd.c b/cc3200/mods/pybsd.c index 55b797dc78..d7efbe872c 100644 --- a/cc3200/mods/pybsd.c +++ b/cc3200/mods/pybsd.c @@ -107,7 +107,7 @@ STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args) pyb_sd_hw_init (self); if (sd_disk_init() != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } // register it with the sleep module @@ -132,7 +132,7 @@ STATIC mp_obj_t pyb_sd_make_new (const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup and initialize the object diff --git a/cc3200/mods/pybspi.c b/cc3200/mods/pybspi.c index d4fcbe94b4..f5c9962728 100644 --- a/cc3200/mods/pybspi.c +++ b/cc3200/mods/pybspi.c @@ -131,7 +131,7 @@ STATIC void pybspi_rx (pyb_spi_obj_t *self, void *data) { STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len, uint32_t *txchar) { if (!self->baudrate) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // send and receive the data MAP_SPICSEnable(GSPI_BASE); @@ -218,7 +218,7 @@ STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, const mp_arg_val_t *arg return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } static const mp_arg_t pyb_spi_init_args[] = { @@ -240,7 +240,7 @@ STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup the object @@ -357,7 +357,7 @@ STATIC mp_obj_t pyb_spi_write_readinto (mp_obj_t self, mp_obj_t writebuf, mp_obj // get the read buffer mp_get_buffer_raise(readbuf, &bufinfo_read, MP_BUFFER_WRITE); if (bufinfo_read.len != bufinfo_write.len) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } diff --git a/cc3200/mods/pybtimer.c b/cc3200/mods/pybtimer.c index 65fc7195e6..2ac71cccb7 100644 --- a/cc3200/mods/pybtimer.c +++ b/cc3200/mods/pybtimer.c @@ -223,7 +223,7 @@ STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t return prescaler; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC void timer_init (pyb_timer_obj_t *tim) { @@ -319,7 +319,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co return mp_const_none; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { @@ -329,7 +329,7 @@ STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args, // create a new Timer object int32_t timer_idx = mp_obj_get_int(args[0]); if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } pyb_timer_obj_t *tim = &pyb_timer_obj[timer_idx]; @@ -370,7 +370,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp // verify that the timer has been already initialized if (!tim->config) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } if (channel_n != TIMER_A && channel_n != TIMER_B && channel_n != (TIMER_A | TIMER_B)) { // invalid channel @@ -440,7 +440,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp return ch; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel); @@ -560,7 +560,7 @@ STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) { // set int32_t _frequency = mp_obj_get_int(args[1]); if (_frequency <= 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } ch->frequency = _frequency; ch->period = 1000000 / _frequency; @@ -579,7 +579,7 @@ STATIC mp_obj_t pyb_timer_channel_period(mp_uint_t n_args, const mp_obj_t *args) // set int32_t _period = mp_obj_get_int(args[1]); if (_period <= 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } ch->period = _period; ch->frequency = 1000000 / _period; @@ -712,7 +712,7 @@ STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_arg return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq); diff --git a/cc3200/mods/pybuart.c b/cc3200/mods/pybuart.c index e7b5255bdf..493522f835 100644 --- a/cc3200/mods/pybuart.c +++ b/cc3200/mods/pybuart.c @@ -280,7 +280,7 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) { STATIC void uart_check_init(pyb_uart_obj_t *self) { // not initialized if (!self->baudrate) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -432,7 +432,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a return mp_const_none; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC const mp_arg_t pyb_uart_init_args[] = { @@ -472,7 +472,7 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, mp_uint_t n_args, m } if (uart_id > PYB_UART_1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // get the correct uart instance @@ -556,7 +556,7 @@ STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map return uart_irq_new (self, trigger, priority, args[2].u_obj); invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq); @@ -622,7 +622,7 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t // write the data if (!uart_tx_strn(self, buf, size)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } return size; } diff --git a/cc3200/mods/pybwdt.c b/cc3200/mods/pybwdt.c index 6e5fe4714a..30478c83ce 100644 --- a/cc3200/mods/pybwdt.c +++ b/cc3200/mods/pybwdt.c @@ -100,14 +100,14 @@ STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_wdt_init_args, args); if (args[0].u_obj != mp_const_none && mp_obj_get_int(args[0].u_obj) > 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } uint timeout_ms = args[1].u_int; if (timeout_ms < PYBWDT_MIN_TIMEOUT_MS) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } if (pyb_wdt_obj.running) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // Enable the WDT peripheral clock diff --git a/cc3200/mpthreadport.c b/cc3200/mpthreadport.c index 064aa6ba10..dd02180982 100644 --- a/cc3200/mpthreadport.c +++ b/cc3200/mpthreadport.c @@ -28,6 +28,7 @@ #include "py/mpconfig.h" #include "py/mpstate.h" +#include "py/runtime.h" #include "py/gc.h" #include "py/mpthread.h" #include "mptask.h" @@ -131,7 +132,7 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { TaskHandle_t id = xTaskCreateStatic(freertos_entry, "Thread", *stack_size / sizeof(void*), arg, 2, stack, tcb); if (id == NULL) { mp_thread_mutex_unlock(&thread_mutex); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + mp_raise_msg(&mp_type_OSError, "can't create thread"); } // add thread to linked list of all threads diff --git a/cc3200/serverstask.c b/cc3200/serverstask.c index 1305afda0b..6b5899e186 100644 --- a/cc3200/serverstask.c +++ b/cc3200/serverstask.c @@ -29,7 +29,7 @@ #include "py/mpconfig.h" #include "py/misc.h" -#include "py/nlr.h" +#include "py/runtime.h" #include "py/mphal.h" #include "serverstask.h" #include "simplelink.h" @@ -187,7 +187,7 @@ void servers_close_socket (int16_t *sd) { void servers_set_login (char *user, char *pass) { if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } memcpy(servers_user, user, SERVERS_USER_PASS_LEN_MAX); memcpy(servers_pass, pass, SERVERS_USER_PASS_LEN_MAX); @@ -196,7 +196,7 @@ void servers_set_login (char *user, char *pass) { void servers_set_timeout (uint32_t timeout) { if (timeout < SERVERS_MIN_TIMEOUT_MS) { // timeout is too low - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } servers_data.timeout = timeout; } From f12047f66d34df3001fd1bec0d7aa46f3a6f25fe Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 10:14:26 +1100 Subject: [PATCH 61/78] docs/machine.SPI: Improve descriptions of xfer methods. In particular remove the "*" because not all ports support keyword arguments. --- docs/library/machine.SPI.rst | 40 +++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst index 7c6627614a..9b4d62e011 100644 --- a/docs/library/machine.SPI.rst +++ b/docs/library/machine.SPI.rst @@ -52,7 +52,7 @@ Methods - ``pins`` is an optional tuple with the pins to assign to the SPI bus (deprecated, only for WiPy). - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most hardware SPI blocks (as selected by ``id`` parameter to the constructore), pins are fixed - and cannot be changed. In some cases, hardware blocks allow 2-3 alterbative pin sets for + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver (``id``=-1). @@ -60,34 +60,42 @@ Methods Turn off the SPI bus. +.. method:: SPI.read(nbytes, write=0x00) + + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + +.. method:: SPI.readinto(buf, write=0x00) + + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + .. method:: SPI.write(buf) - Write the data contained in ``buf``. - Returns the number of bytes written. + Write the bytes contained in ``buf``. + Returns ``None``. -.. method:: SPI.read(nbytes, *, write=0x00) - - Read the ``nbytes`` while writing the data specified by ``write``. - Return the number of bytes read. - -.. method:: SPI.readinto(buf, *, write=0x00) - - Read into the buffer specified by ``buf`` while writing the data specified by - ``write``. - Return the number of bytes read. + Note: on WiPy this function returns the number of bytes written. .. method:: SPI.write_readinto(write_buf, read_buf) - Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the same length. - Returns the number of bytes written. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. Constants --------- .. data:: SPI.MASTER - for initialising the SPI bus to master + for initialising the SPI bus to master; this is only used for the WiPy .. data:: SPI.MSB From 628799cd365e174a53a9328ebe3045f53efdf7d6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 10:16:46 +1100 Subject: [PATCH 62/78] cc3200/mods/pybspi: Allow "write" arg of read/readinto to be positional. To conform with Hardware API. --- cc3200/mods/pybspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cc3200/mods/pybspi.c b/cc3200/mods/pybspi.c index f5c9962728..5a040e3f59 100644 --- a/cc3200/mods/pybspi.c +++ b/cc3200/mods/pybspi.c @@ -295,7 +295,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write); STATIC mp_obj_t pyb_spi_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} }, + { MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} }, }; // parse args @@ -319,7 +319,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_read_obj, 1, pyb_spi_read); STATIC mp_obj_t pyb_spi_readinto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} }, + { MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} }, }; // parse args From 5c93d0b91655dcd32e633d720b5b790b10be989c Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 10:17:54 +1100 Subject: [PATCH 63/78] cc3200: Enable loading of precompiled .mpy files. Adds 1072 bytes to the code size. --- cc3200/mpconfigport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index 0b16d730d0..bf3e691bd8 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -38,6 +38,7 @@ // options to control how Micro Python is built #define MICROPY_ALLOC_PATH_MAX (128) +#define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_COMP_MODULE_CONST (1) From cd9b14bb11c35e013e47db46bcc73734f0d6cd55 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 14:30:00 +1100 Subject: [PATCH 64/78] stmhal/modutime: Refactor to use extmod's version of ticks_cpu. --- stmhal/modutime.c | 14 +------------- stmhal/mphalport.c | 11 +++++++++++ stmhal/mphalport.h | 11 +++++++++++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/stmhal/modutime.c b/stmhal/modutime.c index 63597edde8..fae360bb02 100644 --- a/stmhal/modutime.c +++ b/stmhal/modutime.c @@ -130,18 +130,6 @@ STATIC mp_obj_t time_time(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); -STATIC mp_obj_t time_ticks_cpu(void) { - static bool enabled = false; - if (!enabled) { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - enabled = true; - } - return MP_OBJ_NEW_SMALL_INT(DWT->CYCCNT & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu); - STATIC const mp_map_elem_t time_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) }, @@ -153,7 +141,7 @@ STATIC const mp_map_elem_t time_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&mp_utime_sleep_us_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&mp_utime_ticks_ms_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&mp_utime_ticks_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&mp_utime_ticks_cpu_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&mp_utime_ticks_diff_obj }, }; diff --git a/stmhal/mphalport.c b/stmhal/mphalport.c index f392550b80..3bf993ec25 100644 --- a/stmhal/mphalport.c +++ b/stmhal/mphalport.c @@ -7,6 +7,8 @@ #include "usb.h" #include "uart.h" +bool mp_hal_ticks_cpu_enabled = false; + // this table converts from HAL_StatusTypeDef to POSIX errno const byte mp_hal_status_to_errno_table[4] = { [HAL_OK] = 0, @@ -71,6 +73,15 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { } } +void mp_hal_ticks_cpu_enable(void) { + if (!mp_hal_ticks_cpu_enabled) { + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + mp_hal_ticks_cpu_enabled = true; + } +} + void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { if (0) { #ifdef __GPIOA_CLK_ENABLE diff --git a/stmhal/mphalport.h b/stmhal/mphalport.h index 02b408777c..40e6fb2b48 100644 --- a/stmhal/mphalport.h +++ b/stmhal/mphalport.h @@ -35,13 +35,24 @@ NORETURN void mp_hal_raise(HAL_StatusTypeDef status); void mp_hal_set_interrupt_char(int c); // -1 to disable // timing functions + #include "stmhal/systick.h" + #define mp_hal_delay_ms HAL_Delay #define mp_hal_delay_us(us) sys_tick_udelay(us) #define mp_hal_delay_us_fast(us) sys_tick_udelay(us) #define mp_hal_ticks_ms HAL_GetTick #define mp_hal_ticks_us() sys_tick_get_microseconds() +extern bool mp_hal_ticks_cpu_enabled; +void mp_hal_ticks_cpu_enable(void); +static inline mp_uint_t mp_hal_ticks_cpu(void) { + if (!mp_hal_ticks_cpu_enabled) { + mp_hal_ticks_cpu_enable(); + } + return DWT->CYCCNT; +} + // C-level pin HAL #include "stmhal/pin.h" #define mp_hal_pin_obj_t const pin_obj_t* From d49d81b1675b39c0c29c95b105edbbb7384f9314 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 14:32:42 +1100 Subject: [PATCH 65/78] stmhal: Refactor pin usage to use mp_hal_pin API. --- stmhal/accel.c | 14 ++++---------- stmhal/i2c.c | 4 ++-- stmhal/lcd.c | 44 +++++++++++++++--------------------------- stmhal/modnwwiznet5k.c | 22 ++++++--------------- stmhal/mphalport.c | 6 ++++-- stmhal/mphalport.h | 44 ++++++++++++++++++++---------------------- stmhal/pin.c | 18 +++++------------ stmhal/spi.c | 2 +- 8 files changed, 59 insertions(+), 95 deletions(-) diff --git a/stmhal/accel.c b/stmhal/accel.c index e75f1c9942..827aa46e7c 100644 --- a/stmhal/accel.c +++ b/stmhal/accel.c @@ -57,15 +57,9 @@ #define MMA_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0)) void accel_init(void) { - GPIO_InitTypeDef GPIO_InitStructure; - // PB5 is connected to AVDD; pull high to enable MMA accel device - GPIO_clear_pin(MICROPY_HW_MMA_AVDD_PIN.gpio, MICROPY_HW_MMA_AVDD_PIN.pin_mask); // turn off AVDD - GPIO_InitStructure.Pin = MICROPY_HW_MMA_AVDD_PIN.pin_mask; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_LOW; - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(MICROPY_HW_MMA_AVDD_PIN.gpio, &GPIO_InitStructure); + mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD + mp_hal_pin_output(&MICROPY_HW_MMA_AVDD_PIN); } STATIC void accel_start(void) { @@ -81,9 +75,9 @@ STATIC void accel_start(void) { i2c_init(&I2CHandle1); // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again - GPIO_clear_pin(MICROPY_HW_MMA_AVDD_PIN.gpio, MICROPY_HW_MMA_AVDD_PIN.pin_mask); // turn off + mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off HAL_Delay(30); - GPIO_set_pin(MICROPY_HW_MMA_AVDD_PIN.gpio, MICROPY_HW_MMA_AVDD_PIN.pin_mask); // turn on + mp_hal_pin_high(&MICROPY_HW_MMA_AVDD_PIN); // turn on HAL_Delay(30); HAL_StatusTypeDef status; diff --git a/stmhal/i2c.c b/stmhal/i2c.c index 1909f81606..07269bce5e 100644 --- a/stmhal/i2c.c +++ b/stmhal/i2c.c @@ -238,8 +238,8 @@ void i2c_init(I2C_HandleTypeDef *i2c) { } // init the GPIO lines - mp_hal_gpio_set_af(scl_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); - mp_hal_gpio_set_af(sda_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); + mp_hal_pin_set_af(scl_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); + mp_hal_pin_set_af(sda_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); // init the I2C device if (HAL_I2C_Init(i2c) != HAL_OK) { diff --git a/stmhal/lcd.c b/stmhal/lcd.c index 92f19b8186..c406d64477 100644 --- a/stmhal/lcd.c +++ b/stmhal/lcd.c @@ -113,16 +113,16 @@ STATIC void lcd_delay(void) { STATIC void lcd_out(pyb_lcd_obj_t *lcd, int instr_data, uint8_t i) { lcd_delay(); - GPIO_clear_pin(lcd->pin_cs1->gpio, lcd->pin_cs1->pin_mask); // CS=0; enable + mp_hal_pin_low(lcd->pin_cs1); // CS=0; enable if (instr_data == LCD_INSTR) { - GPIO_clear_pin(lcd->pin_a0->gpio, lcd->pin_a0->pin_mask); // A0=0; select instr reg + mp_hal_pin_low(lcd->pin_a0); // A0=0; select instr reg } else { - GPIO_set_pin(lcd->pin_a0->gpio, lcd->pin_a0->pin_mask); // A0=1; select data reg + mp_hal_pin_high(lcd->pin_a0); // A0=1; select data reg } lcd_delay(); HAL_SPI_Transmit(lcd->spi, &i, 1, 1000); lcd_delay(); - GPIO_set_pin(lcd->pin_cs1->gpio, lcd->pin_cs1->pin_mask); // CS=1; disable + mp_hal_pin_high(lcd->pin_cs1); // CS=1; disable } // write a string to the LCD at the current cursor location @@ -262,34 +262,22 @@ STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp spi_init(lcd->spi, false); // set the pins to default values - GPIO_set_pin(lcd->pin_cs1->gpio, lcd->pin_cs1->pin_mask); - GPIO_set_pin(lcd->pin_rst->gpio, lcd->pin_rst->pin_mask); - GPIO_set_pin(lcd->pin_a0->gpio, lcd->pin_a0->pin_mask); - GPIO_clear_pin(lcd->pin_bl->gpio, lcd->pin_bl->pin_mask); + mp_hal_pin_high(lcd->pin_cs1); + mp_hal_pin_high(lcd->pin_rst); + mp_hal_pin_high(lcd->pin_a0); + mp_hal_pin_low(lcd->pin_bl); // init the pins to be push/pull outputs - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Pull = GPIO_NOPULL; - - GPIO_InitStructure.Pin = lcd->pin_cs1->pin_mask; - HAL_GPIO_Init(lcd->pin_cs1->gpio, &GPIO_InitStructure); - - GPIO_InitStructure.Pin = lcd->pin_rst->pin_mask; - HAL_GPIO_Init(lcd->pin_rst->gpio, &GPIO_InitStructure); - - GPIO_InitStructure.Pin = lcd->pin_a0->pin_mask; - HAL_GPIO_Init(lcd->pin_a0->gpio, &GPIO_InitStructure); - - GPIO_InitStructure.Pin = lcd->pin_bl->pin_mask; - HAL_GPIO_Init(lcd->pin_bl->gpio, &GPIO_InitStructure); + mp_hal_pin_output(lcd->pin_cs1); + mp_hal_pin_output(lcd->pin_rst); + mp_hal_pin_output(lcd->pin_a0); + mp_hal_pin_output(lcd->pin_bl); // init the LCD HAL_Delay(1); // wait a bit - GPIO_clear_pin(lcd->pin_rst->gpio, lcd->pin_rst->pin_mask); // RST=0; reset + mp_hal_pin_low(lcd->pin_rst); // RST=0; reset HAL_Delay(1); // wait for reset; 2us min - GPIO_set_pin(lcd->pin_rst->gpio, lcd->pin_rst->pin_mask); // RST=1; enable + mp_hal_pin_high(lcd->pin_rst); // RST=1; enable HAL_Delay(1); // wait for reset; 2us min lcd_out(lcd, LCD_INSTR, 0xa0); // ADC select, normal lcd_out(lcd, LCD_INSTR, 0xc0); // common output mode select, normal (this flips the display) @@ -372,9 +360,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_contrast_obj, pyb_lcd_contrast); STATIC mp_obj_t pyb_lcd_light(mp_obj_t self_in, mp_obj_t value) { pyb_lcd_obj_t *self = self_in; if (mp_obj_is_true(value)) { - GPIO_set_pin(self->pin_bl->gpio, self->pin_bl->pin_mask); // set pin high to turn backlight on + mp_hal_pin_high(self->pin_bl); // set pin high to turn backlight on } else { - GPIO_clear_pin(self->pin_bl->gpio, self->pin_bl->pin_mask); // set pin low to turn backlight off + mp_hal_pin_low(self->pin_bl); // set pin low to turn backlight off } return mp_const_none; } diff --git a/stmhal/modnwwiznet5k.c b/stmhal/modnwwiznet5k.c index c8b5d628f4..f349e40aff 100644 --- a/stmhal/modnwwiznet5k.c +++ b/stmhal/modnwwiznet5k.c @@ -65,11 +65,11 @@ STATIC void wiz_cris_exit(void) { } STATIC void wiz_cs_select(void) { - GPIO_clear_pin(wiznet5k_obj.cs->gpio, wiznet5k_obj.cs->pin_mask); + mp_hal_pin_low(wiznet5k_obj.cs); } STATIC void wiz_cs_deselect(void) { - GPIO_set_pin(wiznet5k_obj.cs->gpio, wiznet5k_obj.cs->pin_mask); + mp_hal_pin_high(wiznet5k_obj.cs); } STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { @@ -344,22 +344,12 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, mp_uint_t n_args, m wiznet5k_obj.spi->Init.CRCPolynomial = 7; // unused spi_init(wiznet5k_obj.spi, false); - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_FAST; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Pin = wiznet5k_obj.cs->pin_mask; - HAL_GPIO_Init(wiznet5k_obj.cs->gpio, &GPIO_InitStructure); + mp_hal_pin_output(wiznet5k_obj.cs); + mp_hal_pin_output(wiznet5k_obj.rst); - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_FAST; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Pin = wiznet5k_obj.rst->pin_mask; - HAL_GPIO_Init(wiznet5k_obj.rst->gpio, &GPIO_InitStructure); - - GPIO_clear_pin(wiznet5k_obj.rst->gpio, wiznet5k_obj.rst->pin_mask); + mp_hal_pin_low(wiznet5k_obj.rst); HAL_Delay(1); // datasheet says 2us - GPIO_set_pin(wiznet5k_obj.rst->gpio, wiznet5k_obj.rst->pin_mask); + mp_hal_pin_high(wiznet5k_obj.rst); HAL_Delay(160); // datasheet says 150ms reg_wizchip_cris_cbfunc(wiz_cris_enter, wiz_cris_exit); diff --git a/stmhal/mphalport.c b/stmhal/mphalport.c index 3bf993ec25..8d6aa1a759 100644 --- a/stmhal/mphalport.c +++ b/stmhal/mphalport.c @@ -131,7 +131,9 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { } } -void mp_hal_gpio_config(GPIO_TypeDef *gpio, uint32_t pin, uint32_t mode, uint32_t pull, uint32_t alt) { +void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) { + GPIO_TypeDef *gpio = pin_obj->gpio; + uint32_t pin = pin_obj->pin; mp_hal_gpio_clock_enable(gpio); gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); @@ -140,7 +142,7 @@ void mp_hal_gpio_config(GPIO_TypeDef *gpio, uint32_t pin, uint32_t mode, uint32_ gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); } -bool mp_hal_gpio_set_af(const pin_obj_t *pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit) { +bool mp_hal_pin_set_af(mp_hal_pin_obj_t pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit) { mp_hal_gpio_clock_enable(pin->gpio); const pin_af_obj_t *af = pin_find_af(pin, fn, unit); diff --git a/stmhal/mphalport.h b/stmhal/mphalport.h index 40e6fb2b48..e58bb33b5f 100644 --- a/stmhal/mphalport.h +++ b/stmhal/mphalport.h @@ -14,21 +14,6 @@ #error mphalport.h: Unrecognized MCU_SERIES #endif -// Basic GPIO functions -#define GPIO_read_pin(gpio, pin) (((gpio)->IDR >> (pin)) & 1) -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) -#define GPIO_set_pin(gpio, pin_mask) (((gpio)->BSRR) = (pin_mask)) -#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->BSRR) = ((pin_mask) << 16)) -#else -#define GPIO_set_pin(gpio, pin_mask) (((gpio)->BSRRL) = (pin_mask)) -#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->BSRRH) = (pin_mask)) -#endif -#define GPIO_read_output_pin(gpio, pin) (((gpio)->ODR >> (pin)) & 1) - -void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); -void mp_hal_gpio_config(GPIO_TypeDef *gpio, uint32_t pin, uint32_t mode, uint32_t pull, uint32_t alt); -bool mp_hal_gpio_set_af(const pin_obj_t *pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit); - extern const unsigned char mp_hal_status_to_errno_table[4]; NORETURN void mp_hal_raise(HAL_StatusTypeDef status); @@ -54,13 +39,26 @@ static inline mp_uint_t mp_hal_ticks_cpu(void) { } // C-level pin HAL + #include "stmhal/pin.h" + #define mp_hal_pin_obj_t const pin_obj_t* -#define mp_hal_get_pin_obj(o) pin_find(o) -#define mp_hal_pin_input(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 0, 0, 0) -#define mp_hal_pin_output(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 1, 0, 0) -#define mp_hal_pin_open_drain(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 5, 0, 0) -#define mp_hal_pin_od_low(p) GPIO_clear_pin((p)->gpio, (p)->pin_mask) -#define mp_hal_pin_od_high(p) GPIO_set_pin((p)->gpio, (p)->pin_mask) -#define mp_hal_pin_read(p) GPIO_read_pin((p)->gpio, (p)->pin) -#define mp_hal_pin_write(p, v) do { if (v) { GPIO_set_pin((p)->gpio, (p)->pin_mask); } else { GPIO_clear_pin((p)->gpio, (p)->pin_mask); } } while (0) +#define mp_hal_get_pin_obj(o) pin_find(o) +#define mp_hal_pin_input(p) mp_hal_pin_config((p), 0, 0, 0) +#define mp_hal_pin_output(p) mp_hal_pin_config((p), 1, 0, 0) +#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), 5, 0, 0) +#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) +#define mp_hal_pin_high(p) (((p)->gpio->BSRR) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRR) = ((p)->pin_mask << 16)) +#else +#define mp_hal_pin_high(p) (((p)->gpio->BSRRL) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRRH) = (p)->pin_mask) +#endif +#define mp_hal_pin_od_low(p) mp_hal_pin_low(p) +#define mp_hal_pin_od_high(p) mp_hal_pin_high(p) +#define mp_hal_pin_read(p) (((p)->gpio->IDR >> (p)->pin) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) + +void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); +void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt); +bool mp_hal_pin_set_af(mp_hal_pin_obj_t pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit); diff --git a/stmhal/pin.c b/stmhal/pin.c index 9bd4e7a6d9..21012d1865 100644 --- a/stmhal/pin.c +++ b/stmhal/pin.c @@ -266,14 +266,10 @@ STATIC mp_obj_t pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, con pin_obj_t *self = self_in; if (n_args == 0) { // get pin - return MP_OBJ_NEW_SMALL_INT(GPIO_read_pin(self->gpio, self->pin)); + return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self)); } else { // set pin - if (mp_obj_is_true(args[0])) { - GPIO_set_pin(self->gpio, self->pin_mask); - } else { - GPIO_clear_pin(self->gpio, self->pin_mask); - } + mp_hal_pin_write(self, mp_obj_is_true(args[0])); return mp_const_none; } } @@ -371,11 +367,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con // if given, set the pin value before initialising to prevent glitches if (args[3].u_obj != MP_OBJ_NULL) { - if (mp_obj_is_true(args[3].u_obj)) { - GPIO_set_pin(self->gpio, self->pin_mask); - } else { - GPIO_clear_pin(self->gpio, self->pin_mask); - } + mp_hal_pin_write(self, mp_obj_is_true(args[3].u_obj)); } // configure the GPIO as requested @@ -411,7 +403,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); /// Set the pin to a low logic level. STATIC mp_obj_t pin_low(mp_obj_t self_in) { pin_obj_t *self = self_in; - GPIO_clear_pin(self->gpio, self->pin_mask);; + mp_hal_pin_low(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); @@ -420,7 +412,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); /// Set the pin to a high logic level. STATIC mp_obj_t pin_high(mp_obj_t self_in) { pin_obj_t *self = self_in; - GPIO_set_pin(self->gpio, self->pin_mask);; + mp_hal_pin_high(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high); diff --git a/stmhal/spi.c b/stmhal/spi.c index 7f805709d6..e72810d287 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -332,7 +332,7 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { } for (uint i = (enable_nss_pin && pins[0] ? 0 : 1); i < 4; i++) { - mp_hal_gpio_set_af(pins[i], &GPIO_InitStructure, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1); + mp_hal_pin_set_af(pins[i], &GPIO_InitStructure, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1); } // init the SPI device From b4cc68e4a4d656c4b1ae4de8db6a089726f1f572 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 14:43:05 +1100 Subject: [PATCH 66/78] stmhal/led: Refactor LED to use mp_hal_pin_output() init function. As part of this patch the MICROPY_HW_LED_OTYPE setting is removed because it is now unused (all boards anyway had this as OUTPUT_PP). --- stmhal/boards/ESPRUINO_PICO/mpconfigboard.h | 5 ++--- stmhal/boards/HYDRABUS/mpconfigboard.h | 5 ++--- stmhal/boards/LIMIFROG/mpconfigboard.h | 5 ++--- stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h | 5 ++--- stmhal/boards/NUCLEO_F401RE/mpconfigboard.h | 5 ++--- stmhal/boards/NUCLEO_F411RE/mpconfigboard.h | 5 ++--- stmhal/boards/OLIMEX_E407/mpconfigboard.h | 5 ++--- stmhal/boards/PYBLITEV10/mpconfigboard.h | 5 ++--- stmhal/boards/PYBV10/mpconfigboard.h | 5 ++--- stmhal/boards/PYBV11/mpconfigboard.h | 5 ++--- stmhal/boards/PYBV3/mpconfigboard.h | 5 ++--- stmhal/boards/PYBV4/mpconfigboard.h | 5 ++--- stmhal/boards/STM32F411DISC/mpconfigboard.h | 5 ++--- stmhal/boards/STM32F429DISC/mpconfigboard.h | 5 ++--- stmhal/boards/STM32F4DISC/mpconfigboard.h | 5 ++--- stmhal/boards/STM32F7DISC/mpconfigboard.h | 5 ++--- stmhal/boards/STM32L476DISC/mpconfigboard.h | 5 ++--- stmhal/led.c | 11 +---------- 18 files changed, 35 insertions(+), 61 deletions(-) diff --git a/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h b/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h index 885cedc893..d18abb908c 100644 --- a/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h +++ b/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h @@ -66,6 +66,5 @@ #define MICROPY_HW_LED2 (pin_B12) // green #define MICROPY_HW_LED3 (pin_B12) // green #define MICROPY_HW_LED4 (pin_B12) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/stmhal/boards/HYDRABUS/mpconfigboard.h b/stmhal/boards/HYDRABUS/mpconfigboard.h index 4fe0874d73..06d1692360 100644 --- a/stmhal/boards/HYDRABUS/mpconfigboard.h +++ b/stmhal/boards/HYDRABUS/mpconfigboard.h @@ -69,9 +69,8 @@ #define MICROPY_HW_LED2 (pin_A4) // same as LED1 #define MICROPY_HW_LED3 (pin_A4) // same as LED1 #define MICROPY_HW_LED4 (pin_A4) // same as LED1 -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch (not used, always on) #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/LIMIFROG/mpconfigboard.h b/stmhal/boards/LIMIFROG/mpconfigboard.h index 782c9c90f8..47b8922336 100644 --- a/stmhal/boards/LIMIFROG/mpconfigboard.h +++ b/stmhal/boards/LIMIFROG/mpconfigboard.h @@ -63,9 +63,8 @@ void LIMIFROG_board_early_init(void); // LEDs #define MICROPY_HW_LED1 (pin_C3) // red -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = pin->pin_mask<<16) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h index 8ec8df645f..3155b63098 100644 --- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -64,9 +64,8 @@ void NETDUINO_PLUS_2_board_early_init(void); #define MICROPY_HW_LED2 (pin_C13) // White LED (aka Power) #define MICROPY_HW_LED3 (pin_A10) // Same as Led(1) #define MICROPY_HW_LED4 (pin_C13) // Same as Led(2) -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB VBUS detect pin #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h b/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h index 780eaf8fc4..518f65824b 100644 --- a/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h +++ b/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h @@ -54,6 +54,5 @@ // LEDs #define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h b/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h index e7ffd85100..4dac804931 100644 --- a/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h +++ b/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h @@ -65,6 +65,5 @@ // LEDs #define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/stmhal/boards/OLIMEX_E407/mpconfigboard.h b/stmhal/boards/OLIMEX_E407/mpconfigboard.h index c9241fe63a..63ddcfb5d6 100644 --- a/stmhal/boards/OLIMEX_E407/mpconfigboard.h +++ b/stmhal/boards/OLIMEX_E407/mpconfigboard.h @@ -71,9 +71,8 @@ // LEDs #define MICROPY_HW_LED1 (pin_C13) -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_C11) diff --git a/stmhal/boards/PYBLITEV10/mpconfigboard.h b/stmhal/boards/PYBLITEV10/mpconfigboard.h index 83dcb938b3..3147d2d7ab 100644 --- a/stmhal/boards/PYBLITEV10/mpconfigboard.h +++ b/stmhal/boards/PYBLITEV10/mpconfigboard.h @@ -73,9 +73,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_B5) diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h index c654ec9a70..2540cc4eb3 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -84,9 +84,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/PYBV11/mpconfigboard.h b/stmhal/boards/PYBV11/mpconfigboard.h index 9b5b7de27b..881e1ccf02 100644 --- a/stmhal/boards/PYBV11/mpconfigboard.h +++ b/stmhal/boards/PYBV11/mpconfigboard.h @@ -84,9 +84,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h index 44fb221610..48d5549253 100644 --- a/stmhal/boards/PYBV3/mpconfigboard.h +++ b/stmhal/boards/PYBV3/mpconfigboard.h @@ -73,9 +73,8 @@ #define MICROPY_HW_LED4 (pin_C5) // G2 - green #define MICROPY_HW_LED1_PWM { TIM1, 1, TIM_CHANNEL_1, GPIO_AF1_TIM1 } #define MICROPY_HW_LED2_PWM { TIM1, 1, TIM_CHANNEL_3, GPIO_AF1_TIM1 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13) diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h index cc931fb6bf..3e8300d15b 100644 --- a/stmhal/boards/PYBV4/mpconfigboard.h +++ b/stmhal/boards/PYBV4/mpconfigboard.h @@ -81,9 +81,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/STM32F411DISC/mpconfigboard.h b/stmhal/boards/STM32F411DISC/mpconfigboard.h index 3bab1304c0..be3589cd9f 100644 --- a/stmhal/boards/STM32F411DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F411DISC/mpconfigboard.h @@ -63,9 +63,8 @@ #define MICROPY_HW_LED2 (pin_D12) // green #define MICROPY_HW_LED3 (pin_D13) // orange #define MICROPY_HW_LED4 (pin_D15) // blue -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/stmhal/boards/STM32F429DISC/mpconfigboard.h b/stmhal/boards/STM32F429DISC/mpconfigboard.h index f2cf6c1422..63f22e02c2 100644 --- a/stmhal/boards/STM32F429DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F429DISC/mpconfigboard.h @@ -67,9 +67,8 @@ // LEDs #define MICROPY_HW_LED1 (pin_G14) // red #define MICROPY_HW_LED2 (pin_G13) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13) diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h index 01202e0c95..841bf7d15b 100644 --- a/stmhal/boards/STM32F4DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h @@ -82,9 +82,8 @@ #define MICROPY_HW_LED2 (pin_D12) // green #define MICROPY_HW_LED3 (pin_D13) // orange #define MICROPY_HW_LED4 (pin_D15) // blue -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/stmhal/boards/STM32F7DISC/mpconfigboard.h b/stmhal/boards/STM32F7DISC/mpconfigboard.h index a1dbc0f468..acdc4d0055 100644 --- a/stmhal/boards/STM32F7DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F7DISC/mpconfigboard.h @@ -79,9 +79,8 @@ void STM32F7DISC_board_early_init(void); // LEDs #define MICROPY_HW_LED1 (pin_I1) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = (pin->pin_mask << 16)) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13) diff --git a/stmhal/boards/STM32L476DISC/mpconfigboard.h b/stmhal/boards/STM32L476DISC/mpconfigboard.h index 07e3ec7fdc..55e7c9b563 100644 --- a/stmhal/boards/STM32L476DISC/mpconfigboard.h +++ b/stmhal/boards/STM32L476DISC/mpconfigboard.h @@ -61,9 +61,8 @@ // LEDs #define MICROPY_HW_LED1 (pin_B2) // red #define MICROPY_HW_LED2 (pin_E8) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = pin->pin_mask<<16) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/stmhal/led.c b/stmhal/led.c index fdf5b04d8e..310efdcda9 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -67,21 +67,12 @@ STATIC const pyb_led_obj_t pyb_led_obj[] = { #define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj) void led_init(void) { - /* GPIO structure */ - GPIO_InitTypeDef GPIO_InitStructure; - - /* Configure I/O speed, mode, output type and pull */ - GPIO_InitStructure.Speed = GPIO_SPEED_LOW; - GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE; - GPIO_InitStructure.Pull = GPIO_NOPULL; - /* Turn off LEDs and initialize */ for (int led = 0; led < NUM_LEDS; led++) { const pin_obj_t *led_pin = pyb_led_obj[led].led_pin; mp_hal_gpio_clock_enable(led_pin->gpio); MICROPY_HW_LED_OFF(led_pin); - GPIO_InitStructure.Pin = led_pin->pin_mask; - HAL_GPIO_Init(led_pin->gpio, &GPIO_InitStructure); + mp_hal_pin_output(led_pin); } } From 542f05d2281b165a47becd579aeeb8c3ff656e7d Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 18 Oct 2016 15:34:17 +1100 Subject: [PATCH 67/78] teensy: Update to provide new mp_hal_pin_XXX functions following stmhal. --- teensy/teensy_hal.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/teensy/teensy_hal.h b/teensy/teensy_hal.h index b00b6e4ac6..80f320e0c5 100644 --- a/teensy/teensy_hal.h +++ b/teensy/teensy_hal.h @@ -118,7 +118,9 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *init); -#define GPIO_read_pin(gpio, pin) (((gpio)->PDIR >> (pin)) & 1) -#define GPIO_set_pin(gpio, pin_mask) (((gpio)->PSOR) = (pin_mask)) -#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->PCOR) = (pin_mask)) -#define GPIO_read_output_pin(gpio, pin) (((gpio)->PDOR >> (pin)) & 1) +struct _pin_obj_t; +#define mp_hal_pin_obj_t const struct _pin_obj_t* +#define mp_hal_pin_high(p) (((p)->gpio->PSOR) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->PCOR) = (p)->pin_mask) +#define mp_hal_pin_read(p) (((p)->gpio->PDIR >> (p)->pin) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) From 20d0271863bfe231c6f0974e35d11fad60e7e832 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 18 Oct 2016 15:18:07 +0300 Subject: [PATCH 68/78] esp8266/esp_init_data: Auto-initialize system params with vendor SDK 2.0.0. SDK 2.0.0 goes into boot loop if a firmware is programmed over erased flash, causing problems with user experience. This change implements behavior similar to older SDKs': if clean flash is detected, default system parameters are used. --- esp8266/Makefile | 1 + esp8266/esp8266.ld | 2 +- esp8266/esp_init_data.c | 80 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 esp8266/esp_init_data.c diff --git a/esp8266/Makefile b/esp8266/Makefile index 1586c576ca..c57206c4dc 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -65,6 +65,7 @@ SRC_C = \ main.c \ help.c \ esp_mphal.c \ + esp_init_data.c \ gccollect.c \ lexerstr32.c \ uart.c \ diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index c726790d38..5251d16815 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -20,7 +20,7 @@ PHDRS irom0_0_phdr PT_LOAD; } -ENTRY(call_user_start) +ENTRY(firmware_start) EXTERN(_DebugExceptionVector) EXTERN(_DoubleExceptionVector) EXTERN(_KernelExceptionVector) diff --git a/esp8266/esp_init_data.c b/esp8266/esp_init_data.c new file mode 100644 index 0000000000..b229f751da --- /dev/null +++ b/esp8266/esp_init_data.c @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * 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 "ets_sys.h" +#include "etshal.h" +#include "esp_mphal.h" +#include "user_interface.h" +#include "extmod/misc.h" + +uint32_t SPIRead(uint32_t offset, void *buf, uint32_t len); +uint32_t SPIWrite(uint32_t offset, const void *buf, uint32_t len); +uint32_t SPIEraseSector(int sector); +NORETURN void call_user_start(void); +void ets_printf(const char *fmt, ...); +extern char flashchip; + +static const uint8_t default_init_data[] __attribute__((aligned(4))) = { +0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05, +0x04, 0xfe, 0xfd, 0xff, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe1, 0x0a, 0xff, 0xff, 0xf8, 0x00, +0xf8, 0xf8, 0x52, 0x4e, 0x4a, 0x44, 0x40, 0x38, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xe1, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void firmware_start(void) { + // For SDK 1.5.2, either address has shifted and not mirrored in + // eagle.rom.addr.v6.ld, or extra initial member was added. + SpiFlashChip *flash = (SpiFlashChip*)(&flashchip + 4); + + char buf[128]; + SPIRead(flash->chip_size - 4 * 0x1000, buf, sizeof(buf)); + /*for (int i = 0; i < sizeof(buf); i++) { + static char hexf[] = "%x "; + ets_printf(hexf, buf[i]); + }*/ + + bool inited = false; + for (int i = 0; i < sizeof(buf); i++) { + if (buf[i] != 0xff) { + inited = true; + break; + } + } + + if (!inited) { + static char msg[] = "Writing init data\n"; + ets_printf(msg); + SPIRead((uint32_t)&default_init_data - 0x40200000, buf, sizeof(buf)); + SPIWrite(flash->chip_size - 4 * 0x1000, buf, sizeof(buf)); + } + + asm("j call_user_start"); +} From 6566e3f6a87ea0080d93a59f750b6616276841a0 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Oct 2016 00:01:14 +0300 Subject: [PATCH 69/78] esp8266/esp8266.ld: Move help.o to iROM. --- esp8266/esp8266.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index 5251d16815..59d7dd20d4 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -132,6 +132,7 @@ SECTIONS *gccollect.o(.literal* .text*) *gchelper.o(.literal* .text*) + *help.o(.literal* .text*) *lexerstr32.o(.literal* .text*) *utils.o(.literal* .text*) *modpyb.o(.literal*, .text*) From e7e0d91be8ab717b4ba854172a44a9b561e79225 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Oct 2016 00:04:30 +0300 Subject: [PATCH 70/78] esp8266/esp8266.ld: Move modmachine.o to iROM. --- esp8266/esp8266.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index 59d7dd20d4..3329491669 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -142,6 +142,7 @@ SECTIONS *modpybadc.o(.literal*, .text*) *modpybuart.o(.literal*, .text*) *modpybi2c.o(.literal*, .text*) + *modmachine.o(.literal*, .text*) *modmachinewdt.o(.literal*, .text*) *modpybspi.o(.literal*, .text*) *modpybhspi.o(.literal*, .text*) From 462748de0c2668d40b7f2ea8f2b264d134d5d39b Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Oct 2016 00:12:54 +0300 Subject: [PATCH 71/78] esp8266/esp8266.ld: Move main.o to iROM. --- esp8266/esp8266.ld | 1 + 1 file changed, 1 insertion(+) diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index 3329491669..010a4cac60 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -130,6 +130,7 @@ SECTIONS *stmhal/pybstdio.o(.literal*, .text*) + build/main.o(.literal* .text*) *gccollect.o(.literal* .text*) *gchelper.o(.literal* .text*) *help.o(.literal* .text*) From 9514d847feb70c330d310a366b92013960729bdc Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Oct 2016 00:20:10 +0300 Subject: [PATCH 72/78] esp8266: Add MP_FASTCODE modifier to put a function to iRAM. It can be used in the following manner: void MP_FASTCODE(foo)(int arg) { ... } --- esp8266/esp8266.ld | 3 ++- esp8266/mpconfigport.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index 010a4cac60..5fb6f13796 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -202,7 +202,8 @@ SECTIONS *(.entry.text) *(.init.literal) *(.init) - *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.literal .text .literal.* .text.* .iram0.literal .iram0.text .iram0.text.*.literal .iram0.text.*) + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *(.fini.literal) *(.fini) *(.gnu.version) diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 201057f128..602b3e9c81 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -182,4 +182,6 @@ extern const struct _mp_obj_module_t onewire_module; #define MICROPY_HW_MCU_NAME "ESP8266" #define MICROPY_PY_SYS_PLATFORM "esp8266" +#define MP_FASTCODE(n) __attribute__((section(".iram0.text." #n))) n + #define _assert(expr) ((expr) ? (void)0 : __assert_func(__FILE__, __LINE__, __func__, #expr)) From 204222653edbc2d01b5aed38b1de71a767cb5748 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 19 Oct 2016 00:20:34 +0300 Subject: [PATCH 73/78] esp8266/main: Mark nlr_jump_fail() as MP_FASTCODE. It's probably not strictly needed so far, but serves as an example of MP_FASTCODE use and may be helpful in the future. --- esp8266/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp8266/main.c b/esp8266/main.c index c938dcb30b..033ab7afed 100644 --- a/esp8266/main.c +++ b/esp8266/main.c @@ -141,7 +141,7 @@ mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); -void nlr_jump_fail(void *val) { +void MP_FASTCODE(nlr_jump_fail)(void *val) { printf("NLR jump failed\n"); for (;;) { } From 17ba6ef5fa7585d3e91dada3044e8e755cf99537 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 19 Oct 2016 14:24:56 +1100 Subject: [PATCH 74/78] cc3200: Fix thread mutex's so threading works with interrupts. Running Python code on a hard interrupt is incompatible with having a GIL, because most of the time the GIL will be held by the user thread when the interrupt arrives. Hard interrupts mean that we should process them right away and hence can't wait until the GIL is released. The problem with the current code is that a hard interrupt will try to exit/enter the GIL while it is still held by the user thread, hence leading to a deadlock. This patch works around such a problem by just making GIL exit/enter a no-op when in an interrupt context, or when interrupts are disabled. See issue #2406. --- cc3200/mpthreadport.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/cc3200/mpthreadport.c b/cc3200/mpthreadport.c index dd02180982..e77ac4ae53 100644 --- a/cc3200/mpthreadport.c +++ b/cc3200/mpthreadport.c @@ -31,8 +31,10 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/mpthread.h" +#include "py/mphal.h" #include "mptask.h" #include "task.h" +#include "irq.h" #if MICROPY_PY_THREAD @@ -166,14 +168,23 @@ void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); } +// To allow hard interrupts to work with threading we only take/give the semaphore +// if we are not within an interrupt context and interrupts are enabled. + int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { - int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0); - return ret == pdTRUE; + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0); + return ret == pdTRUE; + } else { + return 1; + } } void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { - xSemaphoreGive(mutex->handle); - // TODO check return value + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + xSemaphoreGive(mutex->handle); + // TODO check return value + } } #endif // MICROPY_PY_THREAD From 84679e0c065adb357af39b9efbffcf0f3991eece Mon Sep 17 00:00:00 2001 From: Alex March Date: Tue, 18 Oct 2016 14:18:15 +0100 Subject: [PATCH 75/78] extmod/vfs_fat_file: Check fatfs f_sync() and f_close() returns for errors. --- extmod/vfs_fat_file.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index ecc9ed70f9..e269ef593c 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -110,14 +110,20 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz STATIC mp_obj_t file_obj_flush(mp_obj_t self_in) { pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); - f_sync(&self->fp); + FRESULT res = f_sync(&self->fp); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_flush_obj, file_obj_flush); STATIC mp_obj_t file_obj_close(mp_obj_t self_in) { pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); - f_close(&self->fp); + FRESULT res = f_close(&self->fp); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close); From 3f251efb9bb22fe45ef5392b8ed9d6f9148415e7 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Thu, 20 Oct 2016 16:49:45 +0300 Subject: [PATCH 76/78] esp8266/modules/webrepl: Enforce only one concurrent WebREPL connection. Concurrent WebREPL connections were never supported, now actually check for this. --- esp8266/modules/webrepl.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esp8266/modules/webrepl.py b/esp8266/modules/webrepl.py index da3e70c595..b200f4fc81 100644 --- a/esp8266/modules/webrepl.py +++ b/esp8266/modules/webrepl.py @@ -31,6 +31,10 @@ def setup_conn(port, accept_handler): def accept_conn(listen_sock): global client_s cl, remote_addr = listen_sock.accept() + if uos.dupterm(): + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return print("\nWebREPL connection from:", remote_addr) client_s = cl websocket_helper.server_handshake(cl) From b440307b4a15a540413a7a9f699d388c7428a63c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 21 Oct 2016 01:08:43 +0300 Subject: [PATCH 77/78] py/py.mk: Automatically add frozen.c to source list if FROZEN_DIR is defined. Now frozen modules generation handled fully by py.mk and available for reuse by any port. --- esp8266/Makefile | 6 +++--- py/py.mk | 4 ++++ zephyr/Makefile | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/esp8266/Makefile b/esp8266/Makefile index c57206c4dc..5f0044df05 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -7,14 +7,15 @@ MICROPY_PY_USSL = 1 MICROPY_SSL_AXTLS = 1 MICROPY_PY_BTREE = 1 +FROZEN_DIR = scripts +FROZEN_MPY_DIR = modules + # include py core make definitions include ../py/py.mk MPY_CROSS = ../mpy-cross/mpy-cross MPY_TOOL = ../tools/mpy-tool.py -FROZEN_DIR = scripts -FROZEN_MPY_DIR = modules PORT ?= /dev/ttyACM0 BAUD ?= 115200 FLASH_MODE ?= qio @@ -90,7 +91,6 @@ SRC_C = \ modmachine.c \ modonewire.c \ ets_alt_task.c \ - $(BUILD)/frozen.c \ fatfs_port.c \ axtls_helpers.c \ hspi.c \ diff --git a/py/py.mk b/py/py.mk index 8caa37f8aa..ab07bbbdec 100644 --- a/py/py.mk +++ b/py/py.mk @@ -237,6 +237,10 @@ PY_O_BASENAME = \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) +ifneq ($(FROZEN_DIR),) +PY_O += $(BUILD)/$(BUILD)/frozen.o +endif + # Sources that may contain qstrings SRC_QSTR_IGNORE = nlr% emitnx% emitnthumb% emitnarm% SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c) diff --git a/zephyr/Makefile b/zephyr/Makefile index 1db84cb320..9682dc5ccf 100644 --- a/zephyr/Makefile +++ b/zephyr/Makefile @@ -41,7 +41,6 @@ SRC_C = main.c \ lib/utils/interrupt_char.c \ lib/utils/pyhelp.c \ lib/mp-readline/readline.c \ - $(BUILD)/frozen.c \ $(SRC_MOD) # List of sources for qstr extraction From 3967ca7390ff8257728ef6237b93977b63bde41d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 21 Oct 2016 01:27:17 +0300 Subject: [PATCH 78/78] stmhal/Makefile: Use standard rules for frozen module generation. As defined in py/py.mk. --- stmhal/Makefile | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/stmhal/Makefile b/stmhal/Makefile index 06be7acc89..e2e1dc6a15 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -274,15 +274,9 @@ $(PY_BUILD)/mpprint.o: COPT += -Os all: $(BUILD)/firmware.dfu $(BUILD)/firmware.hex ifneq ($(FROZEN_DIR),) +# To use frozen source modules, put your .py files in a subdirectory (eg scripts/) +# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch). CFLAGS += -DMICROPY_MODULE_FROZEN_STR -OBJ += $(BUILD)/frozen-files.o - -$(BUILD)/frozen-files.o: $(BUILD)/frozen-files.c - $(call compile_c) - -$(BUILD)/frozen-files.c: $(shell find $(FROZEN_DIR) -type f) - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif ifneq ($(FROZEN_MPY_DIR),)