diff --git a/.travis.yml b/.travis.yml index 255f28af2f..4acca3e103 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,9 @@ dist: trusty language: c compiler: - gcc +cache: + directories: + - "${HOME}/persist" before_script: # Extra CPython versions @@ -24,7 +27,12 @@ before_script: script: - make -C mpy-cross - - make -C minimal test + - make -C minimal CROSS=1 build/firmware.bin + - ls -l minimal/build/firmware.bin + - tools/check_code_size.sh + - mkdir -p ${HOME}/persist + # Save new firmware for reference, but only if building a main branch, not a pull request + - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then cp minimal/build/firmware.bin ${HOME}/persist/; fi' - make -C unix deplibs - make -C unix - make -C unix nanbox diff --git a/ACKNOWLEDGEMENTS b/ACKNOWLEDGEMENTS index b9537c0543..65f731b1ff 100644 --- a/ACKNOWLEDGEMENTS +++ b/ACKNOWLEDGEMENTS @@ -1448,7 +1448,7 @@ indicating that they also supported the first campaign. * 902 B Stevens 903 Cptnslick, US 904 janlj@me.com - 905 São Caetano do Sul, SP, Brazil + 905 Fabricio Biazzotto 906 Lenz Hirsch 907 SerSher, RU 908 Florian, DE diff --git a/README.md b/README.md index aeec167cca..61ffce27ca 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,15 @@ time, and struct, etc. Select ports have support for _thread module (multithreading). Note that only subset of Python 3.4 functionality implemented for the data types and modules. -See the repository www.github.com/micropython/pyboard for the Micro -Python board, the officially supported reference electronic circuit board. +See the repository www.github.com/micropython/pyboard for the MicroPython +board (PyBoard), the officially supported reference electronic circuit board. Major components in this repository: - py/ -- the core Python implementation, including compiler, runtime, and core library. - unix/ -- a version of MicroPython that runs on Unix. -- stmhal/ -- a version of MicroPython that runs on the MicroPython board - with an STM32F405RG (using ST's Cube HAL drivers). +- stmhal/ -- a version of MicroPython that runs on the PyBoard and similar + STM32 boards (using ST's Cube HAL drivers). - minimal/ -- a minimal MicroPython port. Start with this if you want to port MicroPython to another microcontroller. - tests/ -- test framework and test scripts. diff --git a/bare-arm/mpconfigport.h b/bare-arm/mpconfigport.h index 79b2b73283..912fae66fc 100644 --- a/bare-arm/mpconfigport.h +++ b/bare-arm/mpconfigport.h @@ -61,7 +61,6 @@ typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) (void)0 // extra built in names to add to the global namespace -extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj; #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, diff --git a/cc3200/hal/cc3200_hal.c b/cc3200/hal/cc3200_hal.c index f4d38d120e..37026db14e 100644 --- a/cc3200/hal/cc3200_hal.c +++ b/cc3200/hal/cc3200_hal.c @@ -130,10 +130,6 @@ void mp_hal_delay_ms(mp_uint_t delay) { } } -NORETURN void mp_hal_raise(int errno) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, mp_obj_new_int(errno))); -} - void mp_hal_set_interrupt_char (int c) { mpexception_set_interrupt_char (c); } diff --git a/cc3200/hal/cc3200_hal.h b/cc3200/hal/cc3200_hal.h index 054d5035a2..9715096b61 100644 --- a/cc3200/hal/cc3200_hal.h +++ b/cc3200/hal/cc3200_hal.h @@ -62,7 +62,6 @@ extern void HAL_SystemInit (void); extern void HAL_SystemDeInit (void); extern void HAL_IncrementTick(void); -extern NORETURN void mp_hal_raise(int errno); extern void mp_hal_set_interrupt_char (int c); #endif /* CC3200_LAUNCHXL_HAL_CC3200_HAL_H_ */ diff --git a/cc3200/misc/mpirq.c b/cc3200/misc/mpirq.c index 29cc4a7bdb..4389ab0c3c 100644 --- a/cc3200/misc/mpirq.c +++ b/cc3200/misc/mpirq.c @@ -112,7 +112,7 @@ void mp_irq_remove (const mp_obj_t parent) { uint mp_irq_translate_priority (uint priority) { if (priority < 1 || priority > MP_ARRAY_SIZE(mp_irq_priorities)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return mp_irq_priorities[priority - 1]; } diff --git a/cc3200/mods/modmachine.c b/cc3200/mods/modmachine.c index f82decda2c..8a57c2eb45 100644 --- a/cc3200/mods/modmachine.c +++ b/cc3200/mods/modmachine.c @@ -130,7 +130,7 @@ STATIC mp_obj_t machine_main(mp_obj_t main) { if (MP_OBJ_IS_STR(main)) { MP_STATE_PORT(machine_config_main) = main; } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return mp_const_none; } diff --git a/cc3200/mods/modnetwork.c b/cc3200/mods/modnetwork.c index 8e086b1d29..f98d9a88ad 100644 --- a/cc3200/mods/modnetwork.c +++ b/cc3200/mods/modnetwork.c @@ -101,7 +101,7 @@ STATIC mp_obj_t network_server_make_new(const mp_obj_type_t *type, mp_uint_t n_a // check the server id if (args[0].u_obj != MP_OBJ_NULL) { if (mp_obj_get_int(args[0].u_obj) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } } diff --git a/cc3200/mods/moduhashlib.c b/cc3200/mods/moduhashlib.c index 93f15540c9..46f30be21d 100644 --- a/cc3200/mods/moduhashlib.c +++ b/cc3200/mods/moduhashlib.c @@ -93,7 +93,7 @@ STATIC void hash_update_internal(mp_obj_t self_in, mp_obj_t data, bool digest) { self->digested = false; } } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -106,7 +106,7 @@ STATIC mp_obj_t hash_read (mp_obj_t self_in) { } } else if (self->c_size < self->b_size) { // it's a fixed len block which is still incomplete - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } if (!self->digested) { diff --git a/cc3200/mods/moduos.c b/cc3200/mods/moduos.c index 8e3e0135ec..d5b29336af 100644 --- a/cc3200/mods/moduos.c +++ b/cc3200/mods/moduos.c @@ -158,7 +158,7 @@ STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonl #endif // cannot mount twice or on existing paths if (f_stat(path, &fno) == FR_OK || osmount_find_by_device(device)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // create a new object @@ -196,7 +196,7 @@ STATIC void mount (mp_obj_t device, const char *path, uint pathlen, bool readonl if (f_mount(&self->fatfs, self->path, 1) != FR_OK) { // remove it and raise mp_obj_list_remove(&MP_STATE_PORT(mount_obj_list), self); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } // mount succeeded, increment the count @@ -252,7 +252,7 @@ STATIC mp_obj_t os_chdir(mp_obj_t path_in) { } if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } return mp_const_none; @@ -263,7 +263,7 @@ STATIC mp_obj_t os_getcwd(void) { char buf[MICROPY_ALLOC_PATH_MAX + 1]; FRESULT res = f_getcwd(buf, sizeof buf); if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } return mp_obj_new_str(buf, strlen(buf), false); } @@ -303,7 +303,7 @@ STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) { res = f_opendir(&dir, path); /* Open the directory */ if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } for ( ; ; ) { @@ -335,10 +335,10 @@ STATIC mp_obj_t os_mkdir(mp_obj_t path_o) { case FR_OK: return mp_const_none; case FR_EXIST: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); break; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_mkdir_obj, os_mkdir); @@ -351,7 +351,7 @@ STATIC mp_obj_t os_rename(mp_obj_t path_in, mp_obj_t path_out) { case FR_OK: return mp_const_none; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } STATIC MP_DEFINE_CONST_FUN_OBJ_2(os_rename_obj, os_rename); @@ -363,7 +363,7 @@ STATIC mp_obj_t os_remove(mp_obj_t path_o) { case FR_OK: return mp_const_none; default: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_remove_obj, os_remove); @@ -394,7 +394,7 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) { fno.ftime = 0; fno.fattrib = AM_DIR; } else if ((res = f_stat(path, &fno)) != FR_OK) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); + mp_raise_OSError(fresult_to_errno_table[res]); } mp_obj_tuple_t *t = mp_obj_new_tuple(10, NULL); @@ -481,7 +481,7 @@ STATIC mp_obj_t os_mount(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *k return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_value_invalid_arguments)); + mp_raise_msg(&mp_type_OSError, mpexception_value_invalid_arguments); } MP_DEFINE_CONST_FUN_OBJ_KW(os_mount_obj, 2, os_mount); @@ -490,7 +490,7 @@ STATIC mp_obj_t os_unmount(mp_obj_t path_o) { // '/flash' cannot be unmounted, also not the current working directory if (path_equal(path, "/flash")) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // now unmount it @@ -498,7 +498,7 @@ STATIC mp_obj_t os_unmount(mp_obj_t path_o) { if ((mount_obj = osmount_find_by_path(path))) { unmount (mount_obj); } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_msg(&mp_type_ValueError, mpexception_value_invalid_arguments); } return mp_const_none; @@ -515,7 +515,7 @@ STATIC mp_obj_t os_mkfs(mp_obj_t device) { path = mp_obj_str_get_str(device); // otherwise the relative path check will pass... if (path[0] != '/') { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_value_invalid_arguments)); + mp_raise_msg(&mp_type_OSError, mpexception_value_invalid_arguments); } } else { // mount it briefly @@ -541,7 +541,7 @@ STATIC mp_obj_t os_mkfs(mp_obj_t device) { } if (res != FR_OK) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } return mp_const_none; } diff --git a/cc3200/mods/modusocket.c b/cc3200/mods/modusocket.c index c7b3fb2035..81a4c2e198 100644 --- a/cc3200/mods/modusocket.c +++ b/cc3200/mods/modusocket.c @@ -156,7 +156,7 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_ // create the socket int _errno; if (wlan_socket_socket(s, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } // add the socket to the list modusocket_socket_add(s->sock_base.sd, true); @@ -182,7 +182,7 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { // call the NIC to bind the socket int _errno; if (wlan_socket_bind(self, ip, port, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -200,7 +200,7 @@ STATIC mp_obj_t socket_listen(mp_uint_t n_args, const mp_obj_t *args) { int _errno; if (wlan_socket_listen(self, backlog, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -220,7 +220,7 @@ STATIC mp_obj_t socket_accept(mp_obj_t self_in) { mp_uint_t port; int _errno; if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } // add the socket to the list @@ -248,7 +248,7 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { if (!self->sock_base.cert_req && _errno == SL_ESECSNOVERIFY) { return mp_const_none; } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -262,7 +262,7 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { int _errno; mp_int_t ret = wlan_socket_send(self, bufinfo.buf, bufinfo.len, &_errno); if (ret < 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_obj_new_int_from_uint(ret); } @@ -278,9 +278,9 @@ STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { mp_int_t ret = wlan_socket_recv(self, (byte*)vstr.buf, len, &_errno); if (ret < 0) { if (_errno == EAGAIN && self->sock_base.has_timeout) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out")); + mp_raise_msg(&mp_type_TimeoutError, "timed out"); } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } if (ret == 0) { return mp_const_empty_bytes; @@ -307,7 +307,7 @@ STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_ int _errno; mp_int_t ret = wlan_socket_sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno); if (ret < 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_obj_new_int(ret); } @@ -324,9 +324,9 @@ STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { mp_int_t ret = wlan_socket_recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); if (ret < 0) { if (_errno == EAGAIN && self->sock_base.has_timeout) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TimeoutError, "timed out")); + mp_raise_msg(&mp_type_TimeoutError, "timed out"); } - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } mp_obj_t tuple[2]; if (ret == 0) { @@ -364,7 +364,7 @@ STATIC mp_obj_t socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) { int _errno; if (wlan_socket_setsockopt(self, level, opt, optval, optlen, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -384,7 +384,7 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { } int _errno; if (wlan_socket_settimeout(self, timeout, &_errno) != 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); + mp_raise_OSError(-_errno); } return mp_const_none; } @@ -408,7 +408,7 @@ STATIC mp_obj_t socket_makefile(mp_uint_t n_args, const mp_obj_t *args) { if (n_args > 1) { const char *mode = mp_obj_str_get_str(args[1]); if (strcmp(mode, "rb") && strcmp(mode, "wb")) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } return self; @@ -504,7 +504,7 @@ STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; int32_t result = wlan_gethostbyname(host, hlen, out_ip, AF_INET); if (result < 0) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-result))); + mp_raise_OSError(-result); } mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); tuple->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET); diff --git a/cc3200/mods/modussl.c b/cc3200/mods/modussl.c index 1f27bdd21f..7a4787b6b3 100644 --- a/cc3200/mods/modussl.c +++ b/cc3200/mods/modussl.c @@ -131,10 +131,10 @@ STATIC mp_obj_t mod_ssl_wrap_socket(mp_uint_t n_args, const mp_obj_t *pos_args, return ssl_sock; socket_error: - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + mp_raise_OSError(_errno); arg_error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_ssl_wrap_socket_obj, 0, mod_ssl_wrap_socket); diff --git a/cc3200/mods/modutime.c b/cc3200/mods/modutime.c index bef8b667f3..7ea8df1eff 100644 --- a/cc3200/mods/modutime.c +++ b/cc3200/mods/modutime.c @@ -29,7 +29,7 @@ #include #include "py/mpconfig.h" -#include "py/nlr.h" +#include "py/runtime.h" #include "py/obj.h" #include "py/smallint.h" #include "py/mphal.h" @@ -109,7 +109,7 @@ STATIC mp_obj_t time_mktime(mp_obj_t tuple) { // localtime generates a tuple of len 8. CPython uses 9, so we accept both. if (len < 8 || len > 9) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, mpexception_num_type_invalid_arguments)); + mp_raise_TypeError(mpexception_num_type_invalid_arguments); } return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), mp_obj_get_int(elem[1]), mp_obj_get_int(elem[2]), diff --git a/cc3200/mods/modwlan.c b/cc3200/mods/modwlan.c index 2fb7ed377d..4b3dd4ec38 100644 --- a/cc3200/mods/modwlan.c +++ b/cc3200/mods/modwlan.c @@ -603,7 +603,7 @@ STATIC void wlan_reset (void) { STATIC void wlan_validate_mode (uint mode) { if (mode != ROLE_STA && mode != ROLE_AP) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -614,7 +614,7 @@ STATIC void wlan_set_mode (uint mode) { STATIC void wlan_validate_ssid_len (uint32_t len) { if (len > MODWLAN_SSID_LEN_MAX) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -647,7 +647,7 @@ STATIC void wlan_validate_security (uint8_t auth, const char *key, uint8_t len) return; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len) { @@ -670,7 +670,7 @@ STATIC void wlan_set_security (uint8_t auth, const char *key, uint8_t len) { STATIC void wlan_validate_channel (uint8_t channel) { if (channel < 1 || channel > 11) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -682,7 +682,7 @@ STATIC void wlan_set_channel (uint8_t channel) { #if MICROPY_HW_ANTENNA_DIVERSITY STATIC void wlan_validate_antenna (uint8_t antenna) { if (antenna != ANTENNA_TYPE_INTERNAL && antenna != ANTENNA_TYPE_EXTERNAL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -847,7 +847,7 @@ STATIC mp_obj_t wlan_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_ui if (n_args > 1 || n_kw > 0) { // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // start the peripheral wlan_init_helper(self, &args[1]); @@ -871,7 +871,7 @@ STATIC mp_obj_t wlan_scan(mp_obj_t self_in) { // check for correct wlan mode if (wlan_obj.mode == ROLE_AP) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } Sl_WlanNetworkEntry_t wlanEntry; @@ -925,7 +925,7 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ // check for the correct wlan mode if (wlan_obj.mode == ROLE_AP) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // parse args @@ -973,9 +973,9 @@ STATIC mp_obj_t wlan_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ modwlan_Status_t status; status = wlan_do_connect (ssid, ssid_len, bssid, auth, key, key_len, timeout); if (status == MODWLAN_ERROR_TIMEOUT) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } else if (status == MODWLAN_ERROR_INVALID_PARAMS) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return mp_const_none; } @@ -1004,7 +1004,7 @@ STATIC mp_obj_t wlan_ifconfig (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma // check the interface id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // get the configuration @@ -1051,7 +1051,7 @@ STATIC mp_obj_t wlan_ifconfig (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma // check for the correct string const char *mode = mp_obj_str_get_str(args[1].u_obj); if (strcmp("dhcp", mode)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } // only if we are not in AP mode @@ -1165,7 +1165,7 @@ STATIC mp_obj_t wlan_mac (mp_uint_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); if (bufinfo.len != 6) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } memcpy(self->mac, bufinfo.buf, SL_MAC_ADDR_LEN); sl_NetCfgSet(SL_MAC_ADDRESS_SET, 1, SL_MAC_ADDR_LEN, (_u8 *)self->mac); @@ -1201,7 +1201,7 @@ STATIC mp_obj_t wlan_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t * return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); @@ -1230,18 +1230,18 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wlan_irq_obj, 1, wlan_irq); // // // the call to sl_NetAppSet corrupts the input string URN=args[1], so we copy into a local buffer // if (len > MAX_DEVICE_URN_LEN) { -// nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); +// mp_raise_ValueError(mpexception_value_invalid_arguments); // } // strcpy(urn, p); // // if (sl_NetAppSet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, len, (unsigned char *)urn) < 0) { -// nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); +// mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); // } // } // else { // // get the URN // if (sl_NetAppGet(SL_NET_APP_DEVICE_CONFIG_ID, NETAPP_SET_GET_DEV_CONF_OPT_DEVICE_URN, &len, (uint8_t *)urn) < 0) { -// nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); +// mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); // } // return mp_obj_new_str(urn, (len - 1), false); // } diff --git a/cc3200/mods/pybadc.c b/cc3200/mods/pybadc.c index 22a90edb0a..f8c9b3da54 100644 --- a/cc3200/mods/pybadc.c +++ b/cc3200/mods/pybadc.c @@ -104,7 +104,7 @@ STATIC void pyb_adc_init (pyb_adc_obj_t *self) { STATIC void pyb_adc_check_init(void) { // not initialized if (!pyb_adc_obj.enabled) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -149,12 +149,12 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // check the number of bits if (args[1].u_int != 12) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } // setup the object @@ -173,7 +173,7 @@ STATIC mp_obj_t adc_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *k mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_adc_init_args[1], args); // check the number of bits if (args[0].u_int != 12) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } pyb_adc_init(pos_args[0]); return mp_const_none; @@ -206,11 +206,11 @@ STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t if (args[0].u_obj != MP_OBJ_NULL) { ch_id = mp_obj_get_int(args[0].u_obj); if (ch_id >= PYB_ADC_NUM_CHANNELS) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_os_resource_not_avaliable)); + mp_raise_ValueError(mpexception_os_resource_not_avaliable); } else if (args[1].u_obj != mp_const_none) { uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0); if (ch_id != pin_ch_id) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } } else { @@ -277,7 +277,7 @@ STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) { // the channel must be enabled if (!self->enabled) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // wait until a new value is available diff --git a/cc3200/mods/pybi2c.c b/cc3200/mods/pybi2c.c index 5022e614f6..d92782d8ae 100644 --- a/cc3200/mods/pybi2c.c +++ b/cc3200/mods/pybi2c.c @@ -144,7 +144,7 @@ STATIC bool pyb_i2c_transaction(uint cmd) { STATIC void pyb_i2c_check_init(pyb_i2c_obj_t *self) { // not initialized if (!self->baudrate) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -256,7 +256,7 @@ STATIC void pyb_i2c_read_into (mp_arg_val_t *args, vstr_t *vstr) { // receive the data if (!pyb_i2c_read(args[0].u_int, (byte *)vstr->buf, vstr->len)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } @@ -275,7 +275,7 @@ STATIC void pyb_i2c_readmem_into (mp_arg_val_t *args, vstr_t *vstr) { if (pyb_i2c_mem_addr_write (i2c_addr, (byte *)&mem_addr, mem_addr_size)) { // Read the specified length of data if (!pyb_i2c_read (i2c_addr, (byte *)vstr->buf, vstr->len)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } } } @@ -323,7 +323,7 @@ STATIC mp_obj_t pyb_i2c_init_helper(pyb_i2c_obj_t *self, const mp_arg_val_t *arg return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC const mp_arg_t pyb_i2c_init_args[] = { @@ -341,7 +341,7 @@ STATIC mp_obj_t pyb_i2c_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup the object @@ -445,7 +445,7 @@ STATIC mp_obj_t pyb_i2c_writeto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m // send the data if (!pyb_i2c_write(args[0].u_int, bufinfo.buf, bufinfo.len, args[2].u_bool)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } // return the number of bytes written @@ -514,7 +514,7 @@ STATIC mp_obj_t pyb_i2c_writeto_mem(mp_uint_t n_args, const mp_obj_t *pos_args, return mp_obj_new_int(bufinfo.len); } - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_i2c_writeto_mem_obj, 1, pyb_i2c_writeto_mem); diff --git a/cc3200/mods/pybpin.c b/cc3200/mods/pybpin.c index ce304404b5..f59e65fc26 100644 --- a/cc3200/mods/pybpin.c +++ b/cc3200/mods/pybpin.c @@ -145,7 +145,7 @@ pin_obj_t *pin_find(mp_obj_t user_obj) { return pin_obj; } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } void pin_config (pin_obj_t *self, int af, uint mode, uint pull, int value, uint strength) { @@ -185,7 +185,7 @@ uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type) return pin_o->af_list[i].unit; } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit) { @@ -195,13 +195,13 @@ uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit) return pin_o->af_list[i].type; } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } int8_t pin_find_af_index (const pin_obj_t* pin, uint8_t fn, uint8_t unit, uint8_t type) { int8_t af = pin_obj_find_af(pin, fn, unit, type); if (af < 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } return af; } @@ -426,18 +426,18 @@ STATIC void pin_extint_register(pin_obj_t *self, uint32_t intmode, uint32_t prio STATIC void pin_validate_mode (uint mode) { if (mode != GPIO_DIR_MODE_IN && mode != GPIO_DIR_MODE_OUT && mode != PIN_TYPE_OD && mode != GPIO_DIR_MODE_ALT && mode != GPIO_DIR_MODE_ALT_OD) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void pin_validate_pull (uint pull) { if (pull != PIN_TYPE_STD && pull != PIN_TYPE_STD_PU && pull != PIN_TYPE_STD_PD) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } STATIC void pin_validate_drive(uint strength) { if (strength != PIN_STRENGTH_2MA && strength != PIN_STRENGTH_4MA && strength != PIN_STRENGTH_6MA) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } @@ -450,7 +450,7 @@ STATIC void pin_validate_af(const pin_obj_t* pin, int8_t idx, uint8_t *fn, uint8 return; } } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC uint8_t pin_get_value (const pin_obj_t* self) { @@ -591,7 +591,7 @@ STATIC mp_obj_t pin_obj_init_helper(pin_obj_t *self, mp_uint_t n_args, const mp_ return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC void pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -905,7 +905,7 @@ STATIC mp_obj_t pin_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *k return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_irq_obj, 1, pin_irq); diff --git a/cc3200/mods/pybrtc.c b/cc3200/mods/pybrtc.c index ea99411052..4662edbe7e 100644 --- a/cc3200/mods/pybrtc.c +++ b/cc3200/mods/pybrtc.c @@ -202,7 +202,7 @@ STATIC uint pyb_rtc_datetime_s_us(const mp_obj_t datetime, uint32_t *seconds) { // verify the tuple if (len < 3 || len > 8) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } tm.tm_year = mp_obj_get_int(items[0]); @@ -294,7 +294,7 @@ STATIC mp_obj_t pyb_rtc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup the object @@ -362,7 +362,7 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma // check the alarm id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } uint32_t f_seconds; @@ -371,7 +371,7 @@ STATIC mp_obj_t pyb_rtc_alarm (mp_uint_t n_args, const mp_obj_t *pos_args, mp_ma if (MP_OBJ_IS_TYPE(args[1].u_obj, &mp_type_tuple)) { // datetime tuple given // repeat cannot be used with a datetime tuple if (repeat) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } f_mseconds = pyb_rtc_datetime_s_us (args[1].u_obj, &f_seconds) / 1000; } else { // then it must be an integer @@ -397,7 +397,7 @@ STATIC mp_obj_t pyb_rtc_alarm_left (mp_uint_t n_args, const mp_obj_t *args) { // only alarm id 0 is available if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // get the current time @@ -415,7 +415,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_alarm_left_obj, 1, 2, pyb_rtc STATIC mp_obj_t pyb_rtc_alarm_cancel (mp_uint_t n_args, const mp_obj_t *args) { // only alarm id 0 is available if (n_args > 1 && mp_obj_get_int(args[1]) != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // disable the alarm pyb_rtc_disable_alarm(); @@ -453,7 +453,7 @@ STATIC mp_obj_t pyb_rtc_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_ return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_rtc_irq_obj, 1, pyb_rtc_irq); diff --git a/cc3200/mods/pybsd.c b/cc3200/mods/pybsd.c index 55b797dc78..d7efbe872c 100644 --- a/cc3200/mods/pybsd.c +++ b/cc3200/mods/pybsd.c @@ -107,7 +107,7 @@ STATIC mp_obj_t pyb_sd_init_helper (pybsd_obj_t *self, const mp_arg_val_t *args) pyb_sd_hw_init (self); if (sd_disk_init() != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } // register it with the sleep module @@ -132,7 +132,7 @@ STATIC mp_obj_t pyb_sd_make_new (const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup and initialize the object diff --git a/cc3200/mods/pybspi.c b/cc3200/mods/pybspi.c index d4fcbe94b4..5a040e3f59 100644 --- a/cc3200/mods/pybspi.c +++ b/cc3200/mods/pybspi.c @@ -131,7 +131,7 @@ STATIC void pybspi_rx (pyb_spi_obj_t *self, void *data) { STATIC void pybspi_transfer (pyb_spi_obj_t *self, const char *txdata, char *rxdata, uint32_t len, uint32_t *txchar) { if (!self->baudrate) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // send and receive the data MAP_SPICSEnable(GSPI_BASE); @@ -218,7 +218,7 @@ STATIC mp_obj_t pyb_spi_init_helper(pyb_spi_obj_t *self, const mp_arg_val_t *arg return mp_const_none; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } static const mp_arg_t pyb_spi_init_args[] = { @@ -240,7 +240,7 @@ STATIC mp_obj_t pyb_spi_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp // check the peripheral id if (args[0].u_int != 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // setup the object @@ -295,7 +295,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_spi_write_obj, pyb_spi_write); STATIC mp_obj_t pyb_spi_read(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_nbytes, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} }, + { MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} }, }; // parse args @@ -319,7 +319,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_spi_read_obj, 1, pyb_spi_read); STATIC mp_obj_t pyb_spi_readinto(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_buf, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_write, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0x00} }, + { MP_QSTR_write, MP_ARG_INT, {.u_int = 0x00} }, }; // parse args @@ -357,7 +357,7 @@ STATIC mp_obj_t pyb_spi_write_readinto (mp_obj_t self, mp_obj_t writebuf, mp_obj // get the read buffer mp_get_buffer_raise(readbuf, &bufinfo_read, MP_BUFFER_WRITE); if (bufinfo_read.len != bufinfo_write.len) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } } diff --git a/cc3200/mods/pybtimer.c b/cc3200/mods/pybtimer.c index 65fc7195e6..2ac71cccb7 100644 --- a/cc3200/mods/pybtimer.c +++ b/cc3200/mods/pybtimer.c @@ -223,7 +223,7 @@ STATIC uint32_t compute_prescaler_period_and_match_value(pyb_timer_channel_obj_t return prescaler; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC void timer_init (pyb_timer_obj_t *tim) { @@ -319,7 +319,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *tim, mp_uint_t n_args, co return mp_const_none; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { @@ -329,7 +329,7 @@ STATIC mp_obj_t pyb_timer_make_new(const mp_obj_type_t *type, mp_uint_t n_args, // create a new Timer object int32_t timer_idx = mp_obj_get_int(args[0]); if (timer_idx < 0 || timer_idx > (PYBTIMER_NUM_TIMERS - 1)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } pyb_timer_obj_t *tim = &pyb_timer_obj[timer_idx]; @@ -370,7 +370,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp // verify that the timer has been already initialized if (!tim->config) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } if (channel_n != TIMER_A && channel_n != TIMER_B && channel_n != (TIMER_A | TIMER_B)) { // invalid channel @@ -440,7 +440,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp return ch; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_obj, 2, pyb_timer_channel); @@ -560,7 +560,7 @@ STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) { // set int32_t _frequency = mp_obj_get_int(args[1]); if (_frequency <= 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } ch->frequency = _frequency; ch->period = 1000000 / _frequency; @@ -579,7 +579,7 @@ STATIC mp_obj_t pyb_timer_channel_period(mp_uint_t n_args, const mp_obj_t *args) // set int32_t _period = mp_obj_get_int(args[1]); if (_period <= 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } ch->period = _period; ch->frequency = 1000000 / _period; @@ -712,7 +712,7 @@ STATIC mp_obj_t pyb_timer_channel_irq (mp_uint_t n_args, const mp_obj_t *pos_arg return _irq; invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_irq_obj, 1, pyb_timer_channel_irq); diff --git a/cc3200/mods/pybuart.c b/cc3200/mods/pybuart.c index e7b5255bdf..493522f835 100644 --- a/cc3200/mods/pybuart.c +++ b/cc3200/mods/pybuart.c @@ -280,7 +280,7 @@ STATIC void UARTGenericIntHandler(uint32_t uart_id) { STATIC void uart_check_init(pyb_uart_obj_t *self) { // not initialized if (!self->baudrate) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } } @@ -432,7 +432,7 @@ STATIC mp_obj_t pyb_uart_init_helper(pyb_uart_obj_t *self, const mp_arg_val_t *a return mp_const_none; error: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC const mp_arg_t pyb_uart_init_args[] = { @@ -472,7 +472,7 @@ STATIC mp_obj_t pyb_uart_make_new(const mp_obj_type_t *type, mp_uint_t n_args, m } if (uart_id > PYB_UART_1) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } // get the correct uart instance @@ -556,7 +556,7 @@ STATIC mp_obj_t pyb_uart_irq (mp_uint_t n_args, const mp_obj_t *pos_args, mp_map return uart_irq_new (self, trigger, priority, args[2].u_obj); invalid_args: - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_uart_irq_obj, 1, pyb_uart_irq); @@ -622,7 +622,7 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t // write the data if (!uart_tx_strn(self, buf, size)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_operation_failed)); + mp_raise_msg(&mp_type_OSError, mpexception_os_operation_failed); } return size; } diff --git a/cc3200/mods/pybwdt.c b/cc3200/mods/pybwdt.c index 6e5fe4714a..30478c83ce 100644 --- a/cc3200/mods/pybwdt.c +++ b/cc3200/mods/pybwdt.c @@ -100,14 +100,14 @@ STATIC mp_obj_t pyb_wdt_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_wdt_init_args, args); if (args[0].u_obj != mp_const_none && mp_obj_get_int(args[0].u_obj) > 0) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + mp_raise_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable); } uint timeout_ms = args[1].u_int; if (timeout_ms < PYBWDT_MIN_TIMEOUT_MS) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } if (pyb_wdt_obj.running) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + mp_raise_msg(&mp_type_OSError, mpexception_os_request_not_possible); } // Enable the WDT peripheral clock diff --git a/cc3200/mpconfigport.h b/cc3200/mpconfigport.h index 0b16d730d0..bf3e691bd8 100644 --- a/cc3200/mpconfigport.h +++ b/cc3200/mpconfigport.h @@ -38,6 +38,7 @@ // options to control how Micro Python is built #define MICROPY_ALLOC_PATH_MAX (128) +#define MICROPY_PERSISTENT_CODE_LOAD (1) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_INLINE_THUMB (0) #define MICROPY_COMP_MODULE_CONST (1) diff --git a/cc3200/mpthreadport.c b/cc3200/mpthreadport.c index 064aa6ba10..e77ac4ae53 100644 --- a/cc3200/mpthreadport.c +++ b/cc3200/mpthreadport.c @@ -28,10 +28,13 @@ #include "py/mpconfig.h" #include "py/mpstate.h" +#include "py/runtime.h" #include "py/gc.h" #include "py/mpthread.h" +#include "py/mphal.h" #include "mptask.h" #include "task.h" +#include "irq.h" #if MICROPY_PY_THREAD @@ -131,7 +134,7 @@ void mp_thread_create(void *(*entry)(void*), void *arg, size_t *stack_size) { TaskHandle_t id = xTaskCreateStatic(freertos_entry, "Thread", *stack_size / sizeof(void*), arg, 2, stack, tcb); if (id == NULL) { mp_thread_mutex_unlock(&thread_mutex); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't create thread")); + mp_raise_msg(&mp_type_OSError, "can't create thread"); } // add thread to linked list of all threads @@ -165,14 +168,23 @@ void mp_thread_mutex_init(mp_thread_mutex_t *mutex) { mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer); } +// To allow hard interrupts to work with threading we only take/give the semaphore +// if we are not within an interrupt context and interrupts are enabled. + int mp_thread_mutex_lock(mp_thread_mutex_t *mutex, int wait) { - int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0); - return ret == pdTRUE; + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + int ret = xSemaphoreTake(mutex->handle, wait ? portMAX_DELAY : 0); + return ret == pdTRUE; + } else { + return 1; + } } void mp_thread_mutex_unlock(mp_thread_mutex_t *mutex) { - xSemaphoreGive(mutex->handle); - // TODO check return value + if ((HAL_NVIC_INT_CTRL_REG & HAL_VECTACTIVE_MASK) == 0 && query_irq() == IRQ_STATE_ENABLED) { + xSemaphoreGive(mutex->handle); + // TODO check return value + } } #endif // MICROPY_PY_THREAD diff --git a/cc3200/serverstask.c b/cc3200/serverstask.c index 1305afda0b..6b5899e186 100644 --- a/cc3200/serverstask.c +++ b/cc3200/serverstask.c @@ -29,7 +29,7 @@ #include "py/mpconfig.h" #include "py/misc.h" -#include "py/nlr.h" +#include "py/runtime.h" #include "py/mphal.h" #include "serverstask.h" #include "simplelink.h" @@ -187,7 +187,7 @@ void servers_close_socket (int16_t *sd) { void servers_set_login (char *user, char *pass) { if (strlen(user) > SERVERS_USER_PASS_LEN_MAX || strlen(pass) > SERVERS_USER_PASS_LEN_MAX) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } memcpy(servers_user, user, SERVERS_USER_PASS_LEN_MAX); memcpy(servers_pass, pass, SERVERS_USER_PASS_LEN_MAX); @@ -196,7 +196,7 @@ void servers_set_login (char *user, char *pass) { void servers_set_timeout (uint32_t timeout) { if (timeout < SERVERS_MIN_TIMEOUT_MS) { // timeout is too low - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + mp_raise_ValueError(mpexception_value_invalid_arguments); } servers_data.timeout = timeout; } diff --git a/cc3200/util/random.h b/cc3200/util/random.h index 860b46173f..67fd1ff855 100644 --- a/cc3200/util/random.h +++ b/cc3200/util/random.h @@ -30,6 +30,6 @@ void rng_init0 (void); uint32_t rng_get (void); -MP_DECLARE_CONST_FUN_OBJ(machine_rng_get_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_rng_get_obj); #endif // __RANDOM_H diff --git a/docs/conf.py b/docs/conf.py index 32d9e971d9..5ff8d640b7 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -99,7 +99,7 @@ copyright = '2014-2016, Damien P. George and contributors' # The short X.Y version. version = '1.8' # The full version, including alpha/beta/rc tags. -release = '1.8.5' +release = '1.8.6' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/esp8266/general.rst b/docs/esp8266/general.rst index 3ffb2ff339..04afed46ed 100644 --- a/docs/esp8266/general.rst +++ b/docs/esp8266/general.rst @@ -71,13 +71,16 @@ and developers, who can diagnose themselves any issues arising from modifying the standard process). Once the filesystem is mounted, ``boot.py`` is executed from it. The standard -version of this file is created during first-time module set up and by -default starts up a WebREPL daemon to handle incoming connections. This -file is customizable by end users (for example, you may want to disable -WebREPL for extra security, or add other services which should be run on +version of this file is created during first-time module set up and has +commands to start a WebREPL daemon (disabled by default, configurable +with ``webrepl_setup`` module), etc. This +file is customizable by end users (for example, you may want to set some +parameters or add other services which should be run on a module start-up). But keep in mind that incorrect modifications to boot.py may still lead to boot loops or lock ups, requiring to reflash a module -from scratch. +from scratch. (In particular, it's recommended that you use either +``webrepl_setup`` module or manual editing to configure WebREPL, but not +both). As a final step of boot procedure, ``main.py`` is executed from filesystem, if exists. This file is a hook to start up a user application each time diff --git a/docs/esp8266/quickref.rst b/docs/esp8266/quickref.rst index d06fe5a6f1..845a94ba7b 100644 --- a/docs/esp8266/quickref.rst +++ b/docs/esp8266/quickref.rst @@ -83,7 +83,7 @@ Use the :mod:`time ` module:: time.sleep_ms(500) # sleep for 500 milliseconds time.sleep_us(10) # sleep for 10 microseconds start = time.ticks_ms() # get millisecond counter - delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference + delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference Timers ------ @@ -336,29 +336,27 @@ WebREPL (web browser interactive prompt) WebREPL (REPL over WebSockets, accessible via a web browser) is an experimental feature available in ESP8266 port. Download web client from https://github.com/micropython/webrepl (hosted version available -at http://micropython.org/webrepl), and start the daemon on a device -using:: +at http://micropython.org/webrepl), and configure it by executing:: + + import webrepl_setup + +and following on-screen instructions. After reboot, it will be available +for connection. If you disabled automatic start-up on boot, you may +run configured daemon on demand using:: import webrepl webrepl.start() -(Release versions have it started on boot by default.) - -On a first connection, you will be prompted to set password for future -sessions to use. - The supported way to use WebREPL is by connecting to ESP8266 access point, but the daemon is also started on STA interface if it is active, so if your router is set up and works correctly, you may also use WebREPL while connected to your normal Internet access point (use the ESP8266 AP connection method if you face any issues). -WebREPL is an experimental feature and a work in progress, and has known -issues. +Besides terminal/command prompt access, WebREPL also has provision for file +transfer (both upload and download). Web client has buttons for the +corresponding functions, or you can use command-line client ``webrepl_cli.py`` +from the repository above. -There's also provision to transfer (both upload and download) -files over WebREPL connection, but it has even more experimental status -than the WebREPL terminal mode. It is still a practical way to -get script files onto ESP8266, so give it a try using ``webrepl_cli.py`` -from the repository above. See the MicroPython forum for other -community-supported alternatives to transfer files to ESP8266. +See the MicroPython forum for other community-supported alternatives +to transfer files to ESP8266. diff --git a/docs/esp8266/tutorial/filesystem.rst b/docs/esp8266/tutorial/filesystem.rst index 9033a8576f..27b0d2608c 100644 --- a/docs/esp8266/tutorial/filesystem.rst +++ b/docs/esp8266/tutorial/filesystem.rst @@ -64,7 +64,6 @@ device starts up. Accessing the filesystem via WebREPL ------------------------------------ -You can access the filesystem over WebREPL using the provided command-line -tool. This tool is found at ``__ -and is called webrepl_cli.py. Please refer to that program for information -on how to use it. +You can access the filesystem over WebREPL using the web client in a browser +or via the command-line tool. Please refer to Quick Reference and Tutorial +sections for more information about WebREPL. diff --git a/docs/esp8266/tutorial/intro.rst b/docs/esp8266/tutorial/intro.rst index 32e9326b37..87d4463406 100644 --- a/docs/esp8266/tutorial/intro.rst +++ b/docs/esp8266/tutorial/intro.rst @@ -54,7 +54,7 @@ device before putting on new MicroPython firmware. Currently we only support esptool.py to copy across the firmware. You can find this tool here: ``__, or install it -using pip:: +using pip (at least version 1.2.1 is required):: pip install esptool @@ -69,7 +69,7 @@ Using esptool.py you can erase the flash with the command:: And then deploy the new firmware using:: - esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m 0 esp8266-2016-05-03-v1.8.bin + esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-2016-05-03-v1.8.bin You might need to change the "port" setting to something else relevant for your PC. You may also need to reduce the baudrate if you get errors when flashing @@ -80,7 +80,7 @@ For some boards with a particular FlashROM configuration (e.g. some variants of a NodeMCU board) you may need to use the following command to deploy the firmware (note the ``-fm dio`` option):: - esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m -fm dio 0 esp8266-2016-05-03-v1.8.bin + esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-2016-05-03-v1.8.bin If the above commands run without error then MicroPython should be installed on your board! @@ -138,6 +138,8 @@ after it, here are troubleshooting recommendations: * If lower baud rate didn't help, you may want to try older version of esptool.py, which had a different programming algorithm:: pip install esptool==1.0.1 + This version doesn't support ``--flash_size=detect`` option, so you will + need to specify FlashROM size explicitly (in megabits). * The ``--flash_size`` option in the commands above is mandatory. Omitting it will lead to a corrupted firmware. diff --git a/docs/esp8266/tutorial/repl.rst b/docs/esp8266/tutorial/repl.rst index 338e9fdd8f..1922da128d 100644 --- a/docs/esp8266/tutorial/repl.rst +++ b/docs/esp8266/tutorial/repl.rst @@ -41,6 +41,18 @@ For your convenience, WebREPL client is hosted at locally from the the GitHub repository ``__ . +Before connecting to WebREPL, you should set a password and enable it via +a normal serial connection. Initial versions of MicroPython for ESP8266 +came with WebREPL automatically enabled on the boot and with the +ability to set a password via WiFi on the first connection, but as WebREPL +was becoming more widely known and popular, the initial setup has switched +to a wired connection for improved security:: + + import webrepl_setup + +Follow the on-screen instructions and prompts. To make any changes active, +you will need to reboot your device. + To use WebREPL connect your computer to the ESP8266's access point (MicroPython-xxxxxx, see the previous section about this). If you have already reconfigured your ESP8266 to connect to a router then you can @@ -49,19 +61,11 @@ skip this part. Once you are on the same network as the ESP8266 you click the "Connect" button (if you are connecting via a router then you may need to change the IP address, by default the IP address is correct when connected to the ESP8266's access -point). If the connection succeeds then you should see a welcome message. +point). If the connection succeeds then you should see a password prompt. -On the first connection you need to set a password. Make sure that the -terminal widget is selected by clicking on it, and then follow prompts to -type in your password twice (they should match each other). Then ESP8266 -will then reboot with the password applied (the WiFi will go down but come -back up again). Note that some modules may have troubles rebooting -automatically and need reset button press or power cycle (do this if -you don't see ESP8266 access point appearing in a minute or so). - -You should then click the "Connect" button again, and enter your password -to connect. If you type in the correct password you should get a prompt -looking like ``>>>``. You can now start typing Python commands! +Once you type the password configured at the setup step above, press Enter once +more and you should get a prompt looking like ``>>>``. You can now start +typing Python commands! Using the REPL -------------- diff --git a/docs/library/builtins.rst b/docs/library/builtins.rst index 42768ab999..d53c4d377b 100644 --- a/docs/library/builtins.rst +++ b/docs/library/builtins.rst @@ -28,6 +28,11 @@ All builtin functions are described here. They are also available via .. class:: complex() +.. function:: delattr(obj, name) + + The argument *name* should be a string, and this function deletes the named + attribute from the object given by *obj*. + .. class:: dict() .. function:: dir() @@ -110,6 +115,10 @@ All builtin functions are described here. They are also available via .. function:: setattr() +.. class:: slice() + + The *slice* builtin is the type that slice objects have. + .. function:: sorted() .. function:: staticmethod() diff --git a/docs/library/index.rst b/docs/library/index.rst index d502ffdfc6..b06c806f73 100644 --- a/docs/library/index.rst +++ b/docs/library/index.rst @@ -51,8 +51,8 @@ library. .. toctree:: :maxdepth: 1 - array.rst builtins.rst + array.rst cmath.rst gc.rst math.rst @@ -76,8 +76,8 @@ library. .. toctree:: :maxdepth: 1 - array.rst builtins.rst + array.rst cmath.rst gc.rst math.rst @@ -101,8 +101,8 @@ library. .. toctree:: :maxdepth: 1 - array.rst builtins.rst + array.rst gc.rst select.rst sys.rst @@ -119,8 +119,8 @@ library. .. toctree:: :maxdepth: 1 - array.rst builtins.rst + array.rst gc.rst math.rst sys.rst diff --git a/docs/library/machine.Pin.rst b/docs/library/machine.Pin.rst index db25787f94..952131f099 100644 --- a/docs/library/machine.Pin.rst +++ b/docs/library/machine.Pin.rst @@ -3,16 +3,44 @@ class Pin -- control I/O pins ============================= -A pin is the basic object to control I/O pins (also known as GPIO - -general-purpose input/output). It has methods to set -the mode of the pin (input, output, etc) and methods to get and set the -digital logic level. For analog control of a pin, see the ADC class. +A pin object is used to control I/O pins (also known as GPIO - general-purpose +input/output). Pin objects are commonly associated with a physical pin that can +drive an output voltage and read input voltages. The pin class has methods to set the mode of +the pin (IN, OUT, etc) and methods to get and set the digital logic level. +For analog control of a pin, see the :class:`ADC` class. -Usage Model: +A pin object is constructed by using an identifier which unambiguously +specifies a certain I/O pin. The allowed forms of the identifier and the +physical pin that the identifier maps to are port-specific. Possibilities +for the identifier are an integer, a string or a tuple with port and pin +number. + +Usage Model:: + + from machine import Pin + + # create an output pin on pin #0 + p0 = Pin(0, Pin.OUT) + + # set the value low then high + p0.value(0) + p0.value(1) + + # create an input pin on pin #2, with a pull up resistor + p2 = Pin(2, Pin.IN, Pin.PULL_UP) + + # read and print the pin value + print(p2.value()) + + # reconfigure pin #0 in input mode + p0.mode(p0.IN) + + # configure an irq callback + p0.irq(lambda p:print(p)) .. only:: port_wipy - Board pins are identified by their string id:: + On the WiPy board the pins are identified by their string id:: from machine import Pin g = machine.Pin('GP9', mode=Pin.OUT, pull=None, drive=Pin.MED_POWER, alt=-1) @@ -40,174 +68,224 @@ Usage Model: All pin objects go through the pin mapper to come up with one of the gpio pins. -.. only:: port_esp8266 + For the ``drive`` parameter the strengths are: - :: + - ``Pin.LOW_POWER`` - 2mA drive capability. + - ``Pin.MED_POWER`` - 4mA drive capability. + - ``Pin.HIGH_POWER`` - 6mA drive capability. - from machine import Pin + For the ``alt`` parameter please refer to the pinout and alternate functions + table at `_ + for the specific alternate functions that each pin supports. - # create an output pin on GPIO0 - p0 = Pin(0, Pin.OUT) - p0.value(0) - p0.value(1) + For interrupts, the ``priority`` can take values in the range 1-7. And the + ``wake`` parameter has the following properties: - # create an input pin on GPIO2 - p2 = Pin(2, Pin.IN, Pin.PULL_UP) - print(p2.value()) + - If ``wake_from=machine.Sleep.ACTIVE`` any pin can wake the board. + - If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``, + ``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1 + of this pins can be enabled as a wake source at the same time, so, only + the last enabled pin as a ``machine.Sleep.SUSPENDED`` wake source will have effect. + - If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``, + ``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the + 6 pins can be enabled as a ``machine.Sleep.HIBERNATE`` wake source at the same time. Constructors ------------ -.. class:: Pin(id, ...) +.. class:: Pin(id, mode=-1, pull=-1, \*, value, drive, alt) - Create a new Pin object associated with the id. If additional arguments are given, - they are used to initialise the pin. See :meth:`Pin.init`. + Access the pin peripheral (GPIO pin) associated with the given ``id``. If + additional arguments are given in the constructor then they are used to initialise + the pin. Any settings that are not specified will remain in their previous state. + + The arguments are: + + - ``id`` is mandatory and can be an arbitrary object. Among possible value + types are: int (an internal Pin identifier), str (a Pin name), and tuple + (pair of [port, pin]). + + - ``mode`` specifies the pin mode, which can be one of: + + - ``Pin.IN`` - Pin is configured for input. If viewed as an output the pin + is in high-impedance state. + + - ``Pin.OUT`` - Pin is configured for (normal) output. + + - ``Pin.OPEN_DRAIN`` - Pin is configured for open-drain output. Open-drain + output works in the following way: if the output value is set to 0 the pin + is active at a low level; if the output value is 1 the pin is in a high-impedance + state. Not all ports implement this mode, or some might only on certain pins. + + - ``Pin.ALT`` - Pin is configured to perform an alternative function, which is + port specific. For a pin configured in such a way any other Pin methods + (except :meth:`Pin.init`) are not applicable (calling them will lead to undefined, + or a hardware-specific, result). Not all ports implement this mode. + + - ``Pin.ALT_OPEN_DRAIN`` - The Same as ``Pin.ALT``, but the pin is configured as + open-drain. Not all ports implement this mode. + + - ``pull`` specifies if the pin has a (weak) pull resistor attached, and can be + one of: + + - ``None`` - No pull up or down resistor. + - ``Pin.PULL_UP`` - Pull up resistor enabled. + - ``Pin.PULL_DOWN`` - Pull down resistor enabled. + + - ``value`` is valid only for Pin.OUT and Pin.OPEN_DRAIN modes and specifies initial + output pin value if given, otherwise the state of the pin peripheral remains + unchanged. + + - ``drive`` specifies the output power of the pin and can be one of: ``Pin.LOW_POWER``, + ``Pin.MED_POWER`` or ``Pin.HIGH_POWER``. The actual current driving capabilities + are port dependent. Not all ports implement this argument. + + - ``alt`` specifies an alternate function for the pin and the values it can take are + port dependent. This argument is valid only for ``Pin.ALT`` and ``Pin.ALT_OPEN_DRAIN`` + modes. It may be used when a pin supports more than one alternate function. If only + one pin alternate function is supported the this argument is not required. Not all + ports implement this argument. + + As specified above, the Pin class allows to set an alternate function for a particular + pin, but it does not specify any further operations on such a pin. Pins configured in + alternate-function mode are usually not used as GPIO but are instead driven by other + hardware peripherals. The only operation supported on such a pin is re-initialising, + by calling the constructor or :meth:`Pin.init` method. If a pin that is configured in + alternate-function mode is re-initialised with ``Pin.IN``, ``Pin.OUT``, or + ``Pin.OPEN_DRAIN``, the alternate function will be removed from the pin. Methods ------- -.. only:: port_wipy +.. method:: Pin.init(mode=-1, pull=-1, \*, value, drive, alt) - .. method:: Pin.init(mode, pull, \*, drive, alt) - - Initialise the pin: + Re-initialise the pin using the given parameters. Only those arguments that + are specified will be set. The rest of the pin peripheral state will remain + unchanged. See the constructor documentation for details of the arguments. - - ``mode`` can be one of: + Returns ``None``. - - ``Pin.IN`` - input pin. - - ``Pin.OUT`` - output pin in push-pull mode. - - ``Pin.OPEN_DRAIN`` - output pin in open-drain mode. - - ``Pin.ALT`` - pin mapped to an alternate function. - - ``Pin.ALT_OPEN_DRAIN`` - pin mapped to an alternate function in open-drain mode. +.. method:: Pin.value([x]) - - ``pull`` can be one of: + This method allows to set and get the value of the pin, depending on whether + the argument ``x`` is supplied or not. - - ``None`` - no pull up or down resistor. - - ``Pin.PULL_UP`` - pull up resistor enabled. - - ``Pin.PULL_DOWN`` - pull down resistor enabled. + If the argument is omitted then this method gets the digital logic level of + the pin, returning 0 or 1 corresponding to low and high voltage signals + respectively. The behaviour of this method depends on the mode of the pin: - - ``drive`` can be one of: + - ``Pin.IN`` - The method returns the actual input value currently present + on the pin. + - ``Pin.OUT`` - The behaviour and return value of the method is undefined. + - ``Pin.OPEN_DRAIN`` - If the pin is in state '0' then the behaviour and + return value of the method is undefined. Otherwise, if the pin is in + state '1', the method returns the actual input value currently present + on the pin. - - ``Pin.LOW_POWER`` - 2mA drive capability. - - ``Pin.MED_POWER`` - 4mA drive capability. - - ``Pin.HIGH_POWER`` - 6mA drive capability. + If the argument is supplied then this method sets the digital logic level of + the pin. The argument ``x`` can be anything that converts to a boolean. + If it converts to ``True``, the pin is set to state '1', otherwise it is set + to state '0'. The behaviour of this method depends on the mode of the pin: - - ``alt`` is the number of the alternate function. Please refer to the - `pinout and alternate functions table. `_ - for the specific alternate functions that each pin supports. + - ``Pin.IN`` - The value is stored in the output buffer for the pin. The + pin state does not change, it remains in the high-impedance state. The + stored value will become active on the pin as soon as it is changed to + ``Pin.OUT`` or ``Pin.OPEN_DRAIN`` mode. + - ``Pin.OUT`` - The output buffer is set to the given value immediately. + - ``Pin.OPEN_DRAIN`` - If the value is '0' the pin is set to a low voltage + state. Otherwise the pin is set to high-impedance state. - Returns: ``None``. + When setting the value this method returns ``None``. - .. method:: Pin.id() +.. method:: Pin.out_value() - Get the pin id. + Return the value stored in the output buffer of a pin, regardless of its mode. -.. only:: port_esp8266 + Not all ports implement this method. - .. method:: Pin.init(mode, pull=None, \*, value) +.. method:: Pin.__call__([x]) - Initialise the pin: + Pin objects are callable. The call method provides a (fast) shortcut to set + and get the value of the pin. It is equivalent to Pin.value([x]). + See :meth:`Pin.value` for more details. - - `mode` can be one of: +.. method:: Pin.toggle() - - ``Pin.IN`` - input pin. - - ``Pin.OUT`` - output pin in push-pull mode. + Toggle the output value of the pin. Equivalent to ``pin.value(not pin.out_value())``. + Returns ``None``. - - `pull` can be one of: + Not all ports implement this method. - - ``None`` - no pull up or down resistor. - - ``Pin.PULL_UP`` - pull up resistor enabled. + Availability: WiPy. - - if `value` is given then it is the output value to set the pin - if it is in output mode. +.. method:: Pin.id() -.. method:: Pin.value([value]) + Get the pin identifier. This may return the ``id`` as specified in the + constructor. Or it may return a canonical software-specific pin id. - Get or set the digital logic level of the pin: +.. method:: Pin.mode([mode]) - - With no argument, return 0 or 1 depending on the logic level of the pin. - - With ``value`` given, set the logic level of the pin. ``value`` can be - anything that converts to a boolean. If it converts to ``True``, the pin - is set high, otherwise it is set low. + Get or set the pin mode. + See the constructor documentation for details of the ``mode`` argument. -.. method:: Pin.__call__([value]) +.. method:: Pin.pull([pull]) - Pin objects are callable. The call method provides a (fast) shortcut to set and get the value of the pin. - See :func:`Pin.value` for more details. + Get or set the pin pull state. + See the constructor documentation for details of the ``pull`` argument. -.. method:: Pin.alt_list() +.. method:: Pin.drive([drive]) - Returns a list of the alternate functions supported by the pin. List items are - a tuple of the form: ``('ALT_FUN_NAME', ALT_FUN_INDEX)`` + Get or set the pin drive strength. + See the constructor documentation for details of the ``drive`` argument. - Availability: WiPy. + Not all ports implement this method. + + Availability: WiPy. + +.. method:: Pin.irq(handler=None, trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING), \*, priority=1, wake=None) + + Configure an interrupt handler to be called when the trigger source of the + pin is active. If the pin mode is ``Pin.IN`` then the trigger source is + the external value on the pin. If the pin mode is ``Pin.OUT`` then the + trigger source is the output buffer of the pin. Otherwise, if the pin mode + is ``Pin.OPEN_DRAIN`` then the trigger source is the output buffer for + state '0' and the external pin value for state '1'. + + The arguments are: + + - ``handler`` is an optional function to be called when the interrupt + triggers. + + - ``trigger`` configures the event which can generate an interrupt. + Possible values are: + + - ``Pin.IRQ_FALLING`` interrupt on falling edge. + - ``Pin.IRQ_RISING`` interrupt on rising edge. + - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. + - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. + + These values can be OR'ed together to trigger on multiple events. + + - ``priority`` sets the priority level of the interrupt. The values it + can take are port-specific, but higher values always represent higher + priorities. + + - ``wake`` selects the power mode in which this interrupt can wake up the + system. It can be ``machine.IDLE``, ``machine.SLEEP`` or ``machine.DEEPSLEEP``. + These values can also be OR'ed together to make a pin generate interrupts in + more than one power mode. + + This method returns a callback object. .. only:: port_wipy - .. method:: Pin.toggle() + .. method:: Pin.alt_list() - Toggle the value of the pin. + Returns a list of the alternate functions supported by the pin. List items are + a tuple of the form: ``('ALT_FUN_NAME', ALT_FUN_INDEX)`` - .. method:: Pin.mode([mode]) + Availability: WiPy. - Get or set the pin mode. - - .. method:: Pin.pull([pull]) - - Get or set the pin pull. - - .. method:: Pin.drive([drive]) - - Get or set the pin drive strength. - - .. method:: Pin.irq(\*, trigger, priority=1, handler=None, wake=None) - - Create a callback to be triggered when the input level at the pin changes. - - - ``trigger`` configures the pin level which can generate an interrupt. Possible values are: - - - ``Pin.IRQ_FALLING`` interrupt on falling edge. - - ``Pin.IRQ_RISING`` interrupt on rising edge. - - ``Pin.IRQ_LOW_LEVEL`` interrupt on low level. - - ``Pin.IRQ_HIGH_LEVEL`` interrupt on high level. - - The values can be *ORed* together, for instance mode=Pin.IRQ_FALLING | Pin.IRQ_RISING - - - ``priority`` level of the interrupt. Can take values in the range 1-7. - Higher values represent higher priorities. - - ``handler`` is an optional function to be called when new characters arrive. - - ``wakes`` selects the power mode in which this interrupt can wake up the - board. Please note: - - - If ``wake_from=machine.Sleep.ACTIVE`` any pin can wake the board. - - If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``, - ``GP11``, GP17`` or ``GP24`` can wake the board. Note that only 1 - of this pins can be enabled as a wake source at the same time, so, only - the last enabled pin as a ``machine.Sleep.SUSPENDED`` wake source will have effect. - - If ``wake_from=machine.Sleep.SUSPENDED`` pins ``GP2``, ``GP4``, ``GP10``, - ``GP11``, ``GP17`` and ``GP24`` can wake the board. In this case all of the - 6 pins can be enabled as a ``machine.Sleep.HIBERNATE`` wake source at the same time. - - Values can be ORed to make a pin generate interrupts in more than one power - mode. - - Returns a callback object. - -.. only:: port_esp8266 - - .. method:: Pin.irq(\*, trigger, handler=None) - - Create a callback to be triggered when the input level at the pin changes. - - - ``trigger`` configures the pin level which can generate an interrupt. Possible values are: - - - ``Pin.IRQ_FALLING`` interrupt on falling edge. - - ``Pin.IRQ_RISING`` interrupt on rising edge. - - The values can be OR'ed together to trigger on multiple events. - - - ``handler`` is an optional function to be called when the interrupt triggers. - - Returns a callback object. Attributes ---------- @@ -239,7 +317,8 @@ not all constants are available on all ports. .. data:: Pin.PULL_UP Pin.PULL_DOWN - Selects the whether there is a pull up/down resistor. + Selects whether there is a pull up/down resistor. Use the value + ``None`` for no pull. .. data:: Pin.LOW_POWER Pin.MED_POWER diff --git a/docs/library/machine.SPI.rst b/docs/library/machine.SPI.rst index 73b3a3996d..dda6314fa2 100644 --- a/docs/library/machine.SPI.rst +++ b/docs/library/machine.SPI.rst @@ -1,10 +1,14 @@ .. currentmodule:: machine -class SPI -- a master-driven serial protocol -============================================ +class SPI -- a Serial Peripheral Interface bus protocol (master side) +===================================================================== -SPI is a serial protocol that is driven by a master. At the physical level -there are 3 lines: SCK, MOSI, MISO. +SPI is a synchronous serial protocol that is driven by a master. At the +physical level, a bus consists of 3 lines: SCK, MOSI, MISO. Multiple devices +can share the same bus. Each device should have a separate, 4th signal, +SS (Slave Select), to select a particualr device on a bus with which +communication takes place. Management of an SS signal should happen in +user code (via machine.Pin class). .. only:: port_wipy @@ -21,65 +25,84 @@ there are 3 lines: SCK, MOSI, MISO. Constructors ------------ -.. only:: port_wipy +.. class:: SPI(id, ...) - .. class:: SPI(id, ...) + Construct an SPI object on the given bus, ``id``. Values of ``id`` depend + on a particular port and its hardware. Values 0, 1, etc. are commonly used + to select hardware SPI block #0, #1, etc. Value -1 can be used for + bitbanging (software) implementation of SPI (if supported by a port). - Construct an SPI object on the given bus. ``id`` can be only 0. - With no additional parameters, the SPI object is created but not - initialised (it has the settings from the last initialisation of - the bus, if any). If extra arguments are given, the bus is initialised. - See ``init`` for parameters of initialisation. + With no additional parameters, the SPI object is created but not + initialised (it has the settings from the last initialisation of + the bus, if any). If extra arguments are given, the bus is initialised. + See ``init`` for parameters of initialisation. Methods ------- -.. method:: SPI.init(mode, baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, pins=(CLK, MOSI, MISO)) +.. method:: SPI.init(baudrate=1000000, \*, polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=None, mosi=None, miso=None, pins=(SCK, MOSI, MISO)) Initialise the SPI bus with the given parameters: - - ``mode`` must be ``SPI.MASTER``. - ``baudrate`` is the SCK clock rate. - ``polarity`` can be 0 or 1, and is the level the idle clock line sits at. - ``phase`` can be 0 or 1 to sample data on the first or second clock edge respectively. - - ``bits`` is the width of each transfer, accepted values are 8, 16 and 32. - - ``firstbit`` can be ``SPI.MSB`` only. - - ``pins`` is an optional tuple with the pins to assign to the SPI bus. + - ``bits`` is the width in bits of each transfer. Only 8 is guaranteed to be supported by all hardware. + - ``firstbit`` can be ``SPI.MSB`` or ``SPI.LSB``. + - ``sck``, ``mosi``, ``miso`` are pins (machine.Pin) objects to use for bus signals. For most + hardware SPI blocks (as selected by ``id`` parameter to the constructore), pins are fixed + and cannot be changed. In some cases, hardware blocks allow 2-3 alternative pin sets for + a hardware SPI block. Arbitrary pin assignments are possible only for a bitbanging SPI driver + (``id`` = -1). + - ``pins`` - WiPy port doesn't ``sck``, ``mosi``, ``miso`` arguments, and instead allows to + specify them as a tuple of ``pins`` paramter. .. method:: SPI.deinit() Turn off the SPI bus. +.. method:: SPI.read(nbytes, write=0x00) + + Read a number of bytes specified by ``nbytes`` while continuously writing + the single byte given by ``write``. + Returns a ``bytes`` object with the data that was read. + +.. method:: SPI.readinto(buf, write=0x00) + + Read into the buffer specified by ``buf`` while continuously writing the + single byte given by ``write``. + Returns ``None``. + + Note: on WiPy this function returns the number of bytes read. + .. method:: SPI.write(buf) - Write the data contained in ``buf``. - Returns the number of bytes written. + Write the bytes contained in ``buf``. + Returns ``None``. -.. method:: SPI.read(nbytes, *, write=0x00) - - Read the ``nbytes`` while writing the data specified by ``write``. - Return the number of bytes read. - -.. method:: SPI.readinto(buf, *, write=0x00) - - Read into the buffer specified by ``buf`` while writing the data specified by - ``write``. - Return the number of bytes read. + Note: on WiPy this function returns the number of bytes written. .. method:: SPI.write_readinto(write_buf, read_buf) - Write from ``write_buf`` and read into ``read_buf``. Both buffers must have the + Write the bytes from ``write_buf`` while reading into ``read_buf``. The + buffers can be the same or different, but both buffers must have the same length. - Returns the number of bytes written + Returns ``None``. + + Note: on WiPy this function returns the number of bytes written. Constants --------- .. data:: SPI.MASTER - for initialising the SPI bus to master + for initialising the SPI bus to master; this is only used for the WiPy .. data:: SPI.MSB set the first bit to be the most significant bit + +.. data:: SPI.LSB + + set the first bit to be the least significant bit diff --git a/docs/library/network.rst b/docs/library/network.rst index 0e18106aa8..251e68c76e 100644 --- a/docs/library/network.rst +++ b/docs/library/network.rst @@ -5,11 +5,12 @@ .. module:: network :synopsis: network configuration -This module provides network drivers and routing configuration. Network -drivers for specific hardware are available within this module and are -used to configure a hardware network interface. Configured interfaces -are then available for use via the :mod:`socket` module. To use this module -the network build of firmware must be installed. +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`socket` +module. For example:: @@ -79,7 +80,7 @@ For example:: class CC3K ========== - This class provides a driver for CC3000 wifi modules. Example usage:: + This class provides a driver for CC3000 WiFi modules. Example usage:: import network nic = network.CC3K(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3) @@ -128,16 +129,16 @@ For example:: .. method:: cc3k.connect(ssid, key=None, \*, security=WPA2, bssid=None) - Connect to a wifi access point using the given SSID, and other security + Connect to a WiFi access point using the given SSID, and other security parameters. .. method:: cc3k.disconnect() - Disconnect from the wifi access point. + Disconnect from the WiFi access point. .. method:: cc3k.isconnected() - Returns True if connected to a wifi access point and has a valid IP address, + Returns True if connected to a WiFi access point and has a valid IP address, False otherwise. .. method:: cc3k.ifconfig() @@ -323,7 +324,7 @@ For example:: .. method:: wlan.isconnected() - In case of STA mode, returns ``True`` if connected to a wifi access + In case of STA mode, returns ``True`` if connected to a WiFi access point and has a valid IP address. In AP mode returns ``True`` when a station is connected. Returns ``False`` otherwise. @@ -348,7 +349,7 @@ For example:: # Set WiFi access point name (formally known as ESSID) and WiFi channel ap.config(essid='My AP', channel=11) - # Queey params one by one + # Query params one by one print(ap.config('essid')) print(ap.config('channel')) @@ -433,7 +434,7 @@ For example:: .. method:: wlan.connect(ssid, \*, auth=None, bssid=None, timeout=None) - Connect to a wifi access point using the given SSID, and other security + Connect to a WiFi access point using the given SSID, and other security parameters. - ``auth`` is a tuple with (sec, key). Security can be ``None``, ``WLAN.WEP``, @@ -451,16 +452,16 @@ For example:: .. method:: wlan.disconnect() - Disconnect from the wifi access point. + Disconnect from the WiFi access point. .. method:: wlan.isconnected() - In case of STA mode, returns ``True`` if connected to a wifi access point and has a valid IP address. + In case of STA mode, returns ``True`` if connected to a WiFi access point and has a valid IP address. In AP mode returns ``True`` when a station is connected, ``False`` otherwise. .. method:: wlan.ifconfig(if_id=0, config=['dhcp' or configtuple]) - With no parameters given eturns a 4-tuple of ``(ip, subnet_mask, gateway, DNS_server)``. + With no parameters given returns a 4-tuple of ``(ip, subnet_mask, gateway, DNS_server)``. if ``'dhcp'`` is passed as a parameter then the DHCP client is enabled and the IP params are negotiated with the AP. @@ -498,10 +499,10 @@ For example:: Create a callback to be triggered when a WLAN event occurs during ``machine.SLEEP`` mode. Events are triggered by socket activity or by WLAN connection/disconnection. - - ``handler`` is the function that gets called when the irq is triggered. + - ``handler`` is the function that gets called when the IRQ is triggered. - ``wake`` must be ``machine.SLEEP``. - Returns an irq object. + Returns an IRQ object. Constants --------- diff --git a/docs/library/utime.rst b/docs/library/utime.rst index 8310673830..109c3560cc 100644 --- a/docs/library/utime.rst +++ b/docs/library/utime.rst @@ -82,37 +82,128 @@ Functions .. function:: ticks_ms() - Returns an increasing millisecond counter with arbitrary reference point, - that wraps after some (unspecified) value. The value should be treated as - opaque, suitable for use only with ticks_diff(). + Returns an increasing millisecond counter with an arbitrary reference point, + that wraps around after some value. This value is not explicitly exposed, + but we will refer to it as `TICKS_MAX` to simplify discussion. Period of + the values is `TICKS_PERIOD = TICKS_MAX + 1`. `TICKS_PERIOD` is guaranteed + to be a power of two, but otherwise may differ from port to port. The same + period value is used for all of ticks_ms(), ticks_us(), ticks_cpu() functions + (for simplicity). Thus, these functions will return a value in range + [0 .. `TICKS_MAX`], inclusive, total `TICKS_PERIOD` values. Note that only + non-negative values are used. For the most part, you should treat values + returned by these functions as opaque. The only operations available for them + are ``ticks_diff()`` and ``ticks_add()`` functions described below. + + Note: Performing standard mathematical operations (+, -) or relational + operators (<, <=, >, >=) directly on these value will lead to invalid + result. Performing mathematical operations and then passing their results + as arguments to ``ticks_diff()`` or ``ticks_add()`` will also lead to + invalid results from the latter functions. .. function:: ticks_us() Just like ``ticks_ms`` above, but in microseconds. -.. only:: port_wipy or port_pyboard +.. function:: ticks_cpu() - .. function:: ticks_cpu() + Similar to ``ticks_ms`` and ``ticks_us``, but with the highest possible resolution + in the system. This is usually CPU clocks, and that's why the function is named that + way. But it doesn't have to a CPU clock, some other timing source available in a + system (e.g. high-resolution timer) can be used instead. The exact timing unit + (resolution) of this function is not specified on ``utime`` module level, but + documentation for a specific port may provide more specific information. This + function is intended for very fine benchmarking or very tight real-time loops. + Avoid using it in portable code. - Similar to ``ticks_ms`` and ``ticks_us``, but with higher resolution (usually CPU clocks). + Availability: Not every port implements this function. -.. only:: port_unix or port_pyboard or port_wipy or port_esp8266 - .. function:: ticks_diff(old, new) +.. function:: ticks_add(ticks, delta) - Measure period between consecutive calls to ticks_ms(), ticks_us(), or ticks_cpu(). - The value returned by these functions may wrap around at any time, so directly - subtracting them is not supported. ticks_diff() should be used instead. "old" value should - actually precede "new" value in time, or result is undefined. This function should not be - used to measure arbitrarily long periods of time (because ticks_*() functions wrap around - and usually would have short period). The expected usage pattern is implementing event - polling with timeout:: + Offset ticks value by a given number, which can be either positive or negative. + Given a ``ticks`` value, this function allows to calculate ticks value ``delta`` + ticks before or after it, following modular-arithmetic definition of tick values + (see ``ticks_ms()`` above). ``ticks`` parameter must be a direct result of call + to ``tick_ms()``, ``ticks_us()``, ``ticks_cpu()`` functions (or from previous + call to ``ticks_add()``). However, ``delta`` can be an arbitrary integer number + or numeric expression. ``ticks_add()`` is useful for calculating deadlines for + events/tasks. (Note: you must use ``ticks_diff()`` function to work with + deadlines.) + + Examples:: + + # Find out what ticks value there was 100ms ago + print(tick_add(time.ticks_ms(), -100)) + + # Calculate deadline for operation and test for it + deadline = tick_add(time.ticks_ms(), 200) + while ticks_diff(deadline, time.ticks_ms()) > 0: + do_a_little_of_something() + + # Find out TICKS_MAX used by this port + print(tick_add(0, -1)) + + +.. function:: ticks_diff(ticks1, ticks2) + + Measure ticks difference between values returned from ticks_ms(), ticks_us(), or ticks_cpu() + functions. The argument order is the same as for subtraction operator, + ``tick_diff(ticks1, ticks2)`` has the same meaning as ``ticks1 - ticks2``. However, values returned by + ticks_ms(), etc. functions may wrap around, so directly using subtraction on them will + produce incorrect result. That is why ticks_diff() is needed, it implements modular + (or more specifically, ring) arithmetics to produce correct result even for wrap-around + values (as long as they not too distant inbetween, see below). The function returns + **signed** value in the range [`-TICKS_PERIOD/2` .. `TICKS_PERIOD/2-1`] (that's a typical + range definition for two's-complement signed binary integers). If the result is negative, + it means that `ticks1` occured earlier in time than `ticks2`. Otherwise, it means that + `ticks1` occured after `ticks2`. This holds `only` if `ticks1` and `ticks2` are apart from + each other for no more than `TICKS_PERIOD/2-1` ticks. If that does not hold, incorrect + result will be returned. Specifically, if 2 tick values are apart for `TICKS_PERIOD/2-1` + ticks, that value will be returned by the function. However, if `TICKS_PERIOD/2` of + real-time ticks has passed between them, the function will return `-TICKS_PERIOD/2` + instead, i.e. result value will wrap around to the negative range of possible values. + + Informal rationale of the constraints above: Suppose you are locked in a room with no + means to monitor passing of time except a standard 12-notch clock. Then if you look at + dial-plate now, and don't look again for another 13 hours (e.g., if you fall for a + long sleep), then once you finally look again, it may seem to you that only 1 hour + has passed. To avoid this mistake, just look at the clock regularly. Your application + should do the same. "Too long sleep" metaphor also maps directly to application + behavior: don't let your application run any single task for too long. Run tasks + in steps, and do time-keeping inbetween. + + ``ticks_diff()`` is designed to accommodate various usage patterns, among them: + + Polling with timeout. In this case, the order of events is known, and you will deal + only with positive results of ``ticks_diff()``:: + + # Wait for GPIO pin to be asserted, but at most 500us + start = time.ticks_us() + while pin.value() == 0: + if time.ticks_diff(time.ticks_us(), start) > 500: + raise TimeoutError + + Scheduling events. In this case, ``ticks_diff()`` result may be negative + if an event is overdue:: + + # This code snippet is not optimized + now = time.ticks_ms() + scheduled_time = task.scheduled_time() + if ticks_diff(now, scheduled_time) > 0: + print("Too early, let's nap") + sleep_ms(ticks_diff(now, scheduled_time)) + task.run() + elif ticks_diff(now, scheduled_time) == 0: + print("Right at time!") + task.run() + elif ticks_diff(now, scheduled_time) < 0: + print("Oops, running late, tell task to run faster!") + task.run(run_faster=true) + + Note: Do not pass ``time()`` values to ``ticks_diff()``, and should use + normal mathematical operations on them. But note that ``time()`` may (and will) + also overflow. This is known as https://en.wikipedia.org/wiki/Year_2038_problem . - # Wait for GPIO pin to be asserted, but at most 500us - start = time.ticks_us() - while pin.value() == 0: - if time.ticks_diff(start, time.ticks_us()) > 500: - raise TimeoutError .. function:: time() diff --git a/docs/pyboard/quickref.rst b/docs/pyboard/quickref.rst index 3d08ae9109..5f1a3a6e6b 100644 --- a/docs/pyboard/quickref.rst +++ b/docs/pyboard/quickref.rst @@ -37,7 +37,7 @@ Use the :mod:`time ` module:: time.sleep_ms(500) # sleep for 500 milliseconds time.sleep_us(10) # sleep for 10 microseconds start = time.ticks_ms() # get value of millisecond counter - delta = time.ticks_diff(start, time.ticks_ms()) # compute time difference + delta = time.ticks_diff(time.ticks_ms(), start) # compute time difference LEDs ---- diff --git a/docs/reference/speed_python.rst b/docs/reference/speed_python.rst index 2f1d16cea1..8efba4702b 100644 --- a/docs/reference/speed_python.rst +++ b/docs/reference/speed_python.rst @@ -132,7 +132,7 @@ The following enables any function or method to be timed by adding an def new_func(*args, **kwargs): t = time.ticks_us() result = f(*args, **kwargs) - delta = time.ticks_diff(t, time.ticks_us()) + delta = time.ticks_diff(time.ticks_us(), t) print('Function {} Time = {:6.3f}ms'.format(myname, delta/1000)) return result return new_func diff --git a/drivers/cc3000/src/ccspi.c b/drivers/cc3000/src/ccspi.c index 1606bfd571..64900efe46 100644 --- a/drivers/cc3000/src/ccspi.c +++ b/drivers/cc3000/src/ccspi.c @@ -99,7 +99,7 @@ STATIC tSpiInformation sSpiInformation; STATIC char spi_buffer[CC3000_RX_BUFFER_SIZE]; unsigned char wlan_tx_buffer[CC3000_TX_BUFFER_SIZE]; -STATIC const mp_obj_fun_builtin_t irq_callback_obj; +STATIC const mp_obj_fun_builtin_fixed_t irq_callback_obj; // set the pins to use to communicate with the CC3000 // the arguments must be of type pin_obj_t* and SPI_HandleTypeDef* diff --git a/drivers/dht/dht.h b/drivers/dht/dht.h index 8274228ac6..20954036df 100644 --- a/drivers/dht/dht.h +++ b/drivers/dht/dht.h @@ -1,3 +1,3 @@ #include "py/obj.h" -MP_DECLARE_CONST_FUN_OBJ(dht_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_2(dht_readinto_obj); diff --git a/drivers/display/ssd1306.py b/drivers/display/ssd1306.py index 34dca769e9..ad57725e74 100644 --- a/drivers/display/ssd1306.py +++ b/drivers/display/ssd1306.py @@ -1,5 +1,6 @@ # MicroPython SSD1306 OLED driver, I2C and SPI interfaces +from micropython import const import time import framebuf diff --git a/drivers/nrf24l01/nrf24l01.py b/drivers/nrf24l01/nrf24l01.py index a244b0b25d..3c79650bf0 100644 --- a/drivers/nrf24l01/nrf24l01.py +++ b/drivers/nrf24l01/nrf24l01.py @@ -1,6 +1,7 @@ """NRF24L01 driver for Micro Python """ +from micropython import const import pyb # nRF24L01+ registers diff --git a/drivers/sdcard/sdcard.py b/drivers/sdcard/sdcard.py index fc7a8af7c5..191630aebd 100644 --- a/drivers/sdcard/sdcard.py +++ b/drivers/sdcard/sdcard.py @@ -21,6 +21,7 @@ Example usage on ESP8266: """ +from micropython import const import time diff --git a/esp8266/Makefile b/esp8266/Makefile index 65a513afd6..b2191353a2 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -5,20 +5,19 @@ QSTR_DEFS = qstrdefsport.h #$(BUILD)/pins_qstr.h MICROPY_PY_USSL = 1 MICROPY_SSL_AXTLS = 1 +MICROPY_FATFS = 1 MICROPY_PY_BTREE = 1 +FROZEN_DIR = scripts +FROZEN_MPY_DIR = modules + # include py core make definitions include ../py/py.mk -MPY_CROSS = ../mpy-cross/mpy-cross -MPY_TOOL = ../tools/mpy-tool.py - -FROZEN_DIR = scripts -FROZEN_MPY_DIR = modules PORT ?= /dev/ttyACM0 BAUD ?= 115200 FLASH_MODE ?= qio -FLASH_SIZE ?= 8m +FLASH_SIZE ?= detect CROSS_COMPILE = xtensa-lx106-elf- ESP_SDK = $(shell $(CC) -print-sysroot)/usr @@ -44,7 +43,8 @@ CFLAGS_XTENSA = -fsingle-precision-constant -Wdouble-promotion \ CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -ansi -std=gnu99 -nostdlib -DUART_OS=$(UART_OS) \ $(CFLAGS_XTENSA) $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA) -LDFLAGS = -nostdlib -T esp8266.ld -Map=$(@:.elf=.map) --cref +LDSCRIPT = esp8266.ld +LDFLAGS = -nostdlib -T $(LDSCRIPT) -Map=$(@:.elf=.map) --cref LIBS = -L$(ESP_SDK)/lib -lmain -ljson -llwip_open -lpp -lnet80211 -lwpa -lphy -lnet80211 $(LDFLAGS_MOD) LIBGCC_FILE_NAME = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) @@ -65,6 +65,7 @@ SRC_C = \ main.c \ help.c \ esp_mphal.c \ + esp_init_data.c \ gccollect.c \ lexerstr32.c \ uart.c \ @@ -74,22 +75,21 @@ SRC_C = \ espapa102.c \ intr.c \ modpyb.c \ - modpybpin.c \ - modpybpwm.c \ - modpybrtc.c \ - modpybadc.c \ - modpybuart.c \ - modmachinewdt.c \ - modpybspi.c \ - modpybhspi.c \ + modmachine.c \ + machine_pin.c \ + machine_pwm.c \ + machine_rtc.c \ + machine_adc.c \ + machine_uart.c \ + machine_wdt.c \ + machine_spi.c \ + machine_hspi.c \ modesp.c \ modnetwork.c \ modutime.c \ moduos.c \ - modmachine.c \ modonewire.c \ ets_alt_task.c \ - $(BUILD)/frozen.c \ fatfs_port.c \ axtls_helpers.c \ hspi.c \ @@ -130,10 +130,14 @@ LIB_SRC_C = $(addprefix lib/,\ utils/pyexec.c \ utils/pyhelp.c \ utils/interrupt_char.c \ - fatfs/ff.c \ - fatfs/option/ccsbcs.c \ ) +ifeq ($(MICROPY_FATFS), 1) +LIB_SRC_C += \ + lib/fatfs/ff.c \ + lib/fatfs/option/ccsbcs.c +endif + DRIVERS_SRC_C = $(addprefix drivers/,\ dht/dht.c \ ) @@ -141,9 +145,6 @@ DRIVERS_SRC_C = $(addprefix drivers/,\ SRC_S = \ gchelper.s \ -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') -FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) - OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) @@ -152,7 +153,6 @@ OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o)) -OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o #OBJ += $(BUILD)/pins_$(BOARD).o # List of sources for qstr extraction @@ -175,23 +175,11 @@ $(BUILD)/uart.o: $(CONFVARS_FILE) FROZEN_EXTRA_DEPS = $(CONFVARS_FILE) -# to build .mpy files from .py files -$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py - @$(ECHO) "MPY $<" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ - -# to build frozen_mpy.c from all .mpy files -$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ - .PHONY: deploy deploy: $(BUILD)/firmware-combined.bin $(ECHO) "Writing $< to the board" $(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --verify --flash_size=$(FLASH_SIZE) --flash_mode=$(FLASH_MODE) 0 $< - #$(Q)esptool.py --port $(PORT) --baud $(BAUD) write_flash --flash_size=8m 0 $(BUILD)/firmware.elf-0x00000.bin 0x9000 $(BUILD)/firmware.elf-0x0[1-f]000.bin reset: echo -e "\r\nimport machine; machine.reset()\r\n" >$(PORT) @@ -206,6 +194,9 @@ $(BUILD)/firmware.elf: $(OBJ) $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ +512k: + $(MAKE) LDSCRIPT=esp8266_512k.ld CFLAGS_EXTRA='-DMP_CONFIGFILE=""' MICROPY_FATFS=0 MICROPY_PY_BTREE=0 + #MAKE_PINS = boards/make-pins.py #BOARD_PINS = boards/$(BOARD)/pins.csv #AF_FILE = boards/stm32f4xx_af.csv diff --git a/esp8266/README.md b/esp8266/README.md index c998b7ad18..54591fcc13 100644 --- a/esp8266/README.md +++ b/esp8266/README.md @@ -70,13 +70,14 @@ $ make deploy ``` This will use the `esptool.py` script to download the images. You must have your ESP module in the bootloader mode, and connected to a serial port on your PC. -The default serial port is `/dev/ttyACM0`, flash mode is `qio` and flash size is `8m`. -To specify other values, use, eg: +The default serial port is `/dev/ttyACM0`, flash mode is `qio` and flash size is +`detect` (auto-detect based on Flash ID). To specify other values, use, eg (note +that flash size is in megabits): ```bash -$ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=8m deploy +$ make PORT=/dev/ttyUSB0 FLASH_MODE=qio FLASH_SIZE=32m deploy ``` -The image produced is `firmware-combined.bin`, to be flashed at 0x00000. +The image produced is `build/firmware-combined.bin`, to be flashed at 0x00000. First start ----------- diff --git a/esp8266/esp8266.ld b/esp8266/esp8266.ld index c726790d38..20b259dff2 100644 --- a/esp8266/esp8266.ld +++ b/esp8266/esp8266.ld @@ -20,7 +20,7 @@ PHDRS irom0_0_phdr PT_LOAD; } -ENTRY(call_user_start) +ENTRY(firmware_start) EXTERN(_DebugExceptionVector) EXTERN(_DoubleExceptionVector) EXTERN(_KernelExceptionVector) @@ -130,20 +130,23 @@ SECTIONS *stmhal/pybstdio.o(.literal*, .text*) + build/main.o(.literal* .text*) *gccollect.o(.literal* .text*) *gchelper.o(.literal* .text*) + *help.o(.literal* .text*) *lexerstr32.o(.literal* .text*) *utils.o(.literal* .text*) *modpyb.o(.literal*, .text*) - *modpybpin.o(.literal*, .text*) - *modpybpwm.o(.literal*, .text*) - *modpybrtc.o(.literal*, .text*) - *modpybadc.o(.literal*, .text*) - *modpybuart.o(.literal*, .text*) + *machine_pin.o(.literal*, .text*) + *machine_pwm.o(.literal*, .text*) + *machine_rtc.o(.literal*, .text*) + *machine_adc.o(.literal*, .text*) + *machine_uart.o(.literal*, .text*) *modpybi2c.o(.literal*, .text*) - *modmachinewdt.o(.literal*, .text*) - *modpybspi.o(.literal*, .text*) - *modpybhspi.o(.literal*, .text*) + *modmachine.o(.literal*, .text*) + *machine_wdt.o(.literal*, .text*) + *machine_spi.o(.literal*, .text*) + *machine_hspi.o(.literal*, .text*) *hspi.o(.literal*, .text*) *modesp.o(.literal* .text*) *modnetwork.o(.literal* .text*) @@ -199,7 +202,8 @@ SECTIONS *(.entry.text) *(.init.literal) *(.init) - *(.literal .text .literal.* .text.* .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.literal .text .literal.* .text.* .iram0.literal .iram0.text .iram0.text.*.literal .iram0.text.*) + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) *(.fini.literal) *(.fini) *(.gnu.version) diff --git a/esp8266/esp8266_512k.ld b/esp8266/esp8266_512k.ld new file mode 100644 index 0000000000..781cbb985c --- /dev/null +++ b/esp8266/esp8266_512k.ld @@ -0,0 +1,303 @@ +/* GNU linker script for ESP8266 */ + +MEMORY +{ + dport0_0_seg : org = 0x3ff00000, len = 0x10 + dram0_0_seg : org = 0x3ffe8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40209000, len = 0x72000 +} + +/* define the top of RAM */ +_heap_end = ORIGIN(dram0_0_seg) + LENGTH(dram0_0_seg); + +PHDRS +{ + dport0_0_phdr PT_LOAD; + dram0_0_phdr PT_LOAD; + dram0_0_bss_phdr PT_LOAD; + iram1_0_phdr PT_LOAD; + irom0_0_phdr PT_LOAD; +} + +ENTRY(firmware_start) +EXTERN(_DebugExceptionVector) +EXTERN(_DoubleExceptionVector) +EXTERN(_KernelExceptionVector) +EXTERN(_NMIExceptionVector) +EXTERN(_UserExceptionVector) + +PROVIDE(_memmap_vecbase_reset = 0x40000000); + +/* Various memory-map dependent cache attribute settings: */ +_memmap_cacheattr_wb_base = 0x00000110; +_memmap_cacheattr_wt_base = 0x00000110; +_memmap_cacheattr_bp_base = 0x00000220; +_memmap_cacheattr_unused_mask = 0xFFFFF00F; +_memmap_cacheattr_wb_trapnull = 0x2222211F; +_memmap_cacheattr_wba_trapnull = 0x2222211F; +_memmap_cacheattr_wbna_trapnull = 0x2222211F; +_memmap_cacheattr_wt_trapnull = 0x2222211F; +_memmap_cacheattr_bp_trapnull = 0x2222222F; +_memmap_cacheattr_wb_strict = 0xFFFFF11F; +_memmap_cacheattr_wt_strict = 0xFFFFF11F; +_memmap_cacheattr_bp_strict = 0xFFFFF22F; +_memmap_cacheattr_wb_allvalid = 0x22222112; +_memmap_cacheattr_wt_allvalid = 0x22222112; +_memmap_cacheattr_bp_allvalid = 0x22222222; +PROVIDE(_memmap_cacheattr_reset = _memmap_cacheattr_wb_trapnull); + +SECTIONS +{ + + .dport0.rodata : ALIGN(4) + { + _dport0_rodata_start = ABSOLUTE(.); + *(.dport0.rodata) + *(.dport.rodata) + _dport0_rodata_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.literal : ALIGN(4) + { + _dport0_literal_start = ABSOLUTE(.); + *(.dport0.literal) + *(.dport.literal) + _dport0_literal_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .dport0.data : ALIGN(4) + { + _dport0_data_start = ABSOLUTE(.); + *(.dport0.data) + *(.dport.data) + _dport0_data_end = ABSOLUTE(.); + } >dport0_0_seg :dport0_0_phdr + + .irom0.text : ALIGN(4) + { + _irom0_text_start = ABSOLUTE(.); + *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) + + /* we put some specific text in this section */ + + *py/argcheck.o*(.literal* .text*) + *py/asm*.o*(.literal* .text*) + *py/bc.o*(.literal* .text*) + *py/binary.o*(.literal* .text*) + *py/builtin*.o*(.literal* .text*) + *py/compile.o*(.literal* .text*) + *py/emit*.o*(.literal* .text*) + *py/formatfloat.o*(.literal* .text*) + *py/frozenmod.o*(.literal* .text*) + *py/gc.o*(.literal* .text*) + *py/lexer*.o*(.literal* .text*) + *py/malloc*.o*(.literal* .text*) + *py/map*.o*(.literal* .text*) + *py/mod*.o*(.literal* .text*) + *py/mpprint.o*(.literal* .text*) + *py/mpstate.o*(.literal* .text*) + *py/mpz.o*(.literal* .text*) + *py/native*.o*(.literal* .text*) + *py/nlr*.o*(.literal* .text*) + *py/obj*.o*(.literal* .text*) + *py/opmethods.o*(.literal* .text*) + *py/parse*.o*(.literal* .text*) + *py/qstr.o*(.literal* .text*) + *py/repl.o*(.literal* .text*) + *py/runtime.o*(.literal* .text*) + *py/scope.o*(.literal* .text*) + *py/sequence.o*(.literal* .text*) + *py/showbc.o*(.literal* .text*) + *py/smallint.o*(.literal* .text*) + *py/stackctrl.o*(.literal* .text*) + *py/stream.o*(.literal* .text*) + *py/unicode.o*(.literal* .text*) + *py/vm.o*(.literal* .text*) + *py/vstr.o*(.literal* .text*) + *py/warning.o*(.literal* .text*) + + *extmod/*.o*(.literal* .text*) + + *lib/fatfs/*.o*(.literal*, .text*) + */libaxtls.a:(.literal*, .text*) + *lib/berkeley-db-1.xx/*.o(.literal*, .text*) + *lib/libm/*.o*(.literal*, .text*) + *lib/mp-readline/*.o(.literal*, .text*) + *lib/netutils/*.o*(.literal*, .text*) + *lib/timeutils/*.o*(.literal*, .text*) + *lib/utils/*.o*(.literal*, .text*) + + *stmhal/pybstdio.o(.literal*, .text*) + + build/main.o(.literal* .text*) + *gccollect.o(.literal* .text*) + *gchelper.o(.literal* .text*) + *help.o(.literal* .text*) + *lexerstr32.o(.literal* .text*) + *utils.o(.literal* .text*) + *modpyb.o(.literal*, .text*) + *machine_pin.o(.literal*, .text*) + *machine_pwm.o(.literal*, .text*) + *machine_rtc.o(.literal*, .text*) + *machine_adc.o(.literal*, .text*) + *machine_uart.o(.literal*, .text*) + *modpybi2c.o(.literal*, .text*) + *modmachine.o(.literal*, .text*) + *machine_wdt.o(.literal*, .text*) + *machine_spi.o(.literal*, .text*) + *machine_hspi.o(.literal*, .text*) + *hspi.o(.literal*, .text*) + *modesp.o(.literal* .text*) + *modnetwork.o(.literal* .text*) + *moduos.o(.literal* .text*) + *modutime.o(.literal* .text*) + *modlwip.o(.literal* .text*) + *modsocket.o(.literal* .text*) + *modonewire.o(.literal* .text*) + + /* we put as much rodata as possible in this section */ + /* note that only rodata accessed as a machine word is allowed here */ + *py/qstr.o(.rodata.const_pool) + *.o(.rodata.mp_type_*) /* catches type: mp_obj_type_t */ + *.o(.rodata.*_locals_dict*) /* catches types: mp_obj_dict_t, mp_map_elem_t */ + *.o(.rodata.mp_module_*) /* catches types: mp_obj_module_t, mp_obj_dict_t, mp_map_elem_t */ + */frozen.o(.rodata.mp_frozen_sizes) /* frozen modules */ + */frozen.o(.rodata.mp_frozen_content) /* frozen modules */ + + /* for -mforce-l32 */ + build/*.o(.rodata*) + + _irom0_text_end = ABSOLUTE(.); + } >irom0_0_seg :irom0_0_phdr + + .text : ALIGN(4) + { + _stext = .; + _text_start = ABSOLUTE(.); + *(.UserEnter.text) + . = ALIGN(16); + *(.DebugExceptionVector.text) + . = ALIGN(16); + *(.NMIExceptionVector.text) + . = ALIGN(16); + *(.KernelExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.UserExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN(16); + *(.DoubleExceptionVector.text) + LONG(0) + LONG(0) + LONG(0) + LONG(0) + . = ALIGN (16); + *(.entry.text) + *(.init.literal) + *(.init) + *(.literal .text .literal.* .text.* .iram0.literal .iram0.text .iram0.text.*.literal .iram0.text.*) + *(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*) + *(.fini.literal) + *(.fini) + *(.gnu.version) + _text_end = ABSOLUTE(.); + _etext = .; + } >iram1_0_seg :iram1_0_phdr + + .lit4 : ALIGN(4) + { + _lit4_start = ABSOLUTE(.); + *(*.lit4) + *(.lit4.*) + *(.gnu.linkonce.lit4.*) + _lit4_end = ABSOLUTE(.); + } >iram1_0_seg :iram1_0_phdr + + .data : ALIGN(4) + { + _data_start = ABSOLUTE(.); + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.data1) + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + *(.jcr) + _data_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .rodata : ALIGN(4) + { + _rodata_start = ABSOLUTE(.); + *(.sdk.version) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + *(.rodata1) + __XT_EXCEPTION_TABLE__ = ABSOLUTE(.); + *(.xt_except_table) + *(.gcc_except_table) + *(.gnu.linkonce.e.*) + *(.gnu.version_r) + *(.eh_frame) + /* C++ constructor and destructor tables, properly ordered: */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* C++ exception handlers table: */ + __XT_EXCEPTION_DESCS__ = ABSOLUTE(.); + *(.xt_except_desc) + *(.gnu.linkonce.h.*) + __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); + *(.xt_except_desc_end) + *(.dynamic) + *(.gnu.version_d) + . = ALIGN(4); /* this table MUST be 4-byte aligned */ + _bss_table_start = ABSOLUTE(.); + LONG(_bss_start) + LONG(_bss_end) + _bss_table_end = ABSOLUTE(.); + _rodata_end = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_phdr + + .bss ALIGN(8) (NOLOAD) : ALIGN(4) + { + . = ALIGN (8); + _bss_start = ABSOLUTE(.); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + . = ALIGN (8); + _bss_end = ABSOLUTE(.); + _heap_start = ABSOLUTE(.); + } >dram0_0_seg :dram0_0_bss_phdr +} + +/* get ROM code address */ +INCLUDE "eagle.rom.addr.v6.ld" diff --git a/esp8266/esp_init_data.c b/esp8266/esp_init_data.c new file mode 100644 index 0000000000..b14de573a7 --- /dev/null +++ b/esp8266/esp_init_data.c @@ -0,0 +1,77 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "ets_sys.h" +#include "etshal.h" +#include "esp_mphal.h" +#include "user_interface.h" +#include "extmod/misc.h" + +NORETURN void call_user_start(void); +void ets_printf(const char *fmt, ...); +extern char flashchip; + +static const uint8_t default_init_data[] __attribute__((aligned(4))) = { +0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05, +0x04, 0xfe, 0xfd, 0xff, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe1, 0x0a, 0xff, 0xff, 0xf8, 0x00, +0xf8, 0xf8, 0x52, 0x4e, 0x4a, 0x44, 0x40, 0x38, 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xe1, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void firmware_start(void) { + // For SDK 1.5.2, either address has shifted and not mirrored in + // eagle.rom.addr.v6.ld, or extra initial member was added. + SpiFlashChip *flash = (SpiFlashChip*)(&flashchip + 4); + + char buf[128]; + SPIRead(flash->chip_size - 4 * 0x1000, buf, sizeof(buf)); + /*for (int i = 0; i < sizeof(buf); i++) { + static char hexf[] = "%x "; + ets_printf(hexf, buf[i]); + }*/ + + bool inited = false; + for (int i = 0; i < sizeof(buf); i++) { + if (buf[i] != 0xff) { + inited = true; + break; + } + } + + if (!inited) { + static char msg[] = "Writing init data\n"; + ets_printf(msg); + SPIRead((uint32_t)&default_init_data - 0x40200000, buf, sizeof(buf)); + SPIWrite(flash->chip_size - 4 * 0x1000, buf, sizeof(buf)); + } + + asm("j call_user_start"); +} diff --git a/esp8266/esp_mphal.h b/esp8266/esp_mphal.h index 7a71c0f032..1622667f93 100644 --- a/esp8266/esp_mphal.h +++ b/esp8266/esp_mphal.h @@ -75,7 +75,7 @@ void ets_event_poll(void); // C-level pin HAL #include "etshal.h" #include "gpio.h" -#include "esp8266/modpyb.h" +#include "esp8266/modmachine.h" #define mp_hal_pin_obj_t uint32_t #define mp_hal_get_pin_obj(o) mp_obj_get_pin(o) void mp_hal_pin_input(mp_hal_pin_obj_t pin); diff --git a/esp8266/espneopixel.c b/esp8266/espneopixel.c index 27c7731064..6c76591865 100644 --- a/esp8266/espneopixel.c +++ b/esp8266/espneopixel.c @@ -33,7 +33,7 @@ void /*ICACHE_RAM_ATTR*/ esp_neopixel_write(uint8_t pin, uint8_t *pixels, uint32 #ifdef NEO_KHZ400 if(is800KHz) { #endif - time0 = fcpu / 2500000; // 0.4us + time0 = fcpu / 2857143; // 0.35us time1 = fcpu / 1250000; // 0.8us period = fcpu / 800000; // 1.25us per bit #ifdef NEO_KHZ400 diff --git a/esp8266/esponewire.c b/esp8266/esponewire.c index 797ec0bd22..22bb45b158 100644 --- a/esp8266/esponewire.c +++ b/esp8266/esponewire.c @@ -28,7 +28,7 @@ #include "etshal.h" #include "user_interface.h" -#include "modpyb.h" +#include "modmachine.h" #include "esponewire.h" #define TIMING_RESET1 (0) diff --git a/esp8266/etshal.h b/esp8266/etshal.h index e7326a43ba..90af63ba2d 100644 --- a/esp8266/etshal.h +++ b/esp8266/etshal.h @@ -24,7 +24,9 @@ extern void ets_wdt_disable(void); extern void wdt_feed(void); // Opaque structure -typedef char MD5_CTX[64]; +#ifndef MD5_CTX +typedef char MD5_CTX[88]; +#endif void MD5Init(MD5_CTX *context); void MD5Update(MD5_CTX *context, const void *data, unsigned int len); @@ -32,6 +34,12 @@ void MD5Final(unsigned char digest[16], MD5_CTX *context); // These prototypes are for recent SDKs with "malloc tracking" void *pvPortMalloc(unsigned sz, const char *fname, int line); +void *pvPortZalloc(unsigned sz, const char *fname, int line); +void *pvPortRealloc(void *p, unsigned sz, const char *fname, int line); void vPortFree(void *p, const char *fname, int line); +uint32_t SPIRead(uint32_t offset, void *buf, uint32_t len); +uint32_t SPIWrite(uint32_t offset, const void *buf, uint32_t len); +uint32_t SPIEraseSector(int sector); + #endif // _INCLUDED_ETSHAL_H_ diff --git a/esp8266/fatfs_port.c b/esp8266/fatfs_port.c index b87906f789..9c84f04e45 100644 --- a/esp8266/fatfs_port.c +++ b/esp8266/fatfs_port.c @@ -27,7 +27,7 @@ #include "py/obj.h" #include "lib/fatfs/ff.h" #include "timeutils.h" -#include "modpybrtc.h" +#include "modmachine.h" DWORD get_fattime(void) { diff --git a/esp8266/intr.c b/esp8266/intr.c index 62da4a721a..456d6cb046 100644 --- a/esp8266/intr.c +++ b/esp8266/intr.c @@ -27,7 +27,7 @@ #include "etshal.h" #include "ets_alt_task.h" -#include "modpyb.h" +#include "modmachine.h" // this is in a separate file so it can go in iRAM void pin_intr_handler_iram(void *arg) { diff --git a/esp8266/modpybadc.c b/esp8266/machine_adc.c similarity index 100% rename from esp8266/modpybadc.c rename to esp8266/machine_adc.c diff --git a/esp8266/modpybhspi.c b/esp8266/machine_hspi.c similarity index 100% rename from esp8266/modpybhspi.c rename to esp8266/machine_hspi.c diff --git a/esp8266/modpybpin.c b/esp8266/machine_pin.c similarity index 99% rename from esp8266/modpybpin.c rename to esp8266/machine_pin.c index 8916da64f6..205c58aaee 100644 --- a/esp8266/modpybpin.c +++ b/esp8266/machine_pin.c @@ -37,7 +37,7 @@ #include "py/runtime.h" #include "py/gc.h" #include "py/mphal.h" -#include "modpyb.h" +#include "modmachine.h" #define GET_TRIGGER(phys_port) \ GPIO_PIN_INT_TYPE_GET(GPIO_REG_READ(GPIO_PIN_ADDR(phys_port))) diff --git a/esp8266/modpybpwm.c b/esp8266/machine_pwm.c similarity index 99% rename from esp8266/modpybpwm.c rename to esp8266/machine_pwm.c index 871e4c3dd7..5d30f09656 100644 --- a/esp8266/modpybpwm.c +++ b/esp8266/machine_pwm.c @@ -31,7 +31,7 @@ #include "py/nlr.h" #include "py/runtime.h" -#include "modpyb.h" +#include "modmachine.h" typedef struct _pyb_pwm_obj_t { mp_obj_base_t base; diff --git a/esp8266/modpybrtc.c b/esp8266/machine_rtc.c similarity index 99% rename from esp8266/modpybrtc.c rename to esp8266/machine_rtc.c index d69fc47a8e..54eeea6f6e 100644 --- a/esp8266/modpybrtc.c +++ b/esp8266/machine_rtc.c @@ -32,7 +32,7 @@ #include "py/runtime.h" #include "timeutils.h" #include "user_interface.h" -#include "modpyb.h" +#include "modmachine.h" typedef struct _pyb_rtc_obj_t { mp_obj_base_t base; diff --git a/esp8266/modpybspi.c b/esp8266/machine_spi.c similarity index 100% rename from esp8266/modpybspi.c rename to esp8266/machine_spi.c diff --git a/esp8266/modpybuart.c b/esp8266/machine_uart.c similarity index 99% rename from esp8266/modpybuart.c rename to esp8266/machine_uart.c index 25320fa1e7..80e10d1310 100644 --- a/esp8266/modpybuart.c +++ b/esp8266/machine_uart.c @@ -34,7 +34,7 @@ #include "py/runtime.h" #include "py/stream.h" #include "py/mperrno.h" -#include "modpyb.h" +#include "modmachine.h" // UartDev is defined and initialized in rom code. extern UartDevice UartDev; diff --git a/esp8266/modmachinewdt.c b/esp8266/machine_wdt.c similarity index 100% rename from esp8266/modmachinewdt.c rename to esp8266/machine_wdt.c diff --git a/esp8266/main.c b/esp8266/main.c index c938dcb30b..a2e747d211 100644 --- a/esp8266/main.c +++ b/esp8266/main.c @@ -39,7 +39,7 @@ #include "gccollect.h" #include "user_interface.h" -STATIC char heap[28 * 1024]; +STATIC char heap[36 * 1024]; STATIC void mp_reset(void) { mp_stack_set_top((void*)0x40000000); @@ -141,7 +141,7 @@ mp_obj_t mp_builtin_open(uint n_args, const mp_obj_t *args, mp_map_t *kwargs) { } MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open); -void nlr_jump_fail(void *val) { +void MP_FASTCODE(nlr_jump_fail)(void *val) { printf("NLR jump failed\n"); for (;;) { } diff --git a/esp8266/modesp.c b/esp8266/modesp.c index 515319c9e0..207422b67d 100644 --- a/esp8266/modesp.c +++ b/esp8266/modesp.c @@ -45,8 +45,7 @@ #include "mem.h" #include "espneopixel.h" #include "espapa102.h" -#include "modpyb.h" -#include "modpybrtc.h" +#include "modmachine.h" #define MODESP_ESPCONN (0) @@ -629,6 +628,11 @@ STATIC mp_obj_t esp_flash_size(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_size_obj, esp_flash_size); +STATIC mp_obj_t esp_flash_user_start(void) { + return MP_OBJ_NEW_SMALL_INT(0x90000); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp_flash_user_start_obj, esp_flash_user_start); + STATIC mp_obj_t esp_check_fw(void) { MD5_CTX ctx; uint32_t *sz_p = (uint32_t*)0x40208ffc; @@ -706,6 +710,7 @@ STATIC const mp_map_elem_t esp_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_flash_write), (mp_obj_t)&esp_flash_write_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_flash_erase), (mp_obj_t)&esp_flash_erase_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_flash_size), (mp_obj_t)&esp_flash_size_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_flash_user_start), (mp_obj_t)&esp_flash_user_start_obj }, #if MODESP_ESPCONN { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&esp_socket_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_getaddrinfo_obj }, diff --git a/esp8266/modmachine.c b/esp8266/modmachine.c index 0ab3c122b7..29a72f7e4a 100644 --- a/esp8266/modmachine.c +++ b/esp8266/modmachine.c @@ -33,8 +33,7 @@ #include "extmod/machine_mem.h" #include "extmod/machine_pulse.h" #include "extmod/machine_i2c.h" -#include "modpyb.h" -#include "modpybrtc.h" +#include "modmachine.h" #include "xtirq.h" #include "os_type.h" diff --git a/esp8266/modpyb.h b/esp8266/modmachine.h similarity index 78% rename from esp8266/modpyb.h rename to esp8266/modmachine.h index 45d0bb8cfd..df7953ecb6 100644 --- a/esp8266/modpyb.h +++ b/esp8266/modmachine.h @@ -13,7 +13,7 @@ extern const mp_obj_type_t pyb_spi_type; extern const mp_obj_type_t pyb_hspi_type; extern const mp_obj_type_t machine_spi_type; -MP_DECLARE_CONST_FUN_OBJ(pyb_info_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_info_obj); typedef struct _pyb_pin_obj_t { mp_obj_base_t base; @@ -33,4 +33,11 @@ pyb_pin_obj_t *mp_obj_get_pin_obj(mp_obj_t pin_in); int pin_get(uint pin); void pin_set(uint pin, int value); +extern uint32_t pyb_rtc_alarm0_wake; +extern uint64_t pyb_rtc_alarm0_expiry; + +void pyb_rtc_set_us_since_2000(uint64_t nowus); +uint64_t pyb_rtc_get_us_since_2000(); +void rtc_prepare_deepsleep(uint64_t sleep_us); + #endif // __MICROPY_INCLUDED_ESP8266_MODPYB_H__ diff --git a/esp8266/modnetwork.c b/esp8266/modnetwork.c index 86bf27ca66..1d8a02bc9b 100644 --- a/esp8266/modnetwork.c +++ b/esp8266/modnetwork.c @@ -100,17 +100,23 @@ STATIC mp_obj_t esp_connect(mp_uint_t n_args, const mp_obj_t *args) { mp_uint_t len; const char *p; - p = mp_obj_str_get_data(args[1], &len); - memcpy(config.ssid, p, len); - p = mp_obj_str_get_data(args[2], &len); - memcpy(config.password, p, len); + if (n_args > 1) { + p = mp_obj_str_get_data(args[1], &len); + memcpy(config.ssid, p, len); + if (n_args > 2) { + p = mp_obj_str_get_data(args[2], &len); + } else { + p = ""; + } + memcpy(config.password, p, len); - error_check(wifi_station_set_config(&config), "Cannot set STA config"); + error_check(wifi_station_set_config(&config), "Cannot set STA config"); + } error_check(wifi_station_connect(), "Cannot connect to AP"); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 3, 7, esp_connect); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp_connect_obj, 1, 7, esp_connect); STATIC mp_obj_t esp_disconnect(mp_obj_t self_in) { require_if(self_in, STATION_IF); @@ -295,7 +301,7 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs switch ((uintptr_t)kwargs->table[i].key) { case QS(MP_QSTR_mac): { mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(kwargs->table[i].value, &bufinfo, MP_BUFFER_READ); if (bufinfo.len != 6) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid buffer length")); @@ -336,6 +342,14 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs cfg.ap.channel = mp_obj_get_int(kwargs->table[i].value); break; } + case QS(MP_QSTR_dhcp_hostname): { + req_if = STATION_IF; + if (self->if_id == STATION_IF) { + const char *s = mp_obj_str_get_str(kwargs->table[i].value); + wifi_station_set_hostname((char*)s); + } + break; + } default: goto unknown; } @@ -389,6 +403,12 @@ STATIC mp_obj_t esp_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs req_if = SOFTAP_IF; val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel); break; + case QS(MP_QSTR_dhcp_hostname): { + req_if = STATION_IF; + char* s = wifi_station_get_hostname(); + val = mp_obj_new_str(s, strlen(s), false); + break; + } default: goto unknown; } diff --git a/esp8266/modonewire.c b/esp8266/modonewire.c index 0d8958ceee..1bf7722409 100644 --- a/esp8266/modonewire.c +++ b/esp8266/modonewire.c @@ -29,7 +29,7 @@ #include "py/obj.h" #include "py/mphal.h" -#include "modpyb.h" +#include "modmachine.h" #include "esponewire.h" STATIC mp_obj_t onewire_timings(mp_obj_t timings_in) { diff --git a/esp8266/modpyb.c b/esp8266/modpyb.c index ba53e71b37..9fe8039bc6 100644 --- a/esp8266/modpyb.c +++ b/esp8266/modpyb.c @@ -28,12 +28,12 @@ #include "py/gc.h" #include "gccollect.h" -#include "modpyb.h" +#include "modmachine.h" // The pyb module no longer exists since all functionality now appears // elsewhere, in more standard places (eg time, machine modules). The // only remaining function is pyb.info() which has been moved to the -// esp module, pending deletion/renaming/moving elsewher. +// esp module, pending deletion/renaming/moving elsewhere. STATIC mp_obj_t pyb_info(mp_uint_t n_args, const mp_obj_t *args) { // print info about memory diff --git a/esp8266/modpybrtc.h b/esp8266/modpybrtc.h deleted file mode 100644 index 5b9d9fc766..0000000000 --- a/esp8266/modpybrtc.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Josef Gajdusek - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -extern uint32_t pyb_rtc_alarm0_wake; -extern uint64_t pyb_rtc_alarm0_expiry; - -void pyb_rtc_set_us_since_2000(uint64_t nowus); - -uint64_t pyb_rtc_get_us_since_2000(); - -void rtc_prepare_deepsleep(uint64_t sleep_us); diff --git a/esp8266/modules/ds18x20.py b/esp8266/modules/ds18x20.py index eb22e2ae30..bf06094835 100644 --- a/esp8266/modules/ds18x20.py +++ b/esp8266/modules/ds18x20.py @@ -1,6 +1,8 @@ # DS18x20 temperature sensor driver for MicroPython. # MIT license; Copyright (c) 2016 Damien P. George +from micropython import const + _CONVERT = const(0x44) _RD_SCRATCH = const(0xbe) _WR_SCRATCH = const(0x4e) @@ -43,4 +45,7 @@ class DS18X20: t = buf[0] >> 1 return t - 0.25 + (buf[7] - buf[6]) / buf[7] else: - return (buf[1] << 8 | buf[0]) / 16 + t = buf[1] << 8 | buf[0] + if t & 0x8000: # sign bit set + t = -((t ^ 0xffff) + 1) + return t / 16 diff --git a/esp8266/modules/flashbdev.py b/esp8266/modules/flashbdev.py index 98b0208fb6..e879895fb0 100644 --- a/esp8266/modules/flashbdev.py +++ b/esp8266/modules/flashbdev.py @@ -3,7 +3,7 @@ import esp class FlashBdev: SEC_SIZE = 4096 - START_SEC = 0x90000 // SEC_SIZE + START_SEC = esp.flash_user_start() // SEC_SIZE NUM_BLK = 0x6b def __init__(self, blocks=NUM_BLK): diff --git a/esp8266/modules/onewire.py b/esp8266/modules/onewire.py index 06b216a57a..83318d1a47 100644 --- a/esp8266/modules/onewire.py +++ b/esp8266/modules/onewire.py @@ -1,6 +1,7 @@ # 1-Wire driver for MicroPython on ESP8266 # MIT license; Copyright (c) 2016 Damien P. George +from micropython import const import _onewire as _ow class OneWireError(Exception): diff --git a/esp8266/modules/upip.py b/esp8266/modules/upip.py new file mode 120000 index 0000000000..20d52a4ab7 --- /dev/null +++ b/esp8266/modules/upip.py @@ -0,0 +1 @@ +../../tools/upip.py \ No newline at end of file diff --git a/esp8266/modules/upip_utarfile.py b/esp8266/modules/upip_utarfile.py new file mode 120000 index 0000000000..1498862916 --- /dev/null +++ b/esp8266/modules/upip_utarfile.py @@ -0,0 +1 @@ +../../tools/upip_utarfile.py \ No newline at end of file diff --git a/esp8266/modules/webrepl.py b/esp8266/modules/webrepl.py index da3e70c595..5a76e9b26d 100644 --- a/esp8266/modules/webrepl.py +++ b/esp8266/modules/webrepl.py @@ -31,6 +31,10 @@ def setup_conn(port, accept_handler): def accept_conn(listen_sock): global client_s cl, remote_addr = listen_sock.accept() + if uos.dupterm(): + print("\nConcurrent WebREPL connection from", remote_addr, "rejected") + cl.close() + return print("\nWebREPL connection from:", remote_addr) client_s = cl websocket_helper.server_handshake(cl) @@ -55,18 +59,16 @@ def start(port=8266, password=None): stop() if password is None: try: - import port_config - _webrepl.password(port_config.WEBREPL_PASS) + import webrepl_cfg + _webrepl.password(webrepl_cfg.PASS) setup_conn(port, accept_conn) print("Started webrepl in normal mode") except: - import webrepl_setup - setup_conn(port, webrepl_setup.handle_conn) - print("Started webrepl in setup mode") + print("WebREPL is not configured, run 'import webrepl_setup'") else: _webrepl.password(password) setup_conn(port, accept_conn) - print("Started webrepl in normal mode") + print("Started webrepl in manual override mode") def start_foreground(port=8266): diff --git a/esp8266/modules/webrepl_setup.py b/esp8266/modules/webrepl_setup.py index d0bf8465d5..d91600e6ec 100644 --- a/esp8266/modules/webrepl_setup.py +++ b/esp8266/modules/webrepl_setup.py @@ -1,83 +1,111 @@ import sys -import socket -import time +#import uos as os +import os +import machine -from websocket import * -import websocket_helper +RC = "./boot.py" +CONFIG = "./webrepl_cfg.py" - -def setup_server(): - s = socket.socket() - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - - ai = socket.getaddrinfo("0.0.0.0", 8266) - addr = ai[0][4] - - s.bind(addr) - s.listen(1) - return s - -def getpass(stream, prompt): - stream.write(prompt) - passwd = b"" +def input_choice(prompt, choices): while 1: - c = stream.read(1) - if c in (b"\r", b"\n"): - stream.write("\r\n") - return passwd - passwd += c - stream.write("*") + resp = input(prompt) + if resp in choices: + return resp -def handle_conn(listen_sock): - cl, remote_addr = listen_sock.accept() - - print(""" - -First-time WebREPL connection has been received. WebREPL initial setup -will now start over this connection. During setup, UART REPL will be -non-responsive. After setup finishes, the board will be rebooted. In -case of error during setup, current session will continue. - -If you receive this message unexpectedly, it may mean that your WebREPL -connection is being hacked (power off board if unsure). -""") - - websocket_helper.server_handshake(cl) - ws = websocket(cl) - - ws.write("""\ -Welcome to MicroPython WebREPL!\r -\r -This is the first time you connect to WebREPL, so please set a password\r -to use for the following WebREPL sessions. Once you enter the password\r -twice, your board will reboot with WebREPL running in active mode. On\r -some boards, you may need to press reset button or reconnect power.\r -\r -""") +def getpass(prompt): + return input(prompt) +def input_pass(): while 1: - passwd1 = getpass(ws, "New password: ") + passwd1 = getpass("New password: ") if len(passwd1) < 4: - ws.write("Password too short\r\n") + print("Password too short") continue elif len(passwd1) > 9: - ws.write("Password too long\r\n") + print("Password too long") continue - passwd2 = getpass(ws, "Confirm password: ") + passwd2 = getpass("Confirm password: ") if passwd1 == passwd2: - break - ws.write("Passwords do not match\r\n") - - with open("port_config.py", "w") as f: - f.write("WEBREPL_PASS = %r\n" % passwd1.decode("ascii")) - - ws.write("Password successfully set, restarting...\r\n") - cl.close() - time.sleep(2) - import machine - machine.reset() + return passwd1 + print("Passwords do not match") -def test(): - s = setup_server() - handle_conn(s) +def exists(fname): + try: + with open(fname): + pass + return True + except OSError: + return False + +def copy_stream(s_in, s_out): + buf = bytearray(64) + while 1: + sz = s_in.readinto(buf) + s_out.write(buf, sz) + + +def get_daemon_status(): + with open(RC) as f: + for l in f: + if "webrepl" in l: + if l.startswith("#"): + return False + return True + return None + +def add_daemon(): + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + new_f.write("import webrepl\nwebrepl.start()\n") + copy_stream(old_f, new_f) + +def change_daemon(action): + LINES = ("import webrepl", "webrepl.start()") + with open(RC) as old_f, open(RC + ".tmp", "w") as new_f: + for l in old_f: + for patt in LINES: + if patt in l: + if action and l.startswith("#"): + l = l[1:] + elif not action and not l.startswith("#"): + l = "#" + l + new_f.write(l) + # FatFs rename() is not POSIX compliant, will raise OSError if + # dest file exists. + os.remove(RC) + os.rename(RC + ".tmp", RC) + + +def main(): + status = get_daemon_status() + + print("WebREPL daemon auto-start status:", "enabled" if status else "disabled") + print("\nWould you like to (E)nable or (D)isable it running on boot?") + print("(Empty line to quit)") + resp = input("> ").upper() + + if resp == "E": + if exists(CONFIG): + resp2 = input_choice("Would you like to change WebREPL password? (y/n) ", ("y", "n", "")) + else: + print("To enable WebREPL, you must set password for it") + resp2 = "y" + + if resp2 == "y": + passwd = input_pass() + with open(CONFIG, "w") as f: + f.write("PASS = %r\n" % passwd) + + + if resp not in ("D", "E") or (resp == "D" and not status) or (resp == "E" and status): + print("No further action required") + sys.exit() + + change_daemon(resp == "E") + + print("Changes will be activated after reboot") + resp = input_choice("Would you like to reboot now? (y/n) ", ("y", "n", "")) + if resp == "y": + machine.reset() + +main() diff --git a/esp8266/modutime.c b/esp8266/modutime.c index abfe069cc3..2adb6c563b 100644 --- a/esp8266/modutime.c +++ b/esp8266/modutime.c @@ -34,8 +34,7 @@ #include "py/runtime.h" #include "py/mphal.h" #include "py/smallint.h" -#include "modpyb.h" -#include "modpybrtc.h" +#include "modmachine.h" #include "timeutils.h" #include "user_interface.h" #include "extmod/utime_mphal.h" @@ -108,19 +107,20 @@ STATIC mp_obj_t time_time(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); -STATIC const mp_map_elem_t time_module_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) }, +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&mp_utime_sleep_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&mp_utime_sleep_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&mp_utime_sleep_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&mp_utime_ticks_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&mp_utime_ticks_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&mp_utime_ticks_cpu_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&mp_utime_ticks_diff_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj }, + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, }; STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index 201057f128..602b3e9c81 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -182,4 +182,6 @@ extern const struct _mp_obj_module_t onewire_module; #define MICROPY_HW_MCU_NAME "ESP8266" #define MICROPY_PY_SYS_PLATFORM "esp8266" +#define MP_FASTCODE(n) __attribute__((section(".iram0.text." #n))) n + #define _assert(expr) ((expr) ? (void)0 : __assert_func(__FILE__, __LINE__, __func__, #expr)) diff --git a/esp8266/mpconfigport_512k.h b/esp8266/mpconfigport_512k.h new file mode 100644 index 0000000000..f0de6035f1 --- /dev/null +++ b/esp8266/mpconfigport_512k.h @@ -0,0 +1,19 @@ +#include + +#undef MICROPY_FSUSERMOUNT +#define MICROPY_FSUSERMOUNT (0) +#undef MICROPY_VFS_FAT +#define MICROPY_VFS_FAT (0) + +#undef MICROPY_PERSISTENT_CODE_LOAD +#define MICROPY_PERSISTENT_CODE_LOAD (0) + +#undef MICROPY_PY_IO_FILEIO +#define MICROPY_PY_IO_FILEIO (0) + +#undef MICROPY_PY_SYS_STDIO_BUFFER +#define MICROPY_PY_SYS_STDIO_BUFFER (0) +#undef MICROPY_PY_BUILTINS_SLICE_ATTRS +#define MICROPY_PY_BUILTINS_SLICE_ATTRS (0) +#undef MICROPY_PY_ALL_SPECIAL_METHODS +#define MICROPY_PY_ALL_SPECIAL_METHODS (0) diff --git a/esp8266/scripts/apa102.py b/esp8266/scripts/apa102.py index 126448cc20..41b7c0485c 100644 --- a/esp8266/scripts/apa102.py +++ b/esp8266/scripts/apa102.py @@ -2,27 +2,16 @@ # MIT license; Copyright (c) 2016 Robert Foss, Daniel Busch from esp import apa102_write +from neopixel import NeoPixel -class APA102: - def __init__(self, clock_pin, data_pin, n): + +class APA102(NeoPixel): + ORDER = (0, 1, 2, 3) + + def __init__(self, clock_pin, data_pin, n, bpp=4): + super().__init__(data_pin, n, bpp) self.clock_pin = clock_pin - self.data_pin = data_pin - self.n = n - self.buf = bytearray(n * 4) - self.clock_pin.init(clock_pin.OUT) - self.data_pin.init(data_pin.OUT) - - def __setitem__(self, index, val): - r, g, b, brightness = val - self.buf[index * 4] = r - self.buf[index * 4 + 1] = g - self.buf[index * 4 + 2] = b - self.buf[index * 4 + 3] = brightness - - def __getitem__(self, index): - i = index * 4 - return self.buf[i], self.buf[i + 1], self.buf[i + 2], self.buf[i + 3] def write(self): - apa102_write(self.clock_pin, self.data_pin, self.buf) + apa102_write(self.clock_pin, self.pin, self.buf) diff --git a/esp8266/scripts/neopixel.py b/esp8266/scripts/neopixel.py index 8aa0348680..b13424d7d8 100644 --- a/esp8266/scripts/neopixel.py +++ b/esp8266/scripts/neopixel.py @@ -3,29 +3,30 @@ from esp import neopixel_write + class NeoPixel: - def __init__(self, pin, n): + ORDER = (1, 0, 2, 3) + + def __init__(self, pin, n, bpp=3): self.pin = pin self.n = n - self.buf = bytearray(n * 3) + self.bpp = bpp + self.buf = bytearray(n * bpp) self.pin.init(pin.OUT) def __setitem__(self, index, val): - r, g, b = val - self.buf[index * 3] = g - self.buf[index * 3 + 1] = r - self.buf[index * 3 + 2] = b + offset = index * self.bpp + for i in range(self.bpp): + self.buf[offset + self.ORDER[i]] = val[i] def __getitem__(self, index): - i = index * 3 - return self.buf[i + 1], self.buf[i], self.buf[i + 2] + offset = index * self.bpp + return tuple(self.buf[offset + self.ORDER[i]] + for i in range(self.bpp)) def fill(self, color): - r, g, b = color - for i in range(len(self.buf) / 3): - self.buf[i * 3] = g - self.buf[i * 3 + 1] = r - self.buf[i * 3 + 2] = b + for i in range(self.n): + self[i] = color def write(self): neopixel_write(self.pin, self.buf, True) diff --git a/esp8266/scripts/port_diag.py b/esp8266/scripts/port_diag.py index f2abd8066d..ef8800355a 100644 --- a/esp8266/scripts/port_diag.py +++ b/esp8266/scripts/port_diag.py @@ -24,8 +24,8 @@ def main(): print("STA ifconfig:", network.WLAN(network.STA_IF).ifconfig()) print("AP ifconfig:", network.WLAN(network.AP_IF).ifconfig()) print("Free WiFi driver buffers of type:") - for i in range(5): - print("%d: %d" % (i, esp.esf_free_bufs(i))) + for i, comm in enumerate(("1,2 TX", "4 Mngmt TX(len: 0x41-0x100)", "5 Mngmt TX (len: 0-0x40)", "7", "8 RX")): + print("%d: %d (%s)" % (i, esp.esf_free_bufs(i), comm)) print("lwIP PCBs:") lwip.print_pcbs() diff --git a/examples/hwapi/README.md b/examples/hwapi/README.md new file mode 100644 index 0000000000..1992eb6609 --- /dev/null +++ b/examples/hwapi/README.md @@ -0,0 +1,126 @@ +This directory shows the best practices for using MicroPython hardware API +(`machine` module). `machine` module strives to provide consistent API +across various boards, with the aim to enable writing portable applications, +which would work from a board to board, from a system to another systems. +This is inherently a hard problem, because hardware is different from one +board type to another, and even from examplar of board to another. For +example, if your app requires an external LED, one user may connect it +to one GPIO pin, while another user may find it much more convinient to +use another pin. This of course applies to relays, buzzers, sensors, etc. + +With complications above in mind, it's still possible to write portable +applications by using "low[est] denominator" subset of hardware API and +following simple rules outlined below. The applications won't be able +to rely on advanced hardware capabilities of a particular board and +will be limited to generic capabilities, but it's still possible to +write many useful applications in such a way, with the obvious benefit of +"write once - run everywhere" approach (only configuration for a particular +board is required). + +The key to this approach is splitting your application into (at least) +2 parts: + +* main application logic +* hardware configuration + +The key point is that hardware configuration should be a separate file +(module in Python terms). A good name would be `hwconfig.py`, and that's +how we'll call it from now on. Another key point is that main application +should never instantiate (construct) hardware objects directly. Instead, +they should be defined in `hwconfig.py`, and main application should +import and reference hardware objects via this module. The simplest +application of this idea would look like: + +`hwconfig.py`: + + from machine import Pin + + LED = Pin("A3", Pin.OUT) + +`app.py`: + + from hwconfig import * + import utime + + while True: + LED.value(1) + utime.sleep_ms(500) + LED.value(0) + utime.sleep_ms(500) + + +To deploy this application to a particular board, a user will need: + +1. Edit `hwconfig.py` to adjust Pin and other hardware peripheral + parameters and locations. +2. Actually deploy `hwconfig.py` and `app.py` to a board (e.g. copy to + board's filesystem, or build new firmware with these modules frozen + into it). + +Note that there's no need to edit the main application code! (Which may +be complex, while `hwconfig.py` should usually remain short enough, and +focused solely on hardware configuration). + +An obvious improvement to this approach is the following. There're few +well-known boards which run MicroPython, and most of them include an +onboard LED. So, to help users of these boards to do configuration +quickly (that's especially important for novice users, for who may +be stumped by the need to reach out to a board reference to find LED +pin assignments), `hwconfig.py` your application ships may include +commented out sections with working configurations for different +boards. The step 1 above then will be: + +1. Look thru `hwconfig.py` to find a section which either exactly + matches your board, or the closest to it. Uncomment, and if any + adjustments required, apply them. + +It's important to keep in mind that adjustments may be always required, +and that there may be users whose configuration doesn't match any of +the available. So, always include a section or instructions for them. +Consider for example that even on a supported board, user may want to +blink not an on-board LED, but the one they connected externally. +MicroPython's Hardware API offers portability not just among "supported" +boards, but to any board at all, so make sure users can enjoy it. + +There's next step of improvement to make. While having one `hwconfig.py` +with many sections would work for smaller projects with few hardware +objects, it may become more cumbersome to maintain both on programmer's +and user's sides for larger projects. Then instead of single +`hwconfig.py` file, you can provide few "template" ones for well-known +boards: + +* `hwconfig_pyboard.py` +* `hwconfig_wipy.py` +* `hwconfig_esp8266.py` +* etc. + +Then step 1 above will be: + +1. Look thru available `hwconfig_*.py` files and find one which matches + your board the best, then rename to `hwconfig.py` and make adjustments, + if any. + +Again, please keep in mind that there may be users whose hardware will be +completely unlike you heard of. Give them some helpful hints too, perhaps +provide `hwconfig_custom.py` with some instructions. + +That's where we stop with improvements to the "separate file for hardware +configuration" idea, as it is already pretty flexible and viable. An +application in this directory shows it in practice, using slightly less +trivial example than just a blinking LED: `soft_pwm.py` implements a +software PWM (pulse width modulation) to produce an LED fade-in/fade-out +effect - without any dependence on hardware PWM availability. + +Note that improvements to board configuration handling may continue further. +For example, one may invent a "configuration manager" helper module which will +try to detect current board (among well-known ones), and load appropriate +`hwconfig_*.py` - this assumes that a user would lazily deploy them all +(or that application will be automatically installed, e.g. using MicroPython's +`upip` package manager). The key point in this case remains the same as +elaborated above - always assume there can, and will be a custom configuration, +and it should be well supported. So, any automatic detection should be +overridable by a user, and instructions how to do so are among the most +important you may provide for your application. + +By following these best practices, you will use MicroPython at its full +potential, and let users enjoy it too. Good luck! diff --git a/examples/hwapi/hwconfig_dragonboard410c.py b/examples/hwapi/hwconfig_dragonboard410c.py new file mode 100644 index 0000000000..00f21a658f --- /dev/null +++ b/examples/hwapi/hwconfig_dragonboard410c.py @@ -0,0 +1,12 @@ +from machine import Pin + +# 96Boards/Qualcomm DragonBoard 410c +# By default, on-board LEDs are controlled by kernel LED driver. +# To make corresponding pins be available as normal GPIO, +# corresponding driver needs to be unbound first (as root): +# echo -n "soc:leds" >/sys/class/leds/apq8016-sbc:green:user1/device/driver/unbind +# Note that application also either should be run as root, or +# /sys/class/gpio ownership needs to be changed. + +# User LED 1 on gpio21 +LED = Pin(21, Pin.OUT) diff --git a/examples/hwapi/hwconfig_esp8266_esp12.py b/examples/hwapi/hwconfig_esp8266_esp12.py new file mode 100644 index 0000000000..e8cf2d12e1 --- /dev/null +++ b/examples/hwapi/hwconfig_esp8266_esp12.py @@ -0,0 +1,5 @@ +from machine import Pin + +# ESP12 module as used by many boards +# Blue LED on pin 2 +LED = Pin(2, Pin.OUT) diff --git a/examples/hwapi/hwconfig_z_frdm_k64f.py b/examples/hwapi/hwconfig_z_frdm_k64f.py new file mode 100644 index 0000000000..c45e3e7567 --- /dev/null +++ b/examples/hwapi/hwconfig_z_frdm_k64f.py @@ -0,0 +1,5 @@ +from machine import Pin + +# Freescale/NXP FRDM-K64F board +# Blue LED on port B, pin 21 +LED = Pin(("GPIO_1", 21), Pin.OUT) diff --git a/examples/hwapi/soft_pwm.py b/examples/hwapi/soft_pwm.py new file mode 100644 index 0000000000..a9a5561717 --- /dev/null +++ b/examples/hwapi/soft_pwm.py @@ -0,0 +1,38 @@ +import utime +from hwconfig import LED + + +# Using sleep_ms() gives pretty poor PWM resolution and +# brightness control, but we use it in the attempt to +# make this demo portable to even more boards (e.g. to +# those which don't provide sleep_us(), or provide, but +# it's not precise, like would be on non realtime OSes). +# We otherwise use 20ms period, to make frequency not less +# than 50Hz to avoid visible flickering (you may still see +# if you're unlucky). +def pwm_cycle(led, duty, cycles): + duty_off = 20 - duty + for i in range(cycles): + if duty: + led.value(1) + utime.sleep_ms(duty) + if duty_off: + led.value(0) + utime.sleep_ms(duty_off) + + +# At the duty setting of 1, an LED is still pretty bright, then +# at duty 0, it's off. This makes rather unsmooth transition, and +# breaks fade effect. So, we avoid value of 0 and oscillate between +# 1 and 20. Actually, highest values like 19 and 20 are also +# barely distinguishible (like, both of them too bright and burn +# your eye). So, improvement to the visible effect would be to use +# more steps (at least 10x), and then higher frequency, and use +# range which includes 1 but excludes values at the top. +while True: + # Fade in + for i in range(1, 21): + pwm_cycle(LED, i, 2) + # Fade out + for i in range(20, 0, -1): + pwm_cycle(LED, i, 2) diff --git a/examples/network/http_server_simplistic.py b/examples/network/http_server_simplistic.py index f932e48f56..67ecb1ad7a 100644 --- a/examples/network/http_server_simplistic.py +++ b/examples/network/http_server_simplistic.py @@ -1,3 +1,5 @@ +# Do not use this code in real projects! Read +# http_server_simplistic_commented.py for details. try: import usocket as socket except: diff --git a/extmod/fsusermount.h b/extmod/fsusermount.h index e1f26f2ce8..af6867d23c 100644 --- a/extmod/fsusermount.h +++ b/extmod/fsusermount.h @@ -57,6 +57,6 @@ typedef struct _fs_user_mount_t { fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs); mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in); -MP_DECLARE_CONST_FUN_OBJ(fsuser_mount_obj); -MP_DECLARE_CONST_FUN_OBJ(fsuser_umount_obj); -MP_DECLARE_CONST_FUN_OBJ(fsuser_mkfs_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(fsuser_mount_obj); +MP_DECLARE_CONST_FUN_OBJ_1(fsuser_umount_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(fsuser_mkfs_obj); diff --git a/extmod/machine_pulse.h b/extmod/machine_pulse.h index 3d5d81c073..cc1c4eda5f 100644 --- a/extmod/machine_pulse.h +++ b/extmod/machine_pulse.h @@ -32,6 +32,6 @@ mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t timeout_us); -MP_DECLARE_CONST_FUN_OBJ(machine_time_pulse_us_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj); #endif // __MICROPY_INCLUDED_EXTMOD_MACHINE_PULSE_H__ diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h index 316d06646e..62f42a8851 100644 --- a/extmod/machine_spi.h +++ b/extmod/machine_spi.h @@ -47,9 +47,9 @@ typedef struct _mp_machine_soft_spi_obj_t { void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest); -MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_read_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_readinto_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_machine_spi_write_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_machine_spi_write_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_machine_spi_write_readinto_obj); #endif // MICROPY_INCLUDED_EXTMOD_MACHINE_SPI_H diff --git a/extmod/misc.h b/extmod/misc.h index 634ea924d0..d7ead06549 100644 --- a/extmod/misc.h +++ b/extmod/misc.h @@ -30,7 +30,7 @@ #include #include "py/runtime.h" -MP_DECLARE_CONST_FUN_OBJ(mp_uos_dupterm_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_uos_dupterm_obj); #if MICROPY_PY_OS_DUPTERM void mp_uos_dupterm_tx_strn(const char *str, size_t len); diff --git a/extmod/modubinascii.h b/extmod/modubinascii.h index 71dd8a6936..33d0f1cbd8 100644 --- a/extmod/modubinascii.h +++ b/extmod/modubinascii.h @@ -33,10 +33,10 @@ extern mp_obj_t mod_binascii_a2b_base64(mp_obj_t data); extern mp_obj_t mod_binascii_b2a_base64(mp_obj_t data); extern mp_obj_t mod_binascii_crc32(size_t n_args, const mp_obj_t *args); -MP_DECLARE_CONST_FUN_OBJ(mod_binascii_hexlify_obj); -MP_DECLARE_CONST_FUN_OBJ(mod_binascii_unhexlify_obj); -MP_DECLARE_CONST_FUN_OBJ(mod_binascii_a2b_base64_obj); -MP_DECLARE_CONST_FUN_OBJ(mod_binascii_b2a_base64_obj); -MP_DECLARE_CONST_FUN_OBJ(mod_binascii_crc32_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_hexlify_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_unhexlify_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_a2b_base64_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mod_binascii_b2a_base64_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_binascii_crc32_obj); #endif /* MICROPY_EXTMOD_MODUBINASCII */ diff --git a/extmod/moduos_dupterm.c b/extmod/uos_dupterm.c similarity index 100% rename from extmod/moduos_dupterm.c rename to extmod/uos_dupterm.c diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c index 3ecdc94469..f447b3a686 100644 --- a/extmod/utime_mphal.c +++ b/extmod/utime_mphal.c @@ -33,14 +33,17 @@ #include "py/obj.h" #include "py/mphal.h" #include "py/smallint.h" +#include "py/runtime.h" #include "extmod/utime_mphal.h" STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { + MP_THREAD_GIL_EXIT(); #if MICROPY_PY_BUILTINS_FLOAT mp_hal_delay_ms(1000 * mp_obj_get_float(seconds_o)); #else mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o)); #endif + MP_THREAD_GIL_ENTER(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep); @@ -48,7 +51,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_obj, time_sleep); STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { mp_int_t ms = mp_obj_get_int(arg); if (ms > 0) { + MP_THREAD_GIL_EXIT(); mp_hal_delay_ms(ms); + MP_THREAD_GIL_ENTER(); } return mp_const_none; } @@ -57,33 +62,47 @@ MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj, time_sleep_ms); STATIC mp_obj_t time_sleep_us(mp_obj_t arg) { mp_int_t us = mp_obj_get_int(arg); if (us > 0) { + MP_THREAD_GIL_EXIT(); mp_hal_delay_us(us); + MP_THREAD_GIL_ENTER(); } return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj, time_sleep_us); STATIC mp_obj_t time_ticks_ms(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & MP_SMALL_INT_POSITIVE_MASK); + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_ms() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj, time_ticks_ms); STATIC mp_obj_t time_ticks_us(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & MP_SMALL_INT_POSITIVE_MASK); + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_us() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj, time_ticks_us); STATIC mp_obj_t time_ticks_cpu(void) { - return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & MP_SMALL_INT_POSITIVE_MASK); + return MP_OBJ_NEW_SMALL_INT(mp_hal_ticks_cpu() & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); } MP_DEFINE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj, time_ticks_cpu); -STATIC mp_obj_t time_ticks_diff(mp_obj_t start_in, mp_obj_t end_in) { +STATIC mp_obj_t time_ticks_diff(mp_obj_t end_in, mp_obj_t start_in) { // we assume that the arguments come from ticks_xx so are small ints - uint32_t start = MP_OBJ_SMALL_INT_VALUE(start_in); - uint32_t end = MP_OBJ_SMALL_INT_VALUE(end_in); - return MP_OBJ_NEW_SMALL_INT((end - start) & MP_SMALL_INT_POSITIVE_MASK); + mp_uint_t start = MP_OBJ_SMALL_INT_VALUE(start_in); + mp_uint_t end = MP_OBJ_SMALL_INT_VALUE(end_in); + // Optimized formula avoiding if conditions. We adjust difference "forward", + // wrap it around and adjust back. + mp_int_t diff = ((end - start + MICROPY_PY_UTIME_TICKS_PERIOD / 2) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)) + - MICROPY_PY_UTIME_TICKS_PERIOD / 2; + return MP_OBJ_NEW_SMALL_INT(diff); } MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj, time_ticks_diff); +STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) { + // we assume that first argument come from ticks_xx so is small int + mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in); + mp_uint_t delta = mp_obj_get_int(delta_in); + return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1)); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add); + #endif // MICROPY_PY_UTIME_MP_HAL diff --git a/extmod/utime_mphal.h b/extmod/utime_mphal.h index 4f2395a090..644387b676 100644 --- a/extmod/utime_mphal.h +++ b/extmod/utime_mphal.h @@ -27,10 +27,11 @@ #include "py/obj.h" -MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_ms_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_utime_sleep_us_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_ms_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_us_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_cpu_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_utime_ticks_diff_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_ms_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_utime_sleep_us_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_ms_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_us_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_utime_ticks_cpu_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_diff_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj); diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index ecc9ed70f9..76ac23685a 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -110,14 +110,23 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz STATIC mp_obj_t file_obj_flush(mp_obj_t self_in) { pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); - f_sync(&self->fp); + FRESULT res = f_sync(&self->fp); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_flush_obj, file_obj_flush); STATIC mp_obj_t file_obj_close(mp_obj_t self_in) { pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); - f_close(&self->fp); + // if fs==NULL then the file is closed and in that case this method is a no-op + if (self->fp.fs != NULL) { + FRESULT res = f_close(&self->fp); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + } return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close); diff --git a/extmod/vfs_fat_file.h b/extmod/vfs_fat_file.h index 6d68889550..5c271b6ee6 100644 --- a/extmod/vfs_fat_file.h +++ b/extmod/vfs_fat_file.h @@ -27,6 +27,6 @@ extern const byte fresult_to_errno_table[20]; mp_obj_t fatfs_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_open_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type); diff --git a/lib/libm/math.c b/lib/libm/math.c index 7cbec5fb32..732049236d 100644 --- a/lib/libm/math.c +++ b/lib/libm/math.c @@ -86,19 +86,6 @@ double __aeabi_dmul(double x , double y) { #endif // defined(__thumb__) -// TODO this needs a better way of testing for Thumb2 FP hardware -#if defined(__thumb2__) - -float sqrtf(float x) { - asm volatile ( - "vsqrt.f32 %[r], %[x]\n" - : [r] "=t" (x) - : [x] "t" (x)); - return x; -} - -#endif - #ifndef NDEBUG float copysignf(float x, float y) { float_s_t fx={.f = x}; diff --git a/lib/libm/thumb_vfp_sqrtf.c b/lib/libm/thumb_vfp_sqrtf.c new file mode 100644 index 0000000000..12ffebf827 --- /dev/null +++ b/lib/libm/thumb_vfp_sqrtf.c @@ -0,0 +1,11 @@ +// an implementation of sqrtf for Thumb using hardware VFP instructions + +#include + +float sqrtf(float x) { + asm volatile ( + "vsqrt.f32 %[r], %[x]\n" + : [r] "=t" (x) + : [x] "t" (x)); + return x; +} diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index d7c2570240..61cd5a98ce 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -118,7 +118,9 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, { size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); - printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + printf("qstr:\n n_pool=" UINT_FMT "\n n_qstr=" UINT_FMT "\n " + "n_str_data_bytes=" UINT_FMT "\n n_total_bytes=" UINT_FMT "\n", + (unsigned)n_pool, (unsigned)n_qstr, (unsigned)n_str_data_bytes, (unsigned)n_total_bytes); } #if MICROPY_ENABLE_GC diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index ae69a195e7..0c7567e273 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -49,6 +49,6 @@ void pyexec_event_repl_init(void); int pyexec_event_repl_process_char(int c); extern uint8_t pyexec_repl_active; -MP_DECLARE_CONST_FUN_OBJ(pyb_set_repl_info_obj); +MP_DECLARE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj); #endif // __MICROPY_INCLUDED_LIB_UTILS_PYEXEC_H__ diff --git a/lib/utils/pyhelp.c b/lib/utils/pyhelp.c index 5c0b2c57b7..30ff391c4b 100644 --- a/lib/utils/pyhelp.c +++ b/lib/utils/pyhelp.c @@ -29,11 +29,11 @@ #include "lib/utils/pyhelp.h" STATIC void pyhelp_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { - printf(" "); + mp_printf(MP_PYTHON_PRINTER, " "); mp_obj_print(name_o, PRINT_STR); - printf(" -- "); + mp_printf(MP_PYTHON_PRINTER, " -- "); mp_obj_print(value, PRINT_STR); - printf("\n"); + mp_printf(MP_PYTHON_PRINTER, "\n"); } // Helper for 1-argument form of builtin help @@ -57,9 +57,9 @@ STATIC void pyhelp_print_info_about_object(mp_obj_t name_o, mp_obj_t value) { // void pyhelp_print_obj(const mp_obj_t obj) { // try to print something sensible about the given object - printf("object "); + mp_printf(MP_PYTHON_PRINTER, "object "); mp_obj_print(obj, PRINT_STR); - printf(" is of type %s\n", mp_obj_get_type_str(obj)); + mp_printf(MP_PYTHON_PRINTER, " is of type %s\n", mp_obj_get_type_str(obj)); mp_map_t *map = NULL; if (MP_OBJ_IS_TYPE(obj, &mp_type_module)) { diff --git a/minimal/Makefile b/minimal/Makefile index 0cecd1c0fd..4117517352 100644 --- a/minimal/Makefile +++ b/minimal/Makefile @@ -68,9 +68,11 @@ $(BUILD)/firmware.elf: $(OBJ) $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) $(Q)$(SIZE) $@ -$(BUILD)/firmware.dfu: $(BUILD)/firmware.elf - $(ECHO) "Create $@" +$(BUILD)/firmware.bin: $(BUILD)/firmware.elf $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin + +$(BUILD)/firmware.dfu: $(BUILD)/firmware.bin + $(ECHO) "Create $@" $(Q)$(PYTHON) $(DFU) -b 0x08000000:$(BUILD)/firmware.bin $@ deploy: $(BUILD)/firmware.dfu diff --git a/minimal/mpconfigport.h b/minimal/mpconfigport.h index fc696c77e5..5236babf68 100644 --- a/minimal/mpconfigport.h +++ b/minimal/mpconfigport.h @@ -70,7 +70,6 @@ typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) // extra built in names to add to the global namespace -extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj; #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, diff --git a/pic16bit/mpconfigport.h b/pic16bit/mpconfigport.h index 24cfe43529..a0371a8ae3 100644 --- a/pic16bit/mpconfigport.h +++ b/pic16bit/mpconfigport.h @@ -88,7 +88,6 @@ typedef int mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) // extra builtin names to add to the global namespace -extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj; #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, diff --git a/py/builtin.h b/py/builtin.h index cd1be3ab88..4477fd2462 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -32,56 +32,56 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args); mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs); mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin___build_class___obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin___import___obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin___repl_print___obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_abs_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_all_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_any_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_bin_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_callable_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_compile_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_chr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_dir_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_divmod_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_eval_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_exec_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_execfile_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_getattr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_setattr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_globals_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hasattr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hash_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_hex_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_id_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_isinstance_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_issubclass_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_iter_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_len_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_list_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_locals_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_max_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_min_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_next_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_oct_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_ord_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_pow_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_print_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_repr_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_round_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sorted_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_sum_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin___import___obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin___repl_print___obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_abs_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_all_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_any_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_bin_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_callable_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_chr_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_eval_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_execfile_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_getattr_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_globals_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_hasattr_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hash_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_hex_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_id_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_iter_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_len_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_builtin_locals_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_max_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_min_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_next_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_oct_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_ord_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_pow_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_print_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_builtin_repr_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_round_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_sum_obj); // Defined by a port, but declared here for simplicity -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_help_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_input_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_builtin_open_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_help_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_input_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_namedtuple_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_namedtuple_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_contains_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_getitem_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_setitem_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_op_delitem_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_contains_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_getitem_obj); +MP_DECLARE_CONST_FUN_OBJ_3(mp_op_setitem_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj); extern const mp_obj_module_t mp_module___main__; extern const mp_obj_module_t mp_module_builtins; @@ -116,7 +116,4 @@ extern const mp_obj_module_t mp_module_webrepl; extern const mp_obj_module_t mp_module_framebuf; extern const mp_obj_module_t mp_module_btree; -// extmod functions -MP_DECLARE_CONST_FUN_OBJ(pyb_mount_obj); - #endif // __MICROPY_INCLUDED_PY_BUILTIN_H__ diff --git a/py/emitbc.c b/py/emitbc.c index d6f2bf333c..e11c9ae94f 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -183,7 +183,6 @@ STATIC void emit_write_bytecode_byte(emit_t *emit, byte b1) { } STATIC void emit_write_bytecode_byte_byte(emit_t* emit, byte b1, byte b2) { - assert((b2 & (~0xff)) == 0); byte *c = emit_get_cur_to_write_bytecode(emit, 2); c[0] = b1; c[1] = b2; @@ -550,7 +549,6 @@ void mp_emit_bc_load_null(emit_t *emit) { void mp_emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; - assert(local_num >= 0); emit_bc_pre(emit, 1); if (local_num <= 15) { emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num); @@ -608,7 +606,6 @@ void mp_emit_bc_load_subscr(emit_t *emit) { void mp_emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) { (void)qst; - assert(local_num >= 0); emit_bc_pre(emit, -1); if (local_num <= 15) { emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num); @@ -927,7 +924,7 @@ void mp_emit_bc_return_value(emit_t *emit) { } void mp_emit_bc_raise_varargs(emit_t *emit, mp_uint_t n_args) { - assert(0 <= n_args && n_args <= 2); + assert(n_args <= 2); emit_bc_pre(emit, -n_args); emit_write_bytecode_byte_byte(emit, MP_BC_RAISE_VARARGS, n_args); } diff --git a/py/mkenv.mk b/py/mkenv.mk index e7262907c8..14e23e074c 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -59,6 +59,8 @@ LD += -m32 endif MAKE_FROZEN = ../tools/make-frozen.py +MPY_CROSS = ../mpy-cross/mpy-cross +MPY_TOOL = ../tools/mpy-tool.py all: .PHONY: all diff --git a/py/mkrules.mk b/py/mkrules.mk index 26e4aeab3f..ea647e86f8 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -106,6 +106,23 @@ $(BUILD)/frozen.c: $(wildcard $(FROZEN_DIR)/*) $(HEADER_BUILD) $(FROZEN_EXTRA_DE $(Q)$(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif +ifneq ($(FROZEN_MPY_DIR),) +# make a list of all the .py files that need compiling and freezing +FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py' -printf '%P\n') +FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/frozen_mpy/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) + +# to build .mpy files from .py files +$(BUILD)/frozen_mpy/%.mpy: $(FROZEN_MPY_DIR)/%.py + @$(ECHO) "MPY $<" + $(Q)$(MKDIR) -p $(dir $@) + $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ + +# to build frozen_mpy.c from all .mpy files +$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h + @$(ECHO) "Creating $@" + $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ +endif + ifneq ($(PROG),) # Build a standalone executable (unix does this) diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 57e52efa52..cbdcc9aae0 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -430,13 +430,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_print_obj, 0, mp_builtin_print); STATIC mp_obj_t mp_builtin___repl_print__(mp_obj_t o) { if (o != mp_const_none) { - #if MICROPY_PY_IO - mp_obj_print_helper(&mp_sys_stdout_print, o, PRINT_REPR); - mp_print_str(&mp_sys_stdout_print, "\n"); - #else - mp_obj_print_helper(&mp_plat_print, o, PRINT_REPR); - mp_print_str(&mp_plat_print, "\n"); - #endif + mp_obj_print_helper(MP_PYTHON_PRINTER, o, PRINT_REPR); + mp_print_str(MP_PYTHON_PRINTER, "\n"); #if MICROPY_CAN_OVERRIDE_BUILTINS // Set "_" special variable mp_obj_t dest[2] = {MP_OBJ_SENTINEL, o}; @@ -547,6 +542,13 @@ STATIC mp_obj_t mp_builtin_setattr(mp_obj_t base, mp_obj_t attr, mp_obj_t value) } MP_DEFINE_CONST_FUN_OBJ_3(mp_builtin_setattr_obj, mp_builtin_setattr); +#if MICROPY_CPYTHON_COMPAT +STATIC mp_obj_t mp_builtin_delattr(mp_obj_t base, mp_obj_t attr) { + return mp_builtin_setattr(base, attr, MP_OBJ_NULL); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_delattr_obj, mp_builtin_delattr); +#endif + STATIC mp_obj_t mp_builtin_hasattr(mp_obj_t object_in, mp_obj_t attr_in) { qstr attr = mp_obj_str_get_qstr(attr_in); @@ -622,6 +624,9 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { #if MICROPY_PY_BUILTINS_SET { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mp_type_set) }, #endif + #if MICROPY_PY_BUILTINS_SLICE + { MP_ROM_QSTR(MP_QSTR_slice), MP_ROM_PTR(&mp_type_slice) }, + #endif { MP_ROM_QSTR(MP_QSTR_str), MP_ROM_PTR(&mp_type_str) }, { MP_ROM_QSTR(MP_QSTR_super), MP_ROM_PTR(&mp_type_super) }, { MP_ROM_QSTR(MP_QSTR_tuple), MP_ROM_PTR(&mp_type_tuple) }, @@ -647,6 +652,9 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mp_builtin_compile_obj) }, #endif { MP_ROM_QSTR(MP_QSTR_chr), MP_ROM_PTR(&mp_builtin_chr_obj) }, + #if MICROPY_CPYTHON_COMPAT + { MP_ROM_QSTR(MP_QSTR_delattr), MP_ROM_PTR(&mp_builtin_delattr_obj) }, + #endif { MP_ROM_QSTR(MP_QSTR_dir), MP_ROM_PTR(&mp_builtin_dir_obj) }, { MP_ROM_QSTR(MP_QSTR_divmod), MP_ROM_PTR(&mp_builtin_divmod_obj) }, #if MICROPY_PY_BUILTINS_EVAL_EXEC diff --git a/py/modmath.c b/py/modmath.c index 0c70f34cd1..7c51eab03a 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -32,9 +32,8 @@ #include // M_PI is not part of the math.h standard and may not be defined -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif +// And by defining our own we can ensure it uses the correct const format. +#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) /// \module math - mathematical functions /// @@ -204,13 +203,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf); /// \function radians(x) STATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) { - return mp_obj_new_float(mp_obj_get_float(x_obj) * M_PI / 180.0); + return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0))); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians); /// \function degrees(x) STATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) { - return mp_obj_new_float(mp_obj_get_float(x_obj) * 180.0 / M_PI); + return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees); diff --git a/py/mpconfig.h b/py/mpconfig.h index dcdaffe0f4..3945a1a5ab 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -110,10 +110,11 @@ // Be conservative and always clear to zero newly (re)allocated memory in the GC. // This helps eliminate stray pointers that hold on to memory that's no longer // used. It decreases performance due to unnecessary memory clearing. +// A memory manager which always clears memory can set this to 0. // TODO Do analysis to understand why some memory is not properly cleared and // find a more efficient way to clear it. #ifndef MICROPY_GC_CONSERVATIVE_CLEAR -#define MICROPY_GC_CONSERVATIVE_CLEAR (1) +#define MICROPY_GC_CONSERVATIVE_CLEAR (MICROPY_ENABLE_GC) #endif // Support automatic GC when reaching allocation threshold, @@ -504,10 +505,12 @@ typedef long long mp_longint_impl_t; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #define MICROPY_PY_BUILTINS_FLOAT (1) +#define MICROPY_FLOAT_CONST(x) x##F #define MICROPY_FLOAT_C_FUN(fun) fun##f typedef float mp_float_t; #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #define MICROPY_PY_BUILTINS_FLOAT (1) +#define MICROPY_FLOAT_CONST(x) x #define MICROPY_FLOAT_C_FUN(fun) fun typedef double mp_float_t; #else @@ -866,6 +869,16 @@ typedef double mp_float_t; #define MICROPY_PY_UTIME_MP_HAL (0) #endif +// Period of values returned by utime.ticks_ms(), ticks_us(), ticks_cpu() +// functions. Should be power of two. All functions above use the same +// period, so if underlying hardware/API has different periods, the +// minimum of them should be used. The value below is the maximum value +// this parameter can take (corresponding to 30 bit tick values on 32-bit +// system). +#ifndef MICROPY_PY_UTIME_TICKS_PERIOD +#define MICROPY_PY_UTIME_TICKS_PERIOD (MP_SMALL_INT_POSITIVE_MASK + 1) +#endif + // Whether to provide "_thread" module #ifndef MICROPY_PY_THREAD #define MICROPY_PY_THREAD (0) diff --git a/py/mpprint.h b/py/mpprint.h index 6e47409ecc..f9204e322d 100644 --- a/py/mpprint.h +++ b/py/mpprint.h @@ -39,6 +39,12 @@ #define PF_FLAG_ADD_PERCENT (0x100) #define PF_FLAG_SHOW_OCTAL_LETTER (0x200) +#if MICROPY_PY_IO +# define MP_PYTHON_PRINTER &mp_sys_stdout_print +#else +# define MP_PYTHON_PRINTER &mp_plat_print +#endif + typedef void (*mp_print_strn_t)(void *data, const char *str, size_t len); typedef struct _mp_print_t { diff --git a/py/mpz.c b/py/mpz.c index cceb079cd3..1dd177b8e7 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1652,7 +1652,10 @@ char *mpz_as_str(const mpz_t *i, mp_uint_t base) { // assumes enough space as calculated by mp_int_format_size // returns length of string, not including null byte mp_uint_t mpz_as_str_inpl(const mpz_t *i, mp_uint_t base, const char *prefix, char base_char, char comma, char *str) { - if (str == NULL || base < 2 || base > 32) { + if (str == NULL) { + return 0; + } + if (base < 2 || base > 32) { str[0] = 0; return 0; } diff --git a/py/nlrx86.S b/py/nlrx86.S index 8a96af81ce..8c538ba176 100644 --- a/py/nlrx86.S +++ b/py/nlrx86.S @@ -37,9 +37,18 @@ #if defined(_WIN32) || defined(__CYGWIN__) #define NLR_OS_WINDOWS +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#define NLR_OS_MAC +#endif + +#if defined(NLR_OS_WINDOWS) || defined(NLR_OS_MAC) #define NLR_TOP (_mp_state_ctx + NLR_TOP_OFFSET) +#define MP_THREAD_GET_STATE _mp_thread_get_state #else #define NLR_TOP (mp_state_ctx + NLR_TOP_OFFSET) +#define MP_THREAD_GET_STATE mp_thread_get_state #endif // offset of nlr_top within mp_state_thread_t structure @@ -55,6 +64,9 @@ .globl _nlr_push .def _nlr_push; .scl 2; .type 32; .endef _nlr_push: +#elif defined(NLR_OS_MAC) + .globl _nlr_push +_nlr_push: #else .globl nlr_push .type nlr_push, @function @@ -75,7 +87,7 @@ nlr_push: mov %edx, NLR_TOP # stor new nlr_buf (to make linked list) #else // to check: stack is aligned to 16-byte boundary before this call - call mp_thread_get_state # get mp_state_thread ptr into eax + call MP_THREAD_GET_STATE # get mp_state_thread ptr into eax mov 4(%esp), %edx # load nlr_buf argument into edx (edx clobbered by call) mov NLR_TOP_TH_OFF(%eax), %ecx # get thread.nlr_top (last nlr_buf) mov %ecx, (%edx) # store it @@ -84,7 +96,7 @@ nlr_push: xor %eax, %eax # return 0, normal return ret # return -#if !defined(NLR_OS_WINDOWS) +#if !defined(NLR_OS_WINDOWS) && !defined(NLR_OS_MAC) .size nlr_push, .-nlr_push #endif @@ -95,6 +107,9 @@ nlr_push: .globl _nlr_pop .def _nlr_pop; .scl 2; .type 32; .endef _nlr_pop: +#elif defined(NLR_OS_MAC) + .globl _nlr_pop +_nlr_pop: #else .globl nlr_pop .type nlr_pop, @function @@ -106,14 +121,14 @@ nlr_pop: mov (%eax), %eax # load prev nlr_buf mov %eax, NLR_TOP # store nlr_top (to unlink list) #else - call mp_thread_get_state # get mp_state_thread ptr into eax + call MP_THREAD_GET_STATE # get mp_state_thread ptr into eax mov NLR_TOP_TH_OFF(%eax), %ecx # get thread.nlr_top (last nlr_buf) mov (%ecx), %ecx # load prev nlr_buf mov %ecx, NLR_TOP_TH_OFF(%eax) # store prev nlr_buf (to unlink list) #endif ret # return -#if !defined(NLR_OS_WINDOWS) +#if !defined(NLR_OS_WINDOWS) && !defined(NLR_OS_MAC) .size nlr_pop, .-nlr_pop #endif @@ -124,6 +139,9 @@ nlr_pop: .globl _nlr_jump .def _nlr_jump; .scl 2; .type 32; .endef _nlr_jump: +#elif defined(NLR_OS_MAC) + .globl _nlr_jump +_nlr_jump: #else .globl nlr_jump .type nlr_jump, @function @@ -133,7 +151,7 @@ nlr_jump: #if !MICROPY_PY_THREAD mov NLR_TOP, %edx # load nlr_top test %edx, %edx # check for nlr_top being NULL -#if defined(NLR_OS_WINDOWS) +#if defined(NLR_OS_WINDOWS) || defined(NLR_OS_MAC) je _nlr_jump_fail # fail if nlr_top is NULL #else je nlr_jump_fail # fail if nlr_top is NULL @@ -143,10 +161,10 @@ nlr_jump: mov (%edx), %eax # load prev nlr_top mov %eax, NLR_TOP # store nlr_top (to unlink list) #else - call mp_thread_get_state # get mp_state_thread ptr into eax + call MP_THREAD_GET_STATE # get mp_state_thread ptr into eax mov NLR_TOP_TH_OFF(%eax), %edx # get thread.nlr_top (last nlr_buf) test %edx, %edx # check for nlr_top being NULL -#if defined(NLR_OS_WINDOWS) +#if defined(NLR_OS_WINDOWS) || defined(NLR_OS_MAC) je _nlr_jump_fail # fail if nlr_top is NULL #else je nlr_jump_fail # fail if nlr_top is NULL @@ -167,7 +185,7 @@ nlr_jump: xor %eax, %eax # clear return register inc %al # increase to make 1, non-local return ret # return -#if !defined(NLR_OS_WINDOWS) +#if !defined(NLR_OS_WINDOWS) && !defined(NLR_OS_MAC) .size nlr_jump, .-nlr_jump #endif diff --git a/py/obj.c b/py/obj.c index 72b7a216bc..5601a73fe7 100644 --- a/py/obj.c +++ b/py/obj.c @@ -76,11 +76,7 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t } void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) { -#if MICROPY_PY_IO - mp_obj_print_helper(&mp_sys_stdout_print, o_in, kind); -#else - mp_obj_print_helper(&mp_plat_print, o_in, kind); -#endif + mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind); } // helper function to print an exception with traceback diff --git a/py/obj.h b/py/obj.h index 72d79ce14b..61db65a9a2 100644 --- a/py/obj.h +++ b/py/obj.h @@ -270,29 +270,35 @@ static inline bool mp_obj_is_integer(mp_const_obj_t o) { return MP_OBJ_IS_INT(o) // These macros are used to declare and define constant function objects // You can put "static" in front of the definitions to make them local -#define MP_DECLARE_CONST_FUN_OBJ(obj_name) extern const mp_obj_fun_builtin_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_0(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_1(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_2(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_3(obj_name) extern const mp_obj_fun_builtin_fixed_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR(obj_name) extern const mp_obj_fun_builtin_var_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name) extern const mp_obj_fun_builtin_var_t obj_name +#define MP_DECLARE_CONST_FUN_OBJ_KW(obj_name) extern const mp_obj_fun_builtin_var_t obj_name #define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 0, 0, .fun._0 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_0}, .fun._0 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 1, 1, .fun._1 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_1}, .fun._1 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 2, 2, .fun._2 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_2}, .fun._2 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, 3, 3, .fun._3 = fun_name} + const mp_obj_fun_builtin_fixed_t obj_name = \ + {{&mp_type_fun_builtin_3}, .fun._3 = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.var = fun_name} + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, false, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.var = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, false, n_args_min, n_args_max, .fun.var = fun_name} + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, false, n_args_min, n_args_max, .fun.var = fun_name} #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \ - const mp_obj_fun_builtin_t obj_name = \ - {{&mp_type_fun_builtin}, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.kw = fun_name} + const mp_obj_fun_builtin_var_t obj_name = \ + {{&mp_type_fun_builtin_var}, true, n_args_min, MP_OBJ_FUN_ARGS_MAX, .fun.kw = fun_name} // These macros are used to define constant map/dict objects // You can put "static" in front of the definition to make it local @@ -530,7 +536,11 @@ extern const mp_obj_type_t mp_type_zip; extern const mp_obj_type_t mp_type_array; extern const mp_obj_type_t mp_type_super; extern const mp_obj_type_t mp_type_gen_instance; -extern const mp_obj_type_t mp_type_fun_builtin; +extern const mp_obj_type_t mp_type_fun_builtin_0; +extern const mp_obj_type_t mp_type_fun_builtin_1; +extern const mp_obj_type_t mp_type_fun_builtin_2; +extern const mp_obj_type_t mp_type_fun_builtin_3; +extern const mp_obj_type_t mp_type_fun_builtin_var; extern const mp_obj_type_t mp_type_fun_bc; extern const mp_obj_type_t mp_type_module; extern const mp_obj_type_t mp_type_staticmethod; @@ -740,27 +750,34 @@ void mp_obj_set_store(mp_obj_t self_in, mp_obj_t item); void mp_obj_slice_get(mp_obj_t self_in, mp_obj_t *start, mp_obj_t *stop, mp_obj_t *step); // functions -#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below -typedef struct _mp_obj_fun_builtin_t { // use this to make const objects that go in ROM + +typedef struct _mp_obj_fun_builtin_fixed_t { mp_obj_base_t base; - bool is_kw : 1; - mp_uint_t n_args_min : 15; // inclusive - mp_uint_t n_args_max : 16; // inclusive union { mp_fun_0_t _0; mp_fun_1_t _1; mp_fun_2_t _2; mp_fun_3_t _3; + } fun; +} mp_obj_fun_builtin_fixed_t; + +#define MP_OBJ_FUN_ARGS_MAX (0xffff) // to set maximum value in n_args_max below +typedef struct _mp_obj_fun_builtin_var_t { + mp_obj_base_t base; + bool is_kw : 1; + mp_uint_t n_args_min : 15; // inclusive + mp_uint_t n_args_max : 16; // inclusive + union { mp_fun_var_t var; mp_fun_kw_t kw; } fun; -} mp_obj_fun_builtin_t; +} mp_obj_fun_builtin_var_t; qstr mp_obj_fun_get_name(mp_const_obj_t fun); qstr 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); +MP_DECLARE_CONST_FUN_OBJ_1(mp_identity_obj); // module typedef struct _mp_obj_module_t { diff --git a/py/objfun.c b/py/objfun.c index 405f38127a..6b8fe6d382 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -50,11 +50,66 @@ /******************************************************************************/ /* builtin functions */ -// mp_obj_fun_builtin_t defined in obj.h +STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void)args; + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_0)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return self->fun._0(); +} -STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin)); - mp_obj_fun_builtin_t *self = MP_OBJ_TO_PTR(self_in); +const mp_obj_type_t mp_type_fun_builtin_0 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_0_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_1)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 1, 1, false); + return self->fun._1(args[0]); +} + +const mp_obj_type_t mp_type_fun_builtin_1 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_1_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_2)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 2, 2, false); + return self->fun._2(args[0], args[1]); +} + +const mp_obj_type_t mp_type_fun_builtin_2 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_2_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_3)); + mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in); + mp_arg_check_num(n_args, n_kw, 3, 3, false); + return self->fun._3(args[0], args[1], args[2]); +} + +const mp_obj_type_t mp_type_fun_builtin_3 = { + { &mp_type_type }, + .name = MP_QSTR_function, + .call = fun_builtin_3_call, + .unary_op = mp_generic_unary_op, +}; + +STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_fun_builtin_var)); + mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in); // check number of arguments mp_arg_check_num(n_args, n_kw, self->n_args_min, self->n_args_max, self->is_kw); @@ -68,25 +123,6 @@ STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c return self->fun.kw(n_args, args, &kw_args); - } else if (self->n_args_min <= 3 && self->n_args_min == self->n_args_max) { - // function requires a fixed number of arguments - - // dispatch function call - switch (self->n_args_min) { - case 0: - return self->fun._0(); - - case 1: - return self->fun._1(args[0]); - - case 2: - return self->fun._2(args[0], args[1]); - - case 3: - default: - return self->fun._3(args[0], args[1], args[2]); - } - } else { // function takes a variable number of arguments, but no keywords @@ -94,10 +130,10 @@ STATIC mp_obj_t fun_builtin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, c } } -const mp_obj_type_t mp_type_fun_builtin = { +const mp_obj_type_t mp_type_fun_builtin_var = { { &mp_type_type }, .name = MP_QSTR_function, - .call = fun_builtin_call, + .call = fun_builtin_var_call, .unary_op = mp_generic_unary_op, }; diff --git a/py/objstr.h b/py/objstr.h index e14568dac4..ad2777afbc 100644 --- a/py/objstr.h +++ b/py/objstr.h @@ -74,32 +74,32 @@ const byte *str_index_to_ptr(const mp_obj_type_t *type, const byte *self_data, s mp_obj_t index, bool is_slice); const byte *find_subbytes(const byte *haystack, mp_uint_t hlen, const byte *needle, mp_uint_t nlen, mp_int_t direction); -MP_DECLARE_CONST_FUN_OBJ(str_encode_obj); -MP_DECLARE_CONST_FUN_OBJ(str_find_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rfind_obj); -MP_DECLARE_CONST_FUN_OBJ(str_index_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rindex_obj); -MP_DECLARE_CONST_FUN_OBJ(str_join_obj); -MP_DECLARE_CONST_FUN_OBJ(str_split_obj); -MP_DECLARE_CONST_FUN_OBJ(str_splitlines_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rsplit_obj); -MP_DECLARE_CONST_FUN_OBJ(str_startswith_obj); -MP_DECLARE_CONST_FUN_OBJ(str_endswith_obj); -MP_DECLARE_CONST_FUN_OBJ(str_strip_obj); -MP_DECLARE_CONST_FUN_OBJ(str_lstrip_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rstrip_obj); -MP_DECLARE_CONST_FUN_OBJ(str_format_obj); -MP_DECLARE_CONST_FUN_OBJ(str_replace_obj); -MP_DECLARE_CONST_FUN_OBJ(str_count_obj); -MP_DECLARE_CONST_FUN_OBJ(str_partition_obj); -MP_DECLARE_CONST_FUN_OBJ(str_rpartition_obj); -MP_DECLARE_CONST_FUN_OBJ(str_center_obj); -MP_DECLARE_CONST_FUN_OBJ(str_lower_obj); -MP_DECLARE_CONST_FUN_OBJ(str_upper_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isspace_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isalpha_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isdigit_obj); -MP_DECLARE_CONST_FUN_OBJ(str_isupper_obj); -MP_DECLARE_CONST_FUN_OBJ(str_islower_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_encode_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_find_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rfind_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_index_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_join_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_split_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(str_splitlines_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rsplit_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_lstrip_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_rstrip_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(str_format_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_partition_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_rpartition_obj); +MP_DECLARE_CONST_FUN_OBJ_2(str_center_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_lower_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_upper_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isspace_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isalpha_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isdigit_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_isupper_obj); +MP_DECLARE_CONST_FUN_OBJ_1(str_islower_obj); #endif // __MICROPY_INCLUDED_PY_OBJSTR_H__ diff --git a/py/parse.c b/py/parse.c index 5920828fe9..397d46d9f0 100644 --- a/py/parse.c +++ b/py/parse.c @@ -1010,9 +1010,10 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { // truncate final chunk and link into chain of chunks if (parser.cur_chunk != NULL) { - (void)m_renew(byte, parser.cur_chunk, + (void)m_renew_maybe(byte, parser.cur_chunk, sizeof(mp_parse_chunk_t) + parser.cur_chunk->alloc, - sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used); + sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used, + false); parser.cur_chunk->alloc = parser.cur_chunk->union_.used; parser.cur_chunk->union_.next = parser.tree.chunk; parser.tree.chunk = parser.cur_chunk; diff --git a/py/parsenum.c b/py/parsenum.c index 1010ad3055..b1c449c9b8 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -227,7 +227,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool } else { if (in == PARSE_DEC_IN_FRAC) { dec_val += dig * frac_mult; - frac_mult *= 0.1; + frac_mult *= MICROPY_FLOAT_CONST(0.1); } else { dec_val = 10 * dec_val + dig; } diff --git a/py/py.mk b/py/py.mk index ec476af0ef..8cdccb9b4b 100644 --- a/py/py.mk +++ b/py/py.mk @@ -230,13 +230,23 @@ PY_O_BASENAME = \ ../extmod/vfs_fat_lexer.o \ ../extmod/vfs_fat_misc.o \ ../extmod/utime_mphal.o \ - ../extmod/moduos_dupterm.o \ + ../extmod/uos_dupterm.o \ ../lib/embed/abort_.o \ ../lib/utils/printf.o \ # prepend the build destination prefix to the py object files PY_O = $(addprefix $(PY_BUILD)/, $(PY_O_BASENAME)) +# object file for frozen files +ifneq ($(FROZEN_DIR),) +PY_O += $(BUILD)/$(BUILD)/frozen.o +endif + +# object file for frozen bytecode (frozen .mpy files) +ifneq ($(FROZEN_MPY_DIR),) +PY_O += $(BUILD)/$(BUILD)/frozen_mpy.o +endif + # Sources that may contain qstrings SRC_QSTR_IGNORE = nlr% emitnx% emitnthumb% emitnarm% SRC_QSTR = $(SRC_MOD) $(addprefix py/,$(filter-out $(SRC_QSTR_IGNORE),$(PY_O_BASENAME:.o=.c)) emitnative.c) diff --git a/py/qstr.c b/py/qstr.c index 28df06ca3d..5aa1610648 100644 --- a/py/qstr.c +++ b/py/qstr.c @@ -199,7 +199,7 @@ qstr qstr_from_strn(const char *str, size_t len) { byte *new_p = m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_alloc) + n_bytes, false); if (new_p == NULL) { // could not grow existing memory; shrink it to fit previous - (void)m_renew(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_used)); + (void)m_renew_maybe(byte, MP_STATE_VM(qstr_last_chunk), MP_STATE_VM(qstr_last_alloc), MP_STATE_VM(qstr_last_used), false); MP_STATE_VM(qstr_last_chunk) = NULL; } else { // could grow existing memory diff --git a/py/runtime.c b/py/runtime.c index 6eda77ee9c..c255574643 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -972,7 +972,13 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t || ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type->name == MP_QSTR_generator))) { // only functions, closures and generators objects can be bound to self #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG - if (self == MP_OBJ_NULL && mp_obj_get_type(member) == &mp_type_fun_builtin) { + const mp_obj_type_t *m_type = ((mp_obj_base_t*)MP_OBJ_TO_PTR(member))->type; + if (self == MP_OBJ_NULL + && (m_type == &mp_type_fun_builtin_0 + || m_type == &mp_type_fun_builtin_1 + || m_type == &mp_type_fun_builtin_2 + || m_type == &mp_type_fun_builtin_3 + || m_type == &mp_type_fun_builtin_var)) { // we extracted a builtin method without a first argument, so we must // wrap this function in a type checker dest[0] = mp_obj_new_checked_fun(type, member); diff --git a/py/sequence.c b/py/sequence.c index 0acdd25be0..bc2cfc077c 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -53,15 +53,35 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice mp_int_t start, stop; mp_obj_slice_get(slice, &ostart, &ostop, &ostep); + if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { + indexes->step = mp_obj_get_int(ostep); + if (indexes->step == 0) { + mp_raise_ValueError("slice step cannot be zero"); + } + } else { + indexes->step = 1; + } + if (ostart == mp_const_none) { - start = 0; + if (indexes->step > 0) { + start = 0; + } else { + start = len - 1; + } } else { start = mp_obj_get_int(ostart); } if (ostop == mp_const_none) { - stop = len; + if (indexes->step > 0) { + stop = len; + } else { + stop = 0; + } } else { stop = mp_obj_get_int(ostop); + if (stop >= 0 && indexes->step < 0) { + stop += 1; + } } // Unlike subscription, out-of-bounds slice indexes are never error @@ -70,29 +90,31 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice if (start < 0) { start = 0; } - } else if ((mp_uint_t)start > len) { + } else if (indexes->step > 0 && (mp_uint_t)start > len) { start = len; + } else if (indexes->step < 0 && (mp_uint_t)start > len - 1) { + start = len - 1; } if (stop < 0) { stop = len + stop; + if (indexes->step < 0) { + stop += 1; + } } else if ((mp_uint_t)stop > len) { stop = len; } // CPython returns empty sequence in such case, or point for assignment is at start - if (start > stop) { + if (indexes->step > 0 && start > stop) { stop = start; + } else if (indexes->step < 0 && start < stop) { + stop = start + 1; } indexes->start = start; indexes->stop = stop; - if (ostep != mp_const_none && ostep != MP_OBJ_NEW_SMALL_INT(1)) { - indexes->step = mp_obj_get_int(ostep); - return false; - } - indexes->step = 1; - return true; + return indexes->step == 1; } #endif @@ -106,10 +128,9 @@ mp_obj_t mp_seq_extract_slice(mp_uint_t len, const mp_obj_t *seq, mp_bound_slice mp_obj_t res = mp_obj_new_list(0, NULL); if (step < 0) { - stop--; - while (start <= stop) { - mp_obj_list_append(res, seq[stop]); - stop += step; + while (start >= stop) { + mp_obj_list_append(res, seq[start]); + start += step; } } else { while (start < stop) { diff --git a/py/stream.c b/py/stream.c index cc8a63ac2e..dadfcf5d62 100644 --- a/py/stream.c +++ b/py/stream.c @@ -391,7 +391,7 @@ STATIC mp_obj_t stream_unbuffered_readline(size_t n_args, const mp_obj_t *args) if (mp_is_nonblocking_error(error)) { if (vstr.len == 1) { // We just incremented it, but otherwise we read nothing - // and immediately got EAGAIN. This is case is not well + // and immediately got EAGAIN. This case is not well // specified in // https://docs.python.org/3/library/io.html#io.IOBase.readline // unlike similar case for read(). But we follow the latter's diff --git a/py/stream.h b/py/stream.h index 33d85e823c..4cdea11eba 100644 --- a/py/stream.h +++ b/py/stream.h @@ -48,18 +48,18 @@ struct mp_stream_seek_t { int whence; }; -MP_DECLARE_CONST_FUN_OBJ(mp_stream_read_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_read1_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_readinto_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); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_write1_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_seek_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_tell_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_flush_obj); -MP_DECLARE_CONST_FUN_OBJ(mp_stream_ioctl_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_readall_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_tell_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_flush_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_ioctl_obj); // these are for mp_get_stream_raise and can be or'd together #define MP_STREAM_OP_READ (1) diff --git a/py/warning.c b/py/warning.c index eae145bd3f..4cdf3b3f10 100644 --- a/py/warning.c +++ b/py/warning.c @@ -38,6 +38,7 @@ void mp_warning(const char *msg, ...) { mp_print_str(&mp_plat_print, "Warning: "); mp_vprintf(&mp_plat_print, msg, args); mp_print_str(&mp_plat_print, "\n"); + va_end(args); } void mp_emitter_warning(pass_kind_t pass, const char *msg) { diff --git a/qemu-arm/Makefile b/qemu-arm/Makefile index 9159f97e54..0af2fc901c 100644 --- a/qemu-arm/Makefile +++ b/qemu-arm/Makefile @@ -14,9 +14,9 @@ INC += -I.. INC += -I$(BUILD) INC += -I../tools/tinytest/ -CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 +CFLAGS_CORTEX_M3 = -mthumb -mcpu=cortex-m3 -mfloat-abi=soft CFLAGS = $(INC) -Wall -Wpointer-arith -Werror -ansi -std=gnu99 $(CFLAGS_CORTEX_M3) $(COPT) \ - -flto -ffunction-sections -fdata-sections + -ffunction-sections -fdata-sections #Debugging/Optimization ifeq ($(DEBUG), 1) @@ -40,6 +40,27 @@ SRC_C = \ SRC_TEST_C = \ test_main.c \ +LIB_SRC_C = $(addprefix lib/,\ + libm/math.c \ + libm/fmodf.c \ + libm/roundf.c \ + libm/ef_sqrt.c \ + libm/kf_rem_pio2.c \ + libm/kf_sin.c \ + libm/kf_cos.c \ + libm/kf_tan.c \ + libm/ef_rem_pio2.c \ + libm/sf_sin.c \ + libm/sf_cos.c \ + libm/sf_tan.c \ + libm/sf_frexp.c \ + libm/sf_modf.c \ + libm/sf_ldexp.c \ + libm/asinfacosf.c \ + libm/atanf.c \ + libm/atan2f.c \ + ) + STM_SRC_C = $(addprefix stmhal/,\ pybstdio.c \ ) @@ -50,12 +71,14 @@ OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ_TEST = OBJ_TEST += $(PY_O) OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_TEST_C:.c=.o)) OBJ_TEST += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) +OBJ_TEST += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) OBJ_TEST += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o)) OBJ_TEST += $(BUILD)/tinytest.o diff --git a/qemu-arm/mpconfigport.h b/qemu-arm/mpconfigport.h index b8806405bc..8ee9cdc4bb 100644 --- a/qemu-arm/mpconfigport.h +++ b/qemu-arm/mpconfigport.h @@ -14,7 +14,7 @@ #define MICROPY_HELPER_LEXER_UNIX (0) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) -#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_CAN_OVERRIDE_BUILTINS (1) #define MICROPY_PY_ALL_SPECIAL_METHODS (1) #define MICROPY_PY_ARRAY_SLICE_ASSIGN (1) @@ -53,7 +53,6 @@ typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) write(1, str, len) // extra built in names to add to the global namespace -extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj; #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, diff --git a/stmhal/Makefile b/stmhal/Makefile index 06be7acc89..59199ea0a1 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -81,6 +81,7 @@ endif SRC_LIB = $(addprefix lib/,\ libc/string0.c \ libm/math.c \ + libm/thumb_vfp_sqrtf.c \ libm/asinfacosf.c \ libm/atanf.c \ libm/atan2f.c \ @@ -274,36 +275,16 @@ $(PY_BUILD)/mpprint.o: COPT += -Os all: $(BUILD)/firmware.dfu $(BUILD)/firmware.hex ifneq ($(FROZEN_DIR),) +# To use frozen source modules, put your .py files in a subdirectory (eg scripts/) +# and then invoke make with FROZEN_DIR=scripts (be sure to build from scratch). CFLAGS += -DMICROPY_MODULE_FROZEN_STR -OBJ += $(BUILD)/frozen-files.o - -$(BUILD)/frozen-files.o: $(BUILD)/frozen-files.c - $(call compile_c) - -$(BUILD)/frozen-files.c: $(shell find $(FROZEN_DIR) -type f) - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MAKE_FROZEN) $(FROZEN_DIR) > $@ endif ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') -FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY -OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o -MPY_CROSS = ../mpy-cross/mpy-cross -MPY_TOOL = ../tools/mpy-tool.py - -$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py - @$(ECHO) "MPY $<" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ - -$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif .PHONY: deploy diff --git a/stmhal/accel.c b/stmhal/accel.c index e75f1c9942..827aa46e7c 100644 --- a/stmhal/accel.c +++ b/stmhal/accel.c @@ -57,15 +57,9 @@ #define MMA_AXIS_SIGNED_VALUE(i) (((i) & 0x3f) | ((i) & 0x20 ? (~0x1f) : 0)) void accel_init(void) { - GPIO_InitTypeDef GPIO_InitStructure; - // PB5 is connected to AVDD; pull high to enable MMA accel device - GPIO_clear_pin(MICROPY_HW_MMA_AVDD_PIN.gpio, MICROPY_HW_MMA_AVDD_PIN.pin_mask); // turn off AVDD - GPIO_InitStructure.Pin = MICROPY_HW_MMA_AVDD_PIN.pin_mask; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_LOW; - GPIO_InitStructure.Pull = GPIO_NOPULL; - HAL_GPIO_Init(MICROPY_HW_MMA_AVDD_PIN.gpio, &GPIO_InitStructure); + mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off AVDD + mp_hal_pin_output(&MICROPY_HW_MMA_AVDD_PIN); } STATIC void accel_start(void) { @@ -81,9 +75,9 @@ STATIC void accel_start(void) { i2c_init(&I2CHandle1); // turn off AVDD, wait 30ms, turn on AVDD, wait 30ms again - GPIO_clear_pin(MICROPY_HW_MMA_AVDD_PIN.gpio, MICROPY_HW_MMA_AVDD_PIN.pin_mask); // turn off + mp_hal_pin_low(&MICROPY_HW_MMA_AVDD_PIN); // turn off HAL_Delay(30); - GPIO_set_pin(MICROPY_HW_MMA_AVDD_PIN.gpio, MICROPY_HW_MMA_AVDD_PIN.pin_mask); // turn on + mp_hal_pin_high(&MICROPY_HW_MMA_AVDD_PIN); // turn on HAL_Delay(30); HAL_StatusTypeDef status; diff --git a/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h b/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h index 885cedc893..d18abb908c 100644 --- a/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h +++ b/stmhal/boards/ESPRUINO_PICO/mpconfigboard.h @@ -66,6 +66,5 @@ #define MICROPY_HW_LED2 (pin_B12) // green #define MICROPY_HW_LED3 (pin_B12) // green #define MICROPY_HW_LED4 (pin_B12) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/stmhal/boards/HYDRABUS/mpconfigboard.h b/stmhal/boards/HYDRABUS/mpconfigboard.h index 4fe0874d73..06d1692360 100644 --- a/stmhal/boards/HYDRABUS/mpconfigboard.h +++ b/stmhal/boards/HYDRABUS/mpconfigboard.h @@ -69,9 +69,8 @@ #define MICROPY_HW_LED2 (pin_A4) // same as LED1 #define MICROPY_HW_LED3 (pin_A4) // same as LED1 #define MICROPY_HW_LED4 (pin_A4) // same as LED1 -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch (not used, always on) #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/LIMIFROG/mpconfigboard.h b/stmhal/boards/LIMIFROG/mpconfigboard.h index 782c9c90f8..47b8922336 100644 --- a/stmhal/boards/LIMIFROG/mpconfigboard.h +++ b/stmhal/boards/LIMIFROG/mpconfigboard.h @@ -63,9 +63,8 @@ void LIMIFROG_board_early_init(void); // LEDs #define MICROPY_HW_LED1 (pin_C3) // red -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = pin->pin_mask<<16) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h index 8ec8df645f..3155b63098 100644 --- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -64,9 +64,8 @@ void NETDUINO_PLUS_2_board_early_init(void); #define MICROPY_HW_LED2 (pin_C13) // White LED (aka Power) #define MICROPY_HW_LED3 (pin_A10) // Same as Led(1) #define MICROPY_HW_LED4 (pin_C13) // Same as Led(2) -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB VBUS detect pin #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h b/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h index 780eaf8fc4..518f65824b 100644 --- a/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h +++ b/stmhal/boards/NUCLEO_F401RE/mpconfigboard.h @@ -54,6 +54,5 @@ // LEDs #define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h b/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h index e7ffd85100..4dac804931 100644 --- a/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h +++ b/stmhal/boards/NUCLEO_F411RE/mpconfigboard.h @@ -65,6 +65,5 @@ // LEDs #define MICROPY_HW_LED1 (pin_A5) // Green LD2 LED on Nucleo -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) diff --git a/stmhal/boards/OLIMEX_E407/mpconfigboard.h b/stmhal/boards/OLIMEX_E407/mpconfigboard.h index c9241fe63a..63ddcfb5d6 100644 --- a/stmhal/boards/OLIMEX_E407/mpconfigboard.h +++ b/stmhal/boards/OLIMEX_E407/mpconfigboard.h @@ -71,9 +71,8 @@ // LEDs #define MICROPY_HW_LED1 (pin_C13) -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_C11) diff --git a/stmhal/boards/PYBLITEV10/mpconfigboard.h b/stmhal/boards/PYBLITEV10/mpconfigboard.h index 83dcb938b3..3147d2d7ab 100644 --- a/stmhal/boards/PYBLITEV10/mpconfigboard.h +++ b/stmhal/boards/PYBLITEV10/mpconfigboard.h @@ -73,9 +73,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_B5) diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h index c654ec9a70..2540cc4eb3 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -84,9 +84,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/PYBV11/mpconfigboard.h b/stmhal/boards/PYBV11/mpconfigboard.h index 9b5b7de27b..881e1ccf02 100644 --- a/stmhal/boards/PYBV11/mpconfigboard.h +++ b/stmhal/boards/PYBV11/mpconfigboard.h @@ -84,9 +84,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h index 44fb221610..48d5549253 100644 --- a/stmhal/boards/PYBV3/mpconfigboard.h +++ b/stmhal/boards/PYBV3/mpconfigboard.h @@ -73,9 +73,8 @@ #define MICROPY_HW_LED4 (pin_C5) // G2 - green #define MICROPY_HW_LED1_PWM { TIM1, 1, TIM_CHANNEL_1, GPIO_AF1_TIM1 } #define MICROPY_HW_LED2_PWM { TIM1, 1, TIM_CHANNEL_3, GPIO_AF1_TIM1 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRH = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRL = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_low(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_high(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13) diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h index cc931fb6bf..3e8300d15b 100644 --- a/stmhal/boards/PYBV4/mpconfigboard.h +++ b/stmhal/boards/PYBV4/mpconfigboard.h @@ -81,9 +81,8 @@ #define MICROPY_HW_LED4 (pin_B4) // blue #define MICROPY_HW_LED3_PWM { TIM2, 2, TIM_CHANNEL_1, GPIO_AF1_TIM2 } #define MICROPY_HW_LED4_PWM { TIM3, 3, TIM_CHANNEL_1, GPIO_AF2_TIM3 } -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_A8) diff --git a/stmhal/boards/STM32F411DISC/mpconfigboard.h b/stmhal/boards/STM32F411DISC/mpconfigboard.h index 3bab1304c0..be3589cd9f 100644 --- a/stmhal/boards/STM32F411DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F411DISC/mpconfigboard.h @@ -63,9 +63,8 @@ #define MICROPY_HW_LED2 (pin_D12) // green #define MICROPY_HW_LED3 (pin_D13) // orange #define MICROPY_HW_LED4 (pin_D15) // blue -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/stmhal/boards/STM32F429DISC/mpconfigboard.h b/stmhal/boards/STM32F429DISC/mpconfigboard.h index f2cf6c1422..63f22e02c2 100644 --- a/stmhal/boards/STM32F429DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F429DISC/mpconfigboard.h @@ -67,9 +67,8 @@ // LEDs #define MICROPY_HW_LED1 (pin_G14) // red #define MICROPY_HW_LED2 (pin_G13) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_B13) diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h index 01202e0c95..841bf7d15b 100644 --- a/stmhal/boards/STM32F4DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h @@ -82,9 +82,8 @@ #define MICROPY_HW_LED2 (pin_D12) // green #define MICROPY_HW_LED3 (pin_D13) // orange #define MICROPY_HW_LED4 (pin_D15) // blue -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRRL = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRRH = pin->pin_mask) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config #define MICROPY_HW_USB_VBUS_DETECT_PIN (pin_A9) diff --git a/stmhal/boards/STM32F4DISC/staccel.py b/stmhal/boards/STM32F4DISC/staccel.py index 7296662cac..2f2561d1cb 100644 --- a/stmhal/boards/STM32F4DISC/staccel.py +++ b/stmhal/boards/STM32F4DISC/staccel.py @@ -14,6 +14,7 @@ See: STM32Cube_FW_F4_V1.1.0/Projects/STM32F4-Discovery/Demonstrations/Src/main.c """ +from micropython import const from pyb import Pin from pyb import SPI diff --git a/stmhal/boards/STM32F7DISC/mpconfigboard.h b/stmhal/boards/STM32F7DISC/mpconfigboard.h index a1dbc0f468..acdc4d0055 100644 --- a/stmhal/boards/STM32F7DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F7DISC/mpconfigboard.h @@ -79,9 +79,8 @@ void STM32F7DISC_board_early_init(void); // LEDs #define MICROPY_HW_LED1 (pin_I1) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = (pin->pin_mask << 16)) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // SD card detect switch #define MICROPY_HW_SDCARD_DETECT_PIN (pin_C13) diff --git a/stmhal/boards/STM32L476DISC/mpconfigboard.h b/stmhal/boards/STM32L476DISC/mpconfigboard.h index 07e3ec7fdc..55e7c9b563 100644 --- a/stmhal/boards/STM32L476DISC/mpconfigboard.h +++ b/stmhal/boards/STM32L476DISC/mpconfigboard.h @@ -61,9 +61,8 @@ // LEDs #define MICROPY_HW_LED1 (pin_B2) // red #define MICROPY_HW_LED2 (pin_E8) // green -#define MICROPY_HW_LED_OTYPE (GPIO_MODE_OUTPUT_PP) -#define MICROPY_HW_LED_ON(pin) (pin->gpio->BSRR = pin->pin_mask) -#define MICROPY_HW_LED_OFF(pin) (pin->gpio->BSRR = pin->pin_mask<<16) +#define MICROPY_HW_LED_ON(pin) (mp_hal_pin_high(pin)) +#define MICROPY_HW_LED_OFF(pin) (mp_hal_pin_low(pin)) // USB config // #define MICROPY_HW_USB_OTG_ID_PIN (pin_C12) // This is not the official ID Pin which should be PA10 diff --git a/stmhal/i2c.c b/stmhal/i2c.c index 1909f81606..07269bce5e 100644 --- a/stmhal/i2c.c +++ b/stmhal/i2c.c @@ -238,8 +238,8 @@ void i2c_init(I2C_HandleTypeDef *i2c) { } // init the GPIO lines - mp_hal_gpio_set_af(scl_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); - mp_hal_gpio_set_af(sda_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); + mp_hal_pin_set_af(scl_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); + mp_hal_pin_set_af(sda_pin, &GPIO_InitStructure, AF_FN_I2C, i2c_unit); // init the I2C device if (HAL_I2C_Init(i2c) != HAL_OK) { diff --git a/stmhal/irq.h b/stmhal/irq.h index 5a08a7d501..bb1749e031 100644 --- a/stmhal/irq.h +++ b/stmhal/irq.h @@ -70,10 +70,10 @@ static inline void restore_irq_pri(uint32_t basepri) { #endif -MP_DECLARE_CONST_FUN_OBJ(pyb_wfi_obj); -MP_DECLARE_CONST_FUN_OBJ(pyb_disable_irq_obj); -MP_DECLARE_CONST_FUN_OBJ(pyb_enable_irq_obj); -MP_DECLARE_CONST_FUN_OBJ(pyb_irq_stats_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_wfi_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_disable_irq_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_irq_stats_obj); // IRQ priority definitions. // diff --git a/stmhal/lcd.c b/stmhal/lcd.c index 92f19b8186..c406d64477 100644 --- a/stmhal/lcd.c +++ b/stmhal/lcd.c @@ -113,16 +113,16 @@ STATIC void lcd_delay(void) { STATIC void lcd_out(pyb_lcd_obj_t *lcd, int instr_data, uint8_t i) { lcd_delay(); - GPIO_clear_pin(lcd->pin_cs1->gpio, lcd->pin_cs1->pin_mask); // CS=0; enable + mp_hal_pin_low(lcd->pin_cs1); // CS=0; enable if (instr_data == LCD_INSTR) { - GPIO_clear_pin(lcd->pin_a0->gpio, lcd->pin_a0->pin_mask); // A0=0; select instr reg + mp_hal_pin_low(lcd->pin_a0); // A0=0; select instr reg } else { - GPIO_set_pin(lcd->pin_a0->gpio, lcd->pin_a0->pin_mask); // A0=1; select data reg + mp_hal_pin_high(lcd->pin_a0); // A0=1; select data reg } lcd_delay(); HAL_SPI_Transmit(lcd->spi, &i, 1, 1000); lcd_delay(); - GPIO_set_pin(lcd->pin_cs1->gpio, lcd->pin_cs1->pin_mask); // CS=1; disable + mp_hal_pin_high(lcd->pin_cs1); // CS=1; disable } // write a string to the LCD at the current cursor location @@ -262,34 +262,22 @@ STATIC mp_obj_t pyb_lcd_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp spi_init(lcd->spi, false); // set the pins to default values - GPIO_set_pin(lcd->pin_cs1->gpio, lcd->pin_cs1->pin_mask); - GPIO_set_pin(lcd->pin_rst->gpio, lcd->pin_rst->pin_mask); - GPIO_set_pin(lcd->pin_a0->gpio, lcd->pin_a0->pin_mask); - GPIO_clear_pin(lcd->pin_bl->gpio, lcd->pin_bl->pin_mask); + mp_hal_pin_high(lcd->pin_cs1); + mp_hal_pin_high(lcd->pin_rst); + mp_hal_pin_high(lcd->pin_a0); + mp_hal_pin_low(lcd->pin_bl); // init the pins to be push/pull outputs - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_HIGH; - GPIO_InitStructure.Pull = GPIO_NOPULL; - - GPIO_InitStructure.Pin = lcd->pin_cs1->pin_mask; - HAL_GPIO_Init(lcd->pin_cs1->gpio, &GPIO_InitStructure); - - GPIO_InitStructure.Pin = lcd->pin_rst->pin_mask; - HAL_GPIO_Init(lcd->pin_rst->gpio, &GPIO_InitStructure); - - GPIO_InitStructure.Pin = lcd->pin_a0->pin_mask; - HAL_GPIO_Init(lcd->pin_a0->gpio, &GPIO_InitStructure); - - GPIO_InitStructure.Pin = lcd->pin_bl->pin_mask; - HAL_GPIO_Init(lcd->pin_bl->gpio, &GPIO_InitStructure); + mp_hal_pin_output(lcd->pin_cs1); + mp_hal_pin_output(lcd->pin_rst); + mp_hal_pin_output(lcd->pin_a0); + mp_hal_pin_output(lcd->pin_bl); // init the LCD HAL_Delay(1); // wait a bit - GPIO_clear_pin(lcd->pin_rst->gpio, lcd->pin_rst->pin_mask); // RST=0; reset + mp_hal_pin_low(lcd->pin_rst); // RST=0; reset HAL_Delay(1); // wait for reset; 2us min - GPIO_set_pin(lcd->pin_rst->gpio, lcd->pin_rst->pin_mask); // RST=1; enable + mp_hal_pin_high(lcd->pin_rst); // RST=1; enable HAL_Delay(1); // wait for reset; 2us min lcd_out(lcd, LCD_INSTR, 0xa0); // ADC select, normal lcd_out(lcd, LCD_INSTR, 0xc0); // common output mode select, normal (this flips the display) @@ -372,9 +360,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_lcd_contrast_obj, pyb_lcd_contrast); STATIC mp_obj_t pyb_lcd_light(mp_obj_t self_in, mp_obj_t value) { pyb_lcd_obj_t *self = self_in; if (mp_obj_is_true(value)) { - GPIO_set_pin(self->pin_bl->gpio, self->pin_bl->pin_mask); // set pin high to turn backlight on + mp_hal_pin_high(self->pin_bl); // set pin high to turn backlight on } else { - GPIO_clear_pin(self->pin_bl->gpio, self->pin_bl->pin_mask); // set pin low to turn backlight off + mp_hal_pin_low(self->pin_bl); // set pin low to turn backlight off } return mp_const_none; } diff --git a/stmhal/led.c b/stmhal/led.c index fdf5b04d8e..310efdcda9 100644 --- a/stmhal/led.c +++ b/stmhal/led.c @@ -67,21 +67,12 @@ STATIC const pyb_led_obj_t pyb_led_obj[] = { #define NUM_LEDS MP_ARRAY_SIZE(pyb_led_obj) void led_init(void) { - /* GPIO structure */ - GPIO_InitTypeDef GPIO_InitStructure; - - /* Configure I/O speed, mode, output type and pull */ - GPIO_InitStructure.Speed = GPIO_SPEED_LOW; - GPIO_InitStructure.Mode = MICROPY_HW_LED_OTYPE; - GPIO_InitStructure.Pull = GPIO_NOPULL; - /* Turn off LEDs and initialize */ for (int led = 0; led < NUM_LEDS; led++) { const pin_obj_t *led_pin = pyb_led_obj[led].led_pin; mp_hal_gpio_clock_enable(led_pin->gpio); MICROPY_HW_LED_OFF(led_pin); - GPIO_InitStructure.Pin = led_pin->pin_mask; - HAL_GPIO_Init(led_pin->gpio, &GPIO_InitStructure); + mp_hal_pin_output(led_pin); } } diff --git a/stmhal/modmachine.h b/stmhal/modmachine.h index 042afb850c..164c5cfda2 100644 --- a/stmhal/modmachine.h +++ b/stmhal/modmachine.h @@ -33,12 +33,12 @@ void machine_init(void); -MP_DECLARE_CONST_FUN_OBJ(machine_info_obj); -MP_DECLARE_CONST_FUN_OBJ(machine_unique_id_obj); -MP_DECLARE_CONST_FUN_OBJ(machine_reset_obj); -MP_DECLARE_CONST_FUN_OBJ(machine_bootloader_obj); -MP_DECLARE_CONST_FUN_OBJ(machine_freq_obj); -MP_DECLARE_CONST_FUN_OBJ(machine_sleep_obj); -MP_DECLARE_CONST_FUN_OBJ(machine_deepsleep_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_info_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_unique_id_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_reset_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_bootloader_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(machine_freq_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_sleep_obj); +MP_DECLARE_CONST_FUN_OBJ_0(machine_deepsleep_obj); #endif // __MICROPY_INCLUDED_STMHAL_MODMACHINE_H__ diff --git a/stmhal/modnwwiznet5k.c b/stmhal/modnwwiznet5k.c index c8b5d628f4..f349e40aff 100644 --- a/stmhal/modnwwiznet5k.c +++ b/stmhal/modnwwiznet5k.c @@ -65,11 +65,11 @@ STATIC void wiz_cris_exit(void) { } STATIC void wiz_cs_select(void) { - GPIO_clear_pin(wiznet5k_obj.cs->gpio, wiznet5k_obj.cs->pin_mask); + mp_hal_pin_low(wiznet5k_obj.cs); } STATIC void wiz_cs_deselect(void) { - GPIO_set_pin(wiznet5k_obj.cs->gpio, wiznet5k_obj.cs->pin_mask); + mp_hal_pin_high(wiznet5k_obj.cs); } STATIC void wiz_spi_read(uint8_t *buf, uint32_t len) { @@ -344,22 +344,12 @@ STATIC mp_obj_t wiznet5k_make_new(const mp_obj_type_t *type, mp_uint_t n_args, m wiznet5k_obj.spi->Init.CRCPolynomial = 7; // unused spi_init(wiznet5k_obj.spi, false); - GPIO_InitTypeDef GPIO_InitStructure; - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_FAST; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Pin = wiznet5k_obj.cs->pin_mask; - HAL_GPIO_Init(wiznet5k_obj.cs->gpio, &GPIO_InitStructure); + mp_hal_pin_output(wiznet5k_obj.cs); + mp_hal_pin_output(wiznet5k_obj.rst); - GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStructure.Speed = GPIO_SPEED_FAST; - GPIO_InitStructure.Pull = GPIO_NOPULL; - GPIO_InitStructure.Pin = wiznet5k_obj.rst->pin_mask; - HAL_GPIO_Init(wiznet5k_obj.rst->gpio, &GPIO_InitStructure); - - GPIO_clear_pin(wiznet5k_obj.rst->gpio, wiznet5k_obj.rst->pin_mask); + mp_hal_pin_low(wiznet5k_obj.rst); HAL_Delay(1); // datasheet says 2us - GPIO_set_pin(wiznet5k_obj.rst->gpio, wiznet5k_obj.rst->pin_mask); + mp_hal_pin_high(wiznet5k_obj.rst); HAL_Delay(160); // datasheet says 150ms reg_wizchip_cris_cbfunc(wiz_cris_enter, wiz_cris_exit); diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c index 5b2bf7aa99..e602234fc6 100644 --- a/stmhal/modpyb.c +++ b/stmhal/modpyb.c @@ -126,7 +126,7 @@ STATIC mp_obj_t pyb_elapsed_micros(mp_obj_t start) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_elapsed_micros_obj, pyb_elapsed_micros); -MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ_KW(pyb_main_obj); // defined in main.c STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, diff --git a/stmhal/modutime.c b/stmhal/modutime.c index 63597edde8..7f2c549bd7 100644 --- a/stmhal/modutime.c +++ b/stmhal/modutime.c @@ -130,31 +130,20 @@ STATIC mp_obj_t time_time(void) { } MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); -STATIC mp_obj_t time_ticks_cpu(void) { - static bool enabled = false; - if (!enabled) { - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; - enabled = true; - } - return MP_OBJ_NEW_SMALL_INT(DWT->CYCCNT & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(time_ticks_cpu_obj, time_ticks_cpu); +STATIC const mp_rom_map_elem_t time_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, -STATIC const mp_map_elem_t time_module_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utime) }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_localtime), (mp_obj_t)&time_localtime_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_mktime), (mp_obj_t)&time_mktime_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_time_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep), (mp_obj_t)&mp_utime_sleep_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_ms), (mp_obj_t)&mp_utime_sleep_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_sleep_us), (mp_obj_t)&mp_utime_sleep_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_ms), (mp_obj_t)&mp_utime_ticks_ms_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_us), (mp_obj_t)&mp_utime_ticks_us_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_cpu), (mp_obj_t)&time_ticks_cpu_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_ticks_diff), (mp_obj_t)&mp_utime_ticks_diff_obj }, + { MP_ROM_QSTR(MP_QSTR_localtime), MP_ROM_PTR(&time_localtime_obj) }, + { MP_ROM_QSTR(MP_QSTR_mktime), MP_ROM_PTR(&time_mktime_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, }; STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table); diff --git a/stmhal/mphalport.c b/stmhal/mphalport.c index f392550b80..8d6aa1a759 100644 --- a/stmhal/mphalport.c +++ b/stmhal/mphalport.c @@ -7,6 +7,8 @@ #include "usb.h" #include "uart.h" +bool mp_hal_ticks_cpu_enabled = false; + // this table converts from HAL_StatusTypeDef to POSIX errno const byte mp_hal_status_to_errno_table[4] = { [HAL_OK] = 0, @@ -71,6 +73,15 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { } } +void mp_hal_ticks_cpu_enable(void) { + if (!mp_hal_ticks_cpu_enabled) { + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + mp_hal_ticks_cpu_enabled = true; + } +} + void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { if (0) { #ifdef __GPIOA_CLK_ENABLE @@ -120,7 +131,9 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio) { } } -void mp_hal_gpio_config(GPIO_TypeDef *gpio, uint32_t pin, uint32_t mode, uint32_t pull, uint32_t alt) { +void mp_hal_pin_config(mp_hal_pin_obj_t pin_obj, uint32_t mode, uint32_t pull, uint32_t alt) { + GPIO_TypeDef *gpio = pin_obj->gpio; + uint32_t pin = pin_obj->pin; mp_hal_gpio_clock_enable(gpio); gpio->MODER = (gpio->MODER & ~(3 << (2 * pin))) | ((mode & 3) << (2 * pin)); gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | ((mode >> 2) << pin); @@ -129,7 +142,7 @@ void mp_hal_gpio_config(GPIO_TypeDef *gpio, uint32_t pin, uint32_t mode, uint32_ gpio->AFR[pin >> 3] = (gpio->AFR[pin >> 3] & ~(15 << (4 * (pin & 7)))) | (alt << (4 * (pin & 7))); } -bool mp_hal_gpio_set_af(const pin_obj_t *pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit) { +bool mp_hal_pin_set_af(mp_hal_pin_obj_t pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit) { mp_hal_gpio_clock_enable(pin->gpio); const pin_af_obj_t *af = pin_find_af(pin, fn, unit); diff --git a/stmhal/mphalport.h b/stmhal/mphalport.h index 02b408777c..e58bb33b5f 100644 --- a/stmhal/mphalport.h +++ b/stmhal/mphalport.h @@ -14,42 +14,51 @@ #error mphalport.h: Unrecognized MCU_SERIES #endif -// Basic GPIO functions -#define GPIO_read_pin(gpio, pin) (((gpio)->IDR >> (pin)) & 1) -#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) -#define GPIO_set_pin(gpio, pin_mask) (((gpio)->BSRR) = (pin_mask)) -#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->BSRR) = ((pin_mask) << 16)) -#else -#define GPIO_set_pin(gpio, pin_mask) (((gpio)->BSRRL) = (pin_mask)) -#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->BSRRH) = (pin_mask)) -#endif -#define GPIO_read_output_pin(gpio, pin) (((gpio)->ODR >> (pin)) & 1) - -void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); -void mp_hal_gpio_config(GPIO_TypeDef *gpio, uint32_t pin, uint32_t mode, uint32_t pull, uint32_t alt); -bool mp_hal_gpio_set_af(const pin_obj_t *pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit); - extern const unsigned char mp_hal_status_to_errno_table[4]; NORETURN void mp_hal_raise(HAL_StatusTypeDef status); void mp_hal_set_interrupt_char(int c); // -1 to disable // timing functions + #include "stmhal/systick.h" + #define mp_hal_delay_ms HAL_Delay #define mp_hal_delay_us(us) sys_tick_udelay(us) #define mp_hal_delay_us_fast(us) sys_tick_udelay(us) #define mp_hal_ticks_ms HAL_GetTick #define mp_hal_ticks_us() sys_tick_get_microseconds() +extern bool mp_hal_ticks_cpu_enabled; +void mp_hal_ticks_cpu_enable(void); +static inline mp_uint_t mp_hal_ticks_cpu(void) { + if (!mp_hal_ticks_cpu_enabled) { + mp_hal_ticks_cpu_enable(); + } + return DWT->CYCCNT; +} + // C-level pin HAL + #include "stmhal/pin.h" + #define mp_hal_pin_obj_t const pin_obj_t* -#define mp_hal_get_pin_obj(o) pin_find(o) -#define mp_hal_pin_input(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 0, 0, 0) -#define mp_hal_pin_output(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 1, 0, 0) -#define mp_hal_pin_open_drain(p) mp_hal_gpio_config((p)->gpio, (p)->pin, 5, 0, 0) -#define mp_hal_pin_od_low(p) GPIO_clear_pin((p)->gpio, (p)->pin_mask) -#define mp_hal_pin_od_high(p) GPIO_set_pin((p)->gpio, (p)->pin_mask) -#define mp_hal_pin_read(p) GPIO_read_pin((p)->gpio, (p)->pin) -#define mp_hal_pin_write(p, v) do { if (v) { GPIO_set_pin((p)->gpio, (p)->pin_mask); } else { GPIO_clear_pin((p)->gpio, (p)->pin_mask); } } while (0) +#define mp_hal_get_pin_obj(o) pin_find(o) +#define mp_hal_pin_input(p) mp_hal_pin_config((p), 0, 0, 0) +#define mp_hal_pin_output(p) mp_hal_pin_config((p), 1, 0, 0) +#define mp_hal_pin_open_drain(p) mp_hal_pin_config((p), 5, 0, 0) +#if defined(MCU_SERIES_F7) || defined(MCU_SERIES_L4) +#define mp_hal_pin_high(p) (((p)->gpio->BSRR) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRR) = ((p)->pin_mask << 16)) +#else +#define mp_hal_pin_high(p) (((p)->gpio->BSRRL) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->BSRRH) = (p)->pin_mask) +#endif +#define mp_hal_pin_od_low(p) mp_hal_pin_low(p) +#define mp_hal_pin_od_high(p) mp_hal_pin_high(p) +#define mp_hal_pin_read(p) (((p)->gpio->IDR >> (p)->pin) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) + +void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); +void mp_hal_pin_config(mp_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, uint32_t alt); +bool mp_hal_pin_set_af(mp_hal_pin_obj_t pin, GPIO_InitTypeDef *init, uint8_t fn, uint8_t unit); diff --git a/stmhal/pin.c b/stmhal/pin.c index 9bd4e7a6d9..21012d1865 100644 --- a/stmhal/pin.c +++ b/stmhal/pin.c @@ -266,14 +266,10 @@ STATIC mp_obj_t pin_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, con pin_obj_t *self = self_in; if (n_args == 0) { // get pin - return MP_OBJ_NEW_SMALL_INT(GPIO_read_pin(self->gpio, self->pin)); + return MP_OBJ_NEW_SMALL_INT(mp_hal_pin_read(self)); } else { // set pin - if (mp_obj_is_true(args[0])) { - GPIO_set_pin(self->gpio, self->pin_mask); - } else { - GPIO_clear_pin(self->gpio, self->pin_mask); - } + mp_hal_pin_write(self, mp_obj_is_true(args[0])); return mp_const_none; } } @@ -371,11 +367,7 @@ STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, mp_uint_t n_args, con // if given, set the pin value before initialising to prevent glitches if (args[3].u_obj != MP_OBJ_NULL) { - if (mp_obj_is_true(args[3].u_obj)) { - GPIO_set_pin(self->gpio, self->pin_mask); - } else { - GPIO_clear_pin(self->gpio, self->pin_mask); - } + mp_hal_pin_write(self, mp_obj_is_true(args[3].u_obj)); } // configure the GPIO as requested @@ -411,7 +403,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value); /// Set the pin to a low logic level. STATIC mp_obj_t pin_low(mp_obj_t self_in) { pin_obj_t *self = self_in; - GPIO_clear_pin(self->gpio, self->pin_mask);; + mp_hal_pin_low(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); @@ -420,7 +412,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low); /// Set the pin to a high logic level. STATIC mp_obj_t pin_high(mp_obj_t self_in) { pin_obj_t *self = self_in; - GPIO_set_pin(self->gpio, self->pin_mask);; + mp_hal_pin_high(self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high); diff --git a/stmhal/pin.h b/stmhal/pin.h index df7df0ce2e..a11b0a0f8e 100644 --- a/stmhal/pin.h +++ b/stmhal/pin.h @@ -86,7 +86,7 @@ extern const mp_obj_type_t pin_cpu_pins_obj_type; extern const mp_obj_dict_t pin_cpu_pins_locals_dict; extern const mp_obj_dict_t pin_board_pins_locals_dict; -MP_DECLARE_CONST_FUN_OBJ(pin_init_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(pin_init_obj); void pin_init0(void); uint32_t pin_get_mode(const pin_obj_t *pin); diff --git a/stmhal/portmodules.h b/stmhal/portmodules.h index 68ae2f47ce..173d53cc68 100644 --- a/stmhal/portmodules.h +++ b/stmhal/portmodules.h @@ -33,8 +33,8 @@ extern const mp_obj_module_t mp_module_usocket; // additional helper functions exported by the modules -MP_DECLARE_CONST_FUN_OBJ(time_sleep_ms_obj); -MP_DECLARE_CONST_FUN_OBJ(time_sleep_us_obj); +MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_ms_obj); +MP_DECLARE_CONST_FUN_OBJ_1(time_sleep_us_obj); -MP_DECLARE_CONST_FUN_OBJ(mod_os_sync_obj); -MP_DECLARE_CONST_FUN_OBJ(mod_os_dupterm_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mod_os_sync_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mod_os_dupterm_obj); diff --git a/stmhal/rng.h b/stmhal/rng.h index f1e5054ad2..ce1833e80b 100644 --- a/stmhal/rng.h +++ b/stmhal/rng.h @@ -27,4 +27,4 @@ void rng_init0(void); uint32_t rng_get(void); -MP_DECLARE_CONST_FUN_OBJ(pyb_rng_get_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_rng_get_obj); diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c index caf6dc8d5d..a2aa4c84d8 100644 --- a/stmhal/sdcard.c +++ b/stmhal/sdcard.c @@ -138,7 +138,7 @@ bool sdcard_power_on(void) { sd_handle.Instance = SDIO; sd_handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; sd_handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; - sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + sd_handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE; sd_handle.Init.BusWide = SDIO_BUS_WIDE_1B; sd_handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; sd_handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV; diff --git a/stmhal/servo.h b/stmhal/servo.h index 121ce922df..0fca8fea17 100644 --- a/stmhal/servo.h +++ b/stmhal/servo.h @@ -29,5 +29,5 @@ void servo_timer_irq_callback(void); extern const mp_obj_type_t pyb_servo_type; -MP_DECLARE_CONST_FUN_OBJ(pyb_servo_set_obj); -MP_DECLARE_CONST_FUN_OBJ(pyb_pwm_set_obj); +MP_DECLARE_CONST_FUN_OBJ_2(pyb_servo_set_obj); +MP_DECLARE_CONST_FUN_OBJ_2(pyb_pwm_set_obj); diff --git a/stmhal/spi.c b/stmhal/spi.c index 7f805709d6..e72810d287 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -332,7 +332,7 @@ void spi_init(SPI_HandleTypeDef *spi, bool enable_nss_pin) { } for (uint i = (enable_nss_pin && pins[0] ? 0 : 1); i < 4; i++) { - mp_hal_gpio_set_af(pins[i], &GPIO_InitStructure, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1); + mp_hal_pin_set_af(pins[i], &GPIO_InitStructure, AF_FN_SPI, (self - &pyb_spi_obj[0]) + 1); } // init the SPI device diff --git a/stmhal/usb.h b/stmhal/usb.h index debb4aa7c4..e153f0c6b6 100644 --- a/stmhal/usb.h +++ b/stmhal/usb.h @@ -53,9 +53,9 @@ extern const struct _mp_obj_tuple_t pyb_usb_hid_mouse_obj; extern const struct _mp_obj_tuple_t pyb_usb_hid_keyboard_obj; extern const mp_obj_type_t pyb_usb_vcp_type; extern const mp_obj_type_t pyb_usb_hid_type; -MP_DECLARE_CONST_FUN_OBJ(pyb_usb_mode_obj); -MP_DECLARE_CONST_FUN_OBJ(pyb_have_cdc_obj); // deprecated -MP_DECLARE_CONST_FUN_OBJ(pyb_hid_send_report_obj); // deprecated +MP_DECLARE_CONST_FUN_OBJ_KW(pyb_usb_mode_obj); +MP_DECLARE_CONST_FUN_OBJ_0(pyb_have_cdc_obj); // deprecated +MP_DECLARE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj); // deprecated void pyb_usb_init0(void); bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_HID_ModeInfoTypeDef *hid_info); diff --git a/teensy/modpyb.c b/teensy/modpyb.c index 0eb2a7b517..9f601e327b 100644 --- a/teensy/modpyb.c +++ b/teensy/modpyb.c @@ -272,9 +272,9 @@ STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report); -MP_DECLARE_CONST_FUN_OBJ(pyb_source_dir_obj); // defined in main.c -MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c -MP_DECLARE_CONST_FUN_OBJ(pyb_usb_mode_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ_1(pyb_source_dir_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ_1(pyb_main_obj); // defined in main.c +MP_DECLARE_CONST_FUN_OBJ_1(pyb_usb_mode_obj); // defined in main.c STATIC const mp_map_elem_t pyb_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) }, diff --git a/teensy/servo.h b/teensy/servo.h index 5dad041138..5f1c87b693 100644 --- a/teensy/servo.h +++ b/teensy/servo.h @@ -2,6 +2,6 @@ void servo_init(void); extern const mp_obj_type_t pyb_servo_type; -MP_DECLARE_CONST_FUN_OBJ(pyb_servo_set_obj); -MP_DECLARE_CONST_FUN_OBJ(pyb_pwm_set_obj); +MP_DECLARE_CONST_FUN_OBJ_2(pyb_servo_set_obj); +MP_DECLARE_CONST_FUN_OBJ_2(pyb_pwm_set_obj); diff --git a/teensy/teensy_hal.h b/teensy/teensy_hal.h index b00b6e4ac6..80f320e0c5 100644 --- a/teensy/teensy_hal.h +++ b/teensy/teensy_hal.h @@ -118,7 +118,9 @@ void mp_hal_gpio_clock_enable(GPIO_TypeDef *gpio); void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *init); -#define GPIO_read_pin(gpio, pin) (((gpio)->PDIR >> (pin)) & 1) -#define GPIO_set_pin(gpio, pin_mask) (((gpio)->PSOR) = (pin_mask)) -#define GPIO_clear_pin(gpio, pin_mask) (((gpio)->PCOR) = (pin_mask)) -#define GPIO_read_output_pin(gpio, pin) (((gpio)->PDOR >> (pin)) & 1) +struct _pin_obj_t; +#define mp_hal_pin_obj_t const struct _pin_obj_t* +#define mp_hal_pin_high(p) (((p)->gpio->PSOR) = (p)->pin_mask) +#define mp_hal_pin_low(p) (((p)->gpio->PCOR) = (p)->pin_mask) +#define mp_hal_pin_read(p) (((p)->gpio->PDIR >> (p)->pin) & 1) +#define mp_hal_pin_write(p, v) do { if (v) { mp_hal_pin_high(p); } else { mp_hal_pin_low(p); } } while (0) diff --git a/tests/basics/builtin_delattr.py b/tests/basics/builtin_delattr.py new file mode 100644 index 0000000000..3743df227c --- /dev/null +++ b/tests/basics/builtin_delattr.py @@ -0,0 +1,18 @@ +# test builtin delattr + +class A: pass +a = A() +a.x = 1 +print(a.x) + +delattr(a, 'x') + +try: + a.x +except AttributeError: + print('AttributeError') + +try: + delattr(a, 'x') +except AttributeError: + print('AttributeError') diff --git a/tests/basics/builtin_slice.py b/tests/basics/builtin_slice.py index 4da1229fa0..df84d5c57b 100644 --- a/tests/basics/builtin_slice.py +++ b/tests/basics/builtin_slice.py @@ -4,4 +4,8 @@ class A: def __getitem__(self, idx): print(idx) -A()[1:2:3] + return idx +s = A()[1:2:3] + +# check type +print(type(s) is slice) diff --git a/tests/basics/gc1.py b/tests/basics/gc1.py index 140c8b0a60..be6c6faed2 100644 --- a/tests/basics/gc1.py +++ b/tests/basics/gc1.py @@ -20,3 +20,11 @@ if hasattr(gc, 'mem_free'): # just test they execute and return an int assert type(gc.mem_free()) is int assert type(gc.mem_alloc()) is int + +if hasattr(gc, 'threshold'): + # uPy has this extra function + # check execution and returns + assert(gc.threshold(1) is None) + assert(gc.threshold() == 0) + assert(gc.threshold(-1) is None) + assert(gc.threshold() == -1) diff --git a/tests/basics/list_slice_3arg.py b/tests/basics/list_slice_3arg.py index b98ca3e4f2..8578d5855e 100644 --- a/tests/basics/list_slice_3arg.py +++ b/tests/basics/list_slice_3arg.py @@ -7,3 +7,22 @@ x = list(range(9)) print(x[::-1]) print(x[::2]) print(x[::-2]) + +x = list(range(5)) +print(x[:0:-1]) +print(x[:1:-1]) +print(x[:2:-1]) +print(x[0::-1]) +print(x[1::-1]) +print(x[2::-1]) + +x = list(range(5)) +print(x[0:0:-1]) +print(x[4:4:-1]) +print(x[5:5:-1]) + +x = list(range(10)) +print(x[-1:-1:-1]) +print(x[-1:-2:-1]) +print(x[-1:-11:-1]) +print(x[-10:-11:-1]) diff --git a/tests/extmod/btree1.py b/tests/extmod/btree1.py index 6629837661..715f628246 100644 --- a/tests/extmod/btree1.py +++ b/tests/extmod/btree1.py @@ -9,7 +9,7 @@ except ImportError: #f = open("_test.db", "w+b") f = uio.BytesIO() -db = btree.open(f) +db = btree.open(f, pagesize=512) db[b"foo3"] = b"bar3" db[b"foo1"] = b"bar1" diff --git a/tests/extmod/framebuf1.py b/tests/extmod/framebuf1.py index f550b6b4f4..52899028c7 100644 --- a/tests/extmod/framebuf1.py +++ b/tests/extmod/framebuf1.py @@ -23,6 +23,10 @@ fbuf.pixel(0, 15, 1) fbuf.pixel(4, 15, 1) print(buf) +# clear pixel +fbuf.pixel(4, 15, 0) +print(buf) + # get pixel print(fbuf.pixel(0, 0), fbuf.pixel(1, 1)) @@ -39,3 +43,14 @@ fbuf.scroll(-1, 0) print(buf) fbuf.scroll(2, 2) print(buf) + +# print text +fbuf.fill(0) +fbuf.text("hello", 0, 0, 1) +print(buf) +fbuf.text("hello", 0, 0, 0) # clear +print(buf) + +# char out of font range set to chr(127) +fbuf.text(str(chr(31)), 0, 0) +print(buf) diff --git a/tests/extmod/framebuf1.py.exp b/tests/extmod/framebuf1.py.exp index 8fd8c37098..1577faac8a 100644 --- a/tests/extmod/framebuf1.py.exp +++ b/tests/extmod/framebuf1.py.exp @@ -1,9 +1,13 @@ bytearray(b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff') bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') bytearray(b'\x01\x00\x00\x00\x01\x80\x00\x00\x00\x80') +bytearray(b'\x01\x00\x00\x00\x01\x80\x00\x00\x00\x00') 1 0 bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00') bytearray(b'\x00\x00@\x00\x00\x00\x00\x00\x00\x00') bytearray(b'\x00\x00\x00@\x00\x00\x00\x00\x00\x00') bytearray(b'\x00\x00@\x00\x00\x00\x00\x00\x00\x00') bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') +bytearray(b'\x00\x7f\x7f\x04\x04\x00\x00\x00\x00\x00') +bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +bytearray(b'\xaaU\xaaU\xaa\x00\x00\x00\x00\x00') diff --git a/tests/extmod/ticks_diff.py b/tests/extmod/ticks_diff.py new file mode 100644 index 0000000000..4d8df83cf9 --- /dev/null +++ b/tests/extmod/ticks_diff.py @@ -0,0 +1,33 @@ +from utime import ticks_diff, ticks_add + +MAX = ticks_add(0, -1) +# Should be done like this to avoid small int overflow +MODULO_HALF = MAX // 2 + 1 + +# Invariants: +# if ticks_diff(a, b) = c, +# then ticks_diff(b, a) = -c + +assert ticks_diff(1, 0) == 1, ticks_diff(1, 0) +assert ticks_diff(0, 1) == -1 + +assert ticks_diff(0, MAX) == 1 +assert ticks_diff(MAX, 0) == -1 + +assert ticks_diff(0, MAX - 1) == 2 + +# Maximum "positive" distance +assert ticks_diff(MODULO_HALF, 1) == MODULO_HALF - 1, ticks_diff(MODULO_HALF, 1) +# Step further, and it becomes a negative distance +assert ticks_diff(MODULO_HALF, 0) == -MODULO_HALF + +# Offsetting that in either direction doesn't affect the result +off = 100 +# Cheating and skipping to use ticks_add() when we know there's no wraparound +# Real apps should use always it. +assert ticks_diff(MODULO_HALF + off, 1 + off) == MODULO_HALF - 1 +assert ticks_diff(MODULO_HALF + off, 0 + off) == -MODULO_HALF +assert ticks_diff(MODULO_HALF - off, ticks_add(1, -off)) == MODULO_HALF - 1 +assert ticks_diff(MODULO_HALF - off, ticks_add(0, -off)) == -MODULO_HALF + +print("OK") diff --git a/tests/extmod/ticks_diff.py.exp b/tests/extmod/ticks_diff.py.exp new file mode 100644 index 0000000000..d86bac9de5 --- /dev/null +++ b/tests/extmod/ticks_diff.py.exp @@ -0,0 +1 @@ +OK diff --git a/tests/extmod/uhashlib_sha1.py b/tests/extmod/uhashlib_sha1.py new file mode 100644 index 0000000000..f12fc649aa --- /dev/null +++ b/tests/extmod/uhashlib_sha1.py @@ -0,0 +1,22 @@ +import sys +try: + import uhashlib as hashlib +except ImportError: + try: + import hashlib + except ImportError: + # This is neither uPy, nor cPy, so must be uPy with + # uhashlib module disabled. + print("SKIP") + sys.exit() + +try: + hashlib.sha1 +except AttributeError: + # SHA1 is only available on some ports + print("SKIP") + sys.exit() + +sha1 = hashlib.sha1(b'hello') +sha1.update(b'world') +print(sha1.digest()) diff --git a/tests/extmod/sha256.py b/tests/extmod/uhashlib_sha256.py similarity index 100% rename from tests/extmod/sha256.py rename to tests/extmod/uhashlib_sha256.py diff --git a/tests/extmod/vfs_fat_fileio.py b/tests/extmod/vfs_fat_fileio.py new file mode 100644 index 0000000000..de8d4953c4 --- /dev/null +++ b/tests/extmod/vfs_fat_fileio.py @@ -0,0 +1,156 @@ +import sys +import uos +import uerrno +try: + uos.VfsFat +except AttributeError: + print("SKIP") + sys.exit() + + +class RAMFS: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return len(self.data) // self.SEC_SIZE + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + + +try: + bdev = RAMFS(48) +except MemoryError: + print("SKIP") + sys.exit() + +uos.VfsFat.mkfs(bdev) +vfs = uos.VfsFat(bdev, "/ramdisk") + +# file IO +f = vfs.open("foo_file.txt", "w") +print(str(f)[:17], str(f)[-1:]) +f.write("hello!") +f.flush() +f.close() +f.close() # allowed +try: + f.write("world!") +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +try: + f.read() +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +try: + f.flush() +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +try: + vfs.open("foo_file.txt", "x") +except OSError as e: + print(e.args[0] == uerrno.EEXIST) + +with vfs.open("foo_file.txt", "a") as f: + f.write("world!") + +with vfs.open("foo_file.txt") as f2: + print(f2.read()) + print(f2.tell()) + + f2.seek(0, 0) # SEEK_SET + print(f2.read(1)) + + f2.seek(0, 1) # SEEK_CUR + print(f2.read(1)) + try: + f2.seek(1, 1) # SEEK_END + except OSError as e: + print(e.args[0] == uerrno.EOPNOTSUPP) + + f2.seek(-2, 2) # SEEK_END + print(f2.read(1)) + +# dirs +vfs.mkdir("foo_dir") + +try: + vfs.rmdir("foo_file.txt") +except OSError as e: + print(e.args[0] == 20) # uerrno.ENOTDIR + +try: + vfs.mkdir("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EEXIST) + +try: + vfs.remove("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EISDIR) + +try: + vfs.remove("no_file.txt") +except OSError as e: + print(e.args[0] == uerrno.ENOENT) + +try: + vfs.rename("foo_dir", "/null") +except OSError as e: + print(e.args[0] == uerrno.ENODEV) + +# file in dir +with vfs.open("foo_dir/file-in-dir.txt", "w+t") as f: + f.write("data in file") + +with vfs.open("foo_dir/file-in-dir.txt", "r+b") as f: + print(f.read()) + +with vfs.open("foo_dir/sub_file.txt", "w") as f: + f.write("subdir file") + +# directory not empty +try: + vfs.rmdir("foo_dir") +except OSError as e: + print(e.args[0] == uerrno.EACCES) + +# trim full path +vfs.rename("foo_dir/file-in-dir.txt", "/ramdisk/foo_dir/file.txt") +print(vfs.listdir("foo_dir")) + +vfs.rename("foo_dir/file.txt", "moved-to-root.txt") +print(vfs.listdir()) + +# valid removes +vfs.remove("foo_dir/sub_file.txt") +vfs.remove("foo_file.txt") +vfs.rmdir("foo_dir") +print(vfs.listdir()) + +# disk full +try: + bsize = vfs.statvfs("/ramdisk")[0] + free = vfs.statvfs("/ramdisk")[2] + 1 + f = vfs.open("large_file.txt", "wb") + f.write(bytearray(bsize * free)) +except OSError as e: + print("ENOSPC:", e.args[0] == 28) # uerrno.ENOSPC diff --git a/tests/extmod/vfs_fat_fileio.py.exp b/tests/extmod/vfs_fat_fileio.py.exp new file mode 100644 index 0000000000..c438bc850c --- /dev/null +++ b/tests/extmod/vfs_fat_fileio.py.exp @@ -0,0 +1,22 @@ + +True +True +True +True +hello!world! +12 +h +e +True +d +True +True +True +True +True +b'data in file' +True +['sub_file.txt', 'file.txt'] +['foo_file.txt', 'foo_dir', 'moved-to-root.txt'] +['moved-to-root.txt'] +ENOSPC: True diff --git a/tests/extmod/vfs_fat_fsusermount.py b/tests/extmod/vfs_fat_fsusermount.py new file mode 100644 index 0000000000..7326172eed --- /dev/null +++ b/tests/extmod/vfs_fat_fsusermount.py @@ -0,0 +1,96 @@ +import sys +import uos +import uerrno +try: + uos.VfsFat +except AttributeError: + print("SKIP") + sys.exit() + + +class RAMFS: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def ioctl(self, op, arg): + #print("ioctl(%d, %r)" % (op, arg)) + if op == 4: # BP_IOCTL_SEC_COUNT + return len(self.data) // self.SEC_SIZE + if op == 5: # BP_IOCTL_SEC_SIZE + return self.SEC_SIZE + + +try: + bdev = RAMFS(48) +except MemoryError: + print("SKIP") + sys.exit() + +# can't mkfs readonly device +try: + uos.vfs_mkfs(bdev, "/ramdisk", readonly=True) +except OSError as e: + print(e) + +# mount before mkfs +try: + uos.vfs_mount(bdev, "/ramdisk") +except OSError as e: + print(e) + +# invalid umount +try: + uos.vfs_umount("/ramdisk") +except OSError as e: + print(e.args[0] == uerrno.EINVAL) + +try: + uos.vfs_mount(None, "/ramdisk") +except OSError as e: + print(e) + +try: + uos.vfs_mkfs(None, "/ramdisk") +except OSError as e: + print(e) + +# valid mkfs/mount +uos.vfs_mkfs(bdev, "/ramdisk") +uos.vfs_mount(bdev, "/ramdisk") + +# umount by path +uos.vfs_umount("/ramdisk") + +# readonly mount +uos.vfs_mount(bdev, "/ramdisk", readonly=True) +vfs = uos.VfsFat(bdev, "/ramdisk") +try: + f = vfs.open("file.txt", "w") +except OSError as e: + print("EROFS:", e.args[0] == 30) # uerrno.EROFS + +# device is None == umount +uos.vfs_mount(None, "/ramdisk") + +# max mounted devices +dev = [] +try: + for i in range(0,4): + dev.append(RAMFS(48)) + uos.vfs_mkfs(dev[i], "/ramdisk" + str(i)) + uos.vfs_mount(dev[i], "/ramdisk" + str(i)) +except OSError as e: + print(e) diff --git a/tests/extmod/vfs_fat_fsusermount.py.exp b/tests/extmod/vfs_fat_fsusermount.py.exp new file mode 100644 index 0000000000..3b30688dd9 --- /dev/null +++ b/tests/extmod/vfs_fat_fsusermount.py.exp @@ -0,0 +1,7 @@ +can't mkfs +can't mount +True +can't umount +can't umount +EROFS: True +too many devices mounted diff --git a/tests/extmod/vfs_fat_oldproto.py b/tests/extmod/vfs_fat_oldproto.py new file mode 100644 index 0000000000..73983567d9 --- /dev/null +++ b/tests/extmod/vfs_fat_oldproto.py @@ -0,0 +1,63 @@ +import sys +import uos +import uerrno +try: + uos.VfsFat + uos.vfs_mkfs + uos.vfs_mount +except AttributeError: + print("SKIP") + sys.exit() + +class RAMFS_OLD: + + SEC_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.SEC_SIZE) + + def readblocks(self, n, buf): + #print("readblocks(%s, %x(%d))" % (n, id(buf), len(buf))) + for i in range(len(buf)): + buf[i] = self.data[n * self.SEC_SIZE + i] + + def writeblocks(self, n, buf): + #print("writeblocks(%s, %x)" % (n, id(buf))) + for i in range(len(buf)): + self.data[n * self.SEC_SIZE + i] = buf[i] + + def sync(self): + pass + + def count(self): + return len(self.data) // self.SEC_SIZE + + +try: + bdev = RAMFS_OLD(48) +except MemoryError: + print("SKIP") + sys.exit() + +uos.vfs_mkfs(bdev, "/ramdisk") +uos.vfs_mount(bdev, "/ramdisk") + +# file io +vfs = uos.VfsFat(bdev, "/ramdisk") +with vfs.open("file.txt", "w") as f: + f.write("hello!") + +print(vfs.listdir()) + +with vfs.open("file.txt", "r") as f: + print(f.read()) + +vfs.remove("file.txt") +print(vfs.listdir()) + +# umount by device +uos.vfs_umount(bdev) +try: + vfs.listdir() +except OSError as e: + print(e.args[0] == uerrno.ENODEV) diff --git a/tests/extmod/vfs_fat_oldproto.py.exp b/tests/extmod/vfs_fat_oldproto.py.exp new file mode 100644 index 0000000000..4120c277ac --- /dev/null +++ b/tests/extmod/vfs_fat_oldproto.py.exp @@ -0,0 +1,4 @@ +['file.txt'] +hello! +[] +True diff --git a/tests/extmod/vfs_fat_ramdisk.py b/tests/extmod/vfs_fat_ramdisk.py index 6380761c6d..184672ff15 100644 --- a/tests/extmod/vfs_fat_ramdisk.py +++ b/tests/extmod/vfs_fat_ramdisk.py @@ -45,55 +45,38 @@ print(b"FOO_FILETXT" not in bdev.data) print(b"hello!" not in bdev.data) vfs = uos.VfsFat(bdev, "/ramdisk") -print("statvfs:", vfs.statvfs("/ramdisk")) +try: + vfs.statvfs("/null") +except OSError as e: + print(e.args[0] == uerrno.ENODEV) + +print("statvfs:", vfs.statvfs("/ramdisk")) print("getcwd:", vfs.getcwd()) -f = vfs.open("foo_file.txt", "w") -f.write("hello!") -f.close() +try: + vfs.stat("no_file.txt") +except OSError as e: + print(e.args[0] == uerrno.ENOENT) -f2 = vfs.open("foo_file.txt") -print(f2.read()) -f2.close() +with vfs.open("foo_file.txt", "w") as f: + f.write("hello!") +print(vfs.listdir()) + +print("stat root:", vfs.stat("/")) +print("stat disk:", vfs.stat("/ramdisk/")) +print("stat file:", vfs.stat("foo_file.txt")) print(b"FOO_FILETXT" in bdev.data) print(b"hello!" in bdev.data) -print(vfs.listdir()) - -try: - vfs.rmdir("foo_file.txt") -except OSError as e: - print(e.args[0] == 20) # uerrno.ENOTDIR - -vfs.remove('foo_file.txt') -print(vfs.listdir()) - vfs.mkdir("foo_dir") -print(vfs.listdir()) - -try: - vfs.remove("foo_dir") -except OSError as e: - print(e.args[0] == uerrno.EISDIR) - -f = vfs.open("foo_dir/file-in-dir.txt", "w") -f.write("data in file") -f.close() - -print(vfs.listdir("foo_dir")) - -vfs.rename("foo_dir/file-in-dir.txt", "moved-to-root.txt") -print(vfs.listdir()) - vfs.chdir("foo_dir") print("getcwd:", vfs.getcwd()) print(vfs.listdir()) with vfs.open("sub_file.txt", "w") as f: - f.write("test2") -print(vfs.listdir()) + f.write("subdir file") try: vfs.chdir("sub_file.txt") @@ -103,20 +86,16 @@ except OSError as e: vfs.chdir("..") print("getcwd:", vfs.getcwd()) -try: - vfs.rmdir("foo_dir") -except OSError as e: - print(e.args[0] == uerrno.EACCES) - -vfs.remove("foo_dir/sub_file.txt") -vfs.rmdir("foo_dir") -print(vfs.listdir()) - vfs.umount() try: vfs.listdir() except OSError as e: print(e.args[0] == uerrno.ENODEV) +try: + vfs.getcwd() +except OSError as e: + print(e.args[0] == uerrno.ENODEV) + vfs = uos.VfsFat(bdev, "/ramdisk") -print(vfs.listdir()) +print(vfs.listdir(b"")) diff --git a/tests/extmod/vfs_fat_ramdisk.py.exp b/tests/extmod/vfs_fat_ramdisk.py.exp index 8a498b2fc4..eaf6371998 100644 --- a/tests/extmod/vfs_fat_ramdisk.py.exp +++ b/tests/extmod/vfs_fat_ramdisk.py.exp @@ -1,23 +1,19 @@ True True +True statvfs: (512, 512, 14, 14, 14, 0, 0, 0, 0, 255) getcwd: /ramdisk -hello! -True True ['foo_file.txt'] +stat root: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) +stat disk: (16384, 0, 0, 0, 0, 0, 0, 0, 0, 0) +stat file: (32768, 0, 0, 0, 0, 0, 6, -631238400, -631238400, -631238400) True -[] -['foo_dir'] True -['file-in-dir.txt'] -['foo_dir', 'moved-to-root.txt'] getcwd: /ramdisk/foo_dir [] -['sub_file.txt'] True getcwd: /ramdisk True -['moved-to-root.txt'] True -['moved-to-root.txt'] +[b'foo_file.txt', b'foo_dir'] diff --git a/tools/check_code_size.sh b/tools/check_code_size.sh new file mode 100755 index 0000000000..c5f0c6ffdd --- /dev/null +++ b/tools/check_code_size.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# +# This script check that changes don't lead to code size regressions. +# (Size of the language core (== minimal port should not grow)). +# + +REFERENCE=$HOME/persist/firmware.bin +#REFERENCE=/tmp/micropython +#TRAVIS_PULL_REQUEST=false + +if [ -f $REFERENCE ]; then + size_old=$(stat -c%s $REFERENCE) + size_new=$(stat -c%s minimal/build/firmware.bin) + echo "Old size: $size_old new size: $size_new" + if [ $size_new -gt $size_old ]; then + echo "Validation failure: Core code size increased" + if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then + exit 1 + fi + fi +else + echo "Warning: reference file doesn't exist, code size check didn't run" +fi diff --git a/tools/micropython-upip-1.1.3.tar.gz b/tools/micropython-upip-1.1.3.tar.gz deleted file mode 100644 index 90f726d862..0000000000 Binary files a/tools/micropython-upip-1.1.3.tar.gz and /dev/null differ diff --git a/tools/pip-micropython b/tools/pip-micropython deleted file mode 100755 index c7b23f1b6d..0000000000 --- a/tools/pip-micropython +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/sh -# -# This tool can be used to install a new package into MicroPython -# library location (for unix port, default behavior), or produce -# complete library snapshot to be deployed on a device for baremetal -# ports (if PIP_MICROPY_DEST environment var is set). -# -# Note: this tool is deprecated in favor of "upip" native MicroPython -# package manager, which is bundled with MicroPython unix binary -# as a frozen module and can be run as "micropython -u pip" or installed -# from PyPI package "micropython-upip". This utility is left for -# reference, regression testing, debugging, etc. -# - -if [ "$1" != "install" ]; then - echo "Only install command is supported currently" - exit 1 -fi -shift - -if [ -z "$TMPDIR" ]; then - TMPDIR=/tmp -fi -TMPVENV="$TMPDIR/pip-micropy-venv" - -if [ -n "$PIP_MICROPY_DEST" ]; then - dest="$PIP_MICROPY_DEST" - echo "Destination snapshot directory: $dest" -elif [ -n "$MICROPYPATH" ]; then - libdest=$(echo "$MICROPYPATH" | awk -F: ' {print $1}') - echo "Destination library directory: $libdest" -else - echo "Warning: MICROPYPATH is not set, assuming default value" - libdest=~/.micropython/lib - echo "Destination library directory: $libdest" -fi - -# Due to bugs in pip, installation should happen with active virtualenv -# The issue (at least with pip 1.0 which is still what's shipped with many -# distros) is that even if --ignore-installed is used, package is not -# installed if it's already installed for main python distribution. -if [ ! -d "$TMPVENV" ]; then - virtualenv --no-site-packages "$TMPVENV" - # distutils, setuptools, pip are buggy and allow target packages affect - # their execution environment. For example, if distribution they install - # has re.py, they will import that instead of system re. So, we need - # to remove current dir from sys.path, but that appear to be quite uneasy - # with CPython, so we hook __import__ and exterminate it persistently. - # See also https://bitbucket.org/pypa/setuptools/issue/187/ - cat > $(ls -1d "$TMPVENV"/lib/python*/)/sitecustomize.py <` argument... # currently these tests are selected because they pass on qemu-arm -test_dirs = ('basics', 'micropython', 'extmod', 'inlineasm') # 'float', 'import', 'io', 'misc') +test_dirs = ('basics', 'micropython', 'float', 'extmod', 'inlineasm') # 'import', 'io', 'misc') exclude_tests = ( + 'float/float2int_doubleprec.py', # requires double precision floating point to work 'inlineasm/asmfpaddsub.py', 'inlineasm/asmfpcmp.py', 'inlineasm/asmfpldrstr.py', 'inlineasm/asmfpmuldiv.py', 'inlineasm/asmfpsqrt.py', - 'extmod/time_ms_us.py', - 'extmod/ujson_dumps_float.py', 'extmod/ujson_loads_float.py', - 'extmod/uctypes_native_float.py', 'extmod/uctypes_le_float.py', + 'extmod/ticks_diff.py', 'extmod/time_ms_us.py', 'extmod/machine_pinbase.py', 'extmod/machine_pulse.py', - 'extmod/vfs_fat_ramdisk.py', + 'extmod/vfs_fat_ramdisk.py', 'extmod/vfs_fat_fileio.py', 'extmod/vfs_fat_fsusermount.py', 'extmod/vfs_fat_oldproto.py', ) output = [] diff --git a/tools/upip.py b/tools/upip.py new file mode 100644 index 0000000000..db18a7427e --- /dev/null +++ b/tools/upip.py @@ -0,0 +1,288 @@ +import sys +import gc +import uos as os +import uerrno as errno +import ujson as json +import uzlib +import upip_utarfile as tarfile +gc.collect() + + +debug = False +install_path = None +cleanup_files = [] +gzdict_sz = 16 + 15 + +file_buf = bytearray(512) + +class NotFoundError(Exception): + pass + +def op_split(path): + if path == "": + return ("", "") + r = path.rsplit("/", 1) + if len(r) == 1: + return ("", path) + head = r[0] + if not head: + head = "/" + return (head, r[1]) + +def op_basename(path): + return op_split(path)[1] + +# Expects *file* name +def _makedirs(name, mode=0o777): + ret = False + s = "" + comps = name.rstrip("/").split("/")[:-1] + if comps[0] == "": + s = "/" + for c in comps: + if s and s[-1] != "/": + s += "/" + s += c + try: + os.mkdir(s) + ret = True + except OSError as e: + if e.args[0] != errno.EEXIST and e.args[0] != errno.EISDIR: + raise + ret = False + return ret + + +def save_file(fname, subf): + global file_buf + with open(fname, "wb") as outf: + while True: + sz = subf.readinto(file_buf) + if not sz: + break + outf.write(file_buf, sz) + +def install_tar(f, prefix): + meta = {} + for info in f: + #print(info) + fname = info.name + try: + fname = fname[fname.index("/") + 1:] + except ValueError: + fname = "" + + save = True + for p in ("setup.", "PKG-INFO", "README"): + #print(fname, p) + if fname.startswith(p) or ".egg-info" in fname: + if fname.endswith("/requires.txt"): + meta["deps"] = f.extractfile(info).read() + save = False + if debug: + print("Skipping", fname) + break + + if save: + outfname = prefix + fname + if info.type != tarfile.DIRTYPE: + if debug: + print("Extracting " + outfname) + _makedirs(outfname) + subf = f.extractfile(info) + save_file(outfname, subf) + return meta + +def expandhome(s): + if "~/" in s: + h = os.getenv("HOME") + s = s.replace("~/", h + "/") + return s + +import ussl +import usocket +warn_ussl = True +def url_open(url): + global warn_ussl + proto, _, host, urlpath = url.split('/', 3) + ai = usocket.getaddrinfo(host, 443) + #print("Address infos:", ai) + addr = ai[0][4] + + s = usocket.socket(ai[0][0]) + #print("Connect address:", addr) + s.connect(addr) + + if proto == "https:": + s = ussl.wrap_socket(s) + if warn_ussl: + print("Warning: %s SSL certificate is not validated" % host) + warn_ussl = False + + # MicroPython rawsocket module supports file interface directly + s.write("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n" % (urlpath, host)) + l = s.readline() + protover, status, msg = l.split(None, 2) + if status != b"200": + if status == b"404": + print("Package not found") + raise ValueError(status) + while 1: + l = s.readline() + if not l: + raise ValueError("Unexpected EOF") + if l == b'\r\n': + break + + return s + + +def get_pkg_metadata(name): + f = url_open("https://pypi.python.org/pypi/%s/json" % name) + s = f.read() + f.close() + return json.loads(s) + + +def fatal(msg): + print(msg) + sys.exit(1) + +def install_pkg(pkg_spec, install_path): + data = get_pkg_metadata(pkg_spec) + + latest_ver = data["info"]["version"] + packages = data["releases"][latest_ver] + del data + gc.collect() + assert len(packages) == 1 + package_url = packages[0]["url"] + print("Installing %s %s from %s" % (pkg_spec, latest_ver, package_url)) + package_fname = op_basename(package_url) + f1 = url_open(package_url) + f2 = uzlib.DecompIO(f1, gzdict_sz) + f3 = tarfile.TarFile(fileobj=f2) + meta = install_tar(f3, install_path) + f1.close() + del f3 + del f2 + gc.collect() + return meta + +def install(to_install, install_path=None): + # Calculate gzip dictionary size to use + global gzdict_sz + sz = gc.mem_free() + gc.mem_alloc() + if sz <= 65536: + gzdict_sz = 16 + 12 + + if install_path is None: + install_path = get_install_path() + if install_path[-1] != "/": + install_path += "/" + if not isinstance(to_install, list): + to_install = [to_install] + print("Installing to: " + install_path) + # sets would be perfect here, but don't depend on them + installed = [] + try: + while to_install: + if debug: + print("Queue:", to_install) + pkg_spec = to_install.pop(0) + if pkg_spec in installed: + continue + meta = install_pkg(pkg_spec, install_path) + installed.append(pkg_spec) + if debug: + print(meta) + deps = meta.get("deps", "").rstrip() + if deps: + deps = deps.decode("utf-8").split("\n") + to_install.extend(deps) + except NotFoundError: + print("Error: cannot find '%s' package (or server error), packages may be partially installed" \ + % pkg_spec, file=sys.stderr) + +def get_install_path(): + global install_path + if install_path is None: + # sys.path[0] is current module's path + install_path = sys.path[1] + install_path = expandhome(install_path) + return install_path + +def cleanup(): + for fname in cleanup_files: + try: + os.unlink(fname) + except OSError: + print("Warning: Cannot delete " + fname) + +def help(): + print("""\ +upip - Simple PyPI package manager for MicroPython +Usage: micropython -m upip install [-p ] ... | -r +import upip; upip.install(package_or_list, []) + +If is not given, packages will be installed into sys.path[1] +(can be set from MICROPYPATH environment variable, if current system +supports that).""") + print("Current value of sys.path[1]:", sys.path[1]) + print("""\ + +Note: only MicroPython packages (usually, named micropython-*) are supported +for installation, upip does not support arbitrary code in setup.py. +""") + +def main(): + global debug + global install_path + install_path = None + + if len(sys.argv) < 2 or sys.argv[1] == "-h" or sys.argv[1] == "--help": + help() + return + + if sys.argv[1] != "install": + fatal("Only 'install' command supported") + + to_install = [] + + i = 2 + while i < len(sys.argv) and sys.argv[i][0] == "-": + opt = sys.argv[i] + i += 1 + if opt == "-h" or opt == "--help": + help() + return + elif opt == "-p": + install_path = sys.argv[i] + i += 1 + elif opt == "-r": + list_file = sys.argv[i] + i += 1 + with open(list_file) as f: + while True: + l = f.readline() + if not l: + break + to_install.append(l.rstrip()) + elif opt == "--debug": + debug = True + else: + fatal("Unknown/unsupported option: " + opt) + + to_install.extend(sys.argv[i:]) + if not to_install: + help() + return + + install(to_install) + + if not debug: + cleanup() + + +if __name__ == "__main__": + main() diff --git a/tools/upip_utarfile.py b/tools/upip_utarfile.py new file mode 100644 index 0000000000..65ce0bdca8 --- /dev/null +++ b/tools/upip_utarfile.py @@ -0,0 +1,94 @@ +import uctypes + +# http://www.gnu.org/software/tar/manual/html_node/Standard.html +TAR_HEADER = { + "name": (uctypes.ARRAY | 0, uctypes.UINT8 | 100), + "size": (uctypes.ARRAY | 124, uctypes.UINT8 | 12), +} + +DIRTYPE = "dir" +REGTYPE = "file" + +def roundup(val, align): + return (val + align - 1) & ~(align - 1) + +class FileSection: + + def __init__(self, f, content_len, aligned_len): + self.f = f + self.content_len = content_len + self.align = aligned_len - content_len + + def read(self, sz=65536): + if self.content_len == 0: + return b"" + if sz > self.content_len: + sz = self.content_len + data = self.f.read(sz) + sz = len(data) + self.content_len -= sz + return data + + def readinto(self, buf): + if self.content_len == 0: + return 0 + if len(buf) > self.content_len: + buf = memoryview(buf)[:self.content_len] + sz = self.f.readinto(buf) + self.content_len -= sz + return sz + + def skip(self): + sz = self.content_len + self.align + if sz: + buf = bytearray(16) + while sz: + s = min(sz, 16) + self.f.readinto(buf, s) + sz -= s + +class TarInfo: + + def __str__(self): + return "TarInfo(%r, %s, %d)" % (self.name, self.type, self.size) + +class TarFile: + + def __init__(self, name=None, fileobj=None): + if fileobj: + self.f = fileobj + else: + self.f = open(name, "rb") + self.subf = None + + def next(self): + if self.subf: + self.subf.skip() + buf = self.f.read(512) + if not buf: + return None + + h = uctypes.struct(uctypes.addressof(buf), TAR_HEADER, uctypes.LITTLE_ENDIAN) + + # Empty block means end of archive + if h.name[0] == 0: + return None + + d = TarInfo() + d.name = str(h.name, "utf-8").rstrip() + d.size = int(bytes(h.size).rstrip(), 8) + d.type = [REGTYPE, DIRTYPE][d.name[-1] == "/"] + self.subf = d.subf = FileSection(self.f, d.size, roundup(d.size, 512)) + return d + + def __iter__(self): + return self + + def __next__(self): + v = self.next() + if v is None: + raise StopIteration + return v + + def extractfile(self, tarinfo): + return tarinfo.subf diff --git a/unix/Makefile b/unix/Makefile index 53ff4cb487..5e212ff709 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -1,6 +1,8 @@ -include mpconfigport.mk include ../py/mkenv.mk +FROZEN_DIR = scripts + # define main target PROG = micropython @@ -58,10 +60,14 @@ endif # On OSX, 'gcc' is a symlink to clang unless a real gcc is installed. # The unix port of micropython on OSX must be compiled with clang, -# while cross-compile ports require gcc, so we test here for OSX and +# while cross-compile ports require gcc, so we test here for OSX and # if necessary override the value of 'CC' set in py/mkenv.mk ifeq ($(UNAME_S),Darwin) +ifeq ($(MICROPY_FORCE_32BIT),1) +CC = clang -m32 +else CC = clang +endif # Use clang syntax for map file LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip else @@ -144,17 +150,6 @@ SRC_C = \ fatfs_port.c \ $(SRC_MOD) -# Include builtin package manager in the standard build (and coverage) -ifeq ($(PROG),micropython) -SRC_C += $(BUILD)/_frozen_upip.c -else ifeq ($(PROG),micropython_coverage) -SRC_C += $(BUILD)/_frozen_upip.c -else ifeq ($(PROG), micropython_nanbox) -SRC_C += $(BUILD)/_frozen_upip.c -else ifeq ($(PROG), micropython_freedos) -SRC_C += $(BUILD)/_frozen_upip.c -endif - LIB_SRC_C = $(addprefix lib/,\ $(LIB_SRC_C_EXTRA) \ timeutils/timeutils.c \ @@ -180,26 +175,10 @@ SRC_QSTR_AUTO_DEPS += ifneq ($(FROZEN_MPY_DIR),) # To use frozen bytecode, put your .py files in a subdirectory (eg frozen/) and # then invoke make with FROZEN_MPY_DIR=frozen (be sure to build from scratch). -MPY_CROSS = ../mpy-cross/mpy-cross -MPY_TOOL = ../tools/mpy-tool.py -FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') -FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool CFLAGS += -DMICROPY_MODULE_FROZEN_MPY CFLAGS += -DMICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE=0 # not supported CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs -OBJ += $(BUILD)/$(BUILD)/frozen_mpy.o - -# to build .mpy files from .py files -$(BUILD)/$(FROZEN_MPY_DIR)/%.mpy: $(FROZEN_MPY_DIR)/%.py - @$(ECHO) "MPY $<" - $(Q)$(MKDIR) -p $(dir $@) - $(Q)$(MPY_CROSS) -o $@ -s $(^:$(FROZEN_MPY_DIR)/%=%) $^ - -# to build frozen_mpy.c from all .mpy files -$(BUILD)/frozen_mpy.c: $(FROZEN_MPY_MPY_FILES) $(BUILD)/genhdr/qstrdefs.generated.h - @$(ECHO) "Creating $@" - $(Q)$(PYTHON) $(MPY_TOOL) -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h $(FROZEN_MPY_MPY_FILES) > $@ endif @@ -215,18 +194,14 @@ test: $(PROG) ../tests/run-tests TARGET = micropython PREFIX = $(DESTDIR)/usr/local BINDIR = $(PREFIX)/bin -PIPSRC = ../tools/pip-micropython -PIPTARGET = pip-micropython install: micropython install -d $(BINDIR) install $(TARGET) $(BINDIR)/$(TARGET) - install $(PIPSRC) $(BINDIR)/$(PIPTARGET) # uninstall micropython uninstall: -rm $(BINDIR)/$(TARGET) - -rm $(BINDIR)/$(PIPTARGET) # build synthetically fast interpreter for benchmarking fast: @@ -235,7 +210,7 @@ fast: # build a minimal interpreter minimal: $(MAKE) COPT="-Os -DNDEBUG" CFLAGS_EXTRA='-DMP_CONFIGFILE=""' \ - BUILD=build-minimal PROG=micropython_minimal \ + BUILD=build-minimal PROG=micropython_minimal FROZEN_DIR= \ MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 MICROPY_PY_SOCKET=0 MICROPY_PY_THREAD=0 \ MICROPY_PY_TERMIOS=0 MICROPY_PY_USSL=0 \ MICROPY_USE_READLINE=0 MICROPY_FATFS=0 @@ -272,22 +247,6 @@ coverage_test: coverage gcov -o build-coverage/py ../py/*.c gcov -o build-coverage/extmod ../extmod/*.c -$(BUILD)/_frozen_upip.c: $(BUILD)/frozen_upip/upip.py - $(MAKE_FROZEN) $(dir $^) > $@ - -# Select latest upip version available -UPIP_TARBALL := $(shell ls -1 -v ../tools/micropython-upip-*.tar.gz | tail -n1) - -$(BUILD)/frozen_upip/upip.py: $(UPIP_TARBALL) - $(ECHO) "MISC Preparing upip as frozen module" - $(Q)mkdir -p $(BUILD) - $(Q)rm -rf $(BUILD)/micropython-upip-* - $(Q)tar -C $(BUILD) -xz -f $^ - $(Q)rm -rf $(dir $@) - $(Q)mkdir -p $(dir $@) - $(Q)cp $(BUILD)/micropython-upip-*/upip*.py $(dir $@) - - # Value of configure's --host= option (required for cross-compilation). # Deduce it from CROSS_COMPILE by default, but can be overriden. ifneq ($(CROSS_COMPILE),) diff --git a/unix/gccollect.c b/unix/gccollect.c index 397c4ffe1c..4ec8c2bf54 100644 --- a/unix/gccollect.c +++ b/unix/gccollect.c @@ -80,6 +80,18 @@ STATIC void gc_helper_get_regs(regs_t arr) { register long esi asm ("esi"); register long edi asm ("edi"); register long ebp asm ("ebp"); +#ifdef __clang__ + // TODO: + // This is dirty workaround for Clang. It tries to get around + // uncompliant (wrt to GCC) behavior of handling register variables. + // Application of this patch here is random, and done only to unbreak + // MacOS build. Better, cross-arch ways to deal with Clang issues should + // be found. + asm("" : "=r"(ebx)); + asm("" : "=r"(esi)); + asm("" : "=r"(edi)); + asm("" : "=r"(ebp)); +#endif arr[0] = ebx; arr[1] = esi; arr[2] = edi; diff --git a/unix/main.c b/unix/main.c index a1c057400f..482d1944e2 100644 --- a/unix/main.c +++ b/unix/main.c @@ -461,7 +461,7 @@ MP_NOINLINE int main_(int argc, char **argv) { #if defined(MICROPY_UNIX_COVERAGE) { - MP_DECLARE_CONST_FUN_OBJ(extra_coverage_obj); + MP_DECLARE_CONST_FUN_OBJ_0(extra_coverage_obj); mp_store_global(QSTR_FROM_STR_STATIC("extra_coverage"), MP_OBJ_FROM_PTR(&extra_coverage_obj)); } #endif diff --git a/unix/modos.c b/unix/modos.c index 36945720d1..72f5d872e4 100644 --- a/unix/modos.c +++ b/unix/modos.c @@ -43,9 +43,9 @@ // Can't include this, as FATFS structure definition is required, // and FatFs header defining it conflicts with POSIX. //#include "extmod/fsusermount.h" -MP_DECLARE_CONST_FUN_OBJ(fsuser_mount_obj); -MP_DECLARE_CONST_FUN_OBJ(fsuser_umount_obj); -MP_DECLARE_CONST_FUN_OBJ(fsuser_mkfs_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(fsuser_mount_obj); +MP_DECLARE_CONST_FUN_OBJ_1(fsuser_umount_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(fsuser_mkfs_obj); extern const mp_obj_type_t mp_fat_vfs_type; #ifdef __ANDROID__ diff --git a/unix/modtime.c b/unix/modtime.c index 8d6d9f4d7e..85d1f55327 100644 --- a/unix/modtime.c +++ b/unix/modtime.c @@ -37,6 +37,7 @@ #include "py/runtime.h" #include "py/smallint.h" #include "py/mphal.h" +#include "extmod/utime_mphal.h" #ifdef _WIN32 static inline int msec_sleep_tv(struct timeval *tv) { @@ -76,29 +77,6 @@ STATIC mp_obj_t mod_time_time(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); -STATIC mp_obj_t mod_time_ticks_us(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - mp_uint_t us = tv.tv_sec * 1000000 + tv.tv_usec; - return MP_OBJ_NEW_SMALL_INT(us & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_ticks_us_obj, mod_time_ticks_us); - -STATIC mp_obj_t mod_time_ticks_ms(void) { - struct timeval tv; - gettimeofday(&tv, NULL); - mp_uint_t ms = tv.tv_sec * 1000 + tv.tv_usec / 1000; - return MP_OBJ_NEW_SMALL_INT(ms & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_ticks_ms_obj, mod_time_ticks_ms); - -STATIC mp_obj_t mod_time_ticks_diff(mp_obj_t oldval, mp_obj_t newval) { - mp_uint_t old = MP_OBJ_SMALL_INT_VALUE(oldval); - mp_uint_t new = MP_OBJ_SMALL_INT_VALUE(newval); - return MP_OBJ_NEW_SMALL_INT((new - old) & MP_SMALL_INT_POSITIVE_MASK); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_time_ticks_diff_obj, mod_time_ticks_diff); - // Note: this is deprecated since CPy3.3, but pystone still uses it. STATIC mp_obj_t mod_time_clock(void) { #if MICROPY_PY_BUILTINS_FLOAT @@ -149,22 +127,6 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_obj, mod_time_sleep); -STATIC mp_obj_t mod_time_sleep_ms(mp_obj_t arg) { - MP_THREAD_GIL_EXIT(); - usleep(mp_obj_get_int(arg) * 1000); - MP_THREAD_GIL_ENTER(); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_ms_obj, mod_time_sleep_ms); - -STATIC mp_obj_t mod_time_sleep_us(mp_obj_t arg) { - MP_THREAD_GIL_EXIT(); - usleep(mp_obj_get_int(arg)); - MP_THREAD_GIL_ENTER(); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_time_sleep_us_obj, mod_time_sleep_us); - STATIC mp_obj_t mod_time_strftime(size_t n_args, const mp_obj_t *args) { time_t t; if (n_args == 1) { @@ -185,12 +147,14 @@ STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, { MP_ROM_QSTR(MP_QSTR_clock), MP_ROM_PTR(&mod_time_clock_obj) }, { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mod_time_sleep_obj) }, - { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mod_time_sleep_ms_obj) }, - { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mod_time_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) }, - { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mod_time_ticks_ms_obj) }, - { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mod_time_ticks_us_obj) }, - { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mod_time_ticks_diff_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, { MP_ROM_QSTR(MP_QSTR_strftime), MP_ROM_PTR(&mod_time_strftime_obj) }, }; diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 56cfaa2ac1..f4f8d2d208 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -106,6 +106,7 @@ #define MICROPY_PY_OS_STATVFS (1) #define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_UERRNO (1) #define MICROPY_PY_UCTYPES (1) #define MICROPY_PY_UZLIB (1) diff --git a/unix/mphalport.h b/unix/mphalport.h index e440eafd4e..00e79ec17c 100644 --- a/unix/mphalport.h +++ b/unix/mphalport.h @@ -34,8 +34,11 @@ void mp_hal_set_interrupt_char(char c); void mp_hal_stdio_mode_raw(void); void mp_hal_stdio_mode_orig(void); +// TODO: POSIX et al. define usleep() as guaranteedly capable only of 1s sleep: +// "The useconds argument shall be less than one million." static inline void mp_hal_delay_ms(mp_uint_t ms) { usleep((ms) * 1000); } static inline void mp_hal_delay_us(mp_uint_t us) { usleep(us); } +#define mp_hal_ticks_cpu() 0 #define RAISE_ERRNO(err_flag, error_val) \ { if (err_flag == -1) \ diff --git a/unix/scripts/upip.py b/unix/scripts/upip.py new file mode 120000 index 0000000000..20d52a4ab7 --- /dev/null +++ b/unix/scripts/upip.py @@ -0,0 +1 @@ +../../tools/upip.py \ No newline at end of file diff --git a/unix/scripts/upip_utarfile.py b/unix/scripts/upip_utarfile.py new file mode 120000 index 0000000000..1498862916 --- /dev/null +++ b/unix/scripts/upip_utarfile.py @@ -0,0 +1 @@ +../../tools/upip_utarfile.py \ No newline at end of file diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index da49bc0dcb..88596977cf 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -92,6 +92,7 @@ #define MICROPY_PY_UBINASCII (1) #define MICROPY_PY_URANDOM (1) #define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_MACHINE (1) #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) diff --git a/windows/msvc/sources.props b/windows/msvc/sources.props index 569f24c76b..4ea917552a 100644 --- a/windows/msvc/sources.props +++ b/windows/msvc/sources.props @@ -23,6 +23,7 @@ + diff --git a/windows/windows_mphal.c b/windows/windows_mphal.c index 6cc4f65428..3ad6939059 100644 --- a/windows/windows_mphal.c +++ b/windows/windows_mphal.c @@ -28,6 +28,7 @@ #include "py/mpstate.h" #include "py/mphal.h" +#include #include #include @@ -204,3 +205,25 @@ void mp_hal_stdout_tx_strn_cooked(const char *str, size_t len) { void mp_hal_stdout_tx_str(const char *str) { mp_hal_stdout_tx_strn(str, strlen(str)); } + +mp_uint_t mp_hal_ticks_ms(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +mp_uint_t mp_hal_ticks_us(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000 + tv.tv_usec; +} + +mp_uint_t mp_hal_ticks_cpu(void) { + LARGE_INTEGER value; + QueryPerformanceCounter(&value); +#ifdef _WIN64 + return value.QuadPart; +#else + return value.LowPart; +#endif +} diff --git a/windows/windows_mphal.h b/windows/windows_mphal.h index dce2484550..854e14a7a8 100644 --- a/windows/windows_mphal.h +++ b/windows/windows_mphal.h @@ -31,3 +31,6 @@ void mp_hal_move_cursor_back(unsigned int pos); void mp_hal_erase_line_from_cursor(unsigned int n_chars_to_erase); + +#undef mp_hal_ticks_cpu +mp_uint_t mp_hal_ticks_cpu(void); diff --git a/zephyr/Makefile b/zephyr/Makefile index 1db84cb320..9ddf121250 100644 --- a/zephyr/Makefile +++ b/zephyr/Makefile @@ -1,20 +1,22 @@ # -# This is main Makefile, which uses MicroPython build system, but -# Zephyr arch-specific toolchain (setup by Zephyr's Makefile.toolchain.*). -# Unfortunately, it's currently not possible to get target (as in: specific -# board to run on) specific compile-time options from Zephyr, so these must -# be set (duplicated) in this Makefile. Currently, these configured for -# ARM Cortex-M3. This Makefile builds MicroPython as a library, and then -# calls recursively Makefile.zephyr to build complete application using -# Zephyr build system. +# This is the main Makefile, which uses MicroPython build system, +# but Zephyr arch-specific toolchain and target-specific flags. +# This Makefile builds MicroPython as a library, and then calls +# recursively Makefile.zephyr to build complete application binary +# using Zephyr build system. # BOARD ?= qemu_x86 +CONF_FILE = prj.conf # Zephyr 1.5.0 #OUTDIR_PREFIX = # Zephyr 1.6.0 OUTDIR_PREFIX = $(BOARD) +# Default heap size is 16KB, which is on conservative side, to let +# it build for smaller boards, but it won't be enough for larger +# applications, and will need to be increased. +MICROPY_HEAP_SIZE = 16384 FROZEN_DIR = scripts # Zephyr (generated) config files - must be defined before include below @@ -34,6 +36,9 @@ INC += -I$(ZEPHYR_BASE)/net/ip/contiki/os SRC_C = main.c \ help.c \ + modutime.c \ + modmachine.c \ + machine_pin.c \ uart_core.c \ lib/utils/stdout_helpers.c \ lib/utils/printf.c \ @@ -41,7 +46,6 @@ SRC_C = main.c \ lib/utils/interrupt_char.c \ lib/utils/pyhelp.c \ lib/mp-readline/readline.c \ - $(BUILD)/frozen.c \ $(SRC_MOD) # List of sources for qstr extraction @@ -50,12 +54,12 @@ SRC_QSTR += $(SRC_C) OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) CFLAGS = $(KBUILD_CFLAGS) $(NOSTDINC_FLAGS) $(ZEPHYRINCLUDE) \ - -std=gnu99 -DNDEBUG $(INC) + -std=gnu99 -fomit-frame-pointer -DNDEBUG -DMICROPY_HEAP_SIZE=$(MICROPY_HEAP_SIZE) $(CFLAGS_EXTRA) $(INC) include ../py/mkrules.mk $(Z_EXPORTS): - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) initconfig outputexports + $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) initconfig outputexports GENERIC_TARGETS = all zephyr qemu qemugdb flash debug KCONFIG_TARGETS = \ @@ -70,14 +74,17 @@ $(CLEAN_TARGETS): clean $(GENERIC_TARGETS) $(KCONFIG_TARGETS) $(CLEAN_TARGETS): $(RM) -f outdir/$(OUTDIR_PREFIX)/zephyr.lnk - $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) $@ + $(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) $@ $(LIBMICROPYTHON): $(Z_SYSGEN_H) build/genhdr/qstr.i.last: $(Z_SYSGEN_H) $(Z_SYSGEN_H): rm -f $(LIBMICROPYTHON) - -$(MAKE) -f Makefile.zephyr BOARD=$(BOARD) + -$(MAKE) -f Makefile.zephyr BOARD=$(BOARD) CONF_FILE=$(CONF_FILE) + +minimal: + $(MAKE) BOARD=$(BOARD) CFLAGS_EXTRA='-DMP_CONFIGFILE=""' FROZEN_DIR= # Clean Zephyr things too clean: z_clean diff --git a/zephyr/README.md b/zephyr/README.md index 63fb0e39f4..30f668bb4a 100644 --- a/zephyr/README.md +++ b/zephyr/README.md @@ -6,12 +6,20 @@ This is an initial port of MicroPython to Zephyr RTOS The port integrates well with Zephyr build system, using the latest features which will be available in 1.6.0, and thus requires Zephyr -master to build against. All boards supported by Zephyr should be -supported (but not all were tested). +master to build against. All boards supported by Zephyr (with standard +level of feature support, like UART console) should work with +MicroPython (but not all were tested). -At this time, only basic interactive prompt (REPL) over UART connection -is supported. Over time, bindings for various Zephyr subsystems may -be added. +Features supported at this time: + +* REPL (interactive prompt) over Zephyr UART console. +* `utime` module for time measurements and delays. +* `machine.Pin` class for GPIO control. +* "Frozen modules" support to allow to bundle Python modules together + with firmware. Including complete applications, including with + run-on-boot capability. + +Over time, bindings for various Zephyr subsystems may be added. Building @@ -36,10 +44,52 @@ supported boards. Running ------- -To run the resulting application in QEMU (for BOARDs like qemu_x86, +To run the resulting firmware in QEMU (for BOARDs like qemu_x86, qemu_cortex_m3): make qemu -For deploying/flashing the application on a real board, follow Zephyr +For deploying/flashing a firmware on a real board, follow Zephyr documentation for a given board. + + +Quick example +------------- + +To blink an LED: + + import time + from machine import Pin + + LED = Pin(("GPIO_1", 21), Pin.OUT) + while True: + LED.value(1) + time.sleep(0.5) + LED.value(0) + time.sleep(0.5) + +The above code uses an LED location for a FRDM-K64F board (port B, pin 21; +following Zephyr conventions port are identified by "GPIO_x", where *x* +starts from 0). You will need to adjust it for another board (using board's +reference materials). To execute the above sample, copy it to clipboard, in +MicroPython REPL enter "paste mode" using Ctrl+E, paste clipboard, press +Ctrl+D to finish paste mode and start execution. + + +Minimal build +------------- + +MicroPython is committed to maintain minimal binary size for Zephyr port +below 128KB, as long as Zephyr project is committed to maintain stable +minimal size of their kernel (which they appear to be). Note that at such +size, there is no support for any Zephyr features beyond REPL over UART, +and only very minimal set of builtin Python modules. Thus, this build +is more suitable for code size control and quick demonstrations even on +smaller systems. It's also suitable for careful enabling of features one +by one to achieve needed functionality and code size. This is in contrast +to the "default" build, which may get more and more features enabled by +default over time. + +To make a minimal build: + + make BOARD= minimal diff --git a/zephyr/machine_pin.c b/zephyr/machine_pin.c new file mode 100644 index 0000000000..049255e9f6 --- /dev/null +++ b/zephyr/machine_pin.c @@ -0,0 +1,180 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014, 2015 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include "py/nlr.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "py/mphal.h" +#include "modmachine.h" + +const mp_obj_base_t machine_pin_obj_template = {&machine_pin_type}; + +STATIC void machine_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + machine_pin_obj_t *self = self_in; + mp_printf(print, "", self->port, self->pin); +} + +// pin.init(mode, pull=None, *, value) +STATIC mp_obj_t machine_pin_obj_init_helper(machine_pin_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_mode, ARG_pull, ARG_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_OBJ, {.u_obj = mp_const_none}}, + { MP_QSTR_value, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get io mode + uint mode = args[ARG_mode].u_int; + + // get pull mode + uint pull = GPIO_PUD_NORMAL; + if (args[ARG_pull].u_obj != mp_const_none) { + pull = mp_obj_get_int(args[ARG_pull].u_obj); + } + + int ret = gpio_pin_configure(self->port, self->pin, mode | pull); + if (ret) { + mp_raise_ValueError("invalid pin"); + } + + // get initial value + if (args[ARG_value].u_obj != MP_OBJ_NULL) { + (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[ARG_value].u_obj)); + } + + return mp_const_none; +} + +// constructor(drv_name, pin, ...) +STATIC mp_obj_t machine_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); + + // get the wanted port + if (!MP_OBJ_IS_TYPE(args[0], &mp_type_tuple)) { + mp_raise_ValueError("Pin id must be tuple of (\"GPIO_x\", pin#)"); + } + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[0], 2, &items); + const char *drv_name = mp_obj_str_get_str(items[0]); + int wanted_pin = mp_obj_get_int(items[1]); + struct device *wanted_port = device_get_binding(drv_name); + if (!wanted_port) { + mp_raise_ValueError("invalid port"); + } + + machine_pin_obj_t *pin = m_new_obj(machine_pin_obj_t); + pin->base = machine_pin_obj_template; + pin->port = wanted_port; + pin->pin = wanted_pin; + + if (n_args > 1 || n_kw > 0) { + // pin mode given, so configure this GPIO + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + machine_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); + } + + return (mp_obj_t)pin; +} + +// fast method for getting/setting pin value +STATIC mp_obj_t machine_pin_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + machine_pin_obj_t *self = self_in; + if (n_args == 0) { + uint32_t pin_val; + (void)gpio_pin_read(self->port, self->pin, &pin_val); + return MP_OBJ_NEW_SMALL_INT(pin_val); + } else { + (void)gpio_pin_write(self->port, self->pin, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +// pin.init(mode, pull) +STATIC mp_obj_t machine_pin_obj_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return machine_pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_init_obj, 1, machine_pin_obj_init); + +// pin.value([value]) +STATIC mp_obj_t machine_pin_value(size_t n_args, const mp_obj_t *args) { + return machine_pin_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_pin_value_obj, 1, 2, machine_pin_value); + +// pin.low() +STATIC mp_obj_t machine_pin_low(mp_obj_t self_in) { + machine_pin_obj_t *self = self_in; + (void)gpio_pin_write(self->port, self->pin, 0); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_low_obj, machine_pin_low); + +// pin.high() +STATIC mp_obj_t machine_pin_high(mp_obj_t self_in) { + machine_pin_obj_t *self = self_in; + (void)gpio_pin_write(self->port, self->pin, 1); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_high_obj, machine_pin_high); + +STATIC const mp_map_elem_t machine_pin_locals_dict_table[] = { + // instance methods + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&machine_pin_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&machine_pin_value_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_low), (mp_obj_t)&machine_pin_low_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_high), (mp_obj_t)&machine_pin_high_obj }, + + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_IN), MP_OBJ_NEW_SMALL_INT(GPIO_DIR_IN) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_OUT), MP_OBJ_NEW_SMALL_INT(GPIO_DIR_OUT) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PUD_PULL_UP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PUD_PULL_DOWN) }, +}; + +STATIC MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); + +const mp_obj_type_t machine_pin_type = { + { &mp_type_type }, + .name = MP_QSTR_Pin, + .print = machine_pin_print, + .make_new = machine_pin_make_new, + .call = machine_pin_call, + .locals_dict = (mp_obj_t)&machine_pin_locals_dict, +}; diff --git a/zephyr/main.c b/zephyr/main.c index 8d319098b2..9146cfadb6 100644 --- a/zephyr/main.c +++ b/zephyr/main.c @@ -58,7 +58,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { } static char *stack_top; -static char heap[16 * 1024]; +static char heap[MICROPY_HEAP_SIZE]; int real_main(void) { int stack_dummy; @@ -72,7 +72,9 @@ int real_main(void) { #endif mp_init(); MP_STATE_PORT(mp_kbd_exception) = mp_obj_new_exception(&mp_type_KeyboardInterrupt); + #if MICROPY_MODULE_FROZEN pyexec_frozen_module("main.py"); + #endif #if MICROPY_REPL_EVENT_DRIVEN pyexec_event_repl_init(); for (;;) { diff --git a/zephyr/modmachine.c b/zephyr/modmachine.c new file mode 100644 index 0000000000..6194a95dad --- /dev/null +++ b/zephyr/modmachine.c @@ -0,0 +1,71 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * Copyright (c) 2016 Paul Sokolovsky + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/machine_mem.h" +#include "extmod/machine_pulse.h" +#include "extmod/machine_i2c.h" +#include "modmachine.h" + +#if MICROPY_PY_MACHINE + +STATIC mp_obj_t machine_reset(void) { + printf("Warning: %s is not implemented\n", __func__); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); + +STATIC mp_obj_t machine_reset_cause(void) { + printf("Warning: %s is not implemented\n", __func__); + return MP_OBJ_NEW_SMALL_INT(42); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_cause_obj, machine_reset_cause); + +STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset_cause), MP_ROM_PTR(&machine_reset_cause_obj) }, + + { MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&machine_pin_type) }, + + // reset causes + /*{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(REASON_DEFAULT_RST) },*/ +}; + +STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table); + +const mp_obj_module_t mp_module_machine = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&machine_module_globals, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/zephyr/modmachine.h b/zephyr/modmachine.h new file mode 100644 index 0000000000..596c59b178 --- /dev/null +++ b/zephyr/modmachine.h @@ -0,0 +1,16 @@ +#ifndef __MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H__ +#define __MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H__ + +#include "py/obj.h" + +extern const mp_obj_type_t machine_pin_type; + +MP_DECLARE_CONST_FUN_OBJ_0(machine_info_obj); + +typedef struct _machine_pin_obj_t { + mp_obj_base_t base; + struct device *port; + uint32_t pin; +} machine_pin_obj_t; + +#endif // __MICROPY_INCLUDED_ZEPHYR_MODMACHINE_H__ diff --git a/zephyr/modutime.c b/zephyr/modutime.c new file mode 100644 index 0000000000..8b96a5ab1e --- /dev/null +++ b/zephyr/modutime.c @@ -0,0 +1,67 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_UTIME + +#include + +#include "py/runtime.h" +#include "py/smallint.h" +#include "py/mphal.h" +#include "extmod/utime_mphal.h" + +STATIC mp_obj_t mod_time_time(void) { + /* The absense of FP support is deliberate. The Zephyr port uses + * single precision floats so the fraction component will start to + * lose precision on devices with a long uptime. + */ + return mp_obj_new_int(sys_tick_get() / sys_clock_ticks_per_sec); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_time_time_obj, mod_time_time); + +STATIC const mp_rom_map_elem_t mp_module_time_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) }, + { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&mod_time_time_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_time_globals, mp_module_time_globals_table); + +const mp_obj_module_t mp_module_time = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_time_globals, +}; + +#endif // MICROPY_PY_UTIME diff --git a/zephyr/mpconfigport.h b/zephyr/mpconfigport.h index 1654e79b8c..e291faf1d6 100644 --- a/zephyr/mpconfigport.h +++ b/zephyr/mpconfigport.h @@ -28,10 +28,10 @@ // Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles #include "autoconf.h" -// Saving extra crumbs to make sure binary fits in 128K -#define MICROPY_COMP_CONST_FOLDING (0) -#define MICROPY_COMP_CONST (0) -#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) +// Usually passed from Makefile +#ifndef MICROPY_HEAP_SIZE +#define MICROPY_HEAP_SIZE (16 * 1024) +#endif #define MICROPY_STACK_CHECK (1) #define MICROPY_ENABLE_GC (1) @@ -53,13 +53,33 @@ #define MICROPY_PY_CMATH (0) #define MICROPY_PY_IO (0) #define MICROPY_PY_MICROPYTHON_MEM_INFO (1) +#define MICROPY_PY_MACHINE (1) +#define MICROPY_MODULE_WEAK_LINKS (1) #define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_UTIME (1) +#define MICROPY_PY_UTIME_MP_HAL (1) #define MICROPY_PY_SYS_MODULES (0) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_PY_BUILTINS_COMPLEX (0) + +// Saving extra crumbs to make sure binary fits in 128K +#define MICROPY_COMP_CONST_FOLDING (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) + +#ifdef CONFIG_BOARD +#define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD +#else #define MICROPY_HW_BOARD_NAME "zephyr-generic" +#endif + +#ifdef CONFIG_SOC +#define MICROPY_HW_MCU_NAME CONFIG_SOC +#else #define MICROPY_HW_MCU_NAME "unknown-cpu" +#endif + #define MICROPY_MODULE_FROZEN_STR (1) typedef int mp_int_t; // must be pointer size @@ -77,6 +97,22 @@ typedef long mp_off_t; mp_obj_t mp_kbd_exception; \ const char *readline_hist[8]; +extern const struct _mp_obj_module_t mp_module_machine; +extern const struct _mp_obj_module_t mp_module_time; + +#if MICROPY_PY_UTIME +#define MICROPY_PY_UTIME_DEF { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_time) }, +#else +#define MICROPY_PY_UTIME_DEF +#endif + +#define MICROPY_PORT_BUILTIN_MODULES \ + { MP_OBJ_NEW_QSTR(MP_QSTR_machine), (mp_obj_t)&mp_module_machine }, \ + MICROPY_PY_UTIME_DEF \ + +#define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ + { MP_OBJ_NEW_QSTR(MP_QSTR_time), MP_ROM_PTR(&mp_module_time) }, \ + // extra built in names to add to the global namespace #define MICROPY_PORT_BUILTINS \ { MP_OBJ_NEW_QSTR(MP_QSTR_help), (mp_obj_t)&mp_builtin_help_obj }, \ diff --git a/zephyr/mpconfigport_minimal.h b/zephyr/mpconfigport_minimal.h new file mode 100644 index 0000000000..6629ffe9c3 --- /dev/null +++ b/zephyr/mpconfigport_minimal.h @@ -0,0 +1,91 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Linaro Limited + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include + +// Include Zephyr's autoconf.h, which should be made first by Zephyr makefiles +#include "autoconf.h" + +// Usually passed from Makefile +#ifndef MICROPY_HEAP_SIZE +#define MICROPY_HEAP_SIZE (16 * 1024) +#endif + +#define MICROPY_STACK_CHECK (1) +#define MICROPY_ENABLE_GC (1) +#define MICROPY_HELPER_REPL (1) +#define MICROPY_REPL_AUTO_INDENT (1) +#define MICROPY_CPYTHON_COMPAT (0) +#define MICROPY_PY_ASYNC_AWAIT (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_BUILTINS_ENUMERATE (0) +#define MICROPY_PY_BUILTINS_FILTER (0) +#define MICROPY_PY_BUILTINS_MIN_MAX (0) +#define MICROPY_PY_BUILTINS_PROPERTY (0) +#define MICROPY_PY_BUILTINS_RANGE_ATTRS (0) +#define MICROPY_PY_BUILTINS_REVERSED (0) +#define MICROPY_PY_BUILTINS_SET (0) +#define MICROPY_PY_BUILTINS_SLICE (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_SYS_MODULES (0) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) +#define MICROPY_PY_BUILTINS_COMPLEX (0) + +// Saving extra crumbs to make sure binary fits in 128K +#define MICROPY_COMP_CONST_FOLDING (0) +#define MICROPY_COMP_CONST (0) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (0) + +#ifdef CONFIG_BOARD +#define MICROPY_HW_BOARD_NAME "zephyr-" CONFIG_BOARD +#else +#define MICROPY_HW_BOARD_NAME "zephyr-generic" +#endif + +#ifdef CONFIG_SOC +#define MICROPY_HW_MCU_NAME CONFIG_SOC +#else +#define MICROPY_HW_MCU_NAME "unknown-cpu" +#endif + +typedef int mp_int_t; // must be pointer size +typedef unsigned mp_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 +typedef long mp_off_t; + +#define BYTES_PER_WORD (sizeof(mp_int_t)) + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_PORT_ROOT_POINTERS \ + mp_obj_t mp_kbd_exception; \ + const char *readline_hist[8]; diff --git a/zephyr/mphalport.h b/zephyr/mphalport.h index 1bb64e0002..fafbb9ebe5 100644 --- a/zephyr/mphalport.h +++ b/zephyr/mphalport.h @@ -1 +1,27 @@ -static inline mp_uint_t mp_hal_ticks_ms(void) { return 0; } +#include +#include "lib/utils/interrupt_char.h" + +static inline mp_uint_t mp_hal_ticks_us(void) { + return sys_tick_get() * sys_clock_us_per_tick; +} + +static inline mp_uint_t mp_hal_ticks_ms(void) { + int64_t us = sys_tick_get() * sys_clock_us_per_tick; + mp_int_t ms = us / 1000; + return ms; +} + +static inline mp_uint_t mp_hal_ticks_cpu(void) { + // ticks_cpu() is defined as using the highest-resolution timing source + // in the system. This is usually a CPU clock, but doesn't have to be, + // here we just use Zephyr hi-res timer. + return sys_cycle_get_32(); +} + +static inline void mp_hal_delay_us(mp_uint_t delay) { + k_busy_wait(delay); +} + +static inline void mp_hal_delay_ms(mp_uint_t delay) { + k_sleep(delay); +} diff --git a/zephyr/prj.conf b/zephyr/prj.conf index 35cb036ded..0b0827d25f 100644 --- a/zephyr/prj.conf +++ b/zephyr/prj.conf @@ -1,4 +1,5 @@ CONFIG_STDOUT_CONSOLE=y CONFIG_CONSOLE_HANDLER=y +CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS=y CONFIG_NEWLIB_LIBC=y CONFIG_FLOAT=y diff --git a/zephyr/src/zephyr_getchar.c b/zephyr/src/zephyr_getchar.c index 89e3e0efbc..0f673c9c80 100644 --- a/zephyr/src/zephyr_getchar.c +++ b/zephyr/src/zephyr_getchar.c @@ -28,7 +28,7 @@ static struct nano_sem uart_sem; static uint8_t uart_ringbuf[UART_BUFSIZE]; static uint8_t i_get, i_put; -static int console_irq_input_hook(struct device *dev, uint8_t ch) +static int console_irq_input_hook(uint8_t ch) { int i_next = (i_put + 1) & (UART_BUFSIZE - 1); if (i_next == i_get) { @@ -58,8 +58,7 @@ uint8_t zephyr_getchar(void) { void zephyr_getchar_init(void) { nano_sem_init(&uart_sem); - struct device *uart_console_dev = device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME); - uart_irq_input_hook_set(uart_console_dev, console_irq_input_hook); + uart_console_in_debug_hook_install(console_irq_input_hook); // All NULLs because we're interested only in the callback above uart_register_input(NULL, NULL, NULL); }