diff options
44 files changed, 1014 insertions, 431 deletions
diff --git a/py/argcheck.c b/py/argcheck.c index 5c5ea1bf80..aea71d0bd8 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -40,7 +40,7 @@ void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_all mp_obj_t given_arg; if (i < n_pos) { if (allowed[i].flags & MP_ARG_PARSE_KW_ONLY) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' argument must be given by a keyword", qstr_str(allowed[i].qstr))); + goto extra_positional; } pos_found++; given_arg = pos[i]; @@ -69,6 +69,7 @@ void mp_arg_parse_all(uint n_pos, const mp_obj_t *pos, mp_map_t *kws, uint n_all } if (pos_found < n_pos) { // TODO better error message + extra_positional: nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "extra positional arguments given")); } if (kws_found < kws->used) { @@ -51,7 +51,6 @@ #define MP_BC_POP_JUMP_IF_FALSE (0x47) // rel byte code offset, 16-bit signed, in excess #define MP_BC_JUMP_IF_TRUE_OR_POP (0x48) // rel byte code offset, 16-bit signed, in excess #define MP_BC_JUMP_IF_FALSE_OR_POP (0x49) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_SETUP_LOOP (0x4a) // rel byte code offset, 16-bit unsigned #define MP_BC_SETUP_WITH (0x4d) // rel byte code offset, 16-bit unsigned #define MP_BC_WITH_CLEANUP (0x4e) #define MP_BC_SETUP_EXCEPT (0x4f) // rel byte code offset, 16-bit unsigned diff --git a/py/binary.c b/py/binary.c index ee95d56e44..e57766b41c 100644 --- a/py/binary.c +++ b/py/binary.c @@ -49,6 +49,8 @@ int mp_binary_get_size(char struct_type, char val_type, uint *palign) { case 'q': case 'Q': // TODO: This is for x86 align = sizeof(int); size = sizeof(long long); break; + case 'P': case 'O': + align = size = sizeof(void*); break; } } } @@ -131,7 +133,9 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { } *ptr += size; - if (is_signed(val_type)) { + if (val_type == 'O') { + return (mp_obj_t)val; + } else if (is_signed(val_type)) { return mp_obj_new_int(val); } else { return mp_obj_new_int_from_uint(val); @@ -156,8 +160,16 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte ** #if MP_ENDIANNESS_BIG #error Not implemented #endif - machine_int_t val = mp_obj_int_get_checked(val_in); + machine_int_t val; byte *in = (byte*)&val; + switch (val_type) { + case 'O': + in = (byte*)&val_in; + break; + default: + val = mp_obj_get_int(val_in); + } + int in_delta, out_delta; uint val_sz = MIN(size, sizeof(val)); if (struct_type == '>') { diff --git a/py/builtinimport.c b/py/builtinimport.c index 262ee04a53..4a2f6510c3 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -3,6 +3,10 @@ #include <stdio.h> #include <string.h> #include <assert.h> +#ifdef __MINGW32__ +// For alloca() +#include <malloc.h> +#endif #include "nlr.h" #include "misc.h" diff --git a/py/compile.c b/py/compile.c index b0f1f9e00d..57f6f1546f 100644 --- a/py/compile.c +++ b/py/compile.c @@ -889,8 +889,7 @@ void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_d if (nfree == 0) { EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults); } else { - EMIT_ARG(build_tuple, nfree); - EMIT_ARG(make_closure, this_scope, n_pos_defaults, n_kw_defaults); + EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults); } } @@ -957,6 +956,8 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) { // we need to do this here before we start building the map for the default keywords if (comp->num_default_params > 0) { EMIT_ARG(build_tuple, comp->num_default_params); + } else { + EMIT(load_null); // sentinel indicating empty default positional args } // first default dict param, so make the map EMIT_ARG(build_map, 0); @@ -1009,6 +1010,7 @@ qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint // the default keywords args may have already made the tuple; if not, do it now if (comp->num_default_params > 0 && comp->num_dict_params == 0) { EMIT_ARG(build_tuple, comp->num_default_params); + EMIT(load_null); // sentinel indicating empty default keyword args } #endif @@ -41,10 +41,9 @@ typedef struct _emit_method_table_t { void (*load_const_dec)(emit_t *emit, qstr qstr); void (*load_const_id)(emit_t *emit, qstr qstr); void (*load_const_str)(emit_t *emit, qstr qstr, bool bytes); - void (*load_const_verbatim_str)(emit_t *emit, const char *str); // only needed for emitcpy + void (*load_null)(emit_t *emit); void (*load_fast)(emit_t *emit, qstr qstr, uint id_flags, int local_num); void (*load_deref)(emit_t *emit, qstr qstr, int local_num); - void (*load_closure)(emit_t *emit, qstr qstr, int local_num); // only needed for emitcpy void (*load_name)(emit_t *emit, qstr qstr); void (*load_global)(emit_t *emit, qstr qstr); void (*load_attr)(emit_t *emit, qstr qstr); @@ -73,7 +72,6 @@ typedef struct _emit_method_table_t { void (*pop_jump_if_false)(emit_t *emit, uint label); void (*jump_if_true_or_pop)(emit_t *emit, uint label); void (*jump_if_false_or_pop)(emit_t *emit, uint label); - void (*setup_loop)(emit_t *emit, uint label); void (*break_loop)(emit_t *emit, uint label, int except_depth); void (*continue_loop)(emit_t *emit, uint label, int except_depth); void (*setup_with)(emit_t *emit, uint label); @@ -100,13 +98,21 @@ typedef struct _emit_method_table_t { void (*unpack_sequence)(emit_t *emit, int n_args); void (*unpack_ex)(emit_t *emit, int n_left, int n_right); void (*make_function)(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults); - void (*make_closure)(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults); + void (*make_closure)(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults); void (*call_function)(emit_t *emit, int n_positional, int n_keyword, uint star_flags); void (*call_method)(emit_t *emit, int n_positional, int n_keyword, uint star_flags); void (*return_value)(emit_t *emit); void (*raise_varargs)(emit_t *emit, int n_args); void (*yield_value)(emit_t *emit); void (*yield_from)(emit_t *emit); + +#if MICROPY_EMIT_CPYTHON + // these methods are only needed for emitcpy + void (*load_const_verbatim_str)(emit_t *emit, const char *str); + void (*load_closure)(emit_t *emit, qstr qstr, int local_num); + void (*setup_loop)(emit_t *emit, uint label); +#endif + } emit_method_table_t; void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr); diff --git a/py/emitbc.c b/py/emitbc.c index d7b309a37f..f58cec1f1f 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -16,6 +16,8 @@ #include "emit.h" #include "bc0.h" +#if !MICROPY_EMIT_CPYTHON + struct _emit_t { pass_kind_t pass; int stack_size; @@ -421,11 +423,6 @@ STATIC void emit_bc_load_const_str(emit_t *emit, qstr qstr, bool bytes) { } } -STATIC void emit_bc_load_const_verbatim_str(emit_t *emit, const char *str) { - // not needed/supported for BC - assert(0); -} - STATIC void emit_bc_load_null(emit_t *emit) { emit_bc_pre(emit, 1); emit_write_byte_code_byte(emit, MP_BC_LOAD_NULL); @@ -447,11 +444,6 @@ STATIC void emit_bc_load_deref(emit_t *emit, qstr qstr, int local_num) { emit_write_byte_code_byte_uint(emit, MP_BC_LOAD_DEREF, local_num); } -STATIC void emit_bc_load_closure(emit_t *emit, qstr qstr, int local_num) { - // not needed/supported for BC - assert(0); -} - STATIC void emit_bc_load_name(emit_t *emit, qstr qstr) { emit_bc_pre(emit, 1); emit_write_byte_code_byte_qstr(emit, MP_BC_LOAD_NAME, qstr); @@ -598,11 +590,6 @@ STATIC void emit_bc_jump_if_false_or_pop(emit_t *emit, uint label) { emit_write_byte_code_byte_signed_label(emit, MP_BC_JUMP_IF_FALSE_OR_POP, label); } -STATIC void emit_bc_setup_loop(emit_t *emit, uint label) { - emit_bc_pre(emit, 0); - emit_write_byte_code_byte_unsigned_label(emit, MP_BC_SETUP_LOOP, label); -} - STATIC void emit_bc_unwind_jump(emit_t *emit, uint label, int except_depth) { if (except_depth == 0) { emit_bc_jump(emit, label); @@ -761,35 +748,21 @@ STATIC void emit_bc_make_function(emit_t *emit, scope_t *scope, uint n_pos_defau emit_bc_pre(emit, 1); emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_FUNCTION, scope->raw_code); } else { - if (n_pos_defaults == 0) { - // load dummy entry for non-existent positional default tuple - emit_bc_load_null(emit); - emit_bc_rot_two(emit); - } else if (n_kw_defaults == 0) { - // load dummy entry for non-existent keyword default dict - emit_bc_load_null(emit); - } emit_bc_pre(emit, -1); emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_FUNCTION_DEFARGS, scope->raw_code); } } -STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) { +STATIC void emit_bc_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) { if (n_pos_defaults == 0 && n_kw_defaults == 0) { - emit_bc_pre(emit, 0); + emit_bc_pre(emit, -n_closed_over + 1); emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_CLOSURE, scope->raw_code); + emit_write_byte_code_byte(emit, n_closed_over); } else { - if (n_pos_defaults == 0) { - // load dummy entry for non-existent positional default tuple - emit_bc_load_null(emit); - emit_bc_rot_three(emit); - } else if (n_kw_defaults == 0) { - // load dummy entry for non-existent keyword default dict - emit_bc_load_null(emit); - emit_bc_rot_two(emit); - } - emit_bc_pre(emit, -2); + assert(n_closed_over <= 255); + emit_bc_pre(emit, -2 - n_closed_over + 1); emit_write_byte_code_byte_ptr(emit, MP_BC_MAKE_CLOSURE_DEFARGS, scope->raw_code); + emit_write_byte_code_byte(emit, n_closed_over); } } @@ -869,10 +842,9 @@ const emit_method_table_t emit_bc_method_table = { emit_bc_load_const_dec, emit_bc_load_const_id, emit_bc_load_const_str, - emit_bc_load_const_verbatim_str, + emit_bc_load_null, emit_bc_load_fast, emit_bc_load_deref, - emit_bc_load_closure, emit_bc_load_name, emit_bc_load_global, emit_bc_load_attr, @@ -901,7 +873,6 @@ const emit_method_table_t emit_bc_method_table = { emit_bc_pop_jump_if_false, emit_bc_jump_if_true_or_pop, emit_bc_jump_if_false_or_pop, - emit_bc_setup_loop, emit_bc_unwind_jump, emit_bc_unwind_jump, emit_bc_setup_with, @@ -936,3 +907,5 @@ const emit_method_table_t emit_bc_method_table = { emit_bc_yield_value, emit_bc_yield_from, }; + +#endif // !MICROPY_EMIT_CPYTHON diff --git a/py/emitcpy.c b/py/emitcpy.c index 119cf818cf..a041c4f1e0 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -221,11 +221,9 @@ STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qstr, bool bytes) { } } -STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) { - emit_pre(emit, 1, 3); - if (emit->pass == PASS_3) { - printf("LOAD_CONST %s\n", str); - } +STATIC void emit_cpy_load_null(emit_t *emit) { + // unused for cpy + assert(0); } STATIC void emit_cpy_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) { @@ -242,13 +240,6 @@ STATIC void emit_cpy_load_deref(emit_t *emit, qstr qstr, int local_num) { } } -STATIC void emit_cpy_load_closure(emit_t *emit, qstr qstr, int local_num) { - emit_pre(emit, 1, 3); - if (emit->pass == PASS_3) { - printf("LOAD_CLOSURE %d %s\n", local_num, qstr_str(qstr)); - } -} - STATIC void emit_cpy_load_name(emit_t *emit, qstr qstr) { emit_pre(emit, 1, 3); if (emit->pass == PASS_3) { @@ -447,13 +438,6 @@ STATIC void emit_cpy_jump_if_false_or_pop(emit_t *emit, uint label) { } } -STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) { - emit_pre(emit, 0, 3); - if (emit->pass == PASS_3) { - printf("SETUP_LOOP %d\n", emit->label_offsets[label]); - } -} - STATIC void emit_cpy_break_loop(emit_t *emit, uint label, int except_depth) { emit_pre(emit, 0, 1); if (emit->pass == PASS_3) { @@ -764,7 +748,8 @@ STATIC void emit_cpy_make_function(emit_t *emit, scope_t *scope, uint n_pos_defa } } -STATIC void emit_cpy_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) { +STATIC void emit_cpy_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) { + emit_cpy_build_tuple(emit, n_closed_over); load_cpy_const_code_and_name(emit, scope->simple_name); emit_pre(emit, -2 - n_pos_defaults - 2 * n_kw_defaults, 3); if (emit->pass == PASS_3) { @@ -792,6 +777,27 @@ STATIC void emit_cpy_yield_from(emit_t *emit) { } } +STATIC void emit_cpy_load_const_verbatim_str(emit_t *emit, const char *str) { + emit_pre(emit, 1, 3); + if (emit->pass == PASS_3) { + printf("LOAD_CONST %s\n", str); + } +} + +STATIC void emit_cpy_load_closure(emit_t *emit, qstr qstr, int local_num) { + emit_pre(emit, 1, 3); + if (emit->pass == PASS_3) { + printf("LOAD_CLOSURE %d %s\n", local_num, qstr_str(qstr)); + } +} + +STATIC void emit_cpy_setup_loop(emit_t *emit, uint label) { + emit_pre(emit, 0, 3); + if (emit->pass == PASS_3) { + printf("SETUP_LOOP %d\n", emit->label_offsets[label]); + } +} + const emit_method_table_t emit_cpython_method_table = { emit_cpy_set_native_types, emit_cpy_start_pass, @@ -814,10 +820,9 @@ const emit_method_table_t emit_cpython_method_table = { emit_cpy_load_const_dec, emit_cpy_load_const_id, emit_cpy_load_const_str, - emit_cpy_load_const_verbatim_str, + emit_cpy_load_null, emit_cpy_load_fast, emit_cpy_load_deref, - emit_cpy_load_closure, emit_cpy_load_name, emit_cpy_load_global, emit_cpy_load_attr, @@ -846,7 +851,6 @@ const emit_method_table_t emit_cpython_method_table = { emit_cpy_pop_jump_if_false, emit_cpy_jump_if_true_or_pop, emit_cpy_jump_if_false_or_pop, - emit_cpy_setup_loop, emit_cpy_break_loop, emit_cpy_continue_loop, emit_cpy_setup_with, @@ -880,6 +884,11 @@ const emit_method_table_t emit_cpython_method_table = { emit_cpy_raise_varargs, emit_cpy_yield_value, emit_cpy_yield_from, + + // emitcpy specific functions + emit_cpy_load_const_verbatim_str, + emit_cpy_load_closure, + emit_cpy_setup_loop, }; #endif // MICROPY_EMIT_CPYTHON diff --git a/py/emitglue.c b/py/emitglue.c index ce296f4321..8b1fd97021 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -158,10 +158,17 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp return fun; } -mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args) { - DEBUG_OP_printf("make_closure_from_raw_code %p\n", rc); +mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args) { + DEBUG_OP_printf("make_closure_from_raw_code %p %u %p\n", rc, n_closed_over, argrs); // make function object - mp_obj_t ffun = mp_make_function_from_raw_code(rc, def_args, def_kw_args); + mp_obj_t ffun; + if (n_closed_over & 0x100) { + // default positional and keyword args given + ffun = mp_make_function_from_raw_code(rc, args[0], args[1]); + } else { + // default positional and keyword args not given + ffun = mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); + } // wrap function in closure object - return mp_obj_new_closure(ffun, closure_tuple); + return mp_obj_new_closure(ffun, n_closed_over & 0xff, args + ((n_closed_over >> 7) & 2)); } diff --git a/py/emitglue.h b/py/emitglue.h index 2f9960bfa1..9aea2e4d45 100644 --- a/py/emitglue.h +++ b/py/emitglue.h @@ -37,4 +37,4 @@ void mp_emit_glue_assign_native_code(mp_raw_code_t *rc, void *f, uint len, int n void mp_emit_glue_assign_inline_asm_code(mp_raw_code_t *rc, void *f, uint len, int n_args); mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args); -mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args); +mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, uint n_closed_over, const mp_obj_t *args); diff --git a/py/emitnative.c b/py/emitnative.c index d86456244a..79d6da67c1 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -695,9 +695,9 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qstr, bool bytes) { } } -STATIC void emit_native_load_const_verbatim_str(emit_t *emit, const char *str) { - // not supported/needed for viper - assert(0); +STATIC void emit_native_load_null(emit_t *emit) { + emit_native_pre(emit); + emit_post_push_imm(emit, VTYPE_PYOBJ, 0); } STATIC void emit_native_load_fast(emit_t *emit, qstr qstr, uint id_flags, int local_num) { @@ -735,11 +735,6 @@ STATIC void emit_native_load_deref(emit_t *emit, qstr qstr, int local_num) { assert(0); } -STATIC void emit_native_load_closure(emit_t *emit, qstr qstr, int local_num) { - // not implemented - assert(0); -} - STATIC void emit_native_load_name(emit_t *emit, qstr qstr) { emit_native_pre(emit); emit_call_with_imm_arg(emit, MP_F_LOAD_NAME, mp_load_name, qstr, REG_ARG_1); @@ -985,11 +980,6 @@ STATIC void emit_native_jump_if_false_or_pop(emit_t *emit, uint label) { assert(0); } -STATIC void emit_native_setup_loop(emit_t *emit, uint label) { - emit_native_pre(emit); - emit_post(emit); -} - STATIC void emit_native_break_loop(emit_t *emit, uint label, int except_depth) { emit_native_jump(emit, label); // TODO properly } @@ -1209,7 +1199,7 @@ STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, uint n_pos_d emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); } -STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, uint n_pos_defaults, uint n_kw_defaults) { +STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, uint n_closed_over, uint n_pos_defaults, uint n_kw_defaults) { assert(0); } @@ -1334,10 +1324,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_load_const_dec, emit_native_load_const_id, emit_native_load_const_str, - emit_native_load_const_verbatim_str, + emit_native_load_null, emit_native_load_fast, emit_native_load_deref, - emit_native_load_closure, emit_native_load_name, emit_native_load_global, emit_native_load_attr, @@ -1366,7 +1355,6 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_pop_jump_if_false, emit_native_jump_if_true_or_pop, emit_native_jump_if_false_or_pop, - emit_native_setup_loop, emit_native_break_loop, emit_native_continue_loop, emit_native_setup_with, diff --git a/py/emitpass1.c b/py/emitpass1.c index ca34f220eb..64b58c4757 100644 --- a/py/emitpass1.c +++ b/py/emitpass1.c @@ -189,6 +189,9 @@ const emit_method_table_t emit_pass1_method_table = { (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, +#if MICROPY_EMIT_CPYTHON + (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, (void*)emit_pass1_dummy, +#endif }; @@ -1,3 +1,4 @@ +#include <assert.h> #include <stdio.h> #include <string.h> #include <stdbool.h> @@ -434,8 +435,14 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) { if (n_bytes <= n_existing) { return ptr; } else { - // TODO check if we can grow inplace - void *ptr2 = gc_alloc(n_bytes); + // TODO false is incorrect! Should get value from current block! + void *ptr2 = gc_alloc(n_bytes, +#if MICROPY_ENABLE_FINALISER + FTB_GET(BLOCK_FROM_PTR((machine_uint_t)ptr)) +#else + false +#endif + ); if (ptr2 == NULL) { return ptr2; } @@ -444,86 +451,101 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) { return ptr2; } } -#endif + +#else // Alternative gc_realloc impl void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) { if (gc_lock_depth > 0) { return NULL; } - void *ptr_out = NULL; - machine_uint_t block = 0; - machine_uint_t ptr = (machine_uint_t)ptr_in; - + // check for pure allocation if (ptr_in == NULL) { return gc_alloc(n_bytes, false); } - if (VERIFY_PTR(ptr) // verify pointer - && (block = BLOCK_FROM_PTR(ptr)) // get first block - && ATB_GET_KIND(block) == AT_HEAD) { // make sure it's a HEAD block - - byte block_type; - machine_uint_t n_free = 0; - machine_uint_t n_blocks = 1; // counting HEAD block - machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB; - - // get the number of consecutive tail blocks and - // the number of free blocks after last tail block - // stop if we reach (or are at) end of heap - while ((block + n_blocks + n_free) < max_block - // stop as soon as we find enough blocks for n_bytes - && (n_bytes > ((n_blocks+n_free) * BYTES_PER_BLOCK)) - // stop if block is HEAD - && (block_type = ATB_GET_KIND(block + n_blocks + n_free)) != AT_HEAD) { - switch (block_type) { - case AT_FREE: n_free++; break; - case AT_TAIL: n_blocks++; break; - default: break; - } + machine_uint_t ptr = (machine_uint_t)ptr_in; + + // sanity check the ptr + if (!VERIFY_PTR(ptr)) { + return NULL; + } + + // get first block + machine_uint_t block = BLOCK_FROM_PTR(ptr); + + // sanity check the ptr is pointing to the head of a block + if (ATB_GET_KIND(block) != AT_HEAD) { + return NULL; + } + + // compute number of new blocks that are requested + machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK; + + // get the number of consecutive tail blocks and + // the number of free blocks after last tail block + // stop if we reach (or are at) end of heap + machine_uint_t n_free = 0; + machine_uint_t n_blocks = 1; // counting HEAD block + machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB; + while (block + n_blocks + n_free < max_block) { + if (n_blocks + n_free >= new_blocks) { + // stop as soon as we find enough blocks for n_bytes + break; } - // number of allocated bytes - machine_uint_t n_existing = n_blocks * BYTES_PER_BLOCK; - - // check if realloc'ing to a smaller size - if (n_bytes <= n_existing) { - ptr_out = ptr_in; - // free unneeded tail blocks - for (machine_uint_t bl = block + n_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) { - ATB_ANY_TO_FREE(bl); - } + byte block_type = ATB_GET_KIND(block + n_blocks + n_free); + switch (block_type) { + case AT_FREE: n_free++; continue; + case AT_TAIL: n_blocks++; continue; + case AT_MARK: assert(0); + } + break; + } - // check if we can expand in place - } else if (n_bytes <= (n_existing + (n_free * BYTES_PER_BLOCK))) { - // number of blocks needed to expand +1 if there's a remainder - machine_uint_t n_diff = ( n_bytes - n_existing)/BYTES_PER_BLOCK+ - ((n_bytes - n_existing)%BYTES_PER_BLOCK!=0); + // return original ptr if it already has the requested number of blocks + if (new_blocks == n_blocks) { + return ptr_in; + } - DEBUG_printf("gc_realloc: expanding " UINT_FMT " blocks (" UINT_FMT " bytes) to " UINT_FMT " blocks (" UINT_FMT " bytes)\n", - n_existing/BYTES_PER_BLOCK, n_existing, n_existing/BYTES_PER_BLOCK+n_diff, n_existing + n_diff*BYTES_PER_BLOCK); + // check if we can shrink the allocated area + if (new_blocks < n_blocks) { + // free unneeded tail blocks + for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) { + ATB_ANY_TO_FREE(bl); + } + return ptr_in; + } - // mark rest of blocks as used tail - for (machine_uint_t bl = block + n_blocks; bl < (block + n_blocks + n_diff); bl++) { - ATB_FREE_TO_TAIL(bl); - } - ptr_out = ptr_in; + // check if we can expand in place + if (new_blocks <= n_blocks + n_free) { + // mark few more blocks as used tail + for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) { + assert(ATB_GET_KIND(bl) == AT_FREE); + ATB_FREE_TO_TAIL(bl); + } + return ptr_in; + } - // try to find a new contiguous chain - } else if ((ptr_out = gc_alloc(n_bytes, + // can't resize inplace; try to find a new contiguous chain + void *ptr_out = gc_alloc(n_bytes, #if MICROPY_ENABLE_FINALISER - FTB_GET(block) + FTB_GET(block) #else - false + false #endif - )) != NULL) { - DEBUG_printf("gc_realloc: allocating new block\n"); - memcpy(ptr_out, ptr_in, n_existing); - gc_free(ptr_in); - } + ); + + // check that the alloc succeeded + if (ptr_out == NULL) { + return NULL; } + DEBUG_printf("gc_realloc: allocating new block\n"); + memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK); + gc_free(ptr_in); return ptr_out; } +#endif // Alternative gc_realloc impl void gc_dump_info() { gc_info_t info; diff --git a/py/nlrx86.S b/py/nlrx86.S index 003de5095f..145bdb9da0 100644 --- a/py/nlrx86.S +++ b/py/nlrx86.S @@ -61,7 +61,11 @@ nlr_jump: #endif mov nlr_top, %edx # load nlr_top test %edx, %edx # check for nlr_top being NULL +#ifdef _WIN32 + je _nlr_jump_fail # fail if nlr_top is NULL +#else je nlr_jump_fail # fail if nlr_top is NULL +#endif mov 4(%esp), %eax # load return value mov %eax, 4(%edx) # store return value mov (%edx), %eax # load prev nlr_top @@ -357,7 +357,7 @@ mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char mp_obj_t mp_obj_new_fun_bc(uint scope_flags, qstr *args, uint n_args, mp_obj_t def_args, const byte *code); mp_obj_t mp_obj_new_fun_asm(uint n_args, void *fun); mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun); -mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple); +mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed, const mp_obj_t *closed); mp_obj_t mp_obj_new_tuple(uint n, const mp_obj_t *items); mp_obj_t mp_obj_new_list(uint n, mp_obj_t *items); mp_obj_t mp_obj_new_dict(int n_args); diff --git a/py/objarray.c b/py/objarray.c index b7a84ba4cf..ce107ddf25 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -136,10 +136,18 @@ STATIC mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value if (value == MP_OBJ_NULL) { // delete item // TODO implement + // TODO: confirmed that both bytearray and array.array support + // slice deletion return MP_OBJ_NOT_SUPPORTED; } else { mp_obj_array_t *o = self_in; if (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) { + if (value != MP_OBJ_SENTINEL) { + // Only getting a slice is suported so far, not assignment + // TODO: confirmed that both bytearray and array.array support + // slice assignment (incl. of different size) + return MP_OBJ_NOT_SUPPORTED; + } machine_uint_t start, stop; if (!m_seq_get_fast_slice_indexes(o->len, index_in, &start, &stop)) { assert(0); diff --git a/py/objcell.c b/py/objcell.c index d8517587df..7fdf07b046 100644 --- a/py/objcell.c +++ b/py/objcell.c @@ -20,9 +20,24 @@ void mp_obj_cell_set(mp_obj_t self_in, mp_obj_t obj) { self->obj = obj; } +#if 0 +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 "); + 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, ">"); +} +#endif + const mp_obj_type_t cell_type = { { &mp_type_type }, .name = MP_QSTR_, // should never need to print cell type + //.print = cell_print, }; mp_obj_t mp_obj_new_cell(mp_obj_t obj) { diff --git a/py/objclosure.c b/py/objclosure.c index 9b4a3f8933..09371b0348 100644 --- a/py/objclosure.c +++ b/py/objclosure.c @@ -5,13 +5,14 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "objtuple.h" #include "runtime.h" typedef struct _mp_obj_closure_t { mp_obj_base_t base; mp_obj_t fun; - uint n_closed; - mp_obj_t *closed; + machine_uint_t n_closed; + mp_obj_t closed[]; } mp_obj_closure_t; mp_obj_t closure_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { @@ -37,16 +38,34 @@ mp_obj_t closure_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t * } } +#if 0 +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); + for (int i = 0; i < o->n_closed; i++) { + if (o->closed[i] == MP_OBJ_NULL) { + print(env, "(nil)"); + } else { + mp_obj_print_helper(print, env, o->closed[i], PRINT_REPR); + } + print(env, " "); + } + print(env, ">"); +} +#endif + const mp_obj_type_t closure_type = { { &mp_type_type }, .name = MP_QSTR_closure, + //.print = closure_print, .call = closure_call, }; -mp_obj_t mp_obj_new_closure(mp_obj_t fun, mp_obj_t closure_tuple) { - mp_obj_closure_t *o = m_new_obj(mp_obj_closure_t); +mp_obj_t mp_obj_new_closure(mp_obj_t fun, uint n_closed_over, const mp_obj_t *closed) { + mp_obj_closure_t *o = m_new_obj_var(mp_obj_closure_t, mp_obj_t, n_closed_over); o->base.type = &closure_type; o->fun = fun; - mp_obj_tuple_get(closure_tuple, &o->n_closed, &o->closed); + o->n_closed = n_closed_over; + memcpy(o->closed, closed, n_closed_over * sizeof(mp_obj_t)); return o; } diff --git a/py/objfun.c b/py/objfun.c index c7144f3078..940b64a66e 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -2,6 +2,10 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#ifdef __MINGW32__ +// For alloca() +#include <malloc.h> +#endif #include "nlr.h" #include "misc.h" diff --git a/py/showbc.c b/py/showbc.c index bf25966e97..4a8e12e68b 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -287,11 +287,6 @@ void mp_byte_code_print(const byte *ip, int len) { printf("JUMP_IF_FALSE_OR_POP " UINT_FMT, ip + unum - ip_start); break; - case MP_BC_SETUP_LOOP: - DECODE_ULABEL; // loop labels are always forward - printf("SETUP_LOOP " UINT_FMT, ip + unum - ip_start); - break; - case MP_BC_SETUP_WITH: DECODE_ULABEL; // loop-like labels are always forward printf("SETUP_WITH " UINT_FMT, ip + unum - ip_start); @@ -481,13 +481,6 @@ dispatch_loop: } DISPATCH(); - /* we are trying to get away without using this opcode - ENTRY(MP_BC_SETUP_LOOP): - DECODE_UINT; - // push_block(MP_BC_SETUP_LOOP, ip + unum, sp) - DISPATCH(); - */ - ENTRY(MP_BC_SETUP_WITH): obj1 = TOP(); SET_TOP(mp_load_attr(obj1, MP_QSTR___exit__)); @@ -759,19 +752,23 @@ unwind_jump: SET_TOP(mp_make_function_from_raw_code((mp_raw_code_t*)unum, TOP(), obj1)); DISPATCH(); - ENTRY(MP_BC_MAKE_CLOSURE): + ENTRY(MP_BC_MAKE_CLOSURE): { DECODE_PTR; - // Stack layout: closure_tuple <- TOS - SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, TOP(), MP_OBJ_NULL, MP_OBJ_NULL)); + machine_uint_t n_closed_over = *ip++; + // Stack layout: closed_overs <- TOS + sp -= n_closed_over - 1; + SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, n_closed_over, sp)); DISPATCH(); + } - ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): + ENTRY(MP_BC_MAKE_CLOSURE_DEFARGS): { DECODE_PTR; - // Stack layout: def_tuple def_dict closure_tuple <- TOS - obj1 = POP(); - obj2 = POP(); - SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, obj1, TOP(), obj2)); + machine_uint_t n_closed_over = *ip++; + // Stack layout: def_tuple def_dict closed_overs <- TOS + sp -= 2 + n_closed_over - 1; + SET_TOP(mp_make_closure_from_raw_code((mp_raw_code_t*)unum, 0x100 | n_closed_over, sp)); DISPATCH(); + } ENTRY(MP_BC_CALL_FUNCTION): DECODE_UINT; diff --git a/py/vmentrytable.h b/py/vmentrytable.h index 2e1d1fb04f..c4d15427d7 100644 --- a/py/vmentrytable.h +++ b/py/vmentrytable.h @@ -45,7 +45,6 @@ static void* entry_table[256] = { [MP_BC_POP_JUMP_IF_FALSE] = &&entry_MP_BC_POP_JUMP_IF_FALSE, [MP_BC_JUMP_IF_TRUE_OR_POP] = &&entry_MP_BC_JUMP_IF_TRUE_OR_POP, [MP_BC_JUMP_IF_FALSE_OR_POP] = &&entry_MP_BC_JUMP_IF_FALSE_OR_POP, -// [MP_BC_SETUP_LOOP] = &&entry_MP_BC_SETUP_LOOP, [MP_BC_SETUP_WITH] = &&entry_MP_BC_SETUP_WITH, [MP_BC_WITH_CLEANUP] = &&entry_MP_BC_WITH_CLEANUP, [MP_BC_UNWIND_JUMP] = &&entry_MP_BC_UNWIND_JUMP, diff --git a/stmhal/Makefile b/stmhal/Makefile index 3cd51c0166..c4c7f7bfc1 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -97,6 +97,7 @@ SRC_C = \ servo.c \ dac.c \ adc.c \ + bufhelper.c \ i2c.c \ spi.c \ diff --git a/stmhal/accel.c b/stmhal/accel.c index 339a93ea40..9890aa3c7f 100644 --- a/stmhal/accel.c +++ b/stmhal/accel.c @@ -12,6 +12,8 @@ #include "i2c.h" #include "accel.h" +#if MICROPY_HW_HAS_MMA7660 + #define MMA_ADDR (0x98) #define MMA_REG_X (0) #define MMA_REG_Y (1) @@ -33,7 +35,15 @@ void accel_init(void) { } STATIC void accel_start(void) { - // start the I2C bus + // start the I2C bus in master mode + I2CHandle1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + I2CHandle1.Init.ClockSpeed = 400000; + I2CHandle1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; + I2CHandle1.Init.DutyCycle = I2C_DUTYCYCLE_16_9; + I2CHandle1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; + I2CHandle1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; + I2CHandle1.Init.OwnAddress1 = PYB_I2C_MASTER_ADDRESS; + I2CHandle1.Init.OwnAddress2 = 0xfe; // unused i2c_init(&I2CHandle1); // turn off AVDD, wait 20ms, turn on AVDD, wait 20ms again @@ -174,3 +184,5 @@ const mp_obj_type_t pyb_accel_type = { .make_new = pyb_accel_make_new, .locals_dict = (mp_obj_t)&pyb_accel_locals_dict, }; + +#endif // MICROPY_HW_HAS_MMA7660 diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h index a01d37aea8..b70b56d9ce 100644 --- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -17,6 +17,9 @@ #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_I2C1 (0) +#define MICROPY_HW_ENABLE_SPI1 (0) +#define MICROPY_HW_ENABLE_SPI3 (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 9386c04a2d..00c6a1acfc 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -13,6 +13,9 @@ #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_I2C1 (1) +#define MICROPY_HW_ENABLE_SPI1 (1) +#define MICROPY_HW_ENABLE_SPI3 (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 f47a01bc4c..02ad78a64c 100644 --- a/stmhal/boards/PYBV3/mpconfigboard.h +++ b/stmhal/boards/PYBV3/mpconfigboard.h @@ -13,6 +13,9 @@ #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_I2C1 (1) +#define MICROPY_HW_ENABLE_SPI1 (1) +#define MICROPY_HW_ENABLE_SPI3 (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 1846491c3a..550f1633f9 100644 --- a/stmhal/boards/PYBV4/mpconfigboard.h +++ b/stmhal/boards/PYBV4/mpconfigboard.h @@ -13,6 +13,9 @@ #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (1) #define MICROPY_HW_ENABLE_DAC (1) +#define MICROPY_HW_ENABLE_I2C1 (1) +#define MICROPY_HW_ENABLE_SPI1 (1) +#define MICROPY_HW_ENABLE_SPI3 (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) @@ -20,7 +23,7 @@ #define MICROPY_HW_USRSW_EXTI_MODE (GPIO_MODE_IT_FALLING) #define MICROPY_HW_USRSW_PRESSED (0) -// LEDs +// The pyboard has 4 LEDs #define MICROPY_HW_LED1 (pin_A13) // red #define MICROPY_HW_LED2 (pin_A14) // green #define MICROPY_HW_LED3 (pin_A15) // yellow diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h index 3bfdfbfb80..c83bb162bb 100644 --- a/stmhal/boards/STM32F4DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h @@ -13,6 +13,9 @@ #define MICROPY_HW_ENABLE_TIMER (1) #define MICROPY_HW_ENABLE_SERVO (0) #define MICROPY_HW_ENABLE_DAC (0) +#define MICROPY_HW_ENABLE_I2C1 (1) +#define MICROPY_HW_ENABLE_SPI1 (1) +#define MICROPY_HW_ENABLE_SPI3 (0) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) diff --git a/stmhal/bufhelper.c b/stmhal/bufhelper.c new file mode 100644 index 0000000000..5612a048dc --- /dev/null +++ b/stmhal/bufhelper.c @@ -0,0 +1,29 @@ +#include "misc.h" +#include "mpconfig.h" +#include "qstr.h" +#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) { + if (MP_OBJ_IS_INT(o)) { + tmp_data[0] = mp_obj_get_int(o); + bufinfo->buf = tmp_data; + bufinfo->len = 1; + bufinfo->typecode = 'B'; + } else { + mp_get_buffer_raise(o, bufinfo, MP_BUFFER_READ); + } +} + +mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, mp_buffer_info_t *bufinfo) { + if (MP_OBJ_IS_INT(o)) { + // allocate a new bytearray of given length + bufinfo->len = mp_obj_get_int(o); + bufinfo->typecode = 'B'; + return mp_obj_str_builder_start(&mp_type_bytes, bufinfo->len, (byte**)&bufinfo->buf); + } else { + // get the existing buffer + mp_get_buffer_raise(o, bufinfo, MP_BUFFER_WRITE); + return MP_OBJ_NULL; + } +} diff --git a/stmhal/bufhelper.h b/stmhal/bufhelper.h new file mode 100644 index 0000000000..9b58e817c8 --- /dev/null +++ b/stmhal/bufhelper.h @@ -0,0 +1,2 @@ +void pyb_buf_get_for_send(mp_obj_t o, mp_buffer_info_t *bufinfo, uint8_t *tmp_data); +mp_obj_t pyb_buf_get_for_recv(mp_obj_t o, mp_buffer_info_t *bufinfo); diff --git a/stmhal/i2c.c b/stmhal/i2c.c index 8a8dd7dc2d..d94a99ee9e 100644 --- a/stmhal/i2c.c +++ b/stmhal/i2c.c @@ -11,15 +11,23 @@ #include "runtime.h" #include "pin.h" #include "genhdr/pins.h" +#include "bufhelper.h" #include "i2c.h" +#define PYB_I2C_MASTER (0) +#define PYB_I2C_SLAVE (1) + +#if MICROPY_HW_ENABLE_I2C1 I2C_HandleTypeDef I2CHandle1 = {.Instance = NULL}; +#endif I2C_HandleTypeDef I2CHandle2 = {.Instance = NULL}; void i2c_init0(void) { // reset the I2C1 handles +#if MICROPY_HW_ENABLE_I2C1 memset(&I2CHandle1, 0, sizeof(I2C_HandleTypeDef)); I2CHandle1.Instance = I2C1; +#endif memset(&I2CHandle2, 0, sizeof(I2C_HandleTypeDef)); I2CHandle2.Instance = I2C2; } @@ -32,20 +40,26 @@ void i2c_init(I2C_HandleTypeDef *i2c) { GPIO_InitStructure.Pull = GPIO_NOPULL; // have external pull-up resistors on both lines const pin_obj_t *pins[2]; - if (i2c == &I2CHandle1) { + if (0) { +#if MICROPY_HW_ENABLE_I2C1 + } else if (i2c == &I2CHandle1) { // X-skin: X9=PB6=SCL, X10=PB7=SDA pins[0] = &pin_B6; pins[1] = &pin_B7; GPIO_InitStructure.Alternate = GPIO_AF4_I2C1; // enable the I2C clock __I2C1_CLK_ENABLE(); - } else { +#endif + } else if (i2c == &I2CHandle2) { // Y-skin: Y9=PB10=SCL, Y10=PB11=SDA pins[0] = &pin_B10; pins[1] = &pin_B11; GPIO_InitStructure.Alternate = GPIO_AF4_I2C2; // enable the I2C clock __I2C2_CLK_ENABLE(); + } else { + // I2C does not exist for this board (shouldn't get here, should be checked by caller) + return; } // init the GPIO lines @@ -54,66 +68,152 @@ void i2c_init(I2C_HandleTypeDef *i2c) { HAL_GPIO_Init(pins[i]->gpio, &GPIO_InitStructure); } - // enable the I2C clock - if (i2c == &I2CHandle1) { - __I2C1_CLK_ENABLE(); - } else { - __I2C2_CLK_ENABLE(); - } - // init the I2C device - i2c->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; - i2c->Init.ClockSpeed = 400000; - i2c->Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; - i2c->Init.DutyCycle = I2C_DUTYCYCLE_16_9; - i2c->Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; - i2c->Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; - i2c->Init.OwnAddress1 = 0xfe; // unused - i2c->Init.OwnAddress2 = 0xfe; // unused - if (HAL_I2C_Init(i2c) != HAL_OK) { // init error + // TODO should raise an exception, but this function is not necessarily going to be + // called via Python, so may not be properly wrapped in an NLR handler printf("HardwareError: HAL_I2C_Init failed\n"); return; } } +void i2c_deinit(I2C_HandleTypeDef *i2c) { + HAL_I2C_DeInit(i2c); + if (0) { +#if MICROPY_HW_ENABLE_I2C1 + } else if (i2c->Instance == I2C1) { + __I2C1_FORCE_RESET(); + __I2C1_RELEASE_RESET(); + __I2C1_CLK_DISABLE(); +#endif + } else if (i2c->Instance == I2C2) { + __I2C2_FORCE_RESET(); + __I2C2_RELEASE_RESET(); + __I2C2_CLK_DISABLE(); + } +} + /******************************************************************************/ /* Micro Python bindings */ -#define PYB_NUM_I2C (2) - typedef struct _pyb_i2c_obj_t { mp_obj_base_t base; I2C_HandleTypeDef *i2c; } pyb_i2c_obj_t; -STATIC const pyb_i2c_obj_t pyb_i2c_obj[PYB_NUM_I2C] = {{{&pyb_i2c_type}, &I2CHandle1}, {{&pyb_i2c_type}, &I2CHandle2}}; +STATIC inline bool in_master_mode(pyb_i2c_obj_t *self) { return self->i2c->Init.OwnAddress1 == PYB_I2C_MASTER_ADDRESS; } + +STATIC const pyb_i2c_obj_t pyb_i2c_obj[] = { +#if MICROPY_HW_ENABLE_I2C1 + {{&pyb_i2c_type}, &I2CHandle1}, +#else + {{&pyb_i2c_type}, NULL}, +#endif + {{&pyb_i2c_type}, &I2CHandle2} +}; +#define PYB_NUM_I2C (sizeof(pyb_i2c_obj) / sizeof(pyb_i2c_obj[0])) + +STATIC void pyb_i2c_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_i2c_obj_t *self = self_in; + + uint i2c_num; + if (self->i2c->Instance == I2C1) { i2c_num = 1; } + else { i2c_num = 2; } + + if (self->i2c->State == HAL_I2C_STATE_RESET) { + print(env, "I2C(%u)", i2c_num); + } else { + if (in_master_mode(self)) { + print(env, "I2C(%u, I2C.MASTER, baudrate=%u)", i2c_num, self->i2c->Init.ClockSpeed); + } else { + print(env, "I2C(%u, I2C.SLAVE, addr=0x%02x)", i2c_num, (self->i2c->Instance->OAR1 >> 1) & 0x7f); + } + } +} + +STATIC const mp_arg_parse_t pyb_i2c_init_accepted_args[] = { + { MP_QSTR_mode, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} }, + { MP_QSTR_addr, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 0x12} }, + { MP_QSTR_baudrate, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 400000} }, + { MP_QSTR_gencall, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_BOOL, {.u_bool = false} }, +}; +#define PYB_I2C_INIT_NUM_ARGS (sizeof(pyb_i2c_init_accepted_args) / sizeof(pyb_i2c_init_accepted_args[0])) + +STATIC mp_obj_t pyb_i2c_init_helper(const pyb_i2c_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + mp_arg_parse_val_t vals[PYB_I2C_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args, args, kw_args, PYB_I2C_INIT_NUM_ARGS, pyb_i2c_init_accepted_args, vals); + + // set the I2C configuration values + I2C_InitTypeDef *init = &self->i2c->Init; + + if (vals[0].u_int == PYB_I2C_MASTER) { + // use a special address to indicate we are a master + init->OwnAddress1 = PYB_I2C_MASTER_ADDRESS; + } else { + init->OwnAddress1 = (vals[1].u_int << 1) & 0xfe; + } + + init->AddressingMode = I2C_ADDRESSINGMODE_7BIT; + init->ClockSpeed = MIN(vals[2].u_int, 400000); + init->DualAddressMode = I2C_DUALADDRESS_DISABLED; + init->DutyCycle = I2C_DUTYCYCLE_16_9; + init->GeneralCallMode = vals[3].u_bool ? I2C_GENERALCALL_ENABLED : I2C_GENERALCALL_DISABLED; + init->NoStretchMode = I2C_NOSTRETCH_DISABLED; + init->OwnAddress2 = 0xfe; // unused + + // init the I2C bus + i2c_init(self->i2c); + + return mp_const_none; +} STATIC mp_obj_t pyb_i2c_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); + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); // get i2c number machine_int_t i2c_id = mp_obj_get_int(args[0]) - 1; // check i2c number - if (!(0 <= i2c_id && i2c_id < PYB_NUM_I2C)) { + if (!(0 <= i2c_id && i2c_id < PYB_NUM_I2C && pyb_i2c_obj[i2c_id].i2c != NULL)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "I2C bus %d does not exist", i2c_id + 1)); } - // get i2c object + // get I2C object const pyb_i2c_obj_t *i2c_obj = &pyb_i2c_obj[i2c_id]; - // start the peripheral - i2c_init(i2c_obj->i2c); + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_i2c_init_helper(i2c_obj, n_args - 1, args + 1, &kw_args); + } return (mp_obj_t)i2c_obj; } +STATIC mp_obj_t pyb_i2c_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_i2c_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_init_obj, 1, pyb_i2c_init); + +STATIC mp_obj_t pyb_i2c_deinit(mp_obj_t self_in) { + pyb_i2c_obj_t *self = self_in; + i2c_deinit(self->i2c); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_deinit_obj, pyb_i2c_deinit); + // Check if an I2C device responds to the given address. STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) { pyb_i2c_obj_t *self = self_in; + + if (!in_master_mode(self)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master")); + } + machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_o) << 1; for (int i = 0; i < 10; i++) { @@ -125,13 +225,16 @@ STATIC mp_obj_t pyb_i2c_is_ready(mp_obj_t self_in, mp_obj_t i2c_addr_o) { return mp_const_false; } - STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_i2c_is_ready_obj, pyb_i2c_is_ready); // Scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond. STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) { pyb_i2c_obj_t *self = self_in; + if (!in_master_mode(self)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master")); + } + mp_obj_t list = mp_obj_new_list(0, NULL); for (uint addr = 1; addr <= 127; addr++) { @@ -146,88 +249,156 @@ STATIC mp_obj_t pyb_i2c_scan(mp_obj_t self_in) { return list; } - STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_i2c_scan_obj, pyb_i2c_scan); -STATIC mp_obj_t pyb_i2c_read(mp_obj_t self_in, mp_obj_t i2c_addr_in, mp_obj_t n_in) { - pyb_i2c_obj_t *self = self_in; - machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_in) << 1; - machine_uint_t n = mp_obj_get_int(n_in); +STATIC const mp_arg_parse_t pyb_i2c_send_accepted_args[] = { + { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_PARSE_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_I2C_SEND_NUM_ARGS (sizeof(pyb_i2c_send_accepted_args) / sizeof(pyb_i2c_send_accepted_args[0])) + +STATIC mp_obj_t pyb_i2c_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + pyb_i2c_obj_t *self = args[0]; + + // parse args + mp_arg_parse_val_t vals[PYB_I2C_SEND_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_SEND_NUM_ARGS, pyb_i2c_send_accepted_args, vals); - byte *data; - mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, n, &data); - HAL_StatusTypeDef status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, data, n, 500); + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); + + // send the data + HAL_StatusTypeDef status; + if (in_master_mode(self)) { + if (vals[1].u_int == PYB_I2C_MASTER_ADDRESS) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "addr argument required")); + } + machine_uint_t i2c_addr = vals[1].u_int << 1; + status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, vals[2].u_int); + } else { + status = HAL_I2C_Slave_Transmit(self->i2c, bufinfo.buf, bufinfo.len, vals[2].u_int); + } if (status != HAL_OK) { // TODO really need a HardwareError object, or something - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Master_Receive failed with code %d", status)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_xxx_Transmit failed with code %d", status)); } - return mp_obj_str_builder_end(o); + return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_send_obj, 1, pyb_i2c_send); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_i2c_read_obj, pyb_i2c_read); +STATIC const mp_arg_parse_t pyb_i2c_recv_accepted_args[] = { + { MP_QSTR_recv, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_PARSE_INT, {.u_int = PYB_I2C_MASTER_ADDRESS} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_I2C_RECV_NUM_ARGS (sizeof(pyb_i2c_recv_accepted_args) / sizeof(pyb_i2c_recv_accepted_args[0])) -STATIC mp_obj_t pyb_i2c_write(mp_obj_t self_in, mp_obj_t i2c_addr_in, mp_obj_t data_in) { - pyb_i2c_obj_t *self = self_in; - machine_uint_t i2c_addr = mp_obj_get_int(i2c_addr_in) << 1; +STATIC mp_obj_t pyb_i2c_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + pyb_i2c_obj_t *self = args[0]; + + // parse args + mp_arg_parse_val_t vals[PYB_I2C_RECV_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_RECV_NUM_ARGS, pyb_i2c_recv_accepted_args, vals); + + // get the buffer to receive into + mp_buffer_info_t bufinfo; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo); + + // receive the data HAL_StatusTypeDef status; - if (MP_OBJ_IS_INT(data_in)) { - uint8_t data[1] = {mp_obj_get_int(data_in)}; - status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, data, 1, 500); + if (in_master_mode(self)) { + if (vals[1].u_int == PYB_I2C_MASTER_ADDRESS) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "addr argument required")); + } + machine_uint_t i2c_addr = vals[1].u_int << 1; + status = HAL_I2C_Master_Receive(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, vals[2].u_int); } else { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); - status = HAL_I2C_Master_Transmit(self->i2c, i2c_addr, bufinfo.buf, bufinfo.len, 500); + status = HAL_I2C_Slave_Receive(self->i2c, bufinfo.buf, bufinfo.len, vals[2].u_int); } if (status != HAL_OK) { // TODO really need a HardwareError object, or something - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Master_Transmit failed with code %d", status)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_xxx_Receive failed with code %d", status)); } - return mp_const_none; + // return the received data + if (o_ret == MP_OBJ_NULL) { + return vals[0].u_obj; + } else { + return mp_obj_str_builder_end(o_ret); + } } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_recv_obj, 1, pyb_i2c_recv); -STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_i2c_write_obj, pyb_i2c_write); +STATIC const mp_arg_parse_t pyb_i2c_mem_read_accepted_args[] = { + { MP_QSTR_data, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_addr, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} }, + { MP_QSTR_memaddr, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_I2C_MEM_READ_NUM_ARGS (sizeof(pyb_i2c_mem_read_accepted_args) / sizeof(pyb_i2c_mem_read_accepted_args[0])) -STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t pyb_i2c_mem_read(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { pyb_i2c_obj_t *self = args[0]; - machine_uint_t i2c_addr = mp_obj_get_int(args[1]) << 1; - machine_uint_t mem_addr = mp_obj_get_int(args[2]); - machine_uint_t n = mp_obj_get_int(args[3]); - byte *data; - mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, n, &data); - HAL_StatusTypeDef status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, data, n, 200); + if (!in_master_mode(self)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master")); + } + + // parse args + mp_arg_parse_val_t vals[PYB_I2C_MEM_READ_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_MEM_READ_NUM_ARGS, pyb_i2c_mem_read_accepted_args, vals); + + // get the buffer to read into + mp_buffer_info_t bufinfo; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo); - //printf("Read got %d\n", status); + // get the addresses + machine_uint_t i2c_addr = vals[1].u_int << 1; + machine_uint_t mem_addr = vals[2].u_int; + + HAL_StatusTypeDef status = HAL_I2C_Mem_Read(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, bufinfo.buf, bufinfo.len, vals[3].u_int); if (status != HAL_OK) { // TODO really need a HardwareError object, or something nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_I2C_Mem_Read failed with code %d", status)); } - return mp_obj_str_builder_end(o); + // return the read data + if (o_ret == MP_OBJ_NULL) { + return vals[0].u_obj; + } else { + return mp_obj_str_builder_end(o_ret); + } } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_read_obj, 1, pyb_i2c_mem_read); -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_read_obj, 4, 4, pyb_i2c_mem_read); - -STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args) { +STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { pyb_i2c_obj_t *self = args[0]; - machine_uint_t i2c_addr = mp_obj_get_int(args[1]) << 1; - machine_uint_t mem_addr = mp_obj_get_int(args[2]); - HAL_StatusTypeDef status; - if (MP_OBJ_IS_INT(args[3])) { - uint8_t data[1] = {mp_obj_get_int(args[3])}; - status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, data, 1, 200); - } else { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); - status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, bufinfo.buf, bufinfo.len, 200); + + if (!in_master_mode(self)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "I2C must be a master")); } - //printf("Write got %d\n", status); + // parse args (same as mem_read) + mp_arg_parse_val_t vals[PYB_I2C_MEM_READ_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_I2C_MEM_READ_NUM_ARGS, pyb_i2c_mem_read_accepted_args, vals); + + // get the buffer to write from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); + + // get the addresses + machine_uint_t i2c_addr = vals[1].u_int << 1; + machine_uint_t mem_addr = vals[2].u_int; + + HAL_StatusTypeDef status = HAL_I2C_Mem_Write(self->i2c, i2c_addr, mem_addr, I2C_MEMADD_SIZE_8BIT, bufinfo.buf, bufinfo.len, vals[3].u_int); if (status != HAL_OK) { // TODO really need a HardwareError object, or something @@ -236,16 +407,22 @@ STATIC mp_obj_t pyb_i2c_mem_write(uint n_args, const mp_obj_t *args) { return mp_const_none; } - -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_i2c_mem_write_obj, 4, 4, pyb_i2c_mem_write); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_mem_write_obj, 1, pyb_i2c_mem_write); STATIC const mp_map_elem_t pyb_i2c_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_i2c_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_i2c_deinit_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_is_ready), (mp_obj_t)&pyb_i2c_is_ready_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&pyb_i2c_scan_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&pyb_i2c_read_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&pyb_i2c_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_i2c_send_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_i2c_recv_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mem_read), (mp_obj_t)&pyb_i2c_mem_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_mem_write), (mp_obj_t)&pyb_i2c_mem_write_obj }, + + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(PYB_I2C_MASTER) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(PYB_I2C_SLAVE) }, }; STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table); @@ -253,6 +430,7 @@ STATIC MP_DEFINE_CONST_DICT(pyb_i2c_locals_dict, pyb_i2c_locals_dict_table); const mp_obj_type_t pyb_i2c_type = { { &mp_type_type }, .name = MP_QSTR_I2C, + .print = pyb_i2c_print, .make_new = pyb_i2c_make_new, .locals_dict = (mp_obj_t)&pyb_i2c_locals_dict, }; diff --git a/stmhal/i2c.h b/stmhal/i2c.h index 00bb744f0c..d4f08efb75 100644 --- a/stmhal/i2c.h +++ b/stmhal/i2c.h @@ -1,3 +1,6 @@ +// use this for OwnAddress1 to configure I2C in master mode +#define PYB_I2C_MASTER_ADDRESS (0xfe) + extern I2C_HandleTypeDef I2CHandle1; extern I2C_HandleTypeDef I2CHandle2; extern const mp_obj_type_t pyb_i2c_type; diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index f59f6131bc..b7102b7267 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -79,12 +79,17 @@ Q(off) Q(toggle) Q(intensity) -// for USART object +// for USART class Q(USART) -Q(status) -Q(recv_chr) -Q(send_chr) +Q(baudrate) +Q(bits) +Q(stop) +Q(parity) +Q(init) +Q(deinit) +Q(all) Q(send) +Q(recv) // for ExtInt class Q(ExtInt) @@ -106,8 +111,19 @@ Q(EVT_RISING_FALLING) // for I2C object Q(I2C) +Q(mode) +Q(addr) +Q(baudrate) +Q(gencall) +Q(data) +Q(memaddr) +Q(timeout) +Q(init) +Q(deinit) Q(is_ready) Q(scan) +Q(send) +Q(recv) Q(mem_read) Q(mem_write) @@ -120,16 +136,18 @@ Q(recv) Q(send_recv) Q(mode) Q(baudrate) -Q(clkpol) -Q(clkphase) +Q(polarity) +Q(phase) Q(dir) -Q(size) +Q(bits) Q(nss) Q(firstbit) Q(ti) -Q(crcpoly) +Q(crc) Q(MASTER) Q(SLAVE) +Q(MSB) +Q(LSB) // for Accel object Q(Accel) diff --git a/stmhal/spi.c b/stmhal/spi.c index 9e48bc899e..352c594c9e 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -11,9 +11,12 @@ #include "runtime.h" #include "pin.h" #include "genhdr/pins.h" +#include "bufhelper.h" #include "spi.h" +#if MICROPY_HW_ENABLE_SPI1 SPI_HandleTypeDef SPIHandle1 = {.Instance = NULL}; +#endif SPI_HandleTypeDef SPIHandle2 = {.Instance = NULL}; #if MICROPY_HW_ENABLE_SPI3 SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL}; @@ -21,8 +24,10 @@ SPI_HandleTypeDef SPIHandle3 = {.Instance = NULL}; void spi_init0(void) { // reset the SPI handles +#if MICROPY_HW_ENABLE_SPI1 memset(&SPIHandle1, 0, sizeof(SPI_HandleTypeDef)); SPIHandle1.Instance = SPI1; +#endif memset(&SPIHandle2, 0, sizeof(SPI_HandleTypeDef)); SPIHandle2.Instance = SPI2; #if MICROPY_HW_ENABLE_SPI3 @@ -37,16 +42,21 @@ void spi_init(SPI_HandleTypeDef *spi) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Speed = GPIO_SPEED_FAST; - GPIO_InitStructure.Pull = GPIO_PULLUP; // ST examples use PULLUP + GPIO_InitStructure.Pull = spi->Init.CLKPolarity == SPI_POLARITY_LOW ? GPIO_PULLDOWN : GPIO_PULLUP; const pin_obj_t *pins[4]; - if (spi->Instance == SPI1) { + if (0) { +#if MICROPY_HW_ENABLE_SPI1 + } else if (spi->Instance == SPI1) { // X-skin: X5=PA4=SPI1_NSS, X6=PA5=SPI1_SCK, X7=PA6=SPI1_MISO, X8=PA7=SPI1_MOSI pins[0] = &pin_A4; pins[1] = &pin_A5; pins[2] = &pin_A6; pins[3] = &pin_A7; GPIO_InitStructure.Alternate = GPIO_AF5_SPI1; + // enable the SPI clock + __SPI1_CLK_ENABLE(); +#endif } else if (spi->Instance == SPI2) { // Y-skin: Y5=PB12=SPI2_NSS, Y6=PB13=SPI2_SCK, Y7=PB14=SPI2_MISO, Y8=PB15=SPI2_MOSI pins[0] = &pin_B12; @@ -54,6 +64,8 @@ void spi_init(SPI_HandleTypeDef *spi) { pins[2] = &pin_B14; pins[3] = &pin_B15; GPIO_InitStructure.Alternate = GPIO_AF5_SPI2; + // enable the SPI clock + __SPI2_CLK_ENABLE(); #if MICROPY_HW_ENABLE_SPI3 } else if (spi->Instance == SPI3) { pins[0] = &pin_A4; @@ -61,10 +73,11 @@ void spi_init(SPI_HandleTypeDef *spi) { pins[2] = &pin_B4; pins[3] = &pin_B5; GPIO_InitStructure.Alternate = GPIO_AF6_SPI3; + // enable the SPI clock + __SPI3_CLK_ENABLE(); #endif } else { - // SPI does not exist for this board - printf("HardwareError: invalid SPI\n"); + // SPI does not exist for this board (shouldn't get here, should be checked by caller) return; } @@ -73,18 +86,7 @@ void spi_init(SPI_HandleTypeDef *spi) { HAL_GPIO_Init(pins[i]->gpio, &GPIO_InitStructure); } - // enable the SPI clock - if (spi->Instance == SPI1) { - __SPI1_CLK_ENABLE(); - } else if (spi->Instance == SPI2) { - __SPI2_CLK_ENABLE(); -#if MICROPY_HW_ENABLE_SPI3 - } else { - __SPI3_CLK_ENABLE(); -#endif - } - - // init the I2C device + // init the SPI device if (HAL_SPI_Init(spi) != HAL_OK) { // init error // TODO should raise an exception, but this function is not necessarily going to be @@ -96,12 +98,21 @@ void spi_init(SPI_HandleTypeDef *spi) { void spi_deinit(SPI_HandleTypeDef *spi) { HAL_SPI_DeInit(spi); - if (spi->Instance == SPI1) { + if (0) { +#if MICROPY_HW_ENABLE_SPI1 + } else if (spi->Instance == SPI1) { + __SPI1_FORCE_RESET(); + __SPI1_RELEASE_RESET(); __SPI1_CLK_DISABLE(); +#endif } else if (spi->Instance == SPI2) { + __SPI2_FORCE_RESET(); + __SPI2_RELEASE_RESET(); __SPI2_CLK_DISABLE(); #if MICROPY_HW_ENABLE_SPI3 - } else { + } else if (spi->Instance == SPI3) { + __SPI3_FORCE_RESET(); + __SPI3_RELEASE_RESET(); __SPI3_CLK_DISABLE(); #endif } @@ -110,14 +121,25 @@ void spi_deinit(SPI_HandleTypeDef *spi) { /******************************************************************************/ /* Micro Python bindings */ -#define PYB_SPI_NUM (2) - typedef struct _pyb_spi_obj_t { mp_obj_base_t base; SPI_HandleTypeDef *spi; } pyb_spi_obj_t; -STATIC const pyb_spi_obj_t pyb_spi_obj[PYB_SPI_NUM] = {{{&pyb_spi_type}, &SPIHandle1}, {{&pyb_spi_type}, &SPIHandle2}}; +STATIC const pyb_spi_obj_t pyb_spi_obj[] = { +#if MICROPY_HW_ENABLE_SPI1 + {{&pyb_spi_type}, &SPIHandle1}, +#else + {{&pyb_spi_type}, NULL}, +#endif + {{&pyb_spi_type}, &SPIHandle2}, +#if MICROPY_HW_ENABLE_SPI3 + {{&pyb_spi_type}, &SPIHandle3}, +#else + {{&pyb_spi_type}, NULL}, +#endif +}; +#define PYB_NUM_SPI (sizeof(pyb_spi_obj) / sizeof(pyb_spi_obj[0])) STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_spi_obj_t *self = self_in; @@ -141,29 +163,34 @@ STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void * spi_clock = HAL_RCC_GetPCLK1Freq(); } uint baudrate = spi_clock >> ((self->spi->Init.BaudRatePrescaler >> 3) + 1); - print(env, "SPI(%u, SPI.MASTER, clock=%u, baudrate=%u)", spi_num, spi_clock, baudrate); + print(env, "SPI(%u, SPI.MASTER, baudrate=%u", spi_num, baudrate); } else { - print(env, "SPI(%u, SPI.SLAVE)", spi_num); + print(env, "SPI(%u, SPI.SLAVE", spi_num); + } + print(env, ", polarity=%u, phase=%u, bits=%u", self->spi->Init.CLKPolarity == SPI_POLARITY_LOW ? 0 : 1, self->spi->Init.CLKPhase == SPI_PHASE_1EDGE ? 1 : 2, self->spi->Init.DataSize == SPI_DATASIZE_8BIT ? 8 : 16); + if (self->spi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLED) { + print(env, ", crc=0x%x", self->spi->Init.CRCPolynomial); } + print(env, ")"); } } STATIC const mp_arg_parse_t pyb_spi_init_accepted_args[] = { { MP_QSTR_mode, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 0} }, - { MP_QSTR_baudrate, MP_ARG_PARSE_INT, {.u_int = 328125} }, - { MP_QSTR_clkpol, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_POLARITY_LOW} }, - { MP_QSTR_clkphase, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_PHASE_1EDGE} }, + { MP_QSTR_baudrate, MP_ARG_PARSE_INT, {.u_int = 328125} }, + { MP_QSTR_polarity, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 1} }, + { MP_QSTR_phase, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 1} }, { MP_QSTR_dir, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_DIRECTION_2LINES} }, - { MP_QSTR_size, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 8} }, + { MP_QSTR_bits, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 8} }, { MP_QSTR_nss, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_NSS_SOFT} }, { MP_QSTR_firstbit, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = SPI_FIRSTBIT_MSB} }, { MP_QSTR_ti, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_BOOL, {.u_bool = false} }, - { MP_QSTR_crcpoly, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_crc, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_OBJ, {.u_obj = mp_const_none} }, }; #define PYB_SPI_INIT_NUM_ARGS (sizeof(pyb_spi_init_accepted_args) / sizeof(pyb_spi_init_accepted_args[0])) STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { - // parse keyword args + // parse args mp_arg_parse_val_t vals[PYB_SPI_INIT_NUM_ARGS]; mp_arg_parse_all(n_args, args, kw_args, PYB_SPI_INIT_NUM_ARGS, pyb_spi_init_accepted_args, vals); @@ -191,8 +218,8 @@ STATIC mp_obj_t pyb_spi_init_helper(const pyb_spi_obj_t *self, uint n_args, cons else if (br_prescale <= 128) { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128; } else { init->BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; } - init->CLKPolarity = vals[2].u_int; - init->CLKPhase = vals[3].u_int; + init->CLKPolarity = vals[2].u_int == 0 ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH; + init->CLKPhase = vals[3].u_int == 1 ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE; init->Direction = vals[4].u_int; init->DataSize = (vals[5].u_int == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT; init->NSS = vals[6].u_int; @@ -220,7 +247,7 @@ STATIC mp_obj_t pyb_spi_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const machine_int_t spi_id = mp_obj_get_int(args[0]) - 1; // check SPI number - if (!(0 <= spi_id && spi_id < PYB_SPI_NUM)) { + if (!(0 <= spi_id && spi_id < PYB_NUM_SPI && pyb_spi_obj[spi_id].spi != NULL)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "SPI bus %d does not exist", spi_id + 1)); } @@ -249,24 +276,28 @@ STATIC mp_obj_t pyb_spi_deinit(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_spi_deinit_obj, pyb_spi_deinit); -STATIC mp_obj_t pyb_spi_send(mp_obj_t self_in, mp_obj_t data_in) { +STATIC const mp_arg_parse_t pyb_spi_send_accepted_args[] = { + { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_SPI_SEND_NUM_ARGS (sizeof(pyb_spi_send_accepted_args) / sizeof(pyb_spi_send_accepted_args[0])) + +STATIC mp_obj_t pyb_spi_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide - // TODO accept timeout as keyword argument - pyb_spi_obj_t *self = self_in; + pyb_spi_obj_t *self = args[0]; - uint8_t data[1]; + // parse args + mp_arg_parse_val_t vals[PYB_SPI_SEND_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_SPI_SEND_NUM_ARGS, pyb_spi_send_accepted_args, vals); + + // get the buffer to send from mp_buffer_info_t bufinfo; - if (MP_OBJ_IS_INT(data_in)) { - data[0] = mp_obj_get_int(data_in); - bufinfo.buf = data; - bufinfo.len = 1; - bufinfo.typecode = 'B'; - } else { - mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); - } + uint8_t data[1]; + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); - HAL_StatusTypeDef status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, 1000); + // send the data + HAL_StatusTypeDef status = HAL_SPI_Transmit(self->spi, bufinfo.buf, bufinfo.len, vals[1].u_int); if (status != HAL_OK) { // TODO really need a HardwareError object, or something @@ -275,57 +306,104 @@ STATIC mp_obj_t pyb_spi_send(mp_obj_t self_in, mp_obj_t data_in) { return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_send_obj, pyb_spi_send); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_obj, 1, pyb_spi_send); + +STATIC const mp_arg_parse_t pyb_spi_recv_accepted_args[] = { + { MP_QSTR_recv, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_SPI_RECV_NUM_ARGS (sizeof(pyb_spi_recv_accepted_args) / sizeof(pyb_spi_recv_accepted_args[0])) -STATIC mp_obj_t pyb_spi_recv(mp_obj_t self_in, mp_obj_t n_in) { +STATIC mp_obj_t pyb_spi_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide - // TODO accept timeout as keyword argument - pyb_spi_obj_t *self = self_in; - machine_uint_t n = mp_obj_get_int(n_in); + pyb_spi_obj_t *self = args[0]; + + // parse args + mp_arg_parse_val_t vals[PYB_SPI_RECV_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_SPI_RECV_NUM_ARGS, pyb_spi_recv_accepted_args, vals); + + // get the buffer to receive into + mp_buffer_info_t bufinfo; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo); - byte *data; - mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, n, &data); - HAL_StatusTypeDef status = HAL_SPI_Receive(self->spi, data, n, 1000); + // receive the data + HAL_StatusTypeDef status = HAL_SPI_Receive(self->spi, bufinfo.buf, bufinfo.len, vals[1].u_int); if (status != HAL_OK) { // TODO really need a HardwareError object, or something nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_SPI_Receive failed with code %d", status)); } - return mp_obj_str_builder_end(o); + // return the received data + if (o_ret == MP_OBJ_NULL) { + return vals[0].u_obj; + } else { + return mp_obj_str_builder_end(o_ret); + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_recv_obj, pyb_spi_recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_recv_obj, 1, pyb_spi_recv); -STATIC mp_obj_t pyb_spi_send_recv(mp_obj_t self_in, mp_obj_t data_in) { +STATIC const mp_arg_parse_t pyb_spi_send_recv_accepted_args[] = { + { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_recv, MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_SPI_SEND_RECV_NUM_ARGS (sizeof(pyb_spi_send_recv_accepted_args) / sizeof(pyb_spi_send_recv_accepted_args[0])) + +STATIC mp_obj_t pyb_spi_send_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { // TODO assumes transmission size is 8-bits wide - // TODO accept timeout as keyword argument - pyb_spi_obj_t *self = self_in; + pyb_spi_obj_t *self = args[0]; + // parse args + mp_arg_parse_val_t vals[PYB_SPI_SEND_RECV_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_SPI_SEND_RECV_NUM_ARGS, pyb_spi_send_recv_accepted_args, vals); + + // get buffers to send from/receive to + mp_buffer_info_t bufinfo_send; uint8_t data_send[1]; - mp_buffer_info_t bufinfo; - if (MP_OBJ_IS_INT(data_in)) { - data_send[0] = mp_obj_get_int(data_in); - bufinfo.buf = data_send; - bufinfo.len = 1; - bufinfo.typecode = 'B'; + mp_buffer_info_t bufinfo_recv; + mp_obj_t o_ret; + + if (vals[0].u_obj == vals[1].u_obj) { + // same object for send and receive, it must be a r/w buffer + mp_get_buffer_raise(vals[0].u_obj, &bufinfo_send, MP_BUFFER_RW); + bufinfo_recv = bufinfo_send; + o_ret = MP_OBJ_NULL; } else { - mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + // get the buffer to send from + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo_send, data_send); + + // get the buffer to receive into + if (vals[1].u_obj == MP_OBJ_NULL) { + // only send argument given, so create a fresh buffer of the send length + bufinfo_recv.len = bufinfo_send.len; + bufinfo_recv.typecode = 'B'; + o_ret = mp_obj_str_builder_start(&mp_type_bytes, bufinfo_recv.len, (byte**)&bufinfo_recv.buf); + } else { + // recv argument given + mp_get_buffer_raise(vals[1].u_obj, &bufinfo_recv, MP_BUFFER_WRITE); + o_ret = MP_OBJ_NULL; + } } - byte *data_recv; - mp_obj_t o = mp_obj_str_builder_start(&mp_type_bytes, bufinfo.len, &data_recv); - HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(self->spi, bufinfo.buf, data_recv, bufinfo.len, 1000); + // send and receive the data + HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(self->spi, bufinfo_send.buf, bufinfo_recv.buf, bufinfo_send.len, vals[2].u_int); if (status != HAL_OK) { // TODO really need a HardwareError object, or something nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_SPI_TransmitReceive failed with code %d", status)); } - return mp_obj_str_builder_end(o); + // return the received data + if (o_ret == MP_OBJ_NULL) { + return vals[1].u_obj; + } else { + return mp_obj_str_builder_end(o_ret); + } } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_send_recv_obj, pyb_spi_send_recv); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_send_recv_obj, 1, pyb_spi_send_recv); STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = { // instance methods @@ -336,21 +414,17 @@ STATIC const mp_map_elem_t pyb_spi_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_send_recv), (mp_obj_t)&pyb_spi_send_recv_obj }, // class constants - { MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(SPI_MODE_MASTER) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(SPI_MODE_SLAVE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MASTER), MP_OBJ_NEW_SMALL_INT(SPI_MODE_MASTER) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SLAVE), MP_OBJ_NEW_SMALL_INT(SPI_MODE_SLAVE) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MSB), MP_OBJ_NEW_SMALL_INT(SPI_FIRSTBIT_MSB) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LSB), MP_OBJ_NEW_SMALL_INT(SPI_FIRSTBIT_LSB) }, /* TODO { MP_OBJ_NEW_QSTR(MP_QSTR_DIRECTION_2LINES ((uint32_t)0x00000000) { MP_OBJ_NEW_QSTR(MP_QSTR_DIRECTION_2LINES_RXONLY SPI_CR1_RXONLY { MP_OBJ_NEW_QSTR(MP_QSTR_DIRECTION_1LINE SPI_CR1_BIDIMODE - { MP_OBJ_NEW_QSTR(MP_QSTR_POLARITY_LOW ((uint32_t)0x00000000) - { MP_OBJ_NEW_QSTR(MP_QSTR_POLARITY_HIGH SPI_CR1_CPOL - { MP_OBJ_NEW_QSTR(MP_QSTR_PHASE_1EDGE ((uint32_t)0x00000000) - { MP_OBJ_NEW_QSTR(MP_QSTR_PHASE_2EDGE SPI_CR1_CPHA { MP_OBJ_NEW_QSTR(MP_QSTR_NSS_SOFT SPI_CR1_SSM { MP_OBJ_NEW_QSTR(MP_QSTR_NSS_HARD_INPUT ((uint32_t)0x00000000) { MP_OBJ_NEW_QSTR(MP_QSTR_NSS_HARD_OUTPUT ((uint32_t)0x00040000) - { MP_OBJ_NEW_QSTR(MP_QSTR_FIRSTBIT_MSB ((uint32_t)0x00000000) - { MP_OBJ_NEW_QSTR(MP_QSTR_FIRSTBIT_LSB SPI_CR1_LSBFIRST */ }; diff --git a/stmhal/usart.c b/stmhal/usart.c index 89770942be..c737955ac2 100644 --- a/stmhal/usart.c +++ b/stmhal/usart.c @@ -8,23 +8,26 @@ #include "mpconfig.h" #include "qstr.h" #include "obj.h" +#include "runtime.h" +#include "bufhelper.h" #include "usart.h" struct _pyb_usart_obj_t { mp_obj_base_t base; pyb_usart_t usart_id; bool is_enabled; - UART_HandleTypeDef handle; + UART_HandleTypeDef uart; }; pyb_usart_obj_t *pyb_usart_global_debug = NULL; -bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { - USART_TypeDef *USARTx=NULL; +// assumes Init parameters have been set up correctly +bool usart_init2(pyb_usart_obj_t *usart_obj) { + USART_TypeDef *USARTx = NULL; - uint32_t GPIO_Pin=0; - uint8_t GPIO_AF_USARTx=0; - GPIO_TypeDef* GPIO_Port=NULL; + uint32_t GPIO_Pin = 0; + uint8_t GPIO_AF_USARTx = 0; + GPIO_TypeDef* GPIO_Port = NULL; switch (usart_obj->usart_id) { // USART1 is on PA9/PA10, PB6/PB7 @@ -71,7 +74,7 @@ bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { __USART3_CLK_ENABLE(); break; - // USART4 is on PA0/PA1, PC10/PC11 + // UART4 is on PA0/PA1, PC10/PC11 case PYB_USART_4: USARTx = UART4; GPIO_AF_USARTx = GPIO_AF8_UART4; @@ -97,8 +100,7 @@ bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { return false; } - // Initialize USARTx - + // init GPIO GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Pin = GPIO_Pin; GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; @@ -107,28 +109,62 @@ bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { GPIO_InitStructure.Alternate = GPIO_AF_USARTx; HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure); - UART_HandleTypeDef *uh = &usart_obj->handle; + // init USARTx + usart_obj->uart.Instance = USARTx; + HAL_UART_Init(&usart_obj->uart); + + usart_obj->is_enabled = true; + + return true; +} + +bool usart_init(pyb_usart_obj_t *usart_obj, uint32_t baudrate) { + UART_HandleTypeDef *uh = &usart_obj->uart; memset(uh, 0, sizeof(*uh)); - uh->Instance = USARTx; uh->Init.BaudRate = baudrate; - uh->Init.WordLength = USART_WORDLENGTH_8B; - uh->Init.StopBits = USART_STOPBITS_1; - uh->Init.Parity = USART_PARITY_NONE; - uh->Init.Mode = USART_MODE_TX_RX; + uh->Init.WordLength = UART_WORDLENGTH_8B; + uh->Init.StopBits = UART_STOPBITS_1; + uh->Init.Parity = UART_PARITY_NONE; + uh->Init.Mode = UART_MODE_TX_RX; uh->Init.HwFlowCtl = UART_HWCONTROL_NONE; uh->Init.OverSampling = UART_OVERSAMPLING_16; - HAL_UART_Init(uh); + return usart_init2(usart_obj); +} - return true; +void usart_deinit(pyb_usart_obj_t *usart_obj) { + usart_obj->is_enabled = false; + UART_HandleTypeDef *uart = &usart_obj->uart; + HAL_UART_DeInit(uart); + if (uart->Instance == USART1) { + __USART1_FORCE_RESET(); + __USART1_RELEASE_RESET(); + __USART1_CLK_DISABLE(); + } else if (uart->Instance == USART2) { + __USART2_FORCE_RESET(); + __USART2_RELEASE_RESET(); + __USART2_CLK_DISABLE(); + } else if (uart->Instance == USART3) { + __USART3_FORCE_RESET(); + __USART3_RELEASE_RESET(); + __USART3_CLK_DISABLE(); + } else if (uart->Instance == UART4) { + __UART4_FORCE_RESET(); + __UART4_RELEASE_RESET(); + __UART4_CLK_DISABLE(); + } else if (uart->Instance == USART6) { + __USART6_FORCE_RESET(); + __USART6_RELEASE_RESET(); + __USART6_CLK_DISABLE(); + } } bool usart_rx_any(pyb_usart_obj_t *usart_obj) { - return __HAL_UART_GET_FLAG(&usart_obj->handle, USART_FLAG_RXNE); + return __HAL_UART_GET_FLAG(&usart_obj->uart, UART_FLAG_RXNE); } int usart_rx_char(pyb_usart_obj_t *usart_obj) { uint8_t ch; - if (HAL_UART_Receive(&usart_obj->handle, &ch, 1, 0) != HAL_OK) { + if (HAL_UART_Receive(&usart_obj->uart, &ch, 1, 0) != HAL_OK) { ch = 0; } return ch; @@ -136,19 +172,15 @@ int usart_rx_char(pyb_usart_obj_t *usart_obj) { void usart_tx_char(pyb_usart_obj_t *usart_obj, int c) { uint8_t ch = c; - HAL_UART_Transmit(&usart_obj->handle, &ch, 1, 100000); + HAL_UART_Transmit(&usart_obj->uart, &ch, 1, 100000); } void usart_tx_str(pyb_usart_obj_t *usart_obj, const char *str) { - for (; *str; str++) { - usart_tx_char(usart_obj, *str); - } + HAL_UART_Transmit(&usart_obj->uart, (uint8_t*)str, strlen(str), 100000); } void usart_tx_strn(pyb_usart_obj_t *usart_obj, const char *str, uint len) { - for (; len > 0; str++, len--) { - usart_tx_char(usart_obj, *str); - } + HAL_UART_Transmit(&usart_obj->uart, (uint8_t*)str, len, 100000); } void usart_tx_strn_cooked(pyb_usart_obj_t *usart_obj, const char *str, uint len) { @@ -163,17 +195,67 @@ void usart_tx_strn_cooked(pyb_usart_obj_t *usart_obj, const char *str, uint len) /******************************************************************************/ /* Micro Python bindings */ -STATIC void usart_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { +STATIC void pyb_usart_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_usart_obj_t *self = self_in; - print(env, "<USART %lu>", self->usart_id); + if (!self->is_enabled) { + print(env, "USART(%lu)", self->usart_id); + } else { + print(env, "USART(%lu, baudrate=%u, bits=%u, stop=%u", + self->usart_id, self->uart.Init.BaudRate, + self->uart.Init.WordLength == UART_WORDLENGTH_8B ? 8 : 9, + self->uart.Init.StopBits == UART_STOPBITS_1 ? 1 : 2); + if (self->uart.Init.Parity == UART_PARITY_NONE) { + print(env, ", parity=None)"); + } else { + print(env, ", parity=%u)", self->uart.Init.Parity == UART_PARITY_EVEN ? 0 : 1); + } + } } -STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { - // check arguments - if (!(n_args == 2 && n_kw == 0)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "USART accepts 2 arguments")); +STATIC const mp_arg_parse_t pyb_usart_init_accepted_args[] = { + { MP_QSTR_baudrate, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_INT, {.u_int = 9600} }, + { MP_QSTR_bits, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 8} }, + { MP_QSTR_stop, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 1} }, + { MP_QSTR_parity, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_OBJ, {.u_obj = mp_const_none} }, +}; +#define PYB_USART_INIT_NUM_ARGS (sizeof(pyb_usart_init_accepted_args) / sizeof(pyb_usart_init_accepted_args[0])) + +STATIC mp_obj_t pyb_usart_init_helper(pyb_usart_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + mp_arg_parse_val_t vals[PYB_USART_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args, args, kw_args, PYB_USART_INIT_NUM_ARGS, pyb_usart_init_accepted_args, vals); + + // set the USART configuration values + memset(&self->uart, 0, sizeof(self->uart)); + UART_InitTypeDef *init = &self->uart.Init; + init->BaudRate = vals[0].u_int; + init->WordLength = vals[1].u_int == 8 ? UART_WORDLENGTH_8B : UART_WORDLENGTH_9B; + switch (vals[2].u_int) { + case 1: init->StopBits = UART_STOPBITS_1; break; + default: init->StopBits = UART_STOPBITS_2; break; + } + if (vals[3].u_obj == mp_const_none) { + init->Parity = UART_PARITY_NONE; + } else { + machine_int_t parity = mp_obj_get_int(vals[3].u_obj); + init->Parity = (parity & 1) ? UART_PARITY_ODD : UART_PARITY_EVEN; + } + init->Mode = UART_MODE_TX_RX; + init->HwFlowCtl = UART_HWCONTROL_NONE; + init->OverSampling = UART_OVERSAMPLING_16; + + // init USART (if it fails, it's because the port doesn't exist) + if (!usart_init2(self)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "USART port %d does not exist", self->usart_id)); } + return mp_const_none; +} + +STATIC mp_obj_t pyb_usart_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); + // create object pyb_usart_obj_t *o = m_new_obj(pyb_usart_obj_t); o->base.type = &pyb_usart_type; @@ -200,17 +282,29 @@ STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con o->usart_id = mp_obj_get_int(args[0]); } - // init USART (if it fails, it's because the port doesn't exist) - if (!usart_init(o, mp_obj_get_int(args[1]))) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "USART port %d does not exist", o->usart_id)); + if (n_args > 1 || n_kw > 0) { + // start the peripheral + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pyb_usart_init_helper(o, n_args - 1, args + 1, &kw_args); } - o->is_enabled = true; - return o; } -STATIC mp_obj_t usart_obj_status(mp_obj_t self_in) { +STATIC mp_obj_t pyb_usart_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pyb_usart_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usart_init_obj, 1, pyb_usart_init); + +STATIC mp_obj_t pyb_usart_deinit(mp_obj_t self_in) { + pyb_usart_obj_t *self = self_in; + usart_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usart_deinit_obj, pyb_usart_deinit); + +STATIC mp_obj_t pyb_usart_any(mp_obj_t self_in) { pyb_usart_obj_t *self = self_in; if (usart_rx_any(self)) { return mp_const_true; @@ -218,57 +312,91 @@ STATIC mp_obj_t usart_obj_status(mp_obj_t self_in) { return mp_const_false; } } +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_usart_any_obj, pyb_usart_any); -STATIC mp_obj_t usart_obj_rx_char(mp_obj_t self_in) { - mp_obj_t ret = mp_const_none; - pyb_usart_obj_t *self = self_in; +STATIC const mp_arg_parse_t pyb_usart_send_accepted_args[] = { + { MP_QSTR_send, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_USART_SEND_NUM_ARGS (sizeof(pyb_usart_send_accepted_args) / sizeof(pyb_usart_send_accepted_args[0])) - if (self->is_enabled) { - ret = mp_obj_new_int(usart_rx_char(self)); - } - return ret; -} +STATIC mp_obj_t pyb_usart_send(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide -STATIC mp_obj_t usart_obj_tx_char(mp_obj_t self_in, mp_obj_t c) { - pyb_usart_obj_t *self = self_in; - uint len; - const char *str = mp_obj_str_get_data(c, &len); - if (len == 1 && self->is_enabled) { - usart_tx_char(self, str[0]); - } - return mp_const_none; -} + pyb_usart_obj_t *self = args[0]; -STATIC mp_obj_t usart_obj_tx_str(mp_obj_t self_in, mp_obj_t s) { - pyb_usart_obj_t *self = self_in; - if (self->is_enabled) { - if (MP_OBJ_IS_STR(s)) { - uint len; - const char *data = mp_obj_str_get_data(s, &len); - usart_tx_strn(self, data, len); - } + // parse args + mp_arg_parse_val_t vals[PYB_USART_SEND_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USART_SEND_NUM_ARGS, pyb_usart_send_accepted_args, vals); + + // get the buffer to send from + mp_buffer_info_t bufinfo; + uint8_t data[1]; + pyb_buf_get_for_send(vals[0].u_obj, &bufinfo, data); + + // send the data + HAL_StatusTypeDef status = HAL_UART_Transmit(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Transmit failed with code %d", status)); } + return mp_const_none; } +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usart_send_obj, 1, pyb_usart_send); + +STATIC const mp_arg_parse_t pyb_usart_recv_accepted_args[] = { + { MP_QSTR_recv, MP_ARG_PARSE_REQUIRED | MP_ARG_PARSE_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_timeout, MP_ARG_PARSE_KW_ONLY | MP_ARG_PARSE_INT, {.u_int = 5000} }, +}; +#define PYB_USART_RECV_NUM_ARGS (sizeof(pyb_usart_recv_accepted_args) / sizeof(pyb_usart_recv_accepted_args[0])) + +STATIC mp_obj_t pyb_usart_recv(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // TODO assumes transmission size is 8-bits wide -STATIC MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_status_obj, usart_obj_status); -STATIC MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_rx_char_obj, usart_obj_rx_char); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_char_obj, usart_obj_tx_char); -STATIC MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_str_obj, usart_obj_tx_str); + pyb_usart_obj_t *self = args[0]; -STATIC const mp_map_elem_t usart_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&usart_obj_status_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_recv_chr), (mp_obj_t)&usart_obj_rx_char_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_send_chr), (mp_obj_t)&usart_obj_tx_char_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&usart_obj_tx_str_obj }, + // parse args + mp_arg_parse_val_t vals[PYB_USART_RECV_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_USART_RECV_NUM_ARGS, pyb_usart_recv_accepted_args, vals); + + // get the buffer to receive into + mp_buffer_info_t bufinfo; + mp_obj_t o_ret = pyb_buf_get_for_recv(vals[0].u_obj, &bufinfo); + + // receive the data + HAL_StatusTypeDef status = HAL_UART_Receive(&self->uart, bufinfo.buf, bufinfo.len, vals[1].u_int); + + if (status != HAL_OK) { + // TODO really need a HardwareError object, or something + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_Exception, "HAL_UART_Receive failed with code %d", status)); + } + + // return the received data + if (o_ret == MP_OBJ_NULL) { + return vals[0].u_obj; + } else { + return mp_obj_str_builder_end(o_ret); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_usart_recv_obj, 1, pyb_usart_recv); + +STATIC const mp_map_elem_t pyb_usart_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_usart_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&pyb_usart_deinit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&pyb_usart_any_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&pyb_usart_send_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&pyb_usart_recv_obj }, }; -STATIC MP_DEFINE_CONST_DICT(usart_locals_dict, usart_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(pyb_usart_locals_dict, pyb_usart_locals_dict_table); const mp_obj_type_t pyb_usart_type = { { &mp_type_type }, .name = MP_QSTR_USART, - .print = usart_obj_print, - .make_new = usart_obj_make_new, - .locals_dict = (mp_obj_t)&usart_locals_dict, + .print = pyb_usart_print, + .make_new = pyb_usart_make_new, + .locals_dict = (mp_obj_t)&pyb_usart_locals_dict, }; diff --git a/unix/file.c b/unix/file.c index a0a865a263..5bda34013f 100644 --- a/unix/file.c +++ b/unix/file.c @@ -1,3 +1,4 @@ +#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> diff --git a/unix/main.c b/unix/main.c index 940fe48c14..4c86edeae5 100644 --- a/unix/main.c +++ b/unix/main.c @@ -250,7 +250,9 @@ int usage(char **argv) { mp_obj_t mem_info(void) { printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated()); +#if MICROPY_ENABLE_GC gc_dump_info(); +#endif return mp_const_none; } @@ -392,7 +394,11 @@ 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/modsocket.c b/unix/modsocket.c index bfa5849c86..6a2ada91f1 100644 --- a/unix/modsocket.c +++ b/unix/modsocket.c @@ -2,6 +2,7 @@ #include <assert.h> #include <string.h> #include <unistd.h> +#include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/socket.h> @@ -179,6 +180,22 @@ STATIC mp_obj_t socket_setsockopt(uint n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) { + mp_obj_socket_t *self = self_in; + int val = mp_obj_is_true(flag_in); + int flags = fcntl(self->fd, F_GETFL, 0); + RAISE_ERRNO(flags, errno); + if (val) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + flags = fcntl(self->fd, F_SETFL, flags); + RAISE_ERRNO(flags, errno); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + STATIC mp_obj_t socket_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { int family = AF_INET; int type = SOCK_STREAM; @@ -216,6 +233,7 @@ STATIC const mp_map_elem_t microsocket_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj }, #if MICROPY_SOCKET_EXTRA { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&mp_stream_read_obj }, diff --git a/unix/qstrdefsport.h b/unix/qstrdefsport.h index 2e7a6aa1e1..f7990322ea 100644 --- a/unix/qstrdefsport.h +++ b/unix/qstrdefsport.h @@ -38,6 +38,7 @@ Q(listen) Q(accept) Q(recv) Q(setsockopt) +Q(setblocking) Q(AF_UNIX) Q(AF_INET) diff --git a/windows/Makefile b/windows/Makefile index 651de7c7f1..2f5418886f 100644 --- a/windows/Makefile +++ b/windows/Makefile @@ -1,4 +1,5 @@ include ../py/mkenv.mk +-include mpconfigport.mk # define main target PROG = micropython.exe @@ -14,14 +15,15 @@ INC += -I$(PY_SRC) INC += -I$(BUILD) # compiler settings -CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -DUNIX -LDFLAGS = -lm +CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) +LDFLAGS = $(LDFLAGS_MOD) -lm # Debugging/Optimization ifdef DEBUG -CFLAGS += -O0 -g +CFLAGS += -g +COPT = -O0 else -CFLAGS += -Os #-DNDEBUG +COPT = -Os #-DNDEBUG endif # source files @@ -30,11 +32,16 @@ SRC_C = \ unix/file.c \ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) -LIB = -lreadline -LIB += -lws2_32 -LIB += -lmman + +ifeq ($(MICROPY_USE_READLINE),1) +CFLAGS_MOD += -DMICROPY_USE_READLINE=1 +LDFLAGS_MOD += -lreadline # the following is needed for BSD -#LIB += -ltermcap +#LDFLAGS_MOD += -ltermcap +endif + +LIB += -lws2_32 +#LIB += -lmman include ../py/mkrules.mk diff --git a/windows/README b/windows/README new file mode 100644 index 0000000000..615ada2012 --- /dev/null +++ b/windows/README @@ -0,0 +1,10 @@ +This is experimental, community-supported Windows port of MicroPython. +It is based on Unix port, and expected to remain so. + +To cross-compile under Debian/Ubuntu Linux system: + +sudo apt-get install mingw32 mingw32-binutils mingw32-runtime +make CC=i586-mingw32msvc-gcc + +The port requires additional testing, debugging, and patches. Please +consider to contribute. diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index 74fe749e1e..993fef9d59 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -2,10 +2,10 @@ // Linking with GNU readline causes binary to be licensed under GPL #ifndef MICROPY_USE_READLINE -#define MICROPY_USE_READLINE (1) +#define MICROPY_USE_READLINE (0) #endif -#define MICROPY_EMIT_X64 (1) +#define MICROPY_EMIT_X64 (0) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_MEM_STATS (1) diff --git a/windows/mpconfigport.mk b/windows/mpconfigport.mk new file mode 100644 index 0000000000..458f23dd1e --- /dev/null +++ b/windows/mpconfigport.mk @@ -0,0 +1,13 @@ +# Enable/disable modules and 3rd-party libs to be included in interpreter + +# Build 32-bit binaries on a 64-bit host +MICROPY_FORCE_32BIT = 0 + +# Linking with GNU readline causes binary to be licensed under GPL +MICROPY_USE_READLINE = 0 + +# Subset of CPython time module +MICROPY_MOD_TIME = 1 + +# ffi module requires libffi (libffi-dev Debian package) +MICROPY_MOD_FFI = 0 |