diff options
151 files changed, 1148 insertions, 386 deletions
diff --git a/.gitignore b/.gitignore index ce2e45af97..4c0191f692 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.map *.hex *.dis +*.exe # Packages ############ diff --git a/bare-arm/main.c b/bare-arm/main.c index 8ad9b15870..bdaded4362 100644 --- a/bare-arm/main.c +++ b/bare-arm/main.c @@ -2,9 +2,9 @@ #include <stdio.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "lexer.h" #include "parse.h" diff --git a/py/argcheck.c b/py/argcheck.c index 6738bb9813..1b6d3a7ec4 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -26,9 +26,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/builtin.c b/py/builtin.c index 250a3558e8..5ff40be0c2 100644 --- a/py/builtin.c +++ b/py/builtin.c @@ -1,9 +1,9 @@ #include <stdio.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objstr.h" @@ -245,7 +245,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) { mp_obj_t max_obj = NULL; mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (max_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, max_obj, item)) { + if (max_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, max_obj, item) == mp_const_true)) { max_obj = item; } } @@ -257,7 +257,7 @@ STATIC mp_obj_t mp_builtin_max(uint n_args, const mp_obj_t *args) { // given many args mp_obj_t max_obj = args[0]; for (int i = 1; i < n_args; i++) { - if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i])) { + if (mp_binary_op(MP_BINARY_OP_LESS, max_obj, args[i]) == mp_const_true) { max_obj = args[i]; } } @@ -274,7 +274,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) { mp_obj_t min_obj = NULL; mp_obj_t item; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (min_obj == NULL || mp_binary_op(MP_BINARY_OP_LESS, item, min_obj)) { + if (min_obj == NULL || (mp_binary_op(MP_BINARY_OP_LESS, item, min_obj) == mp_const_true)) { min_obj = item; } } @@ -286,7 +286,7 @@ STATIC mp_obj_t mp_builtin_min(uint n_args, const mp_obj_t *args) { // given many args mp_obj_t min_obj = args[0]; for (int i = 1; i < n_args; i++) { - if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj)) { + if (mp_binary_op(MP_BINARY_OP_LESS, args[i], min_obj) == mp_const_true) { min_obj = args[i]; } } diff --git a/py/builtinevex.c b/py/builtinevex.c index ae82537374..bc3adb6256 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -1,8 +1,8 @@ #include <stdint.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "lexer.h" #include "lexerunix.h" diff --git a/py/builtinimport.c b/py/builtinimport.c index 07978e61d7..f4e089b5d8 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -1,16 +1,12 @@ #include <stdint.h> -#include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> -#ifdef __MINGW32__ -// For alloca() -#include <malloc.h> -#endif +#include <alloca.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "lexer.h" #include "lexerunix.h" diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 34413f0beb..2ec5a1fb69 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -29,43 +29,15 @@ def compute_hash(qstr): hash = (hash * 33) ^ ord(char) return hash & 0xffff -# given a list of (name,regex) pairs, find the first one that matches the given line -def re_match_first(regexs, line): - for name, regex in regexs: - match = re.match(regex, line) - if match: - return name, match - return None, None - -# regexs to recognise lines that the CPP emits -# use a list so that matching order is honoured -cpp_regexs = [ - ('qstr', r'Q\((.+)\)$'), - ('cdecl', r'(typedef|extern) [A-Za-z0-9_* ]+;$') -] - def do_work(infiles): # read the qstrs in from the input files qstrs = {} for infile in infiles: with open(infile, 'rt') as f: - line_number = 0 for line in f: - line_number += 1 - line = line.strip() - - # ignore blank lines, comments and preprocessor directives - if len(line) == 0 or line.startswith('//') or line.startswith('#'): - continue - - # work out what kind of line it is - match_kind, match = re_match_first(cpp_regexs, line) - if match_kind is None: - # unknown line format - print('({}:{}) bad qstr format, got {}'.format(infile, line_number, line), file=sys.stderr) - return False - elif match_kind != 'qstr': - # not a line with a qstr + # is this a QSTR line? + match = re.match(r'^Q\((.+)\)$', line.strip()) + if not match: continue # get the qstr value diff --git a/py/modcmath.c b/py/modcmath.c index 80dc0c8860..cfafdf84e8 100644 --- a/py/modcmath.c +++ b/py/modcmath.c @@ -65,7 +65,7 @@ mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) { mp_obj_get_complex(z_obj, &real, &imag); mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real*real + imag*imag, 0.25); mp_float_t theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real); - return mp_obj_new_complex(sqrt_abs * cos(theta), sqrt_abs * sin(theta)); + return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt); diff --git a/py/mpconfig.h b/py/mpconfig.h index 04d4a7ddc9..8a2e96cc4a 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -94,6 +94,17 @@ typedef long long mp_longint_impl_t; #define MICROPY_ENABLE_DOC_STRING (0) #endif +// Exception messages are short static strings (TODO) +#define MICROPY_ERROR_REPORTING_TERSE (1) +// Exception messages provide basic error details +#define MICROPY_ERROR_REPORTING_NORMAL (2) +// Exception messages provide full info, e.g. object names +#define MICROPY_ERROR_REPORTING_DETAILED (3) + +#ifndef MICROPY_ERROR_REPORTING +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#endif + // Float and complex implementation #define MICROPY_FLOAT_IMPL_NONE (0) #define MICROPY_FLOAT_IMPL_FLOAT (1) @@ -3,7 +3,6 @@ #include <limits.h> #include <setjmp.h> -#include "mpconfig.h" typedef struct _nlr_buf_t nlr_buf_t; struct _nlr_buf_t { diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index a97c8634b2..a8756d9d87 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -1,5 +1,6 @@ #include <setjmp.h> #include <stdio.h> +#include "mpconfig.h" #include "nlr.h" #if MICROPY_NLR_SETJMP @@ -2,9 +2,9 @@ #include <stdarg.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" @@ -169,9 +169,10 @@ typedef mp_obj_t (*mp_fun_var_t)(uint n, const mp_obj_t *); typedef mp_obj_t (*mp_fun_kw_t)(uint n, const mp_obj_t *, mp_map_t *); typedef enum { - PRINT_STR, - PRINT_REPR, - PRINT_EXC, // Special format for printing exception in unhandled exception message + PRINT_STR = 0, + PRINT_REPR = 1, + PRINT_EXC = 2, // Special format for printing exception in unhandled exception message + PRINT_EXC_SUBCLASS = 4, // Internal flag for printing exception subclasses } mp_print_kind_t; typedef void (*mp_print_fun_t)(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o, mp_print_kind_t kind); @@ -424,6 +425,7 @@ mp_float_t mp_obj_int_as_float(mp_obj_t self_in); machine_int_t mp_obj_int_get_checked(mp_obj_t self_in); // exception +#define mp_obj_is_native_exception_instance(o) (mp_obj_get_type(o)->make_new == mp_obj_exception_make_new) bool mp_obj_is_exception_type(mp_obj_t self_in); bool mp_obj_is_exception_instance(mp_obj_t self_in); bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type); @@ -431,6 +433,7 @@ void mp_obj_exception_clear_traceback(mp_obj_t self_in); void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block); void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values); mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in); +mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args); // str mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data); @@ -508,6 +511,8 @@ typedef struct _mp_obj_fun_native_t { // need this so we can define const object bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args, uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2); +const char *mp_obj_fun_get_name(mp_obj_t fun); +const char *mp_obj_code_get_name(const byte *code_info); mp_obj_t mp_identity(mp_obj_t self); MP_DECLARE_CONST_FUN_OBJ(mp_identity_obj); diff --git a/py/objarray.c b/py/objarray.c index ea37655762..428e619723 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -1,9 +1,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objbool.c b/py/objbool.c index 56020914d0..c479fd3629 100644 --- a/py/objbool.c +++ b/py/objbool.c @@ -1,8 +1,8 @@ #include <stdlib.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objboundmeth.c b/py/objboundmeth.c index 55b75e42cd..346118d518 100644 --- a/py/objboundmeth.c +++ b/py/objboundmeth.c @@ -1,8 +1,8 @@ #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objcell.c b/py/objcell.c index 7fdf07b046..35b44e996d 100644 --- a/py/objcell.c +++ b/py/objcell.c @@ -1,6 +1,6 @@ +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -20,14 +20,13 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) { self->obj = obj; } -#if 0 +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED STATIC void cell_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_cell_t *o = o_in; - print(env, "<cell "); + print(env, "<cell %p ", o->obj); if (o->obj == MP_OBJ_NULL) { print(env, "(nil)"); } else { - //print(env, "%p", o->obj); mp_obj_print_helper(print, env, o->obj, PRINT_REPR); } print(env, ">"); @@ -36,8 +35,10 @@ STATIC void cell_print(void (*print)(void *env, const char *fmt, ...), void *env const mp_obj_type_t cell_type = { { &mp_type_type }, - .name = MP_QSTR_, // should never need to print cell type - //.print = cell_print, + .name = MP_QSTR_, // cell representation is just value in < > +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED + .print = cell_print, +#endif }; mp_obj_t mp_obj_new_cell(mp_obj_t obj) { diff --git a/py/objclosure.c b/py/objclosure.c index 09371b0348..2b83cab71a 100644 --- a/py/objclosure.c +++ b/py/objclosure.c @@ -1,8 +1,8 @@ #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objtuple.h" @@ -38,10 +38,10 @@ mp_obj_t closure_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t * } } -#if 0 +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED STATIC void closure_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_closure_t *o = o_in; - print(env, "<closure %p, n_closed=%u ", o, o->n_closed); + print(env, "<closure %s at %p, n_closed=%u ", mp_obj_fun_get_name(o->fun), o, o->n_closed); for (int i = 0; i < o->n_closed; i++) { if (o->closed[i] == MP_OBJ_NULL) { print(env, "(nil)"); @@ -57,7 +57,9 @@ STATIC void closure_print(void (*print)(void *env, const char *fmt, ...), void * const mp_obj_type_t closure_type = { { &mp_type_type }, .name = MP_QSTR_closure, - //.print = closure_print, +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED + .print = closure_print, +#endif .call = closure_call, }; diff --git a/py/objcomplex.c b/py/objcomplex.c index 9244209647..45cff6a184 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -1,9 +1,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "parsenum.h" diff --git a/py/objdict.c b/py/objdict.c index 0654a198ea..334798c372 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -2,9 +2,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objtuple.h" diff --git a/py/objexcept.c b/py/objexcept.c index 160cf09fd4..abf56ab036 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -2,12 +2,13 @@ #include <stdarg.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objtuple.h" +#include "objtype.h" #include "runtime.h" #include "runtime0.h" @@ -30,12 +31,17 @@ const mp_obj_exception_t mp_const_GeneratorExit_obj = {{&mp_type_GeneratorExit}, STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { mp_obj_exception_t *o = o_in; - if (kind == PRINT_REPR) { + mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; + bool is_subclass = kind & PRINT_EXC_SUBCLASS; + if (!is_subclass && (k == PRINT_REPR || k == PRINT_EXC)) { print(env, "%s", qstr_str(o->base.type->name)); - } else if (kind == PRINT_EXC) { - print(env, "%s: ", qstr_str(o->base.type->name)); } - if (kind == PRINT_STR || kind == PRINT_EXC) { + + if (k == PRINT_EXC) { + print(env, ": "); + } + + if (k == PRINT_STR || k == PRINT_EXC) { if (o->args == NULL || o->args->len == 0) { print(env, ""); return; @@ -47,7 +53,7 @@ STATIC void mp_obj_exception_print(void (*print)(void *env, const char *fmt, ... tuple_print(print, env, o->args, kind); } -STATIC mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { +mp_obj_t mp_obj_exception_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_obj_type_t *type = type_in; if (n_kw != 0) { @@ -266,38 +272,39 @@ bool mp_obj_exception_match(mp_obj_t exc, const mp_obj_type_t *exc_type) { return mp_binary_op(MP_BINARY_OP_EXCEPTION_MATCH, exc, (mp_obj_t)exc_type) == mp_const_true; } -void mp_obj_exception_clear_traceback(mp_obj_t self_in) { - // make sure self_in is an exception instance - // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that) - if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new) { - mp_obj_exception_t *self = self_in; - - // just set the traceback to the null object - // we don't want to call any memory management functions here - self->traceback = MP_OBJ_NULL; +// traceback handling functions + +#define GET_NATIVE_EXCEPTION(self, self_in) \ + /* make sure self_in is an exception instance */ \ + assert(mp_obj_is_exception_instance(self_in)); \ + mp_obj_exception_t *self; \ + if (mp_obj_is_native_exception_instance(self_in)) { \ + self = self_in; \ + } else { \ + self = ((mp_obj_instance_t*)self_in)->subobj[0]; \ } + +void mp_obj_exception_clear_traceback(mp_obj_t self_in) { + GET_NATIVE_EXCEPTION(self, self_in); + // just set the traceback to the null object + // we don't want to call any memory management functions here + self->traceback = MP_OBJ_NULL; } void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, machine_uint_t line, qstr block) { - // make sure self_in is an exception instance - // TODO add traceback information to user-defined exceptions (need proper builtin subclassing for that) - if (mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new && self_in != &mp_emergency_exception_obj) { - mp_obj_exception_t *self = self_in; - - // for traceback, we are just using the list object for convenience, it's not really a list of Python objects - if (self->traceback == MP_OBJ_NULL) { - self->traceback = mp_obj_new_list(0, NULL); - } - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file); - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line); - mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block); + GET_NATIVE_EXCEPTION(self, self_in); + + // for traceback, we are just using the list object for convenience, it's not really a list of Python objects + if (self->traceback == MP_OBJ_NULL) { + self->traceback = mp_obj_new_list(0, NULL); } + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)file); + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)line); + mp_obj_list_append(self->traceback, (mp_obj_t)(machine_uint_t)block); } void mp_obj_exception_get_traceback(mp_obj_t self_in, machine_uint_t *n, machine_uint_t **values) { - // make sure self_in is an exception instance - assert(mp_obj_get_type(self_in)->make_new == mp_obj_exception_make_new); - mp_obj_exception_t *self = self_in; + GET_NATIVE_EXCEPTION(self, self_in); if (self->traceback == MP_OBJ_NULL) { *n = 0; diff --git a/py/objfilter.c b/py/objfilter.c index 3eacdfc9b7..37cb269adc 100644 --- a/py/objfilter.c +++ b/py/objfilter.c @@ -1,9 +1,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objfloat.c b/py/objfloat.c index 9249160579..14d861b66f 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -4,9 +4,9 @@ #include <assert.h> #include <math.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "parsenum.h" diff --git a/py/objfun.c b/py/objfun.c index d828b6d084..4690dc6c88 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -1,15 +1,11 @@ #include <stdbool.h> -#include <stdlib.h> #include <string.h> #include <assert.h> -#ifdef __MINGW32__ -// For alloca() -#include <malloc.h> -#endif +#include <alloca.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objtuple.h" @@ -126,6 +122,24 @@ mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var /******************************************************************************/ /* byte code functions */ +const char *mp_obj_code_get_name(const byte *code_info) { + qstr block_name = code_info[8] | (code_info[9] << 8) | (code_info[10] << 16) | (code_info[11] << 24); + return qstr_str(block_name); +} + +const char *mp_obj_fun_get_name(mp_obj_t fun_in) { + mp_obj_fun_bc_t *fun = fun_in; + const byte *code_info = fun->bytecode; + return mp_obj_code_get_name(code_info); +} + +#if MICROPY_CPYTHON_COMPAT +STATIC void fun_bc_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) { + mp_obj_fun_bc_t *o = o_in; + print(env, "<function %s at 0x%x>", mp_obj_fun_get_name(o), o); +} +#endif + #if DEBUG_PRINT STATIC void dump_args(const mp_obj_t *a, int sz) { DEBUG_printf("%p: ", a); @@ -139,8 +153,18 @@ STATIC void dump_args(const mp_obj_t *a, int sz) { #endif STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, uint given) { +#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE + // Generic message, to be reused for other argument issues + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, + "argument num/types mismatch")); +#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes %d positional arguments but %d were given", expected, given)); +#elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_DETAILED + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "%s() takes %d positional arguments but %d were given", + mp_obj_fun_get_name(f), expected, given)); +#endif } // If it's possible to call a function without allocating new argument array, @@ -155,6 +179,8 @@ STATIC NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, uint expected, ui bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args, uint *out_args1_len, const mp_obj_t **out_args1, uint *out_args2_len, const mp_obj_t **out_args2) { mp_obj_fun_bc_t *self = self_in; + DEBUG_printf("mp_obj_fun_prepare_simple_args: given: %d pos, %d kw, expected: %d pos (%d default)\n", + n_args, n_kw, self->n_pos_args, self->n_def_args); assert(n_kw == 0); assert(self->n_kwonly_args == 0); @@ -167,8 +193,12 @@ bool mp_obj_fun_prepare_simple_args(mp_obj_t self_in, uint n_args, uint n_kw, co if (n_args > self->n_pos_args) { goto arg_error; } else { - extra_args -= self->n_pos_args - n_args; - n_extra_args += self->n_pos_args - n_args; + if (n_args >= self->n_pos_args - self->n_def_args) { + extra_args -= self->n_pos_args - n_args; + n_extra_args += self->n_pos_args - n_args; + } else { + fun_pos_args_mismatch(self, self->n_pos_args - self->n_def_args, n_args); + } } *out_args1 = args; *out_args1_len = n_args; @@ -335,6 +365,9 @@ continue2:; const mp_obj_type_t mp_type_fun_bc = { { &mp_type_type }, .name = MP_QSTR_function, +#if MICROPY_CPYTHON_COMPAT + .print = fun_bc_print, +#endif .call = fun_bc_call, .binary_op = fun_binary_op, }; diff --git a/py/objgenerator.c b/py/objgenerator.c index 895c03cc23..d7d6dcaaf4 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -1,9 +1,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -68,7 +68,8 @@ typedef struct _mp_obj_gen_instance_t { } mp_obj_gen_instance_t; void gen_instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { - print(env, "<generator object 'fun-name' at %p>", self_in); + mp_obj_gen_instance_t *self = self_in; + print(env, "<generator object '%s' at %p>", mp_obj_code_get_name(self->code_info), self_in); } mp_obj_t gen_instance_getiter(mp_obj_t self_in) { diff --git a/py/objgetitemiter.c b/py/objgetitemiter.c index faa8321c34..15676b452b 100644 --- a/py/objgetitemiter.c +++ b/py/objgetitemiter.c @@ -1,8 +1,8 @@ #include <stdlib.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objint.c b/py/objint.c index 110876e003..bec4e920fd 100644 --- a/py/objint.c +++ b/py/objint.c @@ -3,9 +3,9 @@ #include <assert.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "parsenum.h" diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 7d71c5a691..d319e27463 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -2,9 +2,9 @@ #include <stdint.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "mpz.h" diff --git a/py/objint_mpz.c b/py/objint_mpz.c index b94dcfee37..bfc7def357 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -3,9 +3,9 @@ #include <stdio.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "parsenumbase.h" #include "obj.h" diff --git a/py/objlist.c b/py/objlist.c index 0c55f524da..d886affff8 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -1,9 +1,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objmap.c b/py/objmap.c index 45e65549da..c6f8f16572 100644 --- a/py/objmap.c +++ b/py/objmap.c @@ -1,9 +1,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objmodule.c b/py/objmodule.c index 15ccd68ac2..d4a45b84a5 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -1,9 +1,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objmodule.h" diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 4239983589..99a1d7bb9d 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -1,7 +1,7 @@ #include <string.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "nlr.h" #include "qstr.h" #include "obj.h" diff --git a/py/objnone.c b/py/objnone.c index fc55132f39..49b726bdde 100644 --- a/py/objnone.c +++ b/py/objnone.c @@ -1,8 +1,8 @@ #include <stdlib.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objobject.c b/py/objobject.c index 74a4926b34..62fd0c4c9a 100644 --- a/py/objobject.c +++ b/py/objobject.c @@ -1,8 +1,8 @@ #include <stdlib.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objproperty.c b/py/objproperty.c index dd4eedebdb..220388df0a 100644 --- a/py/objproperty.c +++ b/py/objproperty.c @@ -1,9 +1,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objrange.c b/py/objrange.c index 8c0eadd32e..acfeed7d9c 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -1,8 +1,8 @@ #include <stdlib.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objset.c b/py/objset.c index db3683f608..1d10f94e81 100644 --- a/py/objset.c +++ b/py/objset.c @@ -2,9 +2,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objslice.c b/py/objslice.c index 924927db5f..0488eb4220 100644 --- a/py/objslice.c +++ b/py/objslice.c @@ -1,9 +1,9 @@ #include <stdlib.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objstr.c b/py/objstr.c index aab1a4492c..fc7415fe15 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -2,9 +2,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objstringio.c b/py/objstringio.c index a3a7566300..8b3dfaf61e 100644 --- a/py/objstringio.c +++ b/py/objstringio.c @@ -1,9 +1,9 @@ #include <stdio.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/objtuple.c b/py/objtuple.c index e6b902d74f..792c65193c 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -1,9 +1,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/objtype.c b/py/objtype.c index 56a5dd937d..fd187147a0 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -3,13 +3,14 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" #include "runtime.h" +#include "objtype.h" #if 0 // print debugging info #define DEBUG_PRINT (1) @@ -19,28 +20,20 @@ #endif /******************************************************************************/ -// class object -// creating an instance of a class makes one of these objects - -typedef struct _mp_obj_class_t { - mp_obj_base_t base; - mp_map_t members; - mp_obj_t subobj[]; - // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them -} mp_obj_class_t; +// instance object -#define is_native_type(type) ((type)->make_new != class_make_new) -STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args); +#define is_native_type(type) ((type)->make_new != instance_make_new) +STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args); -STATIC mp_obj_t mp_obj_new_class(mp_obj_t class, uint subobjs) { - mp_obj_class_t *o = m_new_obj_var(mp_obj_class_t, mp_obj_t, subobjs); +STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) { + mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs); o->base.type = class; mp_map_init(&o->members, 0); mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj)); return o; } -STATIC int class_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) { +STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) { uint len; mp_obj_t *items; mp_obj_tuple_get(type->bases_tuple, &len, &items); @@ -52,7 +45,7 @@ STATIC int class_count_native_bases(const mp_obj_type_t *type, const mp_obj_type *last_native_base = items[i]; count++; } else { - count += class_count_native_bases(items[i], last_native_base); + count += instance_count_native_bases(items[i], last_native_base); } } @@ -70,8 +63,8 @@ STATIC int class_count_native_bases(const mp_obj_type_t *type, const mp_obj_type // applies to instance->subobj[0]. In most cases, we also don't need to know which type // it was - because instance->subobj[0] is of that type. The only exception is when // object is not yet constructed, then we need to know base native type to construct -// instance->subobj[0]. This case is handled via class_count_native_bases() though. -STATIC void mp_obj_class_lookup(mp_obj_class_t *o, const mp_obj_type_t *type, qstr attr, machine_uint_t meth_offset, mp_obj_t *dest) { +// instance->subobj[0]. This case is handled via instance_count_native_bases() though. +STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type, qstr attr, machine_uint_t meth_offset, mp_obj_t *dest) { assert(dest[0] == NULL); assert(dest[1] == NULL); for (;;) { @@ -137,8 +130,8 @@ STATIC void mp_obj_class_lookup(mp_obj_class_t *o, const mp_obj_type_t *type, qs } } -STATIC void class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { - mp_obj_class_t *self = self_in; +STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + mp_obj_instance_t *self = self_in; qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__; mp_obj_t member[2] = {MP_OBJ_NULL}; mp_obj_class_lookup(self, self->base.type, meth, offsetof(mp_obj_type_t, print), member); @@ -148,7 +141,15 @@ STATIC void class_print(void (*print)(void *env, const char *fmt, ...), void *en } if (member[0] == MP_OBJ_SENTINEL) { - mp_obj_print_helper(print, env, self->subobj[0], kind); + // Handle Exception subclasses specially + if (mp_obj_is_native_exception_instance(self->subobj[0])) { + if (kind != PRINT_STR) { + print(env, "%s", qstr_str(self->base.type->name)); + } + mp_obj_print_helper(print, env, self->subobj[0], kind | PRINT_EXC_SUBCLASS); + } else { + mp_obj_print_helper(print, env, self->subobj[0], kind); + } return; } @@ -162,15 +163,15 @@ STATIC void class_print(void (*print)(void *env, const char *fmt, ...), void *en print(env, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in); } -STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { +STATIC mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); mp_obj_type_t *self = self_in; const mp_obj_type_t *native_base; - uint num_native_bases = class_count_native_bases(self, &native_base); + uint num_native_bases = instance_count_native_bases(self, &native_base); assert(num_native_bases < 2); - mp_obj_class_t *o = mp_obj_new_class(self_in, num_native_bases); + mp_obj_instance_t *o = mp_obj_new_instance(self_in, num_native_bases); // look for __init__ function mp_obj_t init_fn[2] = {MP_OBJ_NULL}; @@ -188,7 +189,7 @@ STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const m // now call Python class __init__ function with all args mp_obj_t init_ret; if (n_args == 0 && n_kw == 0) { - init_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)&o); + init_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&o); } else { mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw); args2[0] = o; @@ -218,8 +219,8 @@ STATIC const qstr unary_op_method_name[] = { [MP_UNARY_OP_NOT] = MP_QSTR_, // don't need to implement this, used to make sure array has full size }; -STATIC mp_obj_t class_unary_op(int op, mp_obj_t self_in) { - mp_obj_class_t *self = self_in; +STATIC mp_obj_t instance_unary_op(int op, mp_obj_t self_in) { + mp_obj_instance_t *self = self_in; qstr op_name = unary_op_method_name[op]; /* Still try to lookup native slot if (op_name == 0) { @@ -281,7 +282,7 @@ STATIC const qstr binary_op_method_name[] = { // and put the result in the dest[] array for a possible method call. // Conversion means dealing with static/class methods, callables, and values. // see http://docs.python.org/3.3/howto/descriptor.html -STATIC void class_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_t *dest) { +STATIC void instance_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_t *dest) { assert(dest[1] == NULL); if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { // return just the function @@ -300,10 +301,10 @@ STATIC void class_convert_return_attr(mp_obj_t self, mp_obj_t member, mp_obj_t * } } -STATIC mp_obj_t class_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { +STATIC mp_obj_t instance_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { // Note: For ducktyping, CPython does not look in the instance members or use // __getattr__ or __getattribute__. It only looks in the class dictionary. - mp_obj_class_t *lhs = lhs_in; + mp_obj_instance_t *lhs = lhs_in; qstr op_name = binary_op_method_name[op]; /* Still try to lookup native slot if (op_name == 0) { @@ -317,7 +318,7 @@ STATIC mp_obj_t class_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } else if (member[0] != MP_OBJ_NULL) { mp_obj_t dest[3]; dest[1] = MP_OBJ_NULL; - class_convert_return_attr(lhs_in, member[0], dest); + instance_convert_return_attr(lhs_in, member[0], dest); dest[2] = rhs_in; return mp_call_method_n_kw(1, 0, dest); } else { @@ -325,9 +326,9 @@ STATIC mp_obj_t class_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } } -STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // logic: look in obj members then class locals (TODO check this against CPython) - mp_obj_class_t *self = self_in; + mp_obj_instance_t *self = self_in; mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); if (elem != NULL) { @@ -345,13 +346,13 @@ STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } else if (MP_OBJ_IS_TYPE(member, &mp_type_property)) { // object member is a property // delegate the store to the property - // TODO should this be part of class_convert_return_attr? + // TODO should this be part of instance_convert_return_attr? const mp_obj_t *proxy = mp_obj_property_get(member); if (proxy[0] == mp_const_none) { // TODO } else { dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in); - // TODO should we convert the returned value using class_convert_return_attr? + // TODO should we convert the returned value using instance_convert_return_attr? } #endif } else { @@ -359,7 +360,7 @@ STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // if we don't yet have bound method (supposedly from native base), go // try to convert own attrs. if (dest[1] == MP_OBJ_NULL) { - class_convert_return_attr(self_in, member, dest); + instance_convert_return_attr(self_in, member, dest); } } return; @@ -379,8 +380,8 @@ STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } } -STATIC bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { - mp_obj_class_t *self = self_in; +STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { + mp_obj_instance_t *self = self_in; #if MICROPY_ENABLE_PROPERTY // for property, we need to do a lookup first in the class dict @@ -413,8 +414,8 @@ STATIC bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { } } -STATIC mp_obj_t class_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - mp_obj_class_t *self = self_in; +STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + mp_obj_instance_t *self = self_in; mp_obj_t member[2] = {MP_OBJ_NULL}; uint meth_args; if (value == MP_OBJ_NULL) { @@ -434,7 +435,7 @@ STATIC mp_obj_t class_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { return mp_obj_subscr(self->subobj[0], index, value); } else if (member[0] != MP_OBJ_NULL) { mp_obj_t args[3] = {self_in, index, value}; - // TODO probably need to call class_convert_return_attr, and use mp_call_method_n_kw + // TODO probably need to call instance_convert_return_attr, and use mp_call_method_n_kw mp_obj_t ret = mp_call_function_n_kw(member[0], meth_args, 0, args); if (value == MP_OBJ_SENTINEL) { return ret; @@ -446,8 +447,8 @@ STATIC mp_obj_t class_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { } } -STATIC mp_obj_t class_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { - mp_obj_class_t *self = self_in; +STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { + mp_obj_instance_t *self = self_in; mp_obj_t member[2] = {MP_OBJ_NULL}; mp_obj_class_lookup(self, self->base.type, MP_QSTR___call__, offsetof(mp_obj_type_t, call), member); if (member[0] == MP_OBJ_NULL) { @@ -604,19 +605,19 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_obj_type_t *o = m_new0(mp_obj_type_t, 1); o->base.type = &mp_type_type; o->name = name; - o->print = class_print; - o->make_new = class_make_new; - o->unary_op = class_unary_op; - o->binary_op = class_binary_op; - o->load_attr = class_load_attr; - o->store_attr = class_store_attr; - o->subscr = class_subscr; - o->call = class_call; + o->print = instance_print; + o->make_new = instance_make_new; + o->unary_op = instance_unary_op; + o->binary_op = instance_binary_op; + o->load_attr = instance_load_attr; + o->store_attr = instance_store_attr; + o->subscr = instance_subscr; + o->call = instance_call; o->bases_tuple = bases_tuple; o->locals_dict = locals_dict; const mp_obj_type_t *native_base; - uint num_native_bases = class_count_native_bases(o, &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")); } @@ -673,7 +674,7 @@ STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_t member[2] = {MP_OBJ_NULL}; mp_obj_class_lookup(self->obj, (mp_obj_type_t*)items[i], attr, 0, member); if (member[0] != MP_OBJ_NULL) { - class_convert_return_attr(self->obj, member[0], dest); + instance_convert_return_attr(self->obj, member[0], dest); return; } } diff --git a/py/objtype.h b/py/objtype.h new file mode 100644 index 0000000000..c3176c3282 --- /dev/null +++ b/py/objtype.h @@ -0,0 +1,8 @@ +// instance object +// creating an instance of a class makes one of these objects +typedef struct _mp_obj_instance_t { + mp_obj_base_t base; + mp_map_t members; + mp_obj_t subobj[]; + // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them +} mp_obj_instance_t; diff --git a/py/objzip.c b/py/objzip.c index 4c7070b7c7..c3bffd830d 100644 --- a/py/objzip.c +++ b/py/objzip.c @@ -1,8 +1,8 @@ #include <stdlib.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/opmethods.c b/py/opmethods.c index a745ec1227..b029eef7c5 100644 --- a/py/opmethods.c +++ b/py/opmethods.c @@ -1,6 +1,6 @@ +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/py/py-version.sh b/py/py-version.sh index f574b574f4..42474ef6a5 100755 --- a/py/py-version.sh +++ b/py/py-version.sh @@ -1,5 +1,6 @@ #!/bin/bash +git_tag="$(git describe --dirty || echo unknown)" git_hash="$(git rev-parse --short HEAD 2> /dev/null || echo unknown)" git_files_are_clean=1 # Check if there are any modified files. @@ -11,6 +12,7 @@ if [ "${git_files_are_clean}" != "1" ]; then fi cat <<EOF // This file was generated by py/py-version.sh +#define MICROPY_GIT_TAG "${git_tag}" #define MICROPY_GIT_HASH "${git_hash}" #define MICROPY_BUILD_DATE "$(date '+%Y-%m-%d')" EOF diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 6960bd06cb..bcaed02d8b 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -314,6 +314,7 @@ Q(unpack) Q(io) Q(readall) Q(readline) +Q(readlines) Q(StringIO) Q(BytesIO) Q(getvalue) diff --git a/py/runtime.c b/py/runtime.c index b56740a022..ba78ec40f3 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -2,9 +2,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objtuple.h" @@ -42,6 +42,11 @@ const mp_obj_module_t mp_module___main__ = { }; void mp_init(void) { + // call port specific initialization if any +#ifdef MICROPY_PORT_INIT_FUNC + MICROPY_PORT_INIT_FUNC; +#endif + mp_emit_glue_init(); // init global module stuff diff --git a/py/sequence.c b/py/sequence.c index f91bf43c74..9fce1c51ad 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -2,9 +2,9 @@ #include <stdbool.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime0.h" diff --git a/py/showbc.c b/py/showbc.c index e3032e8d98..b5b5ce44aa 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -1,8 +1,8 @@ #include <stdio.h> #include <assert.h> -#include "misc.h" #include "mpconfig.h" +#include "misc.h" #include "qstr.h" #include "bc0.h" diff --git a/py/stream.c b/py/stream.c index 72e6ab509d..f20ee0f5e8 100644 --- a/py/stream.c +++ b/py/stream.c @@ -1,8 +1,8 @@ #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "stream.h" @@ -123,8 +123,7 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) { while (max_size == -1 || max_size-- != 0) { char *p = vstr_add_len(vstr, 1); if (p == NULL) { - // TODO - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError/*&mp_type_RuntimeError*/, "Out of memory")); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_MemoryError, "out of memory")); } machine_int_t out_sz = o->type->stream_p->read(o, p, 1, &error); @@ -143,16 +142,29 @@ STATIC mp_obj_t stream_unbuffered_readline(uint n_args, const mp_obj_t *args) { break; } } - // TODO don't intern this string - vstr_shrink(vstr); - return MP_OBJ_NEW_QSTR(qstr_from_strn_take(vstr_str(vstr), vstr->alloc, vstr_len(vstr))); + // TODO need a string creation API that doesn't copy the given data + mp_obj_t ret = mp_obj_new_str((byte*)vstr->buf, vstr->len, false); + vstr_free(vstr); + return ret; +} + +// TODO take an optional extra argument (what does it do exactly?) +STATIC mp_obj_t stream_unbuffered_readlines(mp_obj_t self) { + mp_obj_t lines = mp_obj_new_list(0, NULL); + for (;;) { + mp_obj_t line = stream_unbuffered_readline(1, &self); + if (mp_obj_str_get_len(line) == 0) { + break; + } + mp_obj_list_append(lines, line); + } + return lines; } +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj, stream_unbuffered_readlines); mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self) { mp_obj_t l_in = stream_unbuffered_readline(1, &self); - uint sz; - mp_obj_str_get_data(l_in, &sz); - if (sz != 0) { + if (mp_obj_str_get_len(l_in) != 0) { return l_in; } return MP_OBJ_STOP_ITERATION; diff --git a/py/stream.h b/py/stream.h index a0cc34797b..cb70a3d914 100644 --- a/py/stream.h +++ b/py/stream.h @@ -1,7 +1,8 @@ -extern const mp_obj_fun_native_t mp_stream_read_obj; -extern const mp_obj_fun_native_t mp_stream_readall_obj; -extern const mp_obj_fun_native_t mp_stream_unbuffered_readline_obj; -extern const mp_obj_fun_native_t mp_stream_write_obj; +MP_DECLARE_CONST_FUN_OBJ(mp_stream_read_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_readall_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readline_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_unbuffered_readlines_obj); +MP_DECLARE_CONST_FUN_OBJ(mp_stream_write_obj); // Iterator which uses mp_stream_unbuffered_readline_obj mp_obj_t mp_stream_unbuffered_iter(mp_obj_t self); @@ -2,9 +2,9 @@ #include <string.h> #include <assert.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "emitglue.h" diff --git a/qemu-arm/main.c b/qemu-arm/main.c index 6ecc9a4b2e..91c096289e 100644 --- a/qemu-arm/main.c +++ b/qemu-arm/main.c @@ -2,9 +2,9 @@ #include <stdio.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "lexer.h" #include "parse.h" diff --git a/stmhal/.gitignore b/stmhal/.gitignore new file mode 100644 index 0000000000..61ad25738f --- /dev/null +++ b/stmhal/.gitignore @@ -0,0 +1,5 @@ +build-PYBV3/ +build-PYBV4/ +build-PYBV10/ +build-STM32F4DISC/ +build-NETDUINO_PLUS_2/ diff --git a/stmhal/Makefile b/stmhal/Makefile index a32d9afbba..e27dd7b6ce 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -1,3 +1,13 @@ +# Select the board to build for: if not given on the command line, +# then default to PYBV10. +BOARD ?= PYBV10 +ifeq ($(wildcard boards/$(BOARD)/.),) +$(error Invalid BOARD specified) +endif + +# If the build directory is not given, make it reflect the board name. +BUILD ?= build-$(BOARD) + include ../py/mkenv.mk # qstr definitions (must come before including py.mk) @@ -13,6 +23,9 @@ USBDEV_DIR=usbdev FATFS_DIR=fatfs CC3K_DIR=cc3k DFU=../tools/dfu.py +# may need to prefix dfu-util with sudo +DFU_UTIL=dfu-util +DEVICE=0483:df11 CROSS_COMPILE = arm-none-eabi- @@ -30,10 +43,6 @@ INC += -I$(CC3K_DIR) CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 $(CFLAGS_CORTEX_M4) $(COPT) -BOARD ?= PYBV10 -ifeq ($(wildcard boards/$(BOARD)/.),) -$(error Invalid BOARD specified) -endif CFLAGS += -Iboards/$(BOARD) #Debugging/Optimization @@ -187,19 +196,21 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_FATFS:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_CC3K:.c=.o)) OBJ += $(BUILD)/pins_$(BOARD).o -all: $(BUILD)/flash.dfu +all: $(BUILD)/firmware.dfu -$(BUILD)/flash.dfu: $(BUILD)/flash0.bin $(BUILD)/flash1.bin - $(ECHO) "Create $@" - $(Q)$(PYTHON) $(DFU) -b 0x08000000:$(BUILD)/flash0.bin -b 0x08020000:$(BUILD)/flash1.bin $@ +.PHONY: deploy -$(BUILD)/flash0.bin: $(BUILD)/flash.elf - $(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $@ +deploy: $(BUILD)/firmware.dfu + $(ECHO) "Writing $< to the board" + $(Q)$(DFU_UTIL) -a 0 -d $(DEVICE) -D $< -$(BUILD)/flash1.bin: $(BUILD)/flash.elf - $(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $@ +$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf + $(ECHO) "Create $@" + $(Q)$(OBJCOPY) -O binary -j .isr_vector $^ $(BUILD)/firmware0.bin + $(Q)$(OBJCOPY) -O binary -j .text -j .data $^ $(BUILD)/firmware1.bin + $(Q)$(PYTHON) $(DFU) -b 0x08000000:$(BUILD)/firmware0.bin -b 0x08020000:$(BUILD)/firmware1.bin $@ -$(BUILD)/flash.elf: $(OBJ) +$(BUILD)/firmware.elf: $(OBJ) $(ECHO) "LINK $@" $(Q)$(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS) $(Q)$(SIZE) $@ diff --git a/stmhal/accel.c b/stmhal/accel.c index d3373f1ebd..64ed8b2f1d 100644 --- a/stmhal/accel.c +++ b/stmhal/accel.c @@ -3,9 +3,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/stmhal/adc.c b/stmhal/adc.c index 0cc2a9a904..e04571abee 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -2,9 +2,9 @@ #include <stm32f4xx_hal.h> #include <string.h> +#include "mpconfig.h" #include "misc.h" #include "nlr.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/stmhal/autoflash b/stmhal/autoflash index dc28a97e29..d2240ccb55 100755 --- a/stmhal/autoflash +++ b/stmhal/autoflash @@ -8,6 +8,7 @@ # - run a terminal SERIAL=/dev/ttyACM0 +DEVICE=0483:df11 while true; do echo "waiting for DFU device..." @@ -19,7 +20,7 @@ while true; do done echo "found DFU device, flashing" - dfu-util -a 0 -D build/flash.dfu + dfu-util -a 0 -d $DEVICE -D build/flash.dfu echo "waiting for DFU to exit..." while true; do diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h index b70b56d9ce..0e40545253 100644 --- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -11,7 +11,6 @@ #define MICROPY_HW_HAS_MMA7660 (0) #define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (0) -#define MICROPY_HW_HAS_WLAN (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (0) #define MICROPY_HW_ENABLE_TIMER (1) @@ -20,6 +19,7 @@ #define MICROPY_HW_ENABLE_I2C1 (0) #define MICROPY_HW_ENABLE_SPI1 (0) #define MICROPY_HW_ENABLE_SPI3 (0) +#define MICROPY_HW_ENABLE_CC3K (0) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_B11) diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h index fc22f63341..3def531232 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -7,7 +7,6 @@ #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) -#define MICROPY_HW_HAS_WLAN (1) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) @@ -16,6 +15,7 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) +#define MICROPY_HW_ENABLE_CC3K (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h index 02ad78a64c..ac0d84ca29 100644 --- a/stmhal/boards/PYBV3/mpconfigboard.h +++ b/stmhal/boards/PYBV3/mpconfigboard.h @@ -7,15 +7,15 @@ #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (0) -#define MICROPY_HW_HAS_WLAN (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) -#define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_DAC (1) #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) +#define MICROPY_HW_ENABLE_CC3K (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_A13) diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h index 550f1633f9..9fedb70136 100644 --- a/stmhal/boards/PYBV4/mpconfigboard.h +++ b/stmhal/boards/PYBV4/mpconfigboard.h @@ -7,7 +7,6 @@ #define MICROPY_HW_HAS_MMA7660 (1) #define MICROPY_HW_HAS_LIS3DSH (0) #define MICROPY_HW_HAS_LCD (1) -#define MICROPY_HW_HAS_WLAN (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) @@ -16,6 +15,7 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) +#define MICROPY_HW_ENABLE_CC3K (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h index c83bb162bb..e6780eacbd 100644 --- a/stmhal/boards/STM32F4DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h @@ -7,7 +7,6 @@ #define MICROPY_HW_HAS_MMA7660 (0) #define MICROPY_HW_HAS_LIS3DSH (1) #define MICROPY_HW_HAS_LCD (0) -#define MICROPY_HW_HAS_WLAN (0) #define MICROPY_HW_ENABLE_RNG (1) #define MICROPY_HW_ENABLE_RTC (1) #define MICROPY_HW_ENABLE_TIMER (1) @@ -16,6 +15,7 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) +#define MICROPY_HW_ENABLE_CC3K (0) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) diff --git a/stmhal/boards/stm32f4xx-af.csv b/stmhal/boards/stm32f4xx-af.csv index 0a21fc87d6..5746ac8cc9 100644 --- a/stmhal/boards/stm32f4xx-af.csv +++ b/stmhal/boards/stm32f4xx-af.csv @@ -16,20 +16,20 @@ PortA,PA12,,TIM1_ETR,,,,,,USART1_RTS,,CAN1_TX,OTG_FS_DP,,,,,EVENTOUT PortA,PA13,JTMS-SWDIO,,,,,,,,,,,,,,,EVENTOUT PortA,PA14,JTCK-SWCLK,,,,,,,,,,,,,,,EVENTOUT PortA,PA15,JTDI,TIM2_CH1/TIM2_ETR,,,,SPI1_NSS,SPI3_NSS/I2S3_WS,,,,,,,,,EVENTOUT -PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,AC12_IN8 +PortB,PB0,,TIM1_CH2N,TIM3_CH3,TIM8_CH2N,,,,,,,OTG_HS_ULPI_D1,ETH_MII_RXD2,,,,EVENTOUT,ADC12_IN8 PortB,PB1,,TIM1_CH3N,TIM3_CH4,TIM8_CH3N,,,,,,,OTG_HS_ULPI_D2,ETH_MII_RXD3,,,,EVENTOUT,ADC12_IN9 PortB,PB2,,,,,,,,,,,,,,,,EVENTOUT -PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCKI2S3_CK,,,,,,,,,EVENTOUT +PortB,PB3,JTDO/TRACESWO,TIM2_CH2,,,,SPI1_SCK,SPI3_SCK/I2S3_CK,,,,,,,,,EVENTOUT PortB,PB4,NJTRST,,TIM3_CH1,,,SPI1_MISO,SPI3_MISO,I2S3ext_SD,,,,,,,,EVENTOUT PortB,PB5,,,TIM3_CH2,,I2C1_SMBA,SPI1_MOSI,SPI3_MOSI/I2S3_SD,,,CAN2_RX,OTG_HS_ULPI_D7,ETH_PPS_OUT,,DCMI_D10,,EVENTOUT PortB,PB6,,,TIM4_CH1,,I2C1_SCL,,,USART1_TX,,CAN2_TX,,,,DCMI_D5,,EVENTOUT PortB,PB7,,,TIM4_CH2,,I2C1_SDA,,,USART1_RX,,,,,FSMC_NL,DCMI_VSYNC,,EVENTOUT PortB,PB8,,,TIM4_CH3,TIM10_CH1,I2C1_SCL,,,,,CAN1_RX,,ETH_MII_TXD3,SDIO_D4,DCMI_D6,,EVENTOUT PortB,PB9,,,TIM4_CH4,TIM11_CH1,I2C1_SDA,SPI2_NSS/I2S2_WS,,,,CAN1_TX,,,SDIO_D5,DCMI_D7,,EVENTOUT -PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCKI2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,,EVENTOUT +PortB,PB10,,TIM2_CH3,,,I2C2_SCL,SPI2_SCK/I2S2_CK,,USART3_TX,,,OTG_HS_ULPI_D3,ETH_MII_RX_ER,,,,EVENTOUT PortB,PB11,,TIM2_CH4,,,I2C2_SDA,,,USART3_RX,,,OTG_HS_ULPI_D4,ETH_MII_TX_EN/ETH_RMII_TX_EN,,,,EVENTOUT PortB,PB12,,TIM1_BKIN,,,I2C2_SMBA,SPI2_NSS/I2S2_WS,,USART3_CK,,CAN2_RX,OTG_HS_ULPI_D5,ETH_MII_TXD0/ETH_RMII_TXD0,OTG_HS_ID,,,EVENTOUT -PortB,PB13,,TIM1_CH1N,,,,SPI2_SCKI2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT +PortB,PB13,,TIM1_CH1N,,,,SPI2_SCK/I2S2_CK,,USART3_CTS,,CAN2_TX,OTG_HS_ULPI_D6,ETH_MII_TXD1/ETH_RMII_TXD1,,,,EVENTOUT PortB,PB14,,TIM1_CH2N,,TIM8_CH2N,,SPI2_MISO,I2S2ext_SD,USART3_RTS,,TIM12_CH1,,,OTG_HS_DM,,,EVENTOUT PortB,PB15,RTC_REFIN,TIM1_CH3N,,TIM8_CH3N,,SPI2_MOSI/I2S2_SD,,,,TIM12_CH2,,,OTG_HS_DP,,,EVENTOUT PortC,PC0,,,,,,,,,,,OTG_HS_ULPI_STP,,,,,EVENTOUT,ADC123_IN10 @@ -129,7 +129,7 @@ PortH,PH13,,,,TIM8_CH1N,,,,,,CAN1_TX,,,,,,EVENTOUT PortH,PH14,,,,TIM8_CH2N,,,,,,,,,,DCMI_D4,,EVENTOUT PortH,PH15,,,,TIM8_CH3N,,,,,,,,,,DCMI_D11,,EVENTOUT PortI,PI0,,,TIM5_CH4,,,SPI2_NSS/I2S2_WS,,,,,,,,DCMI_D13,,EVENTOUT -PortI,PI1,,,,,,SPI2_SCKI2S2_CK,,,,,,,,DCMI_D8,,EVENTOUT +PortI,PI1,,,,,,SPI2_SCK/I2S2_CK,,,,,,,,DCMI_D8,,EVENTOUT PortI,PI2,,,,TIM8_CH4,,SPI2_MISO,I2S2ext_SD,,,,,,,DCMI_D9,,EVENTOUT PortI,PI3,,,,TIM8_ETR,,SPI2_MOSI/I2S2_SD,,,,,,,,DCMI_D10,,EVENTOUT PortI,PI4,,,,TIM8_BKIN,,,,,,,,,,DCMI_D5,,EVENTOUT diff --git a/stmhal/bufhelper.c b/stmhal/bufhelper.c index 5612a048dc..c5dcd6c1d2 100644 --- a/stmhal/bufhelper.c +++ b/stmhal/bufhelper.c @@ -4,7 +4,7 @@ #include "obj.h" #include "bufhelper.h" -void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, uint8_t *tmp_data) { +void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data) { if (MP_OBJ_IS_INT(o)) { tmp_data[0] = mp_obj_get_int(o); bufinfo->buf = tmp_data; diff --git a/stmhal/bufhelper.h b/stmhal/bufhelper.h index 9b58e817c8..53ab7ab3e0 100644 --- a/stmhal/bufhelper.h +++ b/stmhal/bufhelper.h @@ -1,2 +1,2 @@ -void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, uint8_t *tmp_data); +void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, byte *tmp_data); mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, mp_buffer_info_t *bufinfo); diff --git a/stmhal/cc3k/cc3000_common.c b/stmhal/cc3k/cc3000_common.c index 48eda26760..8d9bd7d03a 100644 --- a/stmhal/cc3k/cc3000_common.c +++ b/stmhal/cc3k/cc3000_common.c @@ -52,6 +52,9 @@ * *****************************************************************************/ #include <stdint.h> +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "cc3000_common.h" #include "socket.h" @@ -194,3 +197,5 @@ uint32_t STREAM_TO_UINT32_f(char * cp, uint16_t offset) //! @} // //***************************************************************************** + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/ccspi.c b/stmhal/cc3k/ccspi.c index 4785897e13..133b17d030 100644 --- a/stmhal/cc3k/ccspi.c +++ b/stmhal/cc3k/ccspi.c @@ -42,6 +42,9 @@ *****************************************************************************/ #include <stdint.h> #include <string.h> // for memset +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "ccspi.h" #include "hci.h" @@ -735,3 +738,5 @@ void cc3k_int_poll() SpiIntGPIOHandler(); } } + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/evnt_handler.c b/stmhal/cc3k/evnt_handler.c index 5a75fadcc0..cca2e796d7 100644 --- a/stmhal/cc3k/evnt_handler.c +++ b/stmhal/cc3k/evnt_handler.c @@ -52,6 +52,9 @@ //****************************************************************************** #include <stdint.h> +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "cc3000_common.h" #include "string.h" @@ -871,3 +874,5 @@ SimpleLinkWaitData(unsigned char *pBuf, unsigned char *from, //! @} // //***************************************************************************** + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/hci.c b/stmhal/cc3k/hci.c index ef77db95f9..533311f175 100644 --- a/stmhal/cc3k/hci.c +++ b/stmhal/cc3k/hci.c @@ -50,6 +50,9 @@ #include <stdint.h> #include <string.h> // for memcpy +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "cc3000_common.h" #include "hci.h" @@ -240,3 +243,5 @@ hci_patch_send(unsigned char ucOpcode, unsigned char *pucBuff, char *patch, unsi // // //***************************************************************************** + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/netapp.c b/stmhal/cc3k/netapp.c index 4b3efb24df..cdeccefc46 100644 --- a/stmhal/cc3k/netapp.c +++ b/stmhal/cc3k/netapp.c @@ -41,6 +41,9 @@ * *****************************************************************************/ #include <stdint.h> +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "netapp.h" #include "hci.h" @@ -475,3 +478,5 @@ long netapp_set_debug_level(unsigned long ulLevel) } #endif + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/nvmem.c b/stmhal/cc3k/nvmem.c index 4113620086..774759c41f 100644 --- a/stmhal/cc3k/nvmem.c +++ b/stmhal/cc3k/nvmem.c @@ -50,6 +50,9 @@ #include <stdint.h> #include <string.h> +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "nvmem.h" #include "hci.h" @@ -364,3 +367,4 @@ nvmem_create_entry(unsigned long ulFileId, unsigned long ulNewLen) // //***************************************************************************** +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/pybcc3k.c b/stmhal/cc3k/pybcc3k.c index 17b205b949..d43f42f0ba 100644 --- a/stmhal/cc3k/pybcc3k.c +++ b/stmhal/cc3k/pybcc3k.c @@ -2,9 +2,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -17,6 +17,8 @@ #include "ccdebug.h" #include "pybcc3k.h" +#if MICROPY_HW_ENABLE_CC3K + // IRQ on PA14, input, pulled up, active low // EN on PC7, output, active high // CS on PC6, output, active low @@ -165,3 +167,5 @@ uint8_t pyb_cc3000_spi_send(uint8_t val) { HAL_SPI_TransmitReceive(&SPI_HANDLE, data, data, 1, 1000); return data[0]; } + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/security.c b/stmhal/cc3k/security.c index c12aee370d..c52d7f67e6 100644 --- a/stmhal/cc3k/security.c +++ b/stmhal/cc3k/security.c @@ -41,6 +41,9 @@ //***************************************************************************** #include <stdint.h> +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "security.h" @@ -533,3 +536,5 @@ signed long aes_write_key(unsigned char *key) //! @} // //***************************************************************************** + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/socket.c b/stmhal/cc3k/socket.c index cfccbd7831..86a4549ecf 100644 --- a/stmhal/cc3k/socket.c +++ b/stmhal/cc3k/socket.c @@ -50,6 +50,9 @@ #include <stdint.h> #include <string.h> // for memcpy +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "hci.h" #include "socket.h" @@ -1188,3 +1191,5 @@ mdnsAdvertiser(unsigned short mdnsEnabled, char * deviceServiceName, unsigned sh return ret; } + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/cc3k/wlan.c b/stmhal/cc3k/wlan.c index be6b3242ce..b22796a7c8 100644 --- a/stmhal/cc3k/wlan.c +++ b/stmhal/cc3k/wlan.c @@ -49,6 +49,9 @@ //***************************************************************************** #include <stdlib.h> #include <stdint.h> +#include "mpconfigport.h" + +#if MICROPY_HW_ENABLE_CC3K #include "wlan.h" #include "hci.h" @@ -1262,3 +1265,5 @@ wlan_smart_config_process() //! @} // //***************************************************************************** + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/dac.c b/stmhal/dac.c index cd62f017fb..56674c4313 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -3,9 +3,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "parse.h" #include "obj.h" @@ -16,6 +16,31 @@ /// \moduleref pyb /// \class DAC - digital to analog conversion /// +/// The DAC is used to output analog values (a specific voltage) on pin X5 or pin X6. +/// The voltage will be between 0 and 3.3V. +/// +/// *This module will undergo changes to the API.* +/// +/// Example usage: +/// +/// from pyb import DAC +/// +/// dac = DAC(1) # create DAC 1 on pin X5 +/// dac.write(128) # write a value to the DAC (makes X5 1.65V) +/// +/// To output a continuous sine-wave: +/// +/// import math +/// from pyb import DAC +/// +/// # create a buffer containing a sine-wave +/// buf = bytearray(100) +/// for i in range(len(buf)): +/// buf[i] = 128 + 127 * math.sin(2 * math.pi * i / len(buf)) +/// +/// # output the sine-wave at 400Hz +/// dac = DAC(1) +/// dac.write_timed(buf, 400 * len(buf), mode=DAC.CIRCULAR) STATIC DAC_HandleTypeDef DAC_Handle; @@ -52,6 +77,10 @@ typedef struct _pyb_dac_obj_t { // create the dac object // currently support either DAC1 on X5 (id = 1) or DAC2 on X6 (id = 2) +/// \classmethod \constructor(id) +/// Construct a new DAC object. +/// +/// `id` can be 1 or 2: DAC 1 is on pin X5 and DAC 2 is on pin X6. STATIC mp_obj_t pyb_dac_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { // check arguments mp_arg_check_num(n_args, n_kw, 1, 1, false); @@ -93,6 +122,9 @@ STATIC mp_obj_t pyb_dac_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const return dac; } +/// \method noise(freq) +/// Generate a pseudo-random noise signal. A new random sample is written +/// to the DAC output at the given frequency. STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { pyb_dac_obj_t *self = self_in; @@ -117,6 +149,10 @@ STATIC mp_obj_t pyb_dac_noise(mp_obj_t self_in, mp_obj_t freq) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_noise_obj, pyb_dac_noise); +/// \method triangle(freq) +/// Generate a triangle wave. The value on the DAC output changes at +/// the given frequency, and the frequence of the repeating triangle wave +/// itself is 256 (or 1024, need to check) times smaller. STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { pyb_dac_obj_t *self = self_in; @@ -141,7 +177,8 @@ STATIC mp_obj_t pyb_dac_triangle(mp_obj_t self_in, mp_obj_t freq) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_triangle_obj, pyb_dac_triangle); -// direct access to DAC (8 bit only at the moment) +/// \method write(value) +/// Direct access to the DAC output (8 bit only at the moment). STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { pyb_dac_obj_t *self = self_in; @@ -160,12 +197,15 @@ STATIC mp_obj_t pyb_dac_write(mp_obj_t self_in, mp_obj_t val) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_write_obj, pyb_dac_write); -// initiates a burst of RAM->DAC using DMA -// input data is treated as an array of bytes (8 bit data) -// TIM6 is used to set the frequency of the transfer +/// \method write_timed(data, freq, *, mode=DAC.NORMAL) +/// Initiates a burst of RAM to DAC using a DMA transfer. +/// The input data is treated as an array of bytes (8 bit data). +/// +/// `mode` can be `DAC.NORMAL` or `DAC.CIRCULAR`. +/// +/// TIM6 is used to control the frequency of the transfer. // TODO add callback argument, to call when transfer is finished // TODO add double buffer argument - STATIC const mp_arg_t pyb_dac_write_timed_args[] = { { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, diff --git a/stmhal/extint.c b/stmhal/extint.c index 61469e0a17..90016d19a9 100644 --- a/stmhal/extint.c +++ b/stmhal/extint.c @@ -4,9 +4,9 @@ #include <stm32f4xx_hal.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "gc.h" #include "obj.h" diff --git a/stmhal/file.c b/stmhal/file.c index 978ba65fc6..f78709b9f5 100644 --- a/stmhal/file.c +++ b/stmhal/file.c @@ -51,6 +51,7 @@ STATIC const mp_map_elem_t file_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_readlines), (mp_obj_t)&mp_stream_unbuffered_readlines_obj}, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&file_obj_close_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&file_obj_close_obj }, diff --git a/stmhal/gccollect.c b/stmhal/gccollect.c index d40460d70c..8be531416f 100644 --- a/stmhal/gccollect.c +++ b/stmhal/gccollect.c @@ -41,9 +41,9 @@ void gc_collect(void) { gc_info_t info; gc_info(&info); printf("GC@%lu %lums\n", start, ticks); - printf(" %lu total\n", info.total); - printf(" %lu : %lu\n", info.used, info.free); - printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); } } diff --git a/stmhal/gendoc.py b/stmhal/gendoc.py index 42882ad277..0122579ab8 100644 --- a/stmhal/gendoc.py +++ b/stmhal/gendoc.py @@ -343,7 +343,7 @@ def main(): args = cmd_parser.parse_args() if len(args.files) == 0: - args.files = ['modpyb.c', 'accel.c', 'adc.c', 'dac.c', 'extint.c', 'i2c.c', 'led.c', 'pin.c', 'rng.c', 'servo.c', 'spi.c', 'uart.c', 'usrsw.c'] + args.files = ['modpyb.c', 'accel.c', 'adc.c', 'dac.c', 'extint.c', 'i2c.c', 'led.c', 'pin.c', 'rng.c', 'servo.c', 'spi.c', 'uart.c', 'usrsw.c', 'timer.c', 'rtc.c'] doc = Doc() for file in args.files: diff --git a/stmhal/help.c b/stmhal/help.c index 975a102445..084d708e6e 100644 --- a/stmhal/help.c +++ b/stmhal/help.c @@ -1,8 +1,8 @@ #include <stdio.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" diff --git a/stmhal/i2c.c b/stmhal/i2c.c index ef9da496d0..96222bf336 100644 --- a/stmhal/i2c.c +++ b/stmhal/i2c.c @@ -3,9 +3,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -367,7 +367,7 @@ STATIC mp_obj_t pyb_i2c_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_arg } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send); -/// \method recv(send, addr=0x00, timeout=5000) +/// \method recv(recv, addr=0x00, timeout=5000) /// /// Receive data on the bus: /// diff --git a/stmhal/input.c b/stmhal/input.c index 0ded898667..6e98ea960c 100644 --- a/stmhal/input.c +++ b/stmhal/input.c @@ -1,6 +1,8 @@ +#include <stdint.h> + +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "readline.h" diff --git a/stmhal/lcd.c b/stmhal/lcd.c index efee13d233..f121a93d7a 100644 --- a/stmhal/lcd.c +++ b/stmhal/lcd.c @@ -2,9 +2,9 @@ #include <string.h> #include <stm32f4xx_hal.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #if MICROPY_HW_HAS_LCD diff --git a/stmhal/led.c b/stmhal/led.c index 9e32c52483..264a475484 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -1,9 +1,9 @@ #include <stdio.h> #include <stm32f4xx_hal.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/stmhal/main.c b/stmhal/main.c index 603bf31889..5faa70e657 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -495,13 +495,11 @@ soft_reset: vstr_free(vstr); } -#if 0 -#if MICROPY_HW_HAS_WLAN - // wifi +#if MICROPY_HW_ENABLE_CC3K + // wifi using the CC3000 driver pyb_wlan_init(); pyb_wlan_start(); #endif -#endif // enter REPL // REPL mode can change, or it can request a soft reset diff --git a/stmhal/modos.c b/stmhal/modos.c index 33b4ff73e0..3594cbc3a6 100644 --- a/stmhal/modos.c +++ b/stmhal/modos.c @@ -1,8 +1,9 @@ +#include <stdint.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "systick.h" diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 2f53bb5234..1ffff1d17a 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -82,9 +82,9 @@ STATIC mp_obj_t pyb_info(uint n_args, const mp_obj_t *args) { gc_info_t info; gc_info(&info); printf("GC:\n"); - printf(" %lu total\n", info.total); - printf(" %lu : %lu\n", info.used, info.free); - printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); } // free space on flash @@ -143,22 +143,26 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis); /// \function delay(ms) /// Delay for the given number of milliseconds. -STATIC mp_obj_t pyb_delay(mp_obj_t count) { - HAL_Delay(mp_obj_get_int(count)); +STATIC mp_obj_t pyb_delay(mp_obj_t ms_in) { + machine_int_t ms = mp_obj_get_int(ms_in); + if (ms >= 0) { + HAL_Delay(ms); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay); /// \function udelay(us) /// Delay for the given number of microseconds. -STATIC mp_obj_t pyb_udelay(mp_obj_t usec) { - uint32_t count = 0; - const uint32_t utime = (168 * mp_obj_get_int(usec) / 5); - for (;;) { - if (++count > utime) { - return mp_const_none; +STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) { + machine_int_t usec = mp_obj_get_int(usec_in); + if (usec > 0) { + uint32_t count = 0; + const uint32_t utime = (168 * usec / 4); + while (++count <= utime) { } } + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay); diff --git a/stmhal/modstm.c b/stmhal/modstm.c index 078f590ece..a2b72995ae 100644 --- a/stmhal/modstm.c +++ b/stmhal/modstm.c @@ -3,9 +3,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "modstm.h" diff --git a/stmhal/modtime.c b/stmhal/modtime.c index 83be2deaa1..410c6391e2 100644 --- a/stmhal/modtime.c +++ b/stmhal/modtime.c @@ -1,8 +1,8 @@ #include <stm32f4xx_hal.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "modtime.h" diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 24ab20b16b..faa1c806a4 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -1,5 +1,3 @@ -#include <stdint.h> - // options to control how Micro Python is built #define MICROPY_EMIT_THUMB (1) @@ -21,6 +19,7 @@ #define MICROPY_ENABLE_LFN (1) #define MICROPY_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_MOD_SYS_STDFILES (1) +#define MICROPY_ENABLE_MOD_CMATH (1) // extra built in names to add to the global namespace extern const struct _mp_obj_fun_native_t mp_builtin_help_obj; @@ -51,11 +50,11 @@ extern const struct _mp_obj_module_t time_module; #define BYTES_PER_WORD (4) -#define UINT_FMT "%lu" -#define INT_FMT "%ld" +#define UINT_FMT "%u" +#define INT_FMT "%d" -typedef int32_t machine_int_t; // must be pointer size -typedef uint32_t machine_uint_t; // must be pointer size +typedef int machine_int_t; // must be pointer size +typedef unsigned int machine_uint_t; // must be pointer size typedef void *machine_ptr_t; // must be of pointer size typedef const void *machine_const_ptr_t; // must be of pointer size diff --git a/stmhal/pin.c b/stmhal/pin.c index 06923a492d..d390926360 100644 --- a/stmhal/pin.c +++ b/stmhal/pin.c @@ -4,9 +4,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -179,7 +179,7 @@ STATIC mp_obj_t pin_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_ if (n_args >= 2) { // pin mode given, so configure this GPIO - mp_obj_t args2[3] = {(mp_obj_t)pin, args2[1], MP_OBJ_NULL}; + mp_obj_t args2[3] = {(mp_obj_t)pin, args[1], MP_OBJ_NULL}; if (n_args == 3) { args2[2] = args[2]; } @@ -241,6 +241,7 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_o /// - `Pin.PULL_DOWN` - enable the pull-down resistor. /// /// Returns: `None`. +// TODO allow keyword args STATIC mp_obj_t pin_obj_init(uint n_args, mp_obj_t *args) { pin_obj_t *self = args[0]; diff --git a/stmhal/pybwlan.c b/stmhal/pybwlan.c index 72cb9bfd98..fb214209c2 100644 --- a/stmhal/pybwlan.c +++ b/stmhal/pybwlan.c @@ -5,13 +5,15 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" +#if MICROPY_HW_ENABLE_CC3K + #include "cc3k/ccspi.h" #include "cc3k/hci.h" #include "cc3k/socket.h" @@ -377,3 +379,5 @@ void pyb_wlan_start(void) { printf("nvmem_read_sp_version=%d; %02x %02x\n", ret, ver[0], ver[1]); */ } + +#endif // MICROPY_HW_ENABLE_CC3K diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c index 3f9482ec58..00025c8c6f 100644 --- a/stmhal/pyexec.c +++ b/stmhal/pyexec.c @@ -3,9 +3,9 @@ #include <stm32f4xx_hal.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "misc.h" #include "lexer.h" @@ -84,9 +84,9 @@ bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bo gc_info_t info; gc_info(&info); printf("GC:\n"); - printf(" %lu total\n", info.total); - printf(" %lu : %lu\n", info.used, info.free); - printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block); + printf(" " UINT_FMT " total\n", info.total); + printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free); + printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block); } } @@ -155,7 +155,7 @@ int pyexec_friendly_repl(void) { #endif friendly_repl_reset: - stdout_tx_str("Micro Python build " MICROPY_GIT_HASH " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n"); + stdout_tx_str("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n"); stdout_tx_str("Type \"help()\" for more information.\r\n"); // to test ctrl-C diff --git a/stmhal/rtc.c b/stmhal/rtc.c index 79e524cab2..ea7aa789ec 100644 --- a/stmhal/rtc.c +++ b/stmhal/rtc.c @@ -9,6 +9,18 @@ #include "runtime.h" #include "rtc.h" +/// \moduleref pyb +/// \class RTC - real time clock +/// +/// The RTC is and independent clock that keeps track of the date +/// and time. +/// +/// Example usage: +/// +/// rtc = pyb.RTC() +/// rtc.datetime((2014, 5, 1, 4, 13, 0, 0, 0)) +/// print(rtc.datetime()) + RTC_HandleTypeDef RTCHandle; // rtc_info indicates various things about RTC startup @@ -159,13 +171,13 @@ void rtc_init(void) { // fresh reset; configure RTC Calendar RTC_CalendarConfig(); } else { - // RTC was previously set, so leave it alon + // RTC was previously set, so leave it alone if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) { - // power on reset occured + // power on reset occurred rtc_info |= 0x10000; } if(__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET) { - // external reset occured + // external reset occurred rtc_info |= 0x20000; } // Clear source Reset Flag @@ -213,6 +225,8 @@ typedef struct _pyb_rtc_obj_t { STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}}; +/// \classmethod \constructor() +/// Create an RTC object. STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { // check arguments mp_arg_check_num(n_args, n_kw, 0, 0, false); @@ -221,11 +235,32 @@ STATIC mp_obj_t pyb_rtc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const return (mp_obj_t)&pyb_rtc_obj; } +/// \method info() +/// Get information about the startup time and reset source. +/// +/// - The lower 0xffff are the number of milliseconds the RTC took to +/// start up. +/// - Bit 0x10000 is set if a power-on reset occurred. +/// - Bit 0x20000 is set if an external reset occurred mp_obj_t pyb_rtc_info(mp_obj_t self_in) { return mp_obj_new_int(rtc_info); } MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_info_obj, pyb_rtc_info); +/// \method datetime([datetimetuple]) +/// Get or set the date and time of the RTC. +/// +/// With no arguments, this method returns an 8-tuple with the current +/// date and time. With 1 argument (being an 8-tuple) it sets the date +/// and time. +/// +/// The 8-tuple has the following format: +/// +/// (year, month, day, weekday, hours, minutes, seconds, subseconds) +/// +/// `weekday` is 1-7 for Monday through Sunday. +/// +/// `subseconds` counts down from 255 to 0 mp_obj_t pyb_rtc_datetime(uint n_args, const mp_obj_t *args) { if (n_args == 1) { // get date and time diff --git a/stmhal/servo.c b/stmhal/servo.c index 2ebe64376f..6f87197bd2 100644 --- a/stmhal/servo.c +++ b/stmhal/servo.c @@ -2,9 +2,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -203,6 +203,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_servo_pulse_width_obj, 1, 2, pyb_ /// \method calibration([pulse_min, pulse_max, pulse_centre, [pulse_angle_90, pulse_speed_100]]) /// Get or set the calibration of the servo timing. +// TODO should accept 1 arg, a 5-tuple of values to set STATIC mp_obj_t pyb_servo_calibration(uint n_args, const mp_obj_t *args) { pyb_servo_obj_t *self = args[0]; if (n_args == 1) { diff --git a/stmhal/spi.c b/stmhal/spi.c index ba550f9799..a07ebd21a9 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -3,9 +3,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -198,7 +198,7 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void * } } -/// \method init(mode, baudrate=328125, *, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, ti=false, crc=None) +/// \method init(mode, baudrate=328125, *, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, ti=False, crc=None) /// /// Initialise the SPI bus with the given parameters: /// diff --git a/stmhal/timer.c b/stmhal/timer.c index 1578e9b1d9..e92a9988f7 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -16,6 +16,38 @@ #include "timer.h" #include "servo.h" +/// \moduleref pyb +/// \class Timer - periodically call a function +/// +/// Timers can be used for a great variety of tasks. At the moment, only +/// the simplest case is implemented: that of calling a function periodically. +/// +/// Each timer consists of a counter that counts up at a certain rate. The rate +/// at which it counts is the peripheral clock frequency (in Hz) divided by the +/// timer prescaler. When the counter reaches the timer period it triggers an +/// event, and the counter resets back to zero. By using the callback method, +/// the timer event can call a Python function. +/// +/// Example usage to toggle an LED at a fixed frequency: +/// +/// tim = pyb.Timer(4) # create a timer object using timer 4 +/// tim.init(freq=2) # trigger at 2Hz +/// tim.callback(lambda t:pyb.LED(1).toggle()) +/// +/// Further examples: +/// +/// tim = pyb.Timer(4, freq=100) # freq in Hz +/// tim = pyb.Timer(4, prescaler=1, period=100) +/// tim.counter() # get counter (can also set) +/// tim.prescaler(2) # set prescaler (can also get) +/// tim.period(200) # set period (can also get) +/// tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance) +/// tim.callback(None) # clear callback +/// +/// *Note:* Timer 3 is reserved for internal use. Timer 5 controls +/// the servo driver, and Timer 6 is used for timed ADC/DAC reading/writing. +/// It is recommended to use the other timers in your programs. + // The timers can be used by multiple drivers, and need a common point for // the interrupts to be dispatched, so they are all collected here. // @@ -29,16 +61,6 @@ // // TIM6: // - ADC, DAC for read_timed and write_timed -// -// Python usage model: -// -// tim = pyb.Timer(4, freq=100) # freq in Hz -// tim = pyb.Timer(4, prescaler=1, period=100) -// tim.counter() # get counter (can also set) -// tim.prescaler(2) # set prescaler (can also get) -// tim.period(200) # set period (can also get) -// tim.callback(lambda t: ...) # set callback for update interrupt (t=tim instance) -// tim.callback(None) # clear callback typedef struct _pyb_timer_obj_t { mp_obj_base_t base; @@ -173,6 +195,12 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void } } +/// \method init(*, freq, prescaler, period) +/// Initialise the timer. Initialisation must be either by frequency (in Hz) +/// or by prescaler and period: +/// +/// tim.init(freq=100) # set the timer to trigger at 100Hz +/// tim.init(prescaler=100, period=300) # set the prescaler and period directly STATIC const mp_arg_t pyb_timer_init_args[] = { { MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, { MP_QSTR_prescaler, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, @@ -257,6 +285,10 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, uint n_args, const return mp_const_none; } +/// \classmethod \constructor(id, ...) +/// Construct a new timer object of the given id. If additional +/// arguments are given, then the timer is initialised by `init(...)`. +/// `id` can be 1 to 14, excluding 3. STATIC mp_obj_t pyb_timer_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { // check arguments mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); @@ -308,6 +340,10 @@ STATIC mp_obj_t pyb_timer_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_a } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_init_obj, 1, pyb_timer_init); +/// \method deinit() +/// Deinitialises the timer. +/// +/// *This function is not yet implemented.* STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) { //pyb_timer_obj_t *self = self_in; // TODO implement me @@ -315,6 +351,8 @@ STATIC mp_obj_t pyb_timer_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit); +/// \method counter([value]) +/// Get or set the timer counter. mp_obj_t pyb_timer_counter(uint n_args, const mp_obj_t *args) { pyb_timer_obj_t *self = args[0]; if (n_args == 1) { @@ -328,6 +366,8 @@ mp_obj_t pyb_timer_counter(uint n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_timer_counter); +/// \method prescaler([value]) +/// Get or set the prescaler for the timer. mp_obj_t pyb_timer_prescaler(uint n_args, const mp_obj_t *args) { pyb_timer_obj_t *self = args[0]; if (n_args == 1) { @@ -341,6 +381,8 @@ mp_obj_t pyb_timer_prescaler(uint n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_timer_prescaler); +/// \method period([value]) +/// Get or set the period of the timer. mp_obj_t pyb_timer_period(uint n_args, const mp_obj_t *args) { pyb_timer_obj_t *self = args[0]; if (n_args == 1) { @@ -354,6 +396,10 @@ mp_obj_t pyb_timer_period(uint n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_period_obj, 1, 2, pyb_timer_period); +/// \method callback(fun) +/// Set the function to be called when the timer triggers. +/// `fun` is passed 1 argument, the timer object. +/// If `fun` is `None` then the callback will be disabled. STATIC mp_obj_t pyb_timer_callback(mp_obj_t self_in, mp_obj_t callback) { pyb_timer_obj_t *self = self_in; if (callback == mp_const_none) { @@ -421,7 +467,7 @@ void timer_irq_handler(uint tim_id) { // Uncaught exception; disable the callback so it doesn't run again. tim->callback = mp_const_none; __HAL_TIM_DISABLE_IT(&tim->tim, TIM_IT_UPDATE); - printf("Uncaught exception in Timer(%lu) interrupt handler\n", tim->tim_id); + printf("Uncaught exception in Timer(" UINT_FMT ") interrupt handler\n", tim->tim_id); mp_obj_print_exception((mp_obj_t)nlr.ret_val); } gc_unlock(); diff --git a/stmhal/uart.c b/stmhal/uart.c index 6dc60ca084..04373a8840 100644 --- a/stmhal/uart.c +++ b/stmhal/uart.c @@ -3,9 +3,9 @@ #include "stm32f4xx_hal.h" +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/tests/basics/builtin-minmax.py b/tests/basics/builtin-minmax.py new file mode 100644 index 0000000000..8ee4bbca7d --- /dev/null +++ b/tests/basics/builtin-minmax.py @@ -0,0 +1,15 @@ +# test builtin min and max functions + +print(min(0,1)) +print(min(1,0)) +print(min(0,-1)) +print(min(-1,0)) + +print(max(0,1)) +print(max(1,0)) +print(max(0,-1)) +print(max(-1,0)) + +print(min([1,2,4,0,-1,2])) +print(max([1,2,4,0,-1,2])) + diff --git a/tests/basics/subclass-native3.py b/tests/basics/subclass-native3.py index 5d443cf5cd..bd99ab0d6a 100644 --- a/tests/basics/subclass-native3.py +++ b/tests/basics/subclass-native3.py @@ -3,6 +3,20 @@ class MyExc(Exception): e = MyExc(100, "Some error") print(e) -# TODO: Prints native base class name -#print(repr(e)) +print(repr(e)) print(e.args) + +try: + raise MyExc("Some error") +except MyExc as e: + print("Caught exception:", repr(e)) + +try: + raise MyExc("Some error2") +except Exception as e: + print("Caught exception:", repr(e)) + +try: + raise MyExc("Some error2") +except: + print("Caught user exception") diff --git a/tests/float/builtin-float-minmax.py b/tests/float/builtin-float-minmax.py new file mode 100644 index 0000000000..ce45a768a5 --- /dev/null +++ b/tests/float/builtin-float-minmax.py @@ -0,0 +1,26 @@ +# test builtin min and max functions with float args + +print(min(0,1.0)) +print(min(1.0,0)) +print(min(0,-1.0)) +print(min(-1.0,0)) + +print(max(0,1.0)) +print(max(1.0,0)) +print(max(0,-1.0)) +print(max(-1.0,0)) + +print(min(1.5,-1.5)) +print(min(-1.5,1.5)) + +print(max(1.5,-1.5)) +print(max(-1.5,1.5)) + +print(min([1,2.9,4,0,-1,2])) +print(max([1,2.9,4,0,-1,2])) + +print(min([1,2.9,4,6.5,-1,2])) +print(max([1,2.9,4,6.5,-1,2])) +print(min([1,2.9,4,-6.5,-1,2])) +print(max([1,2.9,4,-6.5,-1,2])) + diff --git a/tests/io/file1.py b/tests/io/file1.py index 8552f535bd..7d5154a4f8 100644 --- a/tests/io/file1.py +++ b/tests/io/file1.py @@ -2,3 +2,5 @@ f = open("io/data/file1") print(f.read(5)) print(f.readline()) print(f.read()) +f = open("io/data/file1") +print(f.readlines()) diff --git a/tests/pyb/accel.py b/tests/pyb/accel.py new file mode 100644 index 0000000000..13f53b33c0 --- /dev/null +++ b/tests/pyb/accel.py @@ -0,0 +1,7 @@ +accel = pyb.Accel() +print(accel) +accel.x() +accel.y() +accel.z() +accel.tilt() +accel.filtered_xyz() diff --git a/tests/pyb/accel.py.exp b/tests/pyb/accel.py.exp new file mode 100644 index 0000000000..28070be177 --- /dev/null +++ b/tests/pyb/accel.py.exp @@ -0,0 +1 @@ +<Accel> diff --git a/tests/pyb/adc.py b/tests/pyb/adc.py new file mode 100644 index 0000000000..7bed54e9f8 --- /dev/null +++ b/tests/pyb/adc.py @@ -0,0 +1,10 @@ +from pyb import ADC +from pyb import Pin + +adc = ADC('X22') +print(adc) + +adc.read() + +buf = bytearray(100) +adc.read_timed(buf, 500) diff --git a/tests/pyb/adc.py.exp b/tests/pyb/adc.py.exp new file mode 100644 index 0000000000..bbc6af7379 --- /dev/null +++ b/tests/pyb/adc.py.exp @@ -0,0 +1 @@ +<ADC on X22 channel=13> diff --git a/tests/pyb/dac.py b/tests/pyb/dac.py new file mode 100644 index 0000000000..61ab7bd6e6 --- /dev/null +++ b/tests/pyb/dac.py @@ -0,0 +1,8 @@ +dac = pyb.DAC(1) +print(dac) +dac.noise(100) +dac.triangle(100) +dac.write(0) +dac.write_timed(bytearray(10), 100, mode=pyb.DAC.NORMAL) +pyb.delay(20) +dac.write(0) diff --git a/tests/pyb/dac.py.exp b/tests/pyb/dac.py.exp new file mode 100644 index 0000000000..ae245f2e61 --- /dev/null +++ b/tests/pyb/dac.py.exp @@ -0,0 +1 @@ +<DAC> diff --git a/tests/pyb/extint.py b/tests/pyb/extint.py new file mode 100644 index 0000000000..20648995bc --- /dev/null +++ b/tests/pyb/extint.py @@ -0,0 +1,6 @@ +ext = pyb.ExtInt('X1', pyb.ExtInt.IRQ_RISING, pyb.Pin.PULL_DOWN, lambda l:print('line:', l)) +ext.disable() +ext.enable() +print(ext.line()) +ext.swint() +ext.disable() diff --git a/tests/pyb/extint.py.exp b/tests/pyb/extint.py.exp new file mode 100644 index 0000000000..28019d75c6 --- /dev/null +++ b/tests/pyb/extint.py.exp @@ -0,0 +1,2 @@ +0 +line: 0 diff --git a/tests/pyb/i2c.py b/tests/pyb/i2c.py new file mode 100644 index 0000000000..79169d0553 --- /dev/null +++ b/tests/pyb/i2c.py @@ -0,0 +1,23 @@ +from pyb import I2C + +i2c = I2C(1) +i2c2 = I2C(2) + +i2c.init(I2C.MASTER, baudrate=400000) +print(i2c.scan()) +i2c.deinit() + +# use accelerometer to test i2c bus + +accel_addr = 76 + +pyb.Accel() # this will init the bus for us + +print(i2c.scan()) +print(i2c.is_ready(accel_addr)) + +print(i2c.mem_read(1, accel_addr, 7, timeout=500)) +i2c.mem_write(0, accel_addr, 0, timeout=500) + +i2c.send(7, addr=accel_addr) +i2c.recv(1, addr=accel_addr) diff --git a/tests/pyb/i2c.py.exp b/tests/pyb/i2c.py.exp new file mode 100644 index 0000000000..c2b982f0fe --- /dev/null +++ b/tests/pyb/i2c.py.exp @@ -0,0 +1,4 @@ +[] +[76] +True +b'\x01' diff --git a/tests/pyb/led.py b/tests/pyb/led.py new file mode 100644 index 0000000000..a727c90dfa --- /dev/null +++ b/tests/pyb/led.py @@ -0,0 +1,28 @@ +from pyb import LED + +for i in range(4): + print(LED(i+1)) + +for i in range(4): + LED(i+1).on() +pyb.delay(10) +for i in range(4): + LED(i+1).off() +pyb.delay(10) +for i in range(4): + LED(i+1).toggle() +pyb.delay(10) +for i in range(4): + LED(i+1).intensity(0) + +for i in range(256): + LED(4).intensity(i) + if LED(4).intensity() != i: + print('fail', i) + pyb.delay(1) +for i in range(256): + LED(4).intensity(255 - i) + pyb.delay(1) + +for i in range(4): + LED(i+1).off() diff --git a/tests/pyb/led.py.exp b/tests/pyb/led.py.exp new file mode 100644 index 0000000000..b528706694 --- /dev/null +++ b/tests/pyb/led.py.exp @@ -0,0 +1,4 @@ +<LED 1> +<LED 2> +<LED 3> +<LED 4> diff --git a/tests/pyb/pin.py b/tests/pyb/pin.py new file mode 100644 index 0000000000..448ce53998 --- /dev/null +++ b/tests/pyb/pin.py @@ -0,0 +1,29 @@ +from pyb import Pin + +p = Pin('X1') +print(p) +print(p.name()) +print(p.pin()) +print(p.port()) + +p = Pin('X1', Pin.IN, Pin.PULL_UP) +#p = Pin('X1', Pin.IN, pull=Pin.PULL_UP) +print(p.value()) + +p.init(p.IN, p.PULL_DOWN) +#p.init(p.IN, pull=p.PULL_DOWN) +print(p.value()) + +p.init(p.OUT_PP) +p.low() +print(p.value()) +p.high() +print(p.value()) +p.value(0) +print(p.value()) +p.value(1) +print(p.value()) +p.value(False) +print(p.value()) +p.value(True) +print(p.value()) diff --git a/tests/pyb/pin.py.exp b/tests/pyb/pin.py.exp new file mode 100644 index 0000000000..4856f5b8e7 --- /dev/null +++ b/tests/pyb/pin.py.exp @@ -0,0 +1,12 @@ +<Pin A0> +A0 +0 +0 +1 +0 +0 +1 +0 +1 +0 +1 diff --git a/tests/pyb/pyb1.py b/tests/pyb/pyb1.py new file mode 100644 index 0000000000..0087ec0507 --- /dev/null +++ b/tests/pyb/pyb1.py @@ -0,0 +1,42 @@ +# basic tests of pyb module + +import pyb + +# test delay + +pyb.delay(-1) +pyb.delay(0) +pyb.delay(1) + +start = pyb.millis() +pyb.delay(17) +print((pyb.millis() - start) // 5) # should print 3 + +# test udelay + +pyb.udelay(-1) +pyb.udelay(0) +pyb.udelay(1) + +start = pyb.millis() +pyb.udelay(17000) +print((pyb.millis() - start) // 5) # should print 3 + +# other + +pyb.disable_irq() +pyb.enable_irq() + +print(pyb.freq()) + +print(pyb.have_cdc()) + +pyb.hid((0, 0, 0, 0)) # won't do anything + +pyb.rng() + +pyb.sync() + +print(len(pyb.unique_id())) + +pyb.wfi() diff --git a/tests/pyb/pyb1.py.exp b/tests/pyb/pyb1.py.exp new file mode 100644 index 0000000000..84034d683c --- /dev/null +++ b/tests/pyb/pyb1.py.exp @@ -0,0 +1,5 @@ +3 +3 +(168000000, 168000000, 42000000, 84000000) +True +12 diff --git a/tests/pyb/rtc.py b/tests/pyb/rtc.py new file mode 100644 index 0000000000..ac716b27fc --- /dev/null +++ b/tests/pyb/rtc.py @@ -0,0 +1,6 @@ +from pyb import RTC +rtc = RTC() +print(rtc) +rtc.datetime((2014, 1, 1, 1, 0, 0, 0, 0)) +pyb.delay(1000) +print(rtc.datetime()[:7]) diff --git a/tests/pyb/rtc.py.exp b/tests/pyb/rtc.py.exp new file mode 100644 index 0000000000..d1ea2d9590 --- /dev/null +++ b/tests/pyb/rtc.py.exp @@ -0,0 +1,2 @@ +<RTC> +(2014, 1, 1, 1, 0, 0, 1) diff --git a/tests/pyb/servo.py b/tests/pyb/servo.py new file mode 100644 index 0000000000..d15cafe483 --- /dev/null +++ b/tests/pyb/servo.py @@ -0,0 +1,16 @@ +from pyb import Servo + +servo = Servo(1) +print(servo) + +servo.angle(0) +servo.angle(10, 100) + +servo.speed(-10) +servo.speed(10, 100) + +servo.pulse_width(1500) +print(servo.pulse_width()) + +servo.calibration(630, 2410, 1490, 2460, 2190) +print(servo.calibration()) diff --git a/tests/pyb/servo.py.exp b/tests/pyb/servo.py.exp new file mode 100644 index 0000000000..ac6032ba5f --- /dev/null +++ b/tests/pyb/servo.py.exp @@ -0,0 +1,3 @@ +<Servo 1 at 1500us> +1500 +(630, 2410, 1490, 2460, 2190) diff --git a/tests/pyb/spi.py b/tests/pyb/spi.py new file mode 100644 index 0000000000..90dfb441a3 --- /dev/null +++ b/tests/pyb/spi.py @@ -0,0 +1,17 @@ +from pyb import SPI + +spi = SPI(1) +print(spi) + +spi = SPI(1, SPI.MASTER) +spi = SPI(1, SPI.MASTER, baudrate=500000) +spi = SPI(1, SPI.MASTER, 500000, polarity=1, phase=1, bits=8, firstbit=SPI.MSB, ti=False, crc=None) +print(spi) + +spi.init(SPI.SLAVE) +print(spi) + +spi.init(SPI.MASTER) +spi.send(1, timeout=100) +print(spi.recv(1, timeout=100)) +print(spi.send_recv(1, timeout=100)) diff --git a/tests/pyb/spi.py.exp b/tests/pyb/spi.py.exp new file mode 100644 index 0000000000..030dfe1b34 --- /dev/null +++ b/tests/pyb/spi.py.exp @@ -0,0 +1,5 @@ +SPI(1) +SPI(1, SPI.MASTER, baudrate=328125, polarity=1, phase=1, bits=8) +SPI(1, SPI.SLAVE, polarity=1, phase=1, bits=8) +b'\xff' +b'\xff' diff --git a/tests/pyb/switch.py b/tests/pyb/switch.py new file mode 100644 index 0000000000..4b74e0fd73 --- /dev/null +++ b/tests/pyb/switch.py @@ -0,0 +1,6 @@ +from pyb import Switch + +sw = pyb.Switch() +print(sw()) +sw.callback(print) +sw.callback(None) diff --git a/tests/pyb/switch.py.exp b/tests/pyb/switch.py.exp new file mode 100644 index 0000000000..bc59c12aa1 --- /dev/null +++ b/tests/pyb/switch.py.exp @@ -0,0 +1 @@ +False diff --git a/tests/pyb/timer.py b/tests/pyb/timer.py new file mode 100644 index 0000000000..ff1bda0f23 --- /dev/null +++ b/tests/pyb/timer.py @@ -0,0 +1,28 @@ +from pyb import Timer + +tim = Timer(4) +tim = Timer(4, prescaler=100, period=200) +print(tim.prescaler()) +print(tim.period()) +tim.prescaler(300) +print(tim.prescaler()) +tim.period(400) +print(tim.period()) + +tim = Timer(4, freq=1) +tim.init(freq=2000) +def f(t): + print(1) + t.callback(None) +tim.callback(f) +pyb.delay(10) + +# f3 closes over f2.y +def f2(x): + y = x + def f3(t): + print(2, y) + t.callback(None) + return f3 +tim.callback(f2(3)) +pyb.delay(10) diff --git a/tests/pyb/timer.py.exp b/tests/pyb/timer.py.exp new file mode 100644 index 0000000000..58b81e2af1 --- /dev/null +++ b/tests/pyb/timer.py.exp @@ -0,0 +1,6 @@ +100 +200 +300 +400 +1 +2 3 diff --git a/tests/pyb/uart.py b/tests/pyb/uart.py new file mode 100644 index 0000000000..6e0118d155 --- /dev/null +++ b/tests/pyb/uart.py @@ -0,0 +1,12 @@ +from pyb import UART + +uart = UART(1) +uart = UART(1, 9600) +uart = UART(1, 9600, bits=8, stop=1, parity=None) +print(uart) + +uart.init(1200) +print(uart) + +uart.any() +uart.send(1, timeout=500) diff --git a/tests/pyb/uart.py.exp b/tests/pyb/uart.py.exp new file mode 100644 index 0000000000..58ded4d848 --- /dev/null +++ b/tests/pyb/uart.py.exp @@ -0,0 +1,2 @@ +UART(1, baudrate=9600, bits=8, stop=1, parity=None) +UART(1, baudrate=1200, bits=8, stop=1, parity=None) diff --git a/tests/pyboard.py b/tests/pyboard.py new file mode 120000 index 0000000000..3a82f6a6a3 --- /dev/null +++ b/tests/pyboard.py @@ -0,0 +1 @@ +../tools/pyboard.py
\ No newline at end of file diff --git a/tests/run-tests b/tests/run-tests index 9e94026fa2..c1eee59eaa 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -3,6 +3,7 @@ import os import subprocess import sys +import argparse from glob import glob # Tests require at least CPython 3.3. If your default python3 executable @@ -15,82 +16,113 @@ else: CPYTHON3 = os.getenv('MICROPY_CPYTHON3', 'python3') MICROPYTHON = os.getenv('MICROPY_MICROPYTHON', '../unix/micropython') -# Set of tests that we shouldn't run under Travis CI -skip_travis_tests = set(['basics/memoryerror.py']) - def rm_f(fname): if os.path.exists(fname): os.remove(fname) -test_count = 0 -testcase_count = 0 -passed_count = 0 -failed_tests = [] -tests = [] - -if not sys.argv[1:]: - test_dirs = ('basics', 'float', 'import', 'io', 'misc') - tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) -else: - tests = sys.argv[1:] - -test_on_pyboard = False -if test_on_pyboard: - import pyboard - pyb = pyboard.Pyboard('/dev/ttyACM0') - pyb.enter_raw_repl() - -running_under_travis = os.getenv('TRAVIS') == 'true' - -for test_file in tests: - if running_under_travis and test_file in skip_travis_tests: - print("skip ", test_file) - continue - - # run CPython - try: - output_expected = subprocess.check_output([CPYTHON3, '-B', test_file]) - except subprocess.CalledProcessError: - output_expected = b'CPYTHON3 CRASH' - - # run Micro Python - if test_on_pyboard: +def run_tests(pyb, tests): + test_count = 0 + testcase_count = 0 + passed_count = 0 + failed_tests = [] + + running_under_travis = os.getenv('TRAVIS') == 'true' + + # Set of tests that we shouldn't run under Travis CI + skip_travis_tests = set(['basics/memoryerror.py']) + + for test_file in tests: + if running_under_travis and test_file in skip_travis_tests: + print("skip ", test_file) + continue + + # get expected output + test_file_expected = test_file + '.exp' + if os.path.isfile(test_file_expected): + # expected output given by a file, so read that in + with open(test_file_expected, 'rb') as f: + output_expected = f.read() + else: + # run CPython to work out expeceted output + try: + output_expected = subprocess.check_output([CPYTHON3, '-B', test_file]) + except subprocess.CalledProcessError: + output_expected = b'CPYTHON3 CRASH' + + # run Micro Python + if pyb is None: + # run on PC + try: + output_mupy = subprocess.check_output([MICROPYTHON, '-X', 'emit=bytecode', test_file]) + except subprocess.CalledProcessError: + output_mupy = b'CRASH' + else: + # run on pyboard + pyb.enter_raw_repl() + try: + output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n') + except pyboard.PyboardError: + output_mupy = b'CRASH' + + testcase_count += len(output_expected.splitlines()) + + test_basename = os.path.basename(test_file) + test_name = os.path.splitext(test_basename)[0] + filename_expected = test_basename + ".exp" + filename_mupy = test_basename + ".out" + + if output_expected == output_mupy: + print("pass ", test_file) + passed_count += 1 + rm_f(filename_expected) + rm_f(filename_mupy) + else: + with open(filename_expected, "w") as f: + f.write(str(output_expected, "ascii")) + with open(filename_mupy, "w") as f: + f.write(str(output_mupy, "ascii")) + print("FAIL ", test_file) + failed_tests.append(test_name) + + test_count += 1 + + print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) + print("{} tests passed".format(passed_count)) + + if len(failed_tests) > 0: + print("{} tests failed: {}".format(len(failed_tests), ' '.join(failed_tests))) + return False + + # all tests succeeded + return True + +def main(): + cmd_parser = argparse.ArgumentParser(description='Run tests for Micro Python.') + cmd_parser.add_argument('--pyboard', action='store_true', help='run the tests on the pyboard') + cmd_parser.add_argument('files', nargs='*', help='input test files') + args = cmd_parser.parse_args() + + if args.pyboard: + import pyboard + pyb = pyboard.Pyboard('/dev/ttyACM0') pyb.enter_raw_repl() - try: - output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n') - except pyboard.PyboardError: - output_mupy = b'CRASH' else: - try: - output_mupy = subprocess.check_output([MICROPYTHON, '-X', 'emit=bytecode', test_file]) - except subprocess.CalledProcessError: - output_mupy = b'CRASH' - - testcase_count += len(output_expected.splitlines()) - - test_basename = os.path.basename(test_file) - test_name = os.path.splitext(test_basename)[0] - filename_expected = test_basename + ".exp" - filename_mupy = test_basename + ".out" - - if output_expected == output_mupy: - print("pass ", test_file) - passed_count += 1 - rm_f(filename_expected) - rm_f(filename_mupy) + pyb = None + + if len(args.files) == 0: + if pyb is None: + # run PC tests + test_dirs = ('basics', 'float', 'import', 'io', 'misc') + else: + # run pyboard tests + test_dirs = ('basics', 'float', 'pyb') + tests = sorted(test_file for test_files in (glob('{}/*.py'.format(dir)) for dir in test_dirs) for test_file in test_files) else: - with open(filename_expected, "w") as f: - f.write(str(output_expected, "ascii")) - with open(filename_mupy, "w") as f: - f.write(str(output_mupy, "ascii")) - print("FAIL ", test_file) - failed_tests.append(test_name) - - test_count += 1 + # tests explicitly given + tests = args.files -print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) -print("{} tests passed".format(passed_count)) + if not run_tests(pyb, tests): + sys.exit(1) -if len(failed_tests) > 0: - print("{} tests failed: {}".format(len(failed_tests), ' '.join(failed_tests))) - sys.exit(1) +if __name__ == "__main__": + main() diff --git a/tools/build-stm-latest.sh b/tools/build-stm-latest.sh new file mode 100755 index 0000000000..f0d639d10f --- /dev/null +++ b/tools/build-stm-latest.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# check/get parameters +if [ $# != 1 ]; then + echo "usage: $0 <dest-dir>" + exit 1 +fi + +dest_dir=$1 + +# check we are in the correct directory +if [ ! -r modpyb.c ]; then + echo "must be in stm directory" + exit 1 +fi + +# get the date +date=$(date '+%Y-%m-%d') + +# get the git hash +git_hash="$(git rev-parse --short HEAD 2> /dev/null || echo unknown)" + +# build the versions +for board in PYBV3 PYBV10; do + echo $board + lower_board=$(echo $board | tr A-Z a-z) + build_dir=/tmp/stm-build-$board + make -B BOARD=$board BUILD=$build_dir || exit 1 + mv $build_dir/firmware.dfu $dest_dir/$lower_board-$date-$git_hash.dfu + rm -rf $build_dir +done diff --git a/tools/pyboard.py b/tools/pyboard.py index a44710914e..dce60350d0 100644 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -9,7 +9,7 @@ Example usage: import pyboard pyb = pyboard.Pyboard('/dev/ttyACM0') pyb.enter_raw_repl() - pyb.exec('pyb.Led(1).on()') + pyb.exec('pyb.LED(1).on()') pyb.exit_raw_repl() To run a script from the local machine on the board and print out the results: @@ -17,6 +17,10 @@ To run a script from the local machine on the board and print out the results: import pyboard pyboard.execfile('test.py', device='/dev/ttyACM0') +This script can also be run directly. To execute a local script, use: + + python pyboard.py test.py + """ import time @@ -50,6 +54,7 @@ class Pyboard: return data def enter_raw_repl(self): + self.serial.write(b'\r\x03') # ctrl-C: interrupt any running program self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL self.serial.write(b'\x04') # ctrl-D: soft reset data = self.read_until(1, b'to exit\r\n>') @@ -110,18 +115,19 @@ def run_test(): pyb.exec('def apply(l, f):\r\n for item in l:\r\n f(item)\r\n') - pyb.exec('leds=[pyb.Led(l) for l in range(1, 5)]') + pyb.exec('leds=[pyb.LED(l) for l in range(1, 5)]') pyb.exec('apply(leds, lambda l:l.off())') ## USR switch test - if True: - for i in range(2): - print("press USR button") - pyb.exec('while pyb.switch(): pyb.delay(10)') - pyb.exec('while not pyb.switch(): pyb.delay(10)') + pyb.exec('switch = pyb.Switch()') + + for i in range(2): + print("press USR button") + pyb.exec('while switch(): pyb.delay(10)') + pyb.exec('while not switch(): pyb.delay(10)') - print('USR switch passed') + print('USR switch passed') ## accel test @@ -155,5 +161,19 @@ def run_test(): pyb.exit_raw_repl() pyb.close() +def main(): + import argparse + cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') + cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device of the pyboard') + cmd_parser.add_argument('--test', action='store_true', help='run a small test suite on the pyboard') + cmd_parser.add_argument('files', nargs='*', help='input files') + args = cmd_parser.parse_args() + + if args.test: + run_test() + + for file in args.files: + execfile(file, device=args.device) + if __name__ == "__main__": - run_test() + main() diff --git a/unix-cpy/main.c b/unix-cpy/main.c index 6cdd72c5da..3f42398f59 100644 --- a/unix-cpy/main.c +++ b/unix-cpy/main.c @@ -3,9 +3,9 @@ #include <stdio.h> #include <string.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "lexer.h" #include "lexerunix.h" diff --git a/unix/file.c b/unix/file.c index 041e28e956..2b7e1a04f1 100644 --- a/unix/file.c +++ b/unix/file.c @@ -5,9 +5,9 @@ #include <sys/stat.h> #include <sys/types.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" @@ -18,6 +18,16 @@ typedef struct _mp_obj_fdfile_t { int fd; } mp_obj_fdfile_t; +#ifdef MICROPY_CPYTHON_COMPAT +void check_fd_is_open(const mp_obj_fdfile_t *o) { + if (o->fd < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file")); + } +} +#else +#define check_fd_is_open(o) +#endif + STATIC const mp_obj_type_t rawfile_type; STATIC void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { @@ -27,6 +37,7 @@ STATIC void fdfile_print(void (*print)(void *env, const char *fmt, ...), void *e STATIC machine_int_t fdfile_read(mp_obj_t o_in, void *buf, machine_uint_t size, int *errcode) { mp_obj_fdfile_t *o = o_in; + check_fd_is_open(o); machine_int_t r = read(o->fd, buf, size); if (r == -1) { *errcode = errno; @@ -36,6 +47,7 @@ STATIC machine_int_t fdfile_read(mp_obj_t o_in, void *buf, machine_uint_t size, STATIC machine_int_t fdfile_write(mp_obj_t o_in, const void *buf, machine_uint_t size, int *errcode) { mp_obj_fdfile_t *o = o_in; + check_fd_is_open(o); machine_int_t r = write(o->fd, buf, size); if (r == -1) { *errcode = errno; @@ -46,6 +58,9 @@ STATIC machine_int_t fdfile_write(mp_obj_t o_in, const void *buf, machine_uint_t STATIC mp_obj_t fdfile_close(mp_obj_t self_in) { mp_obj_fdfile_t *self = self_in; close(self->fd); +#ifdef MICROPY_CPYTHON_COMPAT + self->fd = -1; +#endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_close_obj, fdfile_close); @@ -57,6 +72,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fdfile___exit___obj, 4, 4, fdfile___e STATIC mp_obj_t fdfile_fileno(mp_obj_t self_in) { mp_obj_fdfile_t *self = self_in; + check_fd_is_open(self); return MP_OBJ_NEW_SMALL_INT((machine_int_t)self->fd); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fdfile_fileno_obj, fdfile_fileno); @@ -116,6 +132,7 @@ STATIC const mp_map_elem_t rawfile_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readall), (mp_obj_t)&mp_stream_readall_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, + { MP_OBJ_NEW_QSTR(MP_QSTR_readlines), (mp_obj_t)&mp_stream_unbuffered_readlines_obj}, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&fdfile_close_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR___enter__), (mp_obj_t)&mp_identity_obj }, diff --git a/unix/main.c b/unix/main.c index 4c86edeae5..6354184fdc 100644 --- a/unix/main.c +++ b/unix/main.c @@ -8,9 +8,9 @@ #include <sys/types.h> #include <errno.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "lexer.h" #include "lexerunix.h" @@ -142,7 +142,7 @@ STATIC char *prompt(char *p) { } STATIC void do_repl(void) { - printf("Micro Python build " MICROPY_GIT_HASH " on " MICROPY_BUILD_DATE "; UNIX version\n"); + printf("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; UNIX version\n"); for (;;) { char *line = prompt(">>> "); @@ -394,11 +394,7 @@ int main(int argc, char **argv) { return usage(argv); } } else { -#ifdef __MINGW32__ - char *basedir = _fullpath(NULL, argv[a], _MAX_PATH); -#else char *basedir = realpath(argv[a], NULL); -#endif if (basedir == NULL) { fprintf(stderr, "%s: can't open file '%s': [Errno %d] ", argv[0], argv[1], errno); perror(""); diff --git a/unix/modffi.c b/unix/modffi.c index be542625ed..39551c264f 100644 --- a/unix/modffi.c +++ b/unix/modffi.c @@ -4,9 +4,9 @@ #include <dlfcn.h> #include <ffi.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "runtime.h" diff --git a/unix/modsocket.c b/unix/modsocket.c index e52f5d92a9..898d5bfe9f 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -11,9 +11,9 @@ #include <netdb.h> #include <errno.h> +#include "mpconfig.h" #include "nlr.h" #include "misc.h" -#include "mpconfig.h" #include "qstr.h" #include "obj.h" #include "objtuple.h" diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 2d252427f0..b777cfbe31 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -16,6 +16,9 @@ #define MICROPY_USE_COMPUTED_GOTO (1) #define MICROPY_MOD_SYS_STDFILES (1) #define MICROPY_ENABLE_MOD_CMATH (1) +// Define to MICROPY_ERROR_REPORTING_DETAILED to get function, etc. +// names in exception messages (may require more RAM). +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) extern const struct _mp_obj_module_t mp_module_time; extern const struct _mp_obj_module_t mp_module_socket; diff --git a/windows/Makefile b/windows/Makefile index 2f5418886f..ce75a60985 100644 --- a/windows/Makefile +++ b/windows/Makefile @@ -30,6 +30,8 @@ endif SRC_C = \ unix/main.c \ unix/file.c \ + realpath.c \ + init.c \ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) diff --git a/windows/alloca.h b/windows/alloca.h new file mode 100644 index 0000000000..1cf7722669 --- /dev/null +++ b/windows/alloca.h @@ -0,0 +1,3 @@ +// Compatibility header to workaround lack of native alloca.h in some +// Windows toolchains. +#include <malloc.h> diff --git a/windows/init.c b/windows/init.c new file mode 100644 index 0000000000..78b8738f77 --- /dev/null +++ b/windows/init.c @@ -0,0 +1,5 @@ +#include <stdlib.h> + +void init() { + putenv("PRINTF_EXPONENT_DIGITS=2"); +} diff --git a/windows/init.h b/windows/init.h new file mode 100644 index 0000000000..70e535e495 --- /dev/null +++ b/windows/init.h @@ -0,0 +1 @@ +void init(void); diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index 993fef9d59..94b3334007 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -12,8 +12,10 @@ #define MICROPY_DEBUG_PRINTERS (1) #define MICROPY_ENABLE_REPL_HELPERS (1) #define MICROPY_ENABLE_LEXER_UNIX (1) +#define MICROPY_MOD_SYS_STDFILES (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_PORT_INIT_FUNC init() // type definitions for the specific machine @@ -33,3 +35,8 @@ typedef void *machine_ptr_t; // must be of pointer size typedef const void *machine_const_ptr_t; // must be of pointer size extern const struct _mp_obj_fun_native_t mp_builtin_open_obj; +#define MICROPY_EXTRA_BUILTINS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, + +#include "realpath.h" +#include "init.h" diff --git a/windows/realpath.c b/windows/realpath.c new file mode 100644 index 0000000000..550298a7d5 --- /dev/null +++ b/windows/realpath.c @@ -0,0 +1,42 @@ +#include <stdlib.h> +#include <errno.h> +#include <io.h> + +#ifndef R_OK + #define R_OK 4 +#endif + +// Make sure a path only has forward slashes. +char *to_unix_path(char *p) { + if (p != NULL) { + char *pp = p; + while (*pp != 0) { + if (*pp == '\\') + *pp = '/'; + ++pp; + } + } + return p; +} + +// Implement realpath() using _fullpath and make it use the same error codes as realpath() on unix. +// Also have it return a path with forward slashes only as some code relies on this, +// but _fullpath() returns backward slashes no matter what. +char *realpath(const char *path, char *resolved_path) { + char *ret = NULL; + if (path == NULL) { + errno = EINVAL; + } else if (access(path, R_OK) == 0) { + ret = resolved_path; + if (ret == NULL) + ret = malloc(_MAX_PATH); + if (ret == NULL) { + errno = ENOMEM; + } else { + ret = _fullpath(ret, path, _MAX_PATH); + if (ret == NULL) + errno = EIO; + } + } + return to_unix_path(ret); +} diff --git a/windows/realpath.h b/windows/realpath.h new file mode 100644 index 0000000000..77798acd57 --- /dev/null +++ b/windows/realpath.h @@ -0,0 +1,2 @@ + +extern char *realpath(const char *path, char *resolved_path); |